From e74b045205a31dabc2c319469f1b8dc47933339e Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Wed, 20 May 2015 20:25:12 +0100 Subject: [PATCH] Fixes #570 - rebasing "no-url()" imports. `@import '...';` should be treated the same as `@import url(...);`. --- History.md | 1 + lib/text/urls-processor.js | 2 +- lib/urls/reduce.js | 68 ++++++++++++++++++++++++++++++++++++-- lib/urls/rewrite.js | 2 +- test/module-test.js | 22 ++++++++++++ 5 files changed, 91 insertions(+), 4 deletions(-) diff --git a/History.md b/History.md index c9677d4d..04421f87 100644 --- a/History.md +++ b/History.md @@ -13,6 +13,7 @@ * Fixed issue [#517](https://github.com/jakubpawlowicz/clean-css/issues/517) - turning off color optimizations. * Fixed issue [#542](https://github.com/jakubpawlowicz/clean-css/issues/542) - space after closing brace in IE. * Fixed issue [#563](https://github.com/jakubpawlowicz/clean-css/issues/563) - `background:inherit` restoring. +* Fixed issue [#570](https://github.com/jakubpawlowicz/clean-css/issues/570) - rebasing "no-url()" imports. * Fixed issue [#574](https://github.com/jakubpawlowicz/clean-css/issues/574) - rewriting internal URLs. * Fixed issue [#575](https://github.com/jakubpawlowicz/clean-css/issues/575) - missing directory as a `target`. diff --git a/lib/text/urls-processor.js b/lib/text/urls-processor.js index 784b0fea..7e4a5301 100644 --- a/lib/text/urls-processor.js +++ b/lib/text/urls-processor.js @@ -42,7 +42,7 @@ function normalize(url, keepUrlQuotes) { .replace(/^url\((['"])? /, 'url($1') .replace(/ (['"])?\)$/, '$1)'); - if (!keepUrlQuotes && !/url\(.*[\s\(\)].*\)/.test(url) && !/url\(['"]data:[^;]+;charset/.test(url)) + if (!keepUrlQuotes && !/^['"].+['"]$/.test(url) && !/url\(.*[\s\(\)].*\)/.test(url) && !/url\(['"]data:[^;]+;charset/.test(url)) url = url.replace(/["']/g, ''); return url; diff --git a/lib/urls/reduce.js b/lib/urls/reduce.js index 067e6f47..84555c80 100644 --- a/lib/urls/reduce.js +++ b/lib/urls/reduce.js @@ -2,7 +2,10 @@ var URL_PREFIX = 'url('; var UPPERCASE_URL_PREFIX = 'URL('; var URL_SUFFIX = ')'; -function reduceUrls(data, context, callback) { +var IMPORT_URL_PREFIX = '@import'; +var UPPERCASE_IMPORT_URL_PREFIX = '@IMPORT'; + +function byUrl(data, context, callback) { var nextStart = 0; var nextStartUpperCase = 0; var nextEnd = 0; @@ -55,4 +58,65 @@ function reduceUrls(data, context, callback) { data; } -module.exports = reduceUrls; +function byImport(data, context, callback) { + var nextStart = 0; + var nextStartUpperCase = 0; + var nextEnd = 0; + var cursor = 0; + var tempData = []; + var nextSingleQuote = 0; + var nextDoubleQuote = 0; + var withQuote; + var SINGLE_QUOTE = '\''; + var DOUBLE_QUOTE = '"'; + + for (; nextEnd < data.length;) { + nextStart = data.indexOf(IMPORT_URL_PREFIX, nextEnd); + nextStartUpperCase = data.indexOf(UPPERCASE_IMPORT_URL_PREFIX, nextEnd); + if (nextStart == -1 && nextStartUpperCase == -1) + break; + + if (nextStart > -1 && nextStartUpperCase > -1 && nextStartUpperCase < nextStart) + nextStart = nextStartUpperCase; + + nextSingleQuote = data.indexOf(SINGLE_QUOTE, nextStart); + nextDoubleQuote = data.indexOf(DOUBLE_QUOTE, nextStart); + + if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote < nextDoubleQuote) { + nextStart = nextSingleQuote; + withQuote = SINGLE_QUOTE; + } else if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote > nextDoubleQuote) { + nextStart = nextDoubleQuote; + withQuote = DOUBLE_QUOTE; + } else if (nextSingleQuote > -1) { + nextStart = nextSingleQuote; + withQuote = SINGLE_QUOTE; + } else if (nextDoubleQuote > -1) { + nextStart = nextDoubleQuote; + withQuote = DOUBLE_QUOTE; + } + + tempData.push(data.substring(cursor, nextStart)); + + nextEnd = data.indexOf(withQuote, nextStart + 1); + if (nextEnd == -1) + break; + + var url = data.substring(nextStart, nextEnd + 1); + callback(url, tempData); + + cursor = nextEnd + 1; + } + + return tempData.length > 0 ? + tempData.join('') + data.substring(cursor, data.length) : + data; +} + +function reduceAll(data, context, callback) { + data = byUrl(data, context, callback); + data = byImport(data, context, callback); + return data; +} + +module.exports = reduceAll; diff --git a/lib/urls/rewrite.js b/lib/urls/rewrite.js index 54135003..ef25130d 100644 --- a/lib/urls/rewrite.js +++ b/lib/urls/rewrite.js @@ -70,7 +70,7 @@ function rebase(uri, options) { function rewriteUrls(data, options, context) { return reduceUrls(data, context, function (url, tempData) { - url = url.replace(/^url\(\s*['"]?|['"]?\s*\)$/g, ''); + url = url.replace(/^(url\()?\s*['"]?|['"]?\s*\)?$/g, ''); tempData.push('url(' + rebase(url, options) + ')'); }); } diff --git a/test/module-test.js b/test/module-test.js index 9b5da0ea..02239874 100644 --- a/test/module-test.js +++ b/test/module-test.js @@ -556,6 +556,28 @@ vows.describe('module tests').addBatch({ 'should give right output': function (minified) { assert.equal(minified.styles, '@import url(/partials/one.css);@import url(/partials/extra/three.css);@import url(/partials/extra/four.css);.two{color:#fff}'); } + }, + 'with import URL as a string': { + 'topic': function () { + var source = 'test/fixtures/partials/two.css'; + var asHash = sourcesAsHash([source]); + asHash[source].styles = asHash[source].styles.replace(/url\(|\)/g, ''); + return new CleanCSS().minify(asHash); + }, + 'should give right output': function (minified) { + assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'); + } + }, + 'with import URL as an uppercase string': { + 'topic': function () { + var source = 'test/fixtures/partials/two.css'; + var asHash = sourcesAsHash([source]); + asHash[source].styles = asHash[source].styles.replace(/url\(|\)/g, '').replace('@import', '@IMPORT'); + return new CleanCSS().minify(asHash); + }, + 'should give right output': function (minified) { + assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'); + } } }, 'with remote paths': { -- 2.34.1