Skip to content
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

Fix selector-attribute-quotes false positives for "never" #6571

Merged
merged 10 commits into from Jan 27, 2023

Conversation

mattxwang
Copy link
Member

@mattxwang mattxwang commented Jan 9, 2023

Which issue, if any, is this issue related to?

Closes #4300.

Is there anything in the PR that needs further explanation?

First - should I add some documentation to explain this new behaviour? Or do we think the current setup is enough.

There's a bit of discussion in #4300. To reiterate @Mouvedia's point:

so to me

[href='te\'s\'t'] { }
[href="te\"s\"t"] { }

can be processed and become

[href=te\'s\'t] { }
[href=te\"s\"t] { }

but

[href="te'st"] { }
[href='te"st'] { }

should remain untouched.

As such, I've adjusted the relevant test cases. The latter two are moved from being rejected to accepted; let me know if that was the desired change (or if instead we should still report, but not fix).

Regex alternative

I realized that the CSS grammar actually has a FLEX tokenizer, so I tried to directly copy the rule as a Regex:

// directly taken from spec: https://www.w3.org/TR/CSS21/grammar.html#scanner
const h = "[0-9a-f]";
const nonascii = "[\\240-\\377]";
const unicode = "\\\\{h}{1,6}(\\r\\n|[ \\t\\r\\n\\f])?".replace("{h}", h);
const escape = "({unicode}|\\\\[^\\r\\n\\f0-9a-fA-F])".replace("{unicode}", unicode);
const nmstart = "([_a-zA-Z]|{nonascii}|{escape})".replace("{nonascii}", nonascii).replace("{escape}", escape);
const nmchar = "([_a-zA-Z0-9-]|{nonascii}|{escape})".replace("{nonascii}", nonascii).replace("{escape}", escape);
const identifier = "-?{nmstart}{nmchar}*".replace("{nmstart}", nmstart).replace("{nmchar}", nmchar);
	
return Boolean(ident.match(identifier));

Unfortunately, this doesn't work! It misses some "basic" cases, including strings with spaces in them. If anybody has any ideas on what I've done wrong, that would be great - I feel like using the CSS spec when possible seems like a good idea.

@changeset-bot
Copy link

changeset-bot bot commented Jan 9, 2023

🦋 Changeset detected

Latest commit: e6d6781

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
stylelint Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Member Author

@mattxwang mattxwang left a comment

Choose a reason for hiding this comment

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

This ended up being a bit more of a deep dive into the CSS spec than I thought! I think this PR is now ready for review. I've left some comments where I'm unsure of how I'm doing.

lib/rules/selector-attribute-quotes/index.js Show resolved Hide resolved
@@ -0,0 +1,41 @@
'use strict';

Copy link
Member Author

Choose a reason for hiding this comment

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

Should this be its own file? And hopefully, I haven't missed an existing version of this util!

Comment on lines 19 to 38
// trims, removes ISO 10646 characters, and singly-escaped characters
const trimmedIdent = ident
.trim()
.replace(/\\[0-9a-f]{1,6}(\\r\\n|[ \t\r\n\f])?/gi, '')
.replace(/\\./g, '');

// characters that are not alphanumeric, hyphen or underscore
if (trimmedIdent.match(/[^\w-]/)) {
return false;
}

// ident has a leading digit
if (hasDigitAt(0)) {
return false;
}

// ident has a leading dash followed by a digit or a dash
if (trimmedIdent.charAt(0) === '-' && (hasDigitAt(1) || trimmedIdent.charAt(1) === '-')) {
return false;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Would we prefer for me to collapse this into one expression? I did it this way since I felt that it was more naturally readable.

Alt: see my note on the full FLEX-based regex option.

@mattxwang mattxwang marked this pull request as ready for review January 17, 2023 07:52
* @param {string} ident
* @returns {boolean}
*/
module.exports = function isValidIdentifier(ident) {
Copy link
Contributor

@Mouvedia Mouvedia Jan 18, 2023

Choose a reason for hiding this comment

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

question

I dunno the stylelint conventions, but did you check if an npm package already existed?
Even if it does maybe we recommend not relying on dependencies whenever possible.
Iv done an id assert package for HTML/XML so I wouldn't be surprised if something similar existed for your case.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm, to be honest I didn't look too in-depth; I did a quick site:npmjs.com valid css identifier and found nothing on the first page or so of Google (much more support for valid JS identifiers or CSS selectors). If you're aware of one and we think we should use it though, happy to refactor!

lib/utils/isValidIdentifier.js Outdated Show resolved Hide resolved
lib/utils/isValidIdentifier.js Outdated Show resolved Hide resolved
lib/utils/isValidIdentifier.js Outdated Show resolved Hide resolved
lib/utils/isValidIdentifier.js Outdated Show resolved Hide resolved
mattxwang and others added 2 commits January 26, 2023 08:11
Co-authored-by: Masafumi Koba <473530+ybiquitous@users.noreply.github.com>
@mattxwang
Copy link
Member Author

Thanks for the quick review @ybiquitous! Think I've addressed each of the comments, let me know what you think.

@ybiquitous ybiquitous changed the title Fix false positives for "never" in selector-attribute-quotes Fix selector-attribute-quotes false positives for "never" Jan 27, 2023
Copy link
Member

@ybiquitous ybiquitous left a comment

Choose a reason for hiding this comment

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

Thank you. LGTM 👍🏼

.changeset/chilly-ties-trade.md Outdated Show resolved Hide resolved
Co-authored-by: Masafumi Koba <473530+ybiquitous@users.noreply.github.com>
@mattxwang mattxwang merged commit b447409 into main Jan 27, 2023
@mattxwang mattxwang deleted the selector-attribute-quotes-never-false-positives branch January 27, 2023 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Fix false positives for "never" in selector-attribute-quotes
3 participants