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

feat: baseline rule #33

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

feat: baseline rule #33

wants to merge 9 commits into from

Conversation

nzakas
Copy link
Member

@nzakas nzakas commented Dec 12, 2024

Prerequisites checklist

What is the purpose of this pull request?

Create a rule that warns when non-baseline features are used.

What changes did you make? (Give an overview)

  • Added baseline rule
  • Added tests and docs
  • Created a tool to generate baseline data

Related Issues

fixes #26

Is there anything you'd like reviewers to focus on?

  • I'm not 100% sure that the baseline data matches what's on the website. The web-features package doesn't tag things as "widely" or "newly", just "high", "low", or false. I started with the assumption that "high" means "widely" and "low" means "newly", but I'm not sure that's correct. high = widely, low = newly
  • I set this as recommended, as it seems like it would generally be useful, but definitely open to feedback on that.

@jamesnw
Copy link

jamesnw commented Dec 12, 2024

  • I'm not 100% sure that the baseline data matches what's on the website. The web-features package doesn't tag things as "widely" or "newly", just "high", "low", or false. I started with the assumption that "high" means "widely" and "low" means "newly", but I'm not sure that's correct.

Web Features contributor here- your assumption is correct.

low = Newly available: The feature works across the latest devices and browser versions. The feature might not work in older devices or browsers.

high = Widely available: The feature is well established and works across many devices and browser versions. It’s been available across browsers for at least 2½ years (30 months).

false = Limited availability: Some but not all of the latest devices and browser versions support it, and it might not work, even in up to date devices and browsers.

Thanks for doing this!

Copy link

@jamesnw jamesnw left a comment

Choose a reason for hiding this comment

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

This is really exciting to see!

I added a few comments that may help with feature detection. The keys that are used in the web-features package are defined by BCD. While I think they can get you pretty close on feature detection, that isn't the intended use necessarily, and I suspect there will be some edge cases.

["color", 10],
["color-scheme", 10],
["break-after", 0],
["break-after.multicol_context", 0],
Copy link

Choose a reason for hiding this comment

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

This is an example of a contextual modifier on the BCD key- the string "multicol_context" won't show up in CSS, but this modifier denotes that the break-after would work inside a layout that using column.

The convention is that these keys will have underscores, and this potentially could be useful down the road to further target linting. However, CSS properties are going to never have a period, so I think the regex could be adjusted to drop the .multicol_context, or anything after a period. Essentially, anything beginning with css.properties, you could do something like key.split('.')[2] to get the property name.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, that's very helpful, thanks. Yeah, I left these because I was trying to figure out if I could do something with the values after the period.

["custom-property", 10],
["display", 10],
["display.none", 10],
["display.contents", 0],
Copy link

Choose a reason for hiding this comment

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

display.contents signifies a rule like this-

a {display: contents}. If there is not an underscore in the second portion, it is the value. It would be nice to be able to check for this as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for explaining this. I looked into it a bit and this is more complicated than it seems. Sometimes the identifier after the property name is a literal (as in display.content means display: contents), but sometimes it's a type (content.url means content: url(foo)). So it's not enough to just pull that value and check for it, we'd also need to know what type of node to look for in CSSTree.

And it gets even more complicated with types that actually represent multiple values, like border-radius.percentages, which may be represented by 1-4 nodes. I suppose we could filter and just check on the properties that are known to only have literal values, but I don't know how to automate that.

Ultimately, it looks like sussing out all of these details would be a labor-intensive process, so it's unlikely to happen without outside contributions.

["namespace", 10],
["page", 0],
["page.size", 0],
["media.prefers-color-scheme", 10],
Copy link

Choose a reason for hiding this comment

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

This would indicate a rule like

@media (prefers-color-scheme: dark){}.

["starting-style", 0],
["supports", 10],
]);
export const types = new Map([
Copy link

Choose a reason for hiding this comment

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

I noticed you're not testing types yet, so this is more of a note for the future.

Types are going to be tricky to detect from the key. Some will be fairly straightforward- abs, sign, anchor, for instance, will all show up as functions with that name, in a value in an AST.

A few items like gradient.* and easing-function.* would show similarly show up as functions if you took the substring after the ..

Others like time or string would not show up literally, but would need to be detected in a different way.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I figured for the first version of the rule I'd punt on this, but I wanted the data here for easy reference later.

The only way I can think to make this work is to maintain a separate dictionary that maps types to their expected AST locations.

["percentage", 10],
["integer", 10],
]);
export const selectors = new Map([
Copy link

Choose a reason for hiding this comment

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

For selectors, feature detection could be fairly straightforward. Some like :has would have a single : and show up in the AST as PseudoClassSelector, others like ::before would have 2 :: and show up in the AST as a PseudoElementSelector.

I don't think there's a way to differentiate between the two classes based on this data.

There are also some items here that are not actually verbatim selectors- for instance, "class" refers to the . notation for selecting classes.

Copy link
Member Author

@nzakas nzakas Dec 12, 2024

Choose a reason for hiding this comment

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

Yeah, that's the challenge I ran into, so similar to types, I figured I'd just make the data was there and I'd come back to it later. Probably will need to be addressed similar to types where there needs to be a separate dictionary indicating which are pseudoclasses vs. pseudoelements vs. other.

@nzakas
Copy link
Member Author

nzakas commented Dec 16, 2024

Okay, I think I've got this in pretty good shape now.

  • Properties and identifier values are now validated against baseline.
  • You can use @supports to indicate you know what you're doing so the rule doesn't flag its contents. (Also works with nested @supports).
  • There is some rudimentary checking of function values against baseline.

I'd love for folks to try this out and give me some feedback on if it's helpful.

FYI: I'm now offline until December 30, but please feel free to leave your feedback and I'll review when I return. Happy holidays!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New Rule: baselineWidelyAvailable
2 participants