Repository: postcss/postcss-selector-parser
Pull request #256 (2022-03-25 12:46:40)

fix: `isPseudoElement()` supports `:first-letter` and `:first-line`
Browsers supports also `:first-letter` and `:first-line` pseudo-elements introduced in CSS2.

- https://developer.mozilla.org/en-US/docs/Web/CSS/::first-letter
- https://developer.mozilla.org/en-US/docs/Web/CSS/::first-line

alexander-akait: @ybiquitous hm, so we parse them as pseudo elements? I think it is bug (for `before` and `fater`), because we should parse them as is (i.e. no own decisions), if it was written as pseudo elements we should return pseudo element and versa vice, otherwise linters and another tools, can't understand  how developer really write them
ybiquitous: @alexander-akait Thanks for the quick feedback.

Do you mean it's unnecessary to check `:before` or `:after` in the first place like this?

```js
export function isPseudoElement (node) {
    return isPseudo(node) && node.value && node.value.startsWith("::");
}
```

I don't know the background that `isPseudoElement` was introduced, so I don't have a strong opinion about these type-guard functions.
Surely, `postcss-selector-parser` has a `Pseudo` node type, but doesn't have a `PseudoElement` or `PseudoClass` node type.
alexander-akait: > Surely, postcss-selector-parser has a Pseudo node type, but doesn't have a PseudoElement or PseudoClass node type.

Oh... that is bad, I messed it

I see what you want, ideally we should rename function to `isLegacyPseudoElement`, but it will be breaking change, so let's left the same name
ybiquitous: @alexander-akait Don't mind. Thank you for the review. ☺️ 
I'm not hurrying. Feel free to merge and release when you can afford it.

Patch:
diff --git a/src/selectors/guards.js b/src/selectors/guards.js
index 44b16a3..54a5018 100644
--- a/src/selectors/guards.js
+++ b/src/selectors/guards.js
@@ -56,6 +56,8 @@ export function isPseudoElement (node) {
                node.value.startsWith("::")
              || node.value.toLowerCase() === ":before"
              || node.value.toLowerCase() === ":after"
+             || node.value.toLowerCase() === ":first-letter"
+             || node.value.toLowerCase() === ":first-line"
            );
 }
 export function isPseudoClass (node) {


Test patch:
diff --git a/src/__tests__/guards.js b/src/__tests__/guards.js
index 466e639..d84d481 100644
--- a/src/__tests__/guards.js
+++ b/src/__tests__/guards.js
@@ -79,8 +79,8 @@ test('pseudo element guard', '::first-line', (t, tree) => {
     t.false(parser.isNamespace(n));
 });
 
-test('special pseudo element guard', ':before:after', (t, tree) => {
-    [node(tree), node(tree, 1)].forEach((n) => {
+test('special pseudo element guard', ':before:after:first-letter:first-line', (t, tree) => {
+    [node(tree), node(tree, 1), node(tree, 2), node(tree, 3)].forEach((n) => {
         t.true(parser.isPseudo(n));
         t.false(parser.isPseudoClass(n));
         t.true(parser.isPseudoElement(n));
@@ -89,8 +89,8 @@ test('special pseudo element guard', ':before:after', (t, tree) => {
     });
 });
 
-test('special pseudo element guard (uppercase)', ':BEFORE:AFTER', (t, tree) => {
-    [node(tree), node(tree, 1)].forEach((n) => {
+test('special pseudo element guard (uppercase)', ':BEFORE:AFTER:FIRST-LETTER:FIRST-LINE', (t, tree) => {
+    [node(tree), node(tree, 1), node(tree, 2), node(tree, 3)].forEach((n) => {
         t.true(parser.isPseudo(n));
         t.false(parser.isPseudoClass(n));
         t.true(parser.isPseudoElement(n));