Fixes #657 - adds property name validation.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Tue, 20 Dec 2016 16:10:47 +0000 (17:10 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Tue, 20 Dec 2016 16:10:47 +0000 (17:10 +0100)
It's a bit relaxed matching but too strict one would do too much
harm with many false-positives.

Why:

* To prevent processing errors further down the optimization pipeline.

lib/optimizer/basic.js
test/module-test.js
test/optimizer/basic-test.js

index 1775491..bae8b65 100644 (file)
@@ -28,6 +28,7 @@ var FONT_NAME_WEIGHTS_WITHOUT_NORMAL = ['bold', 'bolder', 'lighter'];
 var WHOLE_PIXEL_VALUE = /(?:^|\s|\()(-?\d+)px/;
 var TIME_VALUE = /^(\-?[\d\.]+)(m?s)$/;
 
+var PROPERTY_NAME_PATTERN = /^(?:\-chrome\-|\-[\w\-]+\w|\w[\w\-]+\w|\-\-\S+)$/;
 var IMPORT_PREFIX_PATTERN = /^@import/i;
 var QUOTED_PATTERN = /^('.*'|".*")$/;
 var QUOTED_BUT_SAFE_PATTERN = /^['"][a-zA-Z][a-zA-Z\d\-_]+['"]$/;
@@ -345,6 +346,12 @@ function optimizeBody(properties, context) {
     property = _properties[i];
     name = property.name;
 
+    if (!PROPERTY_NAME_PATTERN.test(name)) {
+      propertyToken = property.all[property.position];
+      context.warnings.push('Invalid property name \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
+      property.unused = true;
+    }
+
     if (property.value.length === 0) {
       propertyToken = property.all[property.position];
       context.warnings.push('Empty property \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
index 5f256b1..4460c2b 100644 (file)
@@ -131,6 +131,21 @@ vows.describe('module tests').addBatch({
       assert.equal(minified.warnings[1], 'Invalid selector \'color:#535353}p\' at 1:16. Ignoring.');
     }
   },
+  'warning on invalid property': {
+    'topic': function () {
+      return new CleanCSS().minify('a{-webkit-:0px}');
+    },
+    'should minify correctly': function (error, minified) {
+      assert.isEmpty(minified.styles);
+    },
+    'should raise no errors': function (error, minified) {
+      assert.isEmpty(minified.errors);
+    },
+    'should raise one warning': function (error, minified) {
+      assert.lengthOf(minified.warnings, 1);
+      assert.equal(minified.warnings[0], 'Invalid property name \'-webkit-\' at 1:2. Ignoring.');
+    }
+  },
   'warnings on empty properties': {
     'topic': function () {
       return new CleanCSS().minify('a{color:}');
index 2fb61eb..3907cd6 100644 (file)
@@ -911,4 +911,24 @@ vows.describe('simple optimizations')
       ]
     }, { advanced: false, compatibility: { properties: { shorterLengthUnits: true }, units: { in: false, pt: false } } })
   )
+  .addBatch(
+    optimizerContext('property name validation', {
+      'trimmed': [
+        'a{-webkit-:0 0 2px red}',
+        ''
+      ],
+      'with incorrect characters': [
+        'a{color+other:red}',
+        ''
+      ],
+      'for chrome only': [
+        'a{-chrome-:only(;color:red;)}',
+        'a{-chrome-:only(;color:red;)}'
+      ],
+      'custom vendor prefix': [
+        'a{-custom-color:red}',
+        'a{-custom-color:red}'
+      ]
+    }, { advanced: false })
+  )
   .export(module);