From 881f736b1047d2547abe8ff0582fa5266a596cc9 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Mon, 12 Dec 2016 14:12:22 +0100 Subject: [PATCH] Ignores `@import` at-rules if after content. Why: * This is what browsers do and we should respect it. --- History.md | 1 + lib/clean.js | 2 +- lib/selectors/simple.js | 14 ++++++++++++-- test/module-test.js | 8 ++++++++ test/protocol-imports-test.js | 2 +- test/test-helper.js | 4 ++-- 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/History.md b/History.md index d800bff3..2aeaa7a1 100644 --- a/History.md +++ b/History.md @@ -7,6 +7,7 @@ ================== * Fixed issue [#841](https://github.com/jakubpawlowicz/clean-css/issues/841) - disabled importing and files passed as array. +* Ignores `@import` at-rules if appearing after any non-`@import` rules. [3.4.21 / 2016-11-16](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.20...v3.4.21) ================== diff --git a/lib/clean.js b/lib/clean.js index 4838c8d2..1fe93909 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -222,7 +222,7 @@ function minify(context, data) { var tokens = tokenize(data, context); - simpleOptimize(tokens, options); + simpleOptimize(tokens, options, context); if (options.advanced) advancedOptimize(tokens, options, context, true); diff --git a/lib/selectors/simple.js b/lib/selectors/simple.js index 5e6fd3c1..b5753e12 100644 --- a/lib/selectors/simple.js +++ b/lib/selectors/simple.js @@ -14,6 +14,7 @@ var removeUnused = require('../properties/remove-unused'); var DEFAULT_ROUNDING_PRECISION = 2; var CHARSET_TOKEN = '@charset'; var CHARSET_REGEXP = new RegExp('^' + CHARSET_TOKEN, 'i'); +var IMPORT_REGEXP = /^@import["'\s]/i; var FONT_NUMERAL_WEIGHTS = ['100', '200', '300', '400', '500', '600', '700', '800', '900']; var FONT_NAME_WEIGHTS = ['normal', 'bold', 'bolder', 'lighter']; @@ -404,11 +405,12 @@ function buildPrecision(options) { return precision; } -function optimize(tokens, options) { +function optimize(tokens, options, context) { var ie7Hack = options.compatibility.selectors.ie7Hack; var adjacentSpace = options.compatibility.selectors.adjacentSpace; var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace; var mayHaveCharset = false; + var afterContent = false; options.unitsRegexp = buildUnitRegexp(options); options.precision = buildPrecision(options); @@ -420,20 +422,28 @@ function optimize(tokens, options) { case 'selector': token[1] = cleanUpSelectors(token[1], !ie7Hack, adjacentSpace); optimizeBody(token[2], options); + afterContent = true; break; case 'block': cleanUpBlock(token[1], spaceAfterClosingBrace); - optimize(token[2], options); + optimize(token[2], options, context); + afterContent = true; break; case 'flat-block': cleanUpBlock(token[1], spaceAfterClosingBrace); optimizeBody(token[2], options); + afterContent = true; break; case 'at-rule': cleanUpAtRule(token[1]); mayHaveCharset = true; } + if (token[0] == 'at-rule' && IMPORT_REGEXP.test(token[1]) && afterContent) { + context.warnings.push('Ignoring @import rule "' + token[1] + '" as it appears after rules thus browsers will ignore them.'); + token[1] = ''; + } + if (token[1].length === 0 || (token[2] && token[2].length === 0)) { tokens.splice(i, 1); i--; diff --git a/test/module-test.js b/test/module-test.js index 7fac792a..695ac226 100644 --- a/test/module-test.js +++ b/test/module-test.js @@ -482,6 +482,14 @@ vows.describe('module tests').addBatch({ 'should give right output': function (minified) { assert.equal(minified.styles, '@import url(http://jakubpawlowicz.com/styles.css);@import url(./extra/sub.css);.base{margin:0}'); } + }, + 'off - many files with content': { + 'topic': function () { + return new CleanCSS({ processImport: false }).minify(['./test/fixtures/partials/two.css', './test/fixtures/partials-absolute/base.css']); + }, + 'should give right output': function (minified) { + assert.equal(minified.styles, '@import url(one.css);@import url(extra/three.css);@import url(./extra/four.css);.two{color:#fff}.base{margin:0}'); + } } } }, diff --git a/test/protocol-imports-test.js b/test/protocol-imports-test.js index 54e3ede4..45648784 100644 --- a/test/protocol-imports-test.js +++ b/test/protocol-imports-test.js @@ -789,7 +789,7 @@ vows.describe('protocol imports').addBatch({ 'should not raise errors': function (error, minified) { assert.isEmpty(minified.errors); }, - 'should not raise warnings': function (error, minified) { + 'should raise a warning': function (error, minified) { assert.lengthOf(minified.warnings, 1); }, 'should process imports': function (error, minified) { diff --git a/test/test-helper.js b/test/test-helper.js index 12e7a762..19eaa67f 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -35,7 +35,7 @@ function selectorContext(group, specs, options) { function optimized(selectors) { return function (source) { var tokens = tokenize(source, { options: {} }); - simpleOptimize(tokens, options); + simpleOptimize(tokens, options, {}); assert.deepEqual(tokens[0] ? tokens[0][1] : null, selectors); }; @@ -59,7 +59,7 @@ function propertyContext(group, specs, options) { function optimized(selectors) { return function (source) { var tokens = tokenize(source, { options: {} }); - simpleOptimize(tokens, options); + simpleOptimize(tokens, options, {}); var value = tokens[0] ? tokens[0][2].map(function (property) { -- 2.34.1