Fixes #460 - unescaped semicolon in selector.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 4 Jan 2017 20:24:26 +0000 (21:24 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 4 Jan 2017 20:24:26 +0000 (21:24 +0100)
Why:

* Such rules should be dropped. Warnings are already in place.

History.md
lib/optimizer/tidy-rules.js
lib/tokenizer/tokenize.js
test/optimizer/basic-test.js
test/tokenizer/tokenize-test.js

index 61881d7..fc74761 100644 (file)
@@ -12,6 +12,7 @@
 * Splits `inliner` option into `inlineRequest` and `inlineTimeout`.
 * Fixed issue [#209](https://github.com/jakubpawlowicz/clean-css/issues/209) - adds output formatting via `beautify` flag.
 * Fixed issue [#432](https://github.com/jakubpawlowicz/clean-css/issues/432) - adds URLs normalization.
+* Fixed issue [#460](https://github.com/jakubpawlowicz/clean-css/issues/460) - unescaped semicolon in selector.
 * Fixed issue [#657](https://github.com/jakubpawlowicz/clean-css/issues/657) - adds property name validation.
 * Fixed issue [#685](https://github.com/jakubpawlowicz/clean-css/issues/685) - adds lowercasing hex colors optimization.
 * Fixed issue [#686](https://github.com/jakubpawlowicz/clean-css/issues/686) - adds rounding precision for all units.
index 61231c3..a57fec7 100644 (file)
@@ -22,7 +22,7 @@ function hasInvalidCharacters(value) {
       // continue as always
     } else if (character == Marker.SINGLE_QUOTE || character == Marker.DOUBLE_QUOTE) {
       isQuote = !isQuote;
-    } else if (!isQuote && (character == Marker.CLOSE_BRACE || character == Marker.EXCLAMATION || character == LESS_THAN)) {
+    } else if (!isQuote && (character == Marker.CLOSE_BRACE || character == Marker.EXCLAMATION || character == LESS_THAN || character == Marker.SEMICOLON)) {
       isInvalid = true;
       break;
     } else if (!isQuote && i === 0 && RELATION_PATTERN.test(character)) {
index 29b15b0..b38ec56 100644 (file)
@@ -147,7 +147,7 @@ function intoTokens(source, externalContext, internalContext, isNested) {
       buffer.push(character);
 
       roundBracketLevel--;
-    } else if (character == Marker.SEMICOLON && level == Level.BLOCK) {
+    } else if (character == Marker.SEMICOLON && level == Level.BLOCK && buffer[0] == Marker.AT) {
       // semicolon ending rule at block level, e.g. @import '...';<--
       serializedBuffer = buffer.join('').trim();
       allTokens.push([Token.AT_RULE, serializedBuffer, [originalMetadata(metadata, serializedBuffer, externalContext)]]);
index 6c95da4..7859d09 100644 (file)
@@ -117,6 +117,10 @@ vows.describe('simple optimizations')
         '>.funky{background:red}',
         ''
       ],
+      'invalid characters #4 - semicolon': [
+        'body;{body}',
+        ''
+      ],
       'missing semicolon and brace in the middle': [
         'body{color:red a{color:blue;}',
         ''
index 54df4df..fe3f798 100644 (file)
@@ -3639,6 +3639,24 @@ vows.describe(tokenize)
             ]
           ]
         ]
+      ],
+      'unexpected semicolon at root level': [
+        'body;{body}',
+        [
+          [
+            'rule',
+            [
+              [
+                'rule-scope',
+                'body;',
+                [
+                  [1, 0, undefined]
+                ]
+              ]
+            ],
+            []
+          ]
+        ]
       ]
     })
   )