Fixes #965 - edge case in parsing comment endings.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sat, 2 Sep 2017 18:01:43 +0000 (20:01 +0200)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Sat, 2 Sep 2017 18:46:21 +0000 (20:46 +0200)
This is an edge case when a comment is closed twice leading to the
second end marker leaking to the next token.

History.md
lib/tokenizer/tokenize.js
test/tokenizer/tokenize-test.js

index 50d7f84..67ffe34 100644 (file)
@@ -11,6 +11,7 @@
 
 * Fixed issue [#959](https://github.com/jakubpawlowicz/clean-css/issues/959) - regression in shortening long hex values.
 * Fixed issue [#960](https://github.com/jakubpawlowicz/clean-css/issues/960) - better explanation of `efficiency` stat.
+* Fixed issue [#965](https://github.com/jakubpawlowicz/clean-css/issues/965) - edge case in parsing comment endings.
 
 [4.1.7 / 2017-07-14](https://github.com/jakubpawlowicz/clean-css/compare/v4.1.6...v4.1.7)
 ==================
index f2d4ae8..8ad55d5 100644 (file)
@@ -101,6 +101,7 @@ function intoTokens(source, externalContext, internalContext, isNested) {
   var wasCommentStart = false;
   var isCommentEnd;
   var wasCommentEnd = false;
+  var isCommentEndMarker;
   var isEscaped;
   var wasEscaped = false;
   var isRaw = false;
@@ -117,7 +118,8 @@ function intoTokens(source, externalContext, internalContext, isNested) {
     isNewLineNix = character == Marker.NEW_LINE_NIX;
     isNewLineWin = character == Marker.NEW_LINE_NIX && source[position.index - 1] == Marker.NEW_LINE_WIN;
     isCommentStart = !wasCommentEnd && level != Level.COMMENT && !isQuoted && character == Marker.ASTERISK && source[position.index - 1] == Marker.FORWARD_SLASH;
-    isCommentEnd = !wasCommentStart && level == Level.COMMENT && character == Marker.FORWARD_SLASH && source[position.index - 1] == Marker.ASTERISK;
+    isCommentEndMarker = !wasCommentStart && !isQuoted && character == Marker.FORWARD_SLASH && source[position.index - 1] == Marker.ASTERISK;
+    isCommentEnd = level == Level.COMMENT && isCommentEndMarker;
 
     metadata = buffer.length === 0 ?
       [position.line, position.column, position.source] :
@@ -182,6 +184,9 @@ function intoTokens(source, externalContext, internalContext, isNested) {
       level = levels.pop();
       metadata = metadatas.pop() || null;
       buffer = buffers.pop() || [];
+    } else if (isCommentEndMarker && source[position.index + 1] != Marker.ASTERISK) {
+      externalContext.warnings.push('Unexpected \'*/\' at ' + formatPosition([position.line, position.column, position.source]) + '.');
+      buffer = [];
     } else if (character == Marker.SINGLE_QUOTE && !isQuoted) {
       // single quotation start, e.g. a[href^='https<--
       levels.push(level);
index cd38c60..f277a30 100644 (file)
@@ -1015,6 +1015,80 @@ vows.describe(tokenize)
           ]
         ]
       ],
+      'two comments one inside another and two rules': [
+        '.block-1{color:red;/* comment 1 /* comment 2 */ */}.block-2{color:blue}',
+        [
+          [
+            'rule',
+            [
+              [
+                'rule-scope',
+                '.block-1',
+                [
+                  [1, 0, undefined]
+                ]
+              ]
+            ],
+            [
+              [
+                'property',
+                [
+                  'property-name',
+                  'color',
+                  [
+                    [1, 9, undefined]
+                  ]
+                ],
+                [
+                  'property-value',
+                  'red',
+                  [
+                    [1, 15, undefined]
+                  ]
+                ]
+              ],
+              [
+                'comment',
+                '/* comment 1 /* comment 2 */',
+                [
+                  [1, 19, undefined]
+                ]
+              ]
+            ]
+          ],
+          [
+            'rule',
+            [
+              [
+                'rule-scope',
+                '.block-2',
+                [
+                  [1, 51, undefined]
+                ]
+              ]
+            ],
+            [
+              [
+                'property',
+                [
+                  'property-name',
+                  'color',
+                  [
+                    [1, 60, undefined]
+                  ]
+                ],
+                [
+                  'property-value',
+                  'blue',
+                  [
+                    [1, 66, undefined]
+                  ]
+                ]
+              ]
+            ]
+          ]
+        ]
+      ],
       'rule wrapped between comments': [
         '/* comment 1 */div/* comment 2 */{color:red}',
         [