Fixes #648 - adds property level at-rule support.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 16 Aug 2015 13:51:56 +0000 (14:51 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 16 Aug 2015 13:51:56 +0000 (14:51 +0100)
Polymer uses `@apply` rule on property level, so we support it now too.

History.md
lib/selectors/extractor.js
lib/stringifier/helpers.js
lib/tokenizer/extract-properties.js
test/integration-test.js
test/tokenizer/tokenizer-test.js

index cf383db..16f2eb1 100644 (file)
@@ -8,6 +8,7 @@
 * Fixed issue [#612](https://github.com/jakubpawlowicz/clean-css/issues/612) - adds HTTP proxy support.
 * Fixed issue [#625](https://github.com/jakubpawlowicz/clean-css/issues/625) - adds length unit optimizations.
 * Fixed issue [#644](https://github.com/jakubpawlowicz/clean-css/issues/644) - adds time unit optimizations.
+* Fixed issue [#648](https://github.com/jakubpawlowicz/clean-css/issues/648) - adds property level at-rule support.
 
 [3.3.9 / 2015-08-09](https://github.com/jakubpawlowicz/clean-css/compare/v3.3.8...v3.3.9)
 ==================
index 2506d6c..72cafca 100644 (file)
@@ -5,6 +5,8 @@
 var stringifySelectors = require('../stringifier/one-time').selectors;
 var stringifyValue = require('../stringifier/one-time').value;
 
+var AT_RULE = 'at-rule';
+
 function extract(token) {
   var properties = [];
 
@@ -16,6 +18,9 @@ function extract(token) {
       if (property.indexOf('__ESCAPED') === 0)
         continue;
 
+      if (property[0] == AT_RULE)
+        continue;
+
       var name = token[2][i][0][0];
       if (name.length === 0)
         continue;
index 0786c24..1411619 100644 (file)
@@ -1,5 +1,8 @@
 var lineBreak = require('os').EOL;
 
+var AT_RULE = 'at-rule';
+var PROPERTY_SEPARATOR = ';';
+
 function hasMoreProperties(tokens, index) {
   for (var i = index, l = tokens.length; i < l; i++) {
     if (typeof tokens[i] != 'string')
@@ -72,6 +75,8 @@ function property(tokens, position, isLast, context) {
 
   if (typeof token == 'string') {
     store(token, context);
+  } else if (token[0] == AT_RULE) {
+    propertyAtRule(token[1], isLast, context);
   } else {
     store(token[0], context);
     store(':', context);
@@ -79,6 +84,14 @@ function property(tokens, position, isLast, context) {
   }
 }
 
+function propertyAtRule(value, isLast, context) {
+  var store = context.store;
+
+  store(value, context);
+  if (!isLast)
+    store(PROPERTY_SEPARATOR, context);
+}
+
 function value(tokens, position, isLast, context) {
   var store = context.store;
   var token = tokens[position];
@@ -89,7 +102,7 @@ function value(tokens, position, isLast, context) {
     if (j < m - 1 && (inFilter(token) || !inSpecialContext(token, j, context))) {
       store(' ', context);
     } else if (j == m - 1 && !isLast && hasMoreProperties(tokens, position + 1)) {
-      store(';', context);
+      store(PROPERTY_SEPARATOR, context);
     }
   }
 }
index a0880d4..83d9005 100644 (file)
@@ -3,6 +3,8 @@ var Splitter = require('../utils/splitter');
 var COMMA = ',';
 var FORWARD_SLASH = '/';
 
+var AT_RULE = 'at-rule';
+
 function selectorName(value) {
   return value[0];
 }
@@ -61,6 +63,13 @@ function extractProperties(string, selectors, context) {
     var candidate = candidates[i];
     var firstColonAt = candidate.indexOf(':');
 
+    var atRule = candidate[0] == '@';
+    if (atRule) {
+      context.track(candidate);
+      list.push([AT_RULE, candidate.trim()]);
+      continue;
+    }
+
     if (firstColonAt == -1) {
       context.track(candidate);
       if (candidate.indexOf('__ESCAPED_COMMENT_SPECIAL') > -1)
index 9cf471b..5836842 100644 (file)
@@ -2142,6 +2142,22 @@ vows.describe('integration tests')
       ]
     }, { processImport: false, root: process.cwd(), relativeTo: process.cwd() })
   )
+  .addBatch(
+    optimizerContext('body at-rules', {
+      'single @apply': [
+        'a{@apply(--rule)}',
+        'a{@apply(--rule)}'
+      ],
+      'multiple @apply': [
+        'a{@apply(--rule1);@apply(--rule2)}',
+        'a{@apply(--rule1);@apply(--rule2)}'
+      ],
+      'multiple @apply with some styling': [
+        'a{@apply(--rule1);@apply(--rule2);color:red;display:block}',
+        'a{@apply(--rule1);@apply(--rule2);color:red;display:block}'
+      ]
+    })
+  )
   .addBatch(
     optimizerContext('duplicate selectors with disabled advanced processing', {
       'of a duplicate selector': [
index 7b40186..1ae2863 100644 (file)
@@ -170,6 +170,16 @@ vows.describe(tokenize)
           ['selector', [['div:nth-child(2n):not(.test)']], []]
         ]
       ],
+      '@apply': [
+        'a{@apply(--rule);}',
+        [
+          [
+            'selector',
+            [['a']],
+            [['at-rule', '@apply(--rule)']]
+          ]
+        ]
+      ],
       'media query': [
         '@media (min-width:980px){}',
         [