From ec905b26945f8d08e5d603c44faa5b334de67fe5 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Sun, 16 Aug 2015 14:51:56 +0100 Subject: [PATCH] Fixes #648 - adds property level at-rule support. Polymer uses `@apply` rule on property level, so we support it now too. --- History.md | 1 + lib/selectors/extractor.js | 5 +++++ lib/stringifier/helpers.js | 15 ++++++++++++++- lib/tokenizer/extract-properties.js | 9 +++++++++ test/integration-test.js | 16 ++++++++++++++++ test/tokenizer/tokenizer-test.js | 10 ++++++++++ 6 files changed, 55 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index cf383db7..16f2eb1e 100644 --- a/History.md +++ b/History.md @@ -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) ================== diff --git a/lib/selectors/extractor.js b/lib/selectors/extractor.js index 2506d6cc..72cafca5 100644 --- a/lib/selectors/extractor.js +++ b/lib/selectors/extractor.js @@ -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; diff --git a/lib/stringifier/helpers.js b/lib/stringifier/helpers.js index 0786c244..14116191 100644 --- a/lib/stringifier/helpers.js +++ b/lib/stringifier/helpers.js @@ -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); } } } diff --git a/lib/tokenizer/extract-properties.js b/lib/tokenizer/extract-properties.js index a0880d41..83d90055 100644 --- a/lib/tokenizer/extract-properties.js +++ b/lib/tokenizer/extract-properties.js @@ -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) diff --git a/test/integration-test.js b/test/integration-test.js index 9cf471bd..58368423 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -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': [ diff --git a/test/tokenizer/tokenizer-test.js b/test/tokenizer/tokenizer-test.js index 7b40186d..1ae28632 100644 --- a/test/tokenizer/tokenizer-test.js +++ b/test/tokenizer/tokenizer-test.js @@ -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){}', [ -- 2.34.1