Repository: postcss/postcss-selector-parser
Pull request #190 (2019-03-15 14:12:10)

fix: do not create invalid combinator before comment
Before:
```
h2, /*test*/ h4 -> type, comment combinator type
```
After:
```
h2, /*test*/ h4 -> type, comment, type
```


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 ++;


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__/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');
+});