Skip to content

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

Merged
merged 11 commits into from
Nov 21, 2022
Merged

Conversation

mgol
Copy link
Member

@mgol mgol commented Aug 10, 2022

Summary

Due to the change of scope for 4.0.0, this re-introduces the selector-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. Fixed

Ref gh-4395

Checklist

@mgol mgol added Selector Needs review Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. labels Aug 10, 2022
@mgol mgol added this to the 4.0.0 milestone Aug 10, 2022
@mgol mgol requested review from timmywil and gibson042 August 10, 2022 22:45
@mgol mgol self-assigned this Aug 10, 2022
@@ -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 );
Copy link
Member Author

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.

@mgol
Copy link
Member Author

mgol commented Aug 14, 2022

CI is green now.

*/
const excluder = flag => {
let additional;
const m = /^(\+|\-|)([\w\/-]+)$/.exec( flag );
const m = /^(\+|-|)([\w\/-]+)$/.exec( flag );
Copy link
Member Author

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.

@timmywil timmywil removed the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Aug 26, 2022
@mgol mgol added the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Sep 21, 2022
mgol added a commit to mgol/jquery that referenced this pull request Sep 21, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass.
mgol added a commit to mgol/jquery that referenced this pull request Sep 21, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass.
mgol added a commit to mgol/jquery that referenced this pull request Sep 21, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus
a few other fixes.
@mgol mgol removed the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Sep 21, 2022
mgol added a commit to mgol/jquery that referenced this pull request Sep 21, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus
a few other fixes.
@mgol mgol added the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Oct 3, 2022
mgol added a commit to mgol/jquery that referenced this pull request Oct 3, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus
a few other fixes.
mgol added a commit to mgol/jquery that referenced this pull request Oct 4, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus
a few other fixes.
@mgol mgol force-pushed the selector-native branch from acdd7b7 to 4072c20 Compare October 7, 2022 14:47
@timmywil timmywil removed the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Oct 10, 2022
@mgol mgol requested a review from gibson042 October 10, 2022 17:54
Comment on lines 16 to 17
* Requiring all parts of a selector to match elements under context
* (e.g., $div.find("div > *") now matches children of $div)
Copy link
Member

@gibson042 gibson042 Oct 10, 2022

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 + " ")

Copy link
Member Author

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?

Copy link
Member

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.

Copy link
Member Author

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?

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

@timmywil timmywil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

mgol added a commit to mgol/jquery that referenced this pull request Nov 17, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus
a few other fixes.
@mgol mgol added the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Nov 17, 2022
@mgol mgol requested a review from gibson042 November 17, 2022 15:19
@timmywil timmywil removed Needs review Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. labels Nov 21, 2022
@mgol mgol merged commit 4c1171f into jquery:main Nov 21, 2022
@mgol mgol deleted the selector-native branch November 21, 2022 22:23
mgol added a commit to mgol/jquery that referenced this pull request Dec 1, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus
a few other fixes.
mgol added a commit to mgol/jquery that referenced this pull request Dec 13, 2022
Backport some changes from jquerygh-5085 to make selector-native tests pass. Plus
a few other fixes.
mgol added a commit to mgol/jquery that referenced this pull request Dec 22, 2022
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
mgol added a commit to mgol/jquery that referenced this pull request Feb 11, 2023
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
mgol added a commit that referenced this pull request Feb 13, 2023
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

3 participants