Repository: postcss/postcss-selector-parser
Pull request #191 (2019-03-15 14:55:09)

fix: handle uppercase pseudo elements


Patch:
diff --git a/src/parser.js b/src/parser.js
index cc7be3a..736d239 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -761,7 +761,8 @@ export default class Parser {
         if (
             this.position === 0 ||
             this.prevToken[TOKEN.TYPE] === tokens.comma ||
-            this.prevToken[TOKEN.TYPE] === tokens.openParenthesis
+            this.prevToken[TOKEN.TYPE] === tokens.openParenthesis ||
+            (this.current.nodes.every((node) => node.type === 'comment'))
         ) {
             this.spaces = this.optionalSpace(content);
             this.position ++;
diff --git a/src/selectors/guards.js b/src/selectors/guards.js
index 6c5e121..44b16a3 100644
--- a/src/selectors/guards.js
+++ b/src/selectors/guards.js
@@ -54,8 +54,8 @@ export function isPseudoElement (node) {
            && node.value
            && (
                node.value.startsWith("::")
-             || node.value === ":before"
-             || node.value === ":after"
+             || node.value.toLowerCase() === ":before"
+             || node.value.toLowerCase() === ":after"
            );
 }
 export function isPseudoClass (node) {


Test patch:
diff --git a/src/__tests__/comments.js b/src/__tests__/comments.js
index b842b6b..bd70c93 100644
--- a/src/__tests__/comments.js
+++ b/src/__tests__/comments.js
@@ -38,3 +38,50 @@ test('ending in comment', ".bar /* comment 3 */", (t, tree) => {
     t.deepEqual(classname.spaces.after, ' ');
     t.deepEqual(classname.raws.spaces.after, ' /* comment 3 */');
 });
+
+test('comments in selector list', 'h2, /*test*/ h4', (t, tree) => {
+    t.deepEqual(tree.nodes[0].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[0].nodes[0].value, 'h2');
+    t.deepEqual(tree.nodes[1].nodes[0].rawSpaceBefore, ' ');
+    t.deepEqual(tree.nodes[1].nodes[0].type, 'comment');
+    t.deepEqual(tree.nodes[1].nodes[0].value, '/*test*/');
+    t.deepEqual(tree.nodes[1].nodes[1].rawSpaceBefore, ' ');
+    t.deepEqual(tree.nodes[1].nodes[1].type, 'tag');
+    t.deepEqual(tree.nodes[1].nodes[1].value, 'h4');
+});
+
+test('comments in selector list (2)', 'h2,/*test*/h4', (t, tree) => {
+    t.deepEqual(tree.nodes[0].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[0].nodes[0].value, 'h2');
+    t.deepEqual(tree.nodes[1].nodes[0].rawSpaceBefore, '');
+    t.deepEqual(tree.nodes[1].nodes[0].type, 'comment');
+    t.deepEqual(tree.nodes[1].nodes[0].value, '/*test*/');
+    t.deepEqual(tree.nodes[1].nodes[1].type, 'tag');
+    t.deepEqual(tree.nodes[1].nodes[1].value, 'h4');
+    t.deepEqual(tree.nodes[1].nodes[1].rawSpaceBefore, '');
+});
+
+test('comments in selector list (3)', 'h2/*test*/, h4', (t, tree) => {
+    t.deepEqual(tree.nodes[0].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[0].nodes[0].value, 'h2');
+    t.deepEqual(tree.nodes[0].nodes[1].rawSpaceBefore, '');
+    t.deepEqual(tree.nodes[0].nodes[1].type, 'comment');
+    t.deepEqual(tree.nodes[0].nodes[1].value, '/*test*/');
+    t.deepEqual(tree.nodes[1].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[1].nodes[0].value, 'h4');
+    t.deepEqual(tree.nodes[1].nodes[0].rawSpaceBefore, ' ');
+});
+
+test('comments in selector list (4)', 'h2, /*test*/ /*test*/ h4', (t, tree) => {
+    t.deepEqual(tree.nodes[0].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[0].nodes[0].value, 'h2');
+    t.deepEqual(tree.nodes[1].nodes[0].rawSpaceBefore, ' ');
+    t.deepEqual(tree.nodes[1].nodes[0].type, 'comment');
+    t.deepEqual(tree.nodes[1].nodes[0].value, '/*test*/');
+    t.deepEqual(tree.nodes[1].nodes[1].rawSpaceBefore, ' ');
+    t.deepEqual(tree.nodes[1].nodes[1].type, 'comment');
+    t.deepEqual(tree.nodes[1].nodes[1].value, '/*test*/');
+    t.deepEqual(tree.nodes[1].nodes[2].rawSpaceBefore, ' ');
+    t.deepEqual(tree.nodes[1].nodes[2].type, 'tag');
+    t.deepEqual(tree.nodes[1].nodes[2].value, 'h4');
+});
diff --git a/src/__tests__/guards.js b/src/__tests__/guards.js
index 7a52c25..466e639 100644
--- a/src/__tests__/guards.js
+++ b/src/__tests__/guards.js
@@ -89,6 +89,16 @@ 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) => {
+        t.true(parser.isPseudo(n));
+        t.false(parser.isPseudoClass(n));
+        t.true(parser.isPseudoElement(n));
+        t.true(parser.isContainer(n));
+        t.false(parser.isNamespace(n));
+    });
+});
+
 test('string guard', '"string"', (t, tree) => {
     let n = node(tree);
     t.true(parser.isNode(n));
diff --git a/src/__tests__/nonstandard.js b/src/__tests__/nonstandard.js
index 686def8..422112b 100644
--- a/src/__tests__/nonstandard.js
+++ b/src/__tests__/nonstandard.js
@@ -20,16 +20,32 @@ test('leading combinator', '> *', (t, tree) => {
 });
 
 test('sass escapes', '.#{$classname}', (t, tree) => {
-    t.deepEqual(tree.nodes[0].nodes.map(n => n.type), ["class"]);
+    t.deepEqual(tree.nodes[0].nodes[0].type, "class");
     t.deepEqual(tree.nodes[0].nodes[0].value, "#{$classname}");
 });
 
 test('sass escapes (2)', '[lang=#{$locale}]', (t, tree) => {
-    t.deepEqual(tree.nodes[0].nodes.map(n => n.type), ["attribute"]);
+    t.deepEqual(tree.nodes[0].nodes[0].type, "attribute");
+    t.deepEqual(tree.nodes[0].nodes[0].attribute, "lang");
+    t.deepEqual(tree.nodes[0].nodes[0].operator, "=");
     t.deepEqual(tree.nodes[0].nodes[0].value, "#{$locale}");
 });
 
 test('placeholder', '%foo', (t, tree) => {
-    t.deepEqual(tree.nodes[0].nodes.map(n => n.type), ["tag"]);
+    t.deepEqual(tree.nodes[0].nodes[0].type, "tag");
     t.deepEqual(tree.nodes[0].nodes[0].value, "%foo");
 });
+
+test('styled selector', '${Step}', (t, tree) => {
+    t.deepEqual(tree.nodes[0].nodes[0].type, "tag");
+    t.deepEqual(tree.nodes[0].nodes[0].value, "${Step}");
+});
+
+test('styled selector (2)', '${Step}:nth-child(odd)', (t, tree) => {
+    t.deepEqual(tree.nodes[0].nodes[0].type, "tag");
+    t.deepEqual(tree.nodes[0].nodes[0].value, "${Step}");
+    t.deepEqual(tree.nodes[0].nodes[1].type, "pseudo");
+    t.deepEqual(tree.nodes[0].nodes[1].value, ":nth-child");
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].type, "tag");
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].value, "odd");
+});
diff --git a/src/__tests__/pseudos.js b/src/__tests__/pseudos.js
index 9af748b..56a5670 100644
--- a/src/__tests__/pseudos.js
+++ b/src/__tests__/pseudos.js
@@ -111,3 +111,16 @@ test('non standard pseudo (@custom-selector) (1)', "a, :--foobar", (t, tree) =>
     t.deepEqual(tree.nodes[1].nodes[0].value, ':--foobar');
     t.deepEqual(tree.nodes[1].nodes[0].type, 'pseudo');
 });
+
+test('nested pseudo classes', "section:not( :has(h1, h2 ) )", (t, tree) => {
+    t.deepEqual(tree.nodes[0].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[0].nodes[0].value, 'section');
+    t.deepEqual(tree.nodes[0].nodes[1].type, 'pseudo');
+    t.deepEqual(tree.nodes[0].nodes[1].value, ':not');
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].type, 'pseudo');
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].value, ':has');
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].nodes[0].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].nodes[0].nodes[0].value, 'h1');
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].nodes[1].nodes[0].type, 'tag');
+    t.deepEqual(tree.nodes[0].nodes[1].nodes[0].nodes[0].nodes[1].nodes[0].value, 'h2');
+});