aboutsummaryrefslogtreecommitdiffstats
path: root/src/selector.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/selector.js')
-rw-r--r--src/selector.js380
1 files changed, 63 insertions, 317 deletions
diff --git a/src/selector.js b/src/selector.js
index 117ee3051..328eca45f 100644
--- a/src/selector.js
+++ b/src/selector.js
@@ -1,7 +1,6 @@
import jQuery from "./core.js";
import nodeName from "./core/nodeName.js";
import document from "./var/document.js";
-import documentElement from "./var/documentElement.js";
import indexOf from "./var/indexOf.js";
import pop from "./var/pop.js";
import push from "./var/push.js";
@@ -9,19 +8,31 @@ import whitespace from "./var/whitespace.js";
import rbuggyQSA from "./selector/rbuggyQSA.js";
import rtrim from "./var/rtrim.js";
import isIE from "./var/isIE.js";
+import identifier from "./selector/var/identifier.js";
+import booleans from "./selector/var/booleans.js";
+import rleadingCombinator from "./selector/var/rleadingCombinator.js";
+import rdescend from "./selector/var/rdescend.js";
+import rsibling from "./selector/var/rsibling.js";
+import matches from "./selector/var/matches.js";
+import createCache from "./selector/createCache.js";
+import testContext from "./selector/testContext.js";
+import filterMatchExpr from "./selector/filterMatchExpr.js";
+import preFilter from "./selector/preFilter.js";
+import selectorError from "./selector/selectorError.js";
+import unescapeSelector from "./selector/unescapeSelector.js";
+import tokenize from "./selector/tokenize.js";
+import toSelector from "./selector/toSelector.js";
import support from "./selector/support.js";
// The following utils are attached directly to the jQuery object.
import "./selector/escapeSelector.js";
import "./selector/uniqueSort.js";
-var preferredDoc = document,
- matches = documentElement.matches || documentElement.msMatchesSelector;
+var preferredDoc = document;
( function() {
var i,
- Expr,
outermostContext,
// Local document vars
@@ -30,67 +41,20 @@ var i,
documentIsHTML,
// Instance-specific data
- expando = jQuery.expando,
dirruns = 0,
done = 0,
classCache = createCache(),
- tokenCache = createCache(),
compilerCache = createCache(),
nonnativeSelectorCache = createCache(),
- booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" +
- "loop|multiple|open|readonly|required|scoped",
-
// Regular expressions
- // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
- identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
- "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",
-
- // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors
- attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
-
- // Operator (capture 2)
- "*([*^$|!~]?=)" + whitespace +
-
- // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
- "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
- whitespace + "*\\]",
-
- pseudos = ":(" + identifier + ")(?:\\((" +
-
- // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
- // 1. quoted (capture 3; capture 4 or capture 5)
- "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
-
- // 2. simple (capture 6)
- "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
-
- // 3. anything else (capture 2)
- ".*" +
- ")\\)|)",
-
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
rwhitespace = new RegExp( whitespace + "+", "g" ),
- rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" +
- whitespace + "*" ),
- rdescend = new RegExp( whitespace + "|>" ),
-
- rpseudo = new RegExp( pseudos ),
ridentifier = new RegExp( "^" + identifier + "$" ),
- matchExpr = {
- ID: new RegExp( "^#(" + identifier + ")" ),
- CLASS: new RegExp( "^\\.(" + identifier + ")" ),
- TAG: new RegExp( "^(" + identifier + "|[*])" ),
- ATTR: new RegExp( "^" + attributes ),
- PSEUDO: new RegExp( "^" + pseudos ),
- CHILD: new RegExp(
- "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
- whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
- whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ matchExpr = jQuery.extend( {
bool: new RegExp( "^(?:" + booleans + ")$", "i" ),
// For use in libraries implementing .is()
@@ -98,7 +62,7 @@ var i,
needsContext: new RegExp( "^" + whitespace +
"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
"*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
- },
+ }, filterMatchExpr ),
rinputs = /^(?:input|select|textarea|button)$/i,
rheader = /^h\d$/i,
@@ -106,30 +70,6 @@ var i,
// Easily-parseable/retrievable ID or TAG or CLASS selectors
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
- rsibling = /[+~]/,
-
- // CSS escapes
- // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters
- runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace +
- "?|\\\\([^\\r\\n\\f])", "g" ),
- funescape = function( escape, nonHex ) {
- var high = "0x" + escape.slice( 1 ) - 0x10000;
-
- if ( nonHex ) {
-
- // Strip the backslash prefix from a non-hex escape sequence
- return nonHex;
- }
-
- // Replace a hexadecimal escape sequence with the encoded Unicode code point
- // Support: IE <=11+
- // For values outside the Basic Multilingual Plane (BMP), manually construct a
- // surrogate pair
- return high < 0 ?
- String.fromCharCode( high + 0x10000 ) :
- String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- },
-
// Used for iframes; see `setDocument`.
// Support: IE 9 - 11+
// Removing the function wrapper causes a "Permission Denied"
@@ -145,10 +85,6 @@ var i,
{ dir: "parentNode", next: "legend" }
);
-function selectorError( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
-}
-
function find( selector, context, results, seed ) {
var m, i, elem, nid, match, groups, newSelector,
newContext = context && context.ownerDocument,
@@ -223,10 +159,11 @@ function find( selector, context, results, seed ) {
// as such selectors are not recognized by querySelectorAll.
// Thanks to Andrew Dupont for this technique.
if ( nodeType === 1 &&
- ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {
+ ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) {
// Expand context for sibling selectors
- newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ newContext = rsibling.test( selector ) &&
+ testContext( context.parentNode ) ||
context;
// Outside of IE, if we're not changing the context we can
@@ -237,7 +174,7 @@ function find( selector, context, results, seed ) {
if ( ( nid = context.getAttribute( "id" ) ) ) {
nid = jQuery.escapeSelector( nid );
} else {
- context.setAttribute( "id", ( nid = expando ) );
+ context.setAttribute( "id", ( nid = jQuery.expando ) );
}
}
@@ -285,7 +222,7 @@ function find( selector, context, results, seed ) {
} catch ( qsaError ) {
nonnativeSelectorCache( selector, true );
} finally {
- if ( nid === expando ) {
+ if ( nid === jQuery.expando ) {
context.removeAttribute( "id" );
}
}
@@ -298,34 +235,11 @@ function find( selector, context, results, seed ) {
}
/**
- * Create key-value caches of limited size
- * @returns {function(string, object)} Returns the Object data after storing it on itself with
- * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
- * deleting the oldest entry
- */
-function createCache() {
- var keys = [];
-
- function cache( key, value ) {
-
- // Use (key + " ") to avoid collision with native prototype properties
- // (see https://github.com/jquery/sizzle/issues/157)
- if ( keys.push( key + " " ) > Expr.cacheLength ) {
-
- // Only keep the most recent entries
- delete cache[ keys.shift() ];
- }
- return ( cache[ key + " " ] = value );
- }
- return cache;
-}
-
-/**
* Mark a function for special use by jQuery selector module
* @param {Function} fn The function to mark
*/
function markFunction( fn ) {
- fn[ expando ] = true;
+ fn[ jQuery.expando ] = true;
return fn;
}
@@ -428,15 +342,6 @@ function createPositionalPseudo( fn ) {
}
/**
- * Checks a node for validity as a jQuery selector context
- * @param {Element|Object=} context
- * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
- */
-function testContext( context ) {
- return context && typeof context.getElementsByTagName !== "undefined" && context;
-}
-
-/**
* Sets document-related variables once based on the current document
* @param {Element|Object} [node] An element or document object to use to set the document
*/
@@ -491,7 +396,7 @@ find.matchesSelector = function( elem, expr ) {
return find( expr, document, null, [ elem ] ).length > 0;
};
-Expr = jQuery.expr = {
+jQuery.expr = {
// Can be adjusted by the user
cacheLength: 50,
@@ -532,99 +437,18 @@ Expr = jQuery.expr = {
"~": { dir: "previousSibling" }
},
- preFilter: {
- ATTR: function( match ) {
- match[ 1 ] = match[ 1 ].replace( runescape, funescape );
-
- // Move the given value to match[3] whether quoted or unquoted
- match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" )
- .replace( runescape, funescape );
-
- if ( match[ 2 ] === "~=" ) {
- match[ 3 ] = " " + match[ 3 ] + " ";
- }
-
- return match.slice( 0, 4 );
- },
-
- CHILD: function( match ) {
-
- /* matches from matchExpr["CHILD"]
- 1 type (only|nth|...)
- 2 what (child|of-type)
- 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
- 4 xn-component of xn+y argument ([+-]?\d*n|)
- 5 sign of xn-component
- 6 x of xn-component
- 7 sign of y-component
- 8 y of y-component
- */
- match[ 1 ] = match[ 1 ].toLowerCase();
-
- if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {
-
- // nth-* requires argument
- if ( !match[ 3 ] ) {
- selectorError( match[ 0 ] );
- }
-
- // numeric x and y parameters for Expr.filter.CHILD
- // remember that false/true cast respectively to 0/1
- match[ 4 ] = +( match[ 4 ] ?
- match[ 5 ] + ( match[ 6 ] || 1 ) :
- 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" )
- );
- match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
-
- // other types prohibit arguments
- } else if ( match[ 3 ] ) {
- selectorError( match[ 0 ] );
- }
-
- return match;
- },
-
- PSEUDO: function( match ) {
- var excess,
- unquoted = !match[ 6 ] && match[ 2 ];
-
- if ( matchExpr.CHILD.test( match[ 0 ] ) ) {
- return null;
- }
-
- // Accept quoted arguments as-is
- if ( match[ 3 ] ) {
- match[ 2 ] = match[ 4 ] || match[ 5 ] || "";
-
- // Strip excess characters from unquoted arguments
- } else if ( unquoted && rpseudo.test( unquoted ) &&
-
- // Get excess from tokenize (recursively)
- ( excess = tokenize( unquoted, true ) ) &&
-
- // advance to the next closing parenthesis
- ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) {
-
- // excess is a negative index
- match[ 0 ] = match[ 0 ].slice( 0, excess );
- match[ 2 ] = unquoted.slice( 0, excess );
- }
-
- // Return only captures needed by the pseudo filter method (type and argument)
- return match.slice( 0, 3 );
- }
- },
+ preFilter: preFilter,
filter: {
ID: function( id ) {
- var attrId = id.replace( runescape, funescape );
+ var attrId = unescapeSelector( id );
return function( elem ) {
return elem.getAttribute( "id" ) === attrId;
};
},
TAG: function( nodeNameSelector ) {
- var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ var expectedNodeName = unescapeSelector( nodeNameSelector ).toLowerCase();
return nodeNameSelector === "*" ?
function() {
@@ -739,7 +563,8 @@ Expr = jQuery.expr = {
if ( forward && useCache ) {
// Seek `elem` from a previously-cached index
- outerCache = parent[ expando ] || ( parent[ expando ] = {} );
+ outerCache = parent[ jQuery.expando ] ||
+ ( parent[ jQuery.expando ] = {} );
cache = outerCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex && cache[ 2 ];
@@ -761,7 +586,8 @@ Expr = jQuery.expr = {
// Use previously-cached element index if available
if ( useCache ) {
- outerCache = elem[ expando ] || ( elem[ expando ] = {} );
+ outerCache = elem[ jQuery.expando ] ||
+ ( elem[ jQuery.expando ] = {} );
cache = outerCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex;
@@ -782,8 +608,8 @@ Expr = jQuery.expr = {
// Cache the index of each encountered element
if ( useCache ) {
- outerCache = node[ expando ] ||
- ( node[ expando ] = {} );
+ outerCache = node[ jQuery.expando ] ||
+ ( node[ jQuery.expando ] = {} );
outerCache[ type ] = [ dirruns, diff ];
}
@@ -808,13 +634,14 @@ Expr = jQuery.expr = {
// https://www.w3.org/TR/selectors/#pseudo-classes
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
// Remember that setFilters inherits from pseudos
- var fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ var fn = jQuery.expr.pseudos[ pseudo ] ||
+ jQuery.expr.setFilters[ pseudo.toLowerCase() ] ||
selectorError( "unsupported pseudo: " + pseudo );
// The user may use createPseudo to indicate that
// arguments are needed to create the filter function
// just as jQuery does
- if ( fn[ expando ] ) {
+ if ( fn[ jQuery.expando ] ) {
return fn( argument );
}
@@ -834,7 +661,7 @@ Expr = jQuery.expr = {
results = [],
matcher = compile( selector.replace( rtrim, "$1" ) );
- return matcher[ expando ] ?
+ return matcher[ jQuery.expando ] ?
markFunction( function( seed, matches, _context, xml ) {
var elem,
unmatched = matcher( seed, null, xml, [] ),
@@ -865,7 +692,7 @@ Expr = jQuery.expr = {
} ),
contains: markFunction( function( text ) {
- text = text.replace( runescape, funescape );
+ text = unescapeSelector( text );
return function( elem ) {
return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;
};
@@ -884,7 +711,7 @@ Expr = jQuery.expr = {
if ( !ridentifier.test( lang || "" ) ) {
selectorError( "unsupported lang: " + lang );
}
- lang = lang.replace( runescape, funescape ).toLowerCase();
+ lang = unescapeSelector( lang ).toLowerCase();
return function( elem ) {
var elemLang;
do {
@@ -958,7 +785,7 @@ Expr = jQuery.expr = {
},
parent: function( elem ) {
- return !Expr.pseudos.empty( elem );
+ return !jQuery.expr.pseudos.empty( elem );
},
// Element/input types
@@ -1035,102 +862,20 @@ Expr = jQuery.expr = {
}
};
-Expr.pseudos.nth = Expr.pseudos.eq;
+jQuery.expr.pseudos.nth = jQuery.expr.pseudos.eq;
// Add button/input type pseudos
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
- Expr.pseudos[ i ] = createInputPseudo( i );
+ jQuery.expr.pseudos[ i ] = createInputPseudo( i );
}
for ( i in { submit: true, reset: true } ) {
- Expr.pseudos[ i ] = createButtonPseudo( i );
+ jQuery.expr.pseudos[ i ] = createButtonPseudo( i );
}
// Easy API for creating new setFilters
function setFilters() {}
-setFilters.prototype = Expr.filters = Expr.pseudos;
-Expr.setFilters = new setFilters();
-
-function tokenize( selector, parseOnly ) {
- var matched, match, tokens, type,
- soFar, groups, preFilters,
- cached = tokenCache[ selector + " " ];
-
- if ( cached ) {
- return parseOnly ? 0 : cached.slice( 0 );
- }
-
- soFar = selector;
- groups = [];
- preFilters = Expr.preFilter;
-
- while ( soFar ) {
-
- // Comma and first run
- if ( !matched || ( match = rcomma.exec( soFar ) ) ) {
- if ( match ) {
-
- // Don't consume trailing commas as valid
- soFar = soFar.slice( match[ 0 ].length ) || soFar;
- }
- groups.push( ( tokens = [] ) );
- }
-
- matched = false;
-
- // Combinators
- if ( ( match = rcombinators.exec( soFar ) ) ) {
- matched = match.shift();
- tokens.push( {
- value: matched,
-
- // Cast descendant combinators to space
- type: match[ 0 ].replace( rtrim, " " )
- } );
- soFar = soFar.slice( matched.length );
- }
-
- // Filters
- for ( type in Expr.filter ) {
- if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||
- ( match = preFilters[ type ]( match ) ) ) ) {
- matched = match.shift();
- tokens.push( {
- value: matched,
- type: type,
- matches: match
- } );
- soFar = soFar.slice( matched.length );
- }
- }
-
- if ( !matched ) {
- break;
- }
- }
-
- // Return the length of the invalid excess
- // if we're just parsing
- // Otherwise, throw an error or return tokens
- if ( parseOnly ) {
- return soFar.length;
- }
-
- return soFar ?
- selectorError( selector ) :
-
- // Cache the tokens
- tokenCache( selector, groups ).slice( 0 );
-}
-
-function toSelector( tokens ) {
- var i = 0,
- len = tokens.length,
- selector = "";
- for ( ; i < len; i++ ) {
- selector += tokens[ i ].value;
- }
- return selector;
-}
+setFilters.prototype = jQuery.expr.filters = jQuery.expr.pseudos;
+jQuery.expr.setFilters = new setFilters();
function addCombinator( matcher, combinator, base ) {
var dir = combinator.dir,
@@ -1168,7 +913,7 @@ function addCombinator( matcher, combinator, base ) {
} else {
while ( ( elem = elem[ dir ] ) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
- outerCache = elem[ expando ] || ( elem[ expando ] = {} );
+ outerCache = elem[ jQuery.expando ] || ( elem[ jQuery.expando ] = {} );
if ( skip && nodeName( elem, skip ) ) {
elem = elem[ dir ] || elem;
@@ -1239,10 +984,10 @@ function condense( unmatched, map, filter, context, xml ) {
}
function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
- if ( postFilter && !postFilter[ expando ] ) {
+ if ( postFilter && !postFilter[ jQuery.expando ] ) {
postFilter = setMatcher( postFilter );
}
- if ( postFinder && !postFinder[ expando ] ) {
+ if ( postFinder && !postFinder[ jQuery.expando ] ) {
postFinder = setMatcher( postFinder, postSelector );
}
return markFunction( function( seed, results, context, xml ) {
@@ -1340,8 +1085,8 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS
function matcherFromTokens( tokens ) {
var checkContext, matcher, j,
len = tokens.length,
- leadingRelative = Expr.relative[ tokens[ 0 ].type ],
- implicitRelative = leadingRelative || Expr.relative[ " " ],
+ leadingRelative = jQuery.expr.relative[ tokens[ 0 ].type ],
+ implicitRelative = leadingRelative || jQuery.expr.relative[ " " ],
i = leadingRelative ? 1 : 0,
// The foundational matcher ensures that elements are reachable from top-level context(s)
@@ -1364,18 +1109,18 @@ function matcherFromTokens( tokens ) {
} ];
for ( ; i < len; i++ ) {
- if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {
+ if ( ( matcher = jQuery.expr.relative[ tokens[ i ].type ] ) ) {
matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
} else {
- matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
+ matcher = jQuery.expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
// Return special upon seeing a positional matcher
- if ( matcher[ expando ] ) {
+ if ( matcher[ jQuery.expando ] ) {
// Find the next relative operator (if any) for proper handling
j = ++i;
for ( ; j < len; j++ ) {
- if ( Expr.relative[ tokens[ j ].type ] ) {
+ if ( jQuery.expr.relative[ tokens[ j ].type ] ) {
break;
}
}
@@ -1412,7 +1157,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
contextBackup = outermostContext,
// We must always have either seed elements or outermost context
- elems = seed || byElement && Expr.find.TAG( "*", outermost ),
+ elems = seed || byElement && jQuery.expr.find.TAG( "*", outermost ),
// Use integer dirruns iff this is the outermost matcher
dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 );
@@ -1537,7 +1282,7 @@ function compile( selector, match /* Internal Use Only */ ) {
i = match.length;
while ( i-- ) {
cached = matcherFromTokens( match[ i ] );
- if ( cached[ expando ] ) {
+ if ( cached[ jQuery.expando ] ) {
setMatchers.push( cached );
} else {
elementMatchers.push( cached );
@@ -1577,10 +1322,11 @@ function select( selector, context, results, seed ) {
// Reduce context if the leading compound selector is an ID
tokens = match[ 0 ] = match[ 0 ].slice( 0 );
if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
- context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
+ context.nodeType === 9 && documentIsHTML &&
+ jQuery.expr.relative[ tokens[ 1 ].type ] ) {
- context = ( Expr.find.ID(
- token.matches[ 0 ].replace( runescape, funescape ),
+ context = ( jQuery.expr.find.ID(
+ unescapeSelector( token.matches[ 0 ] ),
context
) || [] )[ 0 ];
if ( !context ) {
@@ -1600,14 +1346,14 @@ function select( selector, context, results, seed ) {
token = tokens[ i ];
// Abort if we hit a combinator
- if ( Expr.relative[ ( type = token.type ) ] ) {
+ if ( jQuery.expr.relative[ ( type = token.type ) ] ) {
break;
}
- if ( ( find = Expr.find[ type ] ) ) {
+ if ( ( find = jQuery.expr.find[ type ] ) ) {
// Search, expanding context for leading sibling combinators
if ( ( seed = find(
- token.matches[ 0 ].replace( runescape, funescape ),
+ unescapeSelector( token.matches[ 0 ] ),
rsibling.test( tokens[ 0 ].type ) &&
testContext( context.parentNode ) || context
) ) ) {