-
Notifications
You must be signed in to change notification settings - Fork 20.6k
Selector: Re-introduce selector-native.js #5085
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -1,7 +1,7 @@ | |||
QUnit.module( "selector", { | |||
beforeEach: function() { | |||
this.safari = /\bsafari\b/i.test( navigator.userAgent ) && | |||
!/\bchrome\b/i.test( navigator.userAgent ); | |||
!/\b(?:headless)?chrome\b/i.test( navigator.userAgent ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests in CI are running on Chrome Headless which has a different user agent, making this.safari === true
. This is what caused the original test failures; it was just a test issue.
CI is green now. |
*/ | ||
const excluder = flag => { | ||
let additional; | ||
const m = /^(\+|\-|)([\w\/-]+)$/.exec( flag ); | ||
const m = /^(\+|-|)([\w\/-]+)$/.exec( flag ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was just WebStorm complaining that the escape was not necessary.
d322d87
to
09d7eaf
Compare
Backport some changes from jquerygh-5085 to make selector-native tests pass.
9ad788a
to
acdd7b7
Compare
Backport some changes from jquerygh-5085 to make selector-native tests pass.
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus a few other fixes.
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus a few other fixes.
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus a few other fixes.
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus a few other fixes.
src/selector-native.js
Outdated
* Requiring all parts of a selector to match elements under context | ||
* (e.g., $div.find("div > *") now matches children of $div) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this a step too far... would it be worthwhile to preserve that jQuery behavior by filtering querySelectorAll
results like e.g. elem => jQuery.find.matchesSelector( elem, "#" + ephemeralId + " *" )
or elem => jQuery.contains( context, elem )
?
There's also a larger but more performant version of the former using rudimentary selector transformation, e.g.
// Prefix each item in the `selector` list with a scope prefix.
var match,
extracts = [],
// Helper here for clarity, inlining at its two call sites probably compresses better.
restore = s => s.replace( /'(\d+)'/g, (_, i) => extracts[ i - 1 ] );
// Temporarily replace backslash escapes and strings,
// which could otherwise disrupt identification of the list's constituent selectors
// (e.g., `a\\,[attr*='foo,bar']`)
selector = selector.replace(
/\\[^]|(['"])(?:\\[^]|(?!\1)[^\\])*\1/g,
s => "'" + extracts.push( s ) + "'"
);
// Likewise for functional pseudo-classes, but recursively
// (e.g., `:not(:is(h1,h2), article header)`).
while ( (match = /([^]*?)(\([^()]*,[^()]*\))([^]*)/.exec(selector)) ) {
selector = match[ 1 ] +
"'" + extracts.push( restore( match[ 2 ] ) ) + "'" +
match[ 3 ];
}
// Prefix and restore replacements in each selector of the list.
selector = selector.replace(
/[^,]+/g,
// ...but don't prefix selectors that already start with a :scope pseudo.
sel => restore( sel )
.replace( /^(?![ \t\r\n\f]*:scope(?![\\\w-]|[^\0-\x7f]))/, scopePrefix )
);
(where scopePrefix
is either ":scope "
or "#" + ephemeralId + " "
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gibson042 The issue is not that the results are not children of the context but that not the whole selector matches the contents part. It seems to me that just checking elem => jQuery.find.matchesSelector( elem, "#" + ephemeralId + " *" )
or elem => jQuery.contains( context, elem )
doesn't find those issues?
To make sure the whole selector matches within the context, we'd need to first split the selector list into individual selectors which requires some parsing; that would make selector-native
much larger. Am I missing anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that's right. It would not be covered by the simple filters, but would be covered by the rewriting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, would you like any further changes to this module for 4.0.0
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That behavioral seems really severe to me, but if consumers tolerate it then I guess it's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gibson042 I'm checking this right now but would you mind merging this PR as-is and exploring such an extension in a separate one? This PR largely restores the current 3.x version of selector-native
so I feel it'd be beneficial to separate extending it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preliminary checks seem to indicate resolving this issue would cost about 1000 bytes minified gzipped; it'd still be 3300 bytes minified gzipped smaller than the full build compared to 4300 bytes minified gzipped without this change.
@timmywil @gibson042 what do you think? Is it a good idea? I can prepare a POC PR. I'd still like to keep it separate from this one, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with separating it, since selector-native has always had such a limitation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created #5185 to track this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...and a PR to review: #5186.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Chrome Headless has a different user agent than Safari and our check didn't take that into account.
Previously, they were loaded after test files which meant top level usage was not evaluated correctly.
Co-authored-by: Richard Gibson <richard.gibson@gmail.com>
8e102f3
to
5167381
Compare
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus a few other fixes.
8244a93
to
733f55f
Compare
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus a few other fixes.
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus a few other fixes.
This makes: ```js $div.find("div > *") ``` no longer matching children of `$div`. Also, leading combinators now work, e.g.: ```js $div.find( "> *" ); ``` returns children of `$div`. As a result of that, a number of tests are no longer skipped in the `selector-native` mode. Fixes jquerygh-5185 Ref jquerygh-5085
This makes: ```js $div.find("div > *") ``` no longer matching children of `$div`. Also, leading combinators now work, e.g.: ```js $div.find( "> *" ); ``` returns children of `$div`. As a result of that, a number of tests are no longer skipped in the `selector-native` mode. Fixes jquerygh-5185 Ref jquerygh-5085
This makes: ```js $div.find("div > *") ``` no longer matching children of `$div`. Also, leading combinators now work, e.g.: ```js $div.find( "> *" ); ``` returns children of `$div`. As a result of that, a number of tests are no longer skipped in the `selector-native` mode. Also, rename `rcombinators` to `rleadingCombinator`. Fixes gh-5185 Closes gh-5186 Ref gh-5085
Summary
Due to the change of scope for
4.0.0
, this re-introduces theselector-native
module (removed in gh-4395) known from jQuery 3.x.I wasn't sure what to name it as we shouldn't use the name Sizzle anymore so I opted for
selector-full
. Suggestions for better naming welcome.There are two selector tests that I still need to fix.FixedRef gh-4395
Checklist
If needed, a docs issue/PR was created at https://github.com/jquery/api.jquery.com