From: Jakub Pawlowicz Date: Sun, 1 Mar 2015 16:49:01 +0000 (+0000) Subject: Fixes #462 - escaped apostrophes in selector rules. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=35cb43d1c67eee770dd9816c084fe4a152dc69b4;p=clean-css.git Fixes #462 - escaped apostrophes in selector rules. QuoteScanner were not scanning correctly for escaped apostrophes. --- diff --git a/History.md b/History.md index e3b51cb0..414159f4 100644 --- a/History.md +++ b/History.md @@ -7,6 +7,7 @@ ================== * Refixed issue [#471](https://github.com/jakubpawlowicz/clean-css/issues/471) - correct order after restructuring. +* Fixes issue [#462](https://github.com/jakubpawlowicz/clean-css/issues/462) - escaped apostrophes in selectors. [3.1.1 / 2015-02-27](https://github.com/jakubpawlowicz/clean-css/compare/v3.1.0...v3.1.1) ================== diff --git a/lib/utils/quote-scanner.js b/lib/utils/quote-scanner.js index 9e2c8dcd..69980f54 100644 --- a/lib/utils/quote-scanner.js +++ b/lib/utils/quote-scanner.js @@ -38,6 +38,19 @@ var findQuoteEnd = function (data, matched, cursor, oldCursor) { return cursor; }; +function findNext(data, mark, startAt) { + var escapeMark = '\\'; + var candidate = startAt; + + while (true) { + candidate = data.indexOf(mark, candidate + 1); + if (candidate == -1) + return -1; + if (data[candidate - 1] != escapeMark) + return candidate; + } +} + QuoteScanner.prototype.each = function (callback) { var data = this.data; var tempData = []; @@ -50,8 +63,8 @@ QuoteScanner.prototype.each = function (callback) { var dataLength = data.length; for (; nextEnd < data.length;) { - var nextStartSingle = data.indexOf(singleMark, nextEnd + 1); - var nextStartDouble = data.indexOf(doubleMark, nextEnd + 1); + var nextStartSingle = findNext(data, singleMark, nextEnd); + var nextStartDouble = findNext(data, doubleMark, nextEnd); if (nextStartSingle == -1) nextStartSingle = dataLength; diff --git a/test/integration-test.js b/test/integration-test.js index adccfdfc..fdc9262a 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -337,6 +337,14 @@ vows.describe('integration tests').addBatch({ 'escaped @ symbol in id': '#id\\@sm{padding:0}', 'escaped slash': 'a{content:"\\\\"}', 'escaped quote': 'a{content:"\\\""}', + 'escaped quote in selector name': [ + '.this-class\\\'s-got-an-apostrophe{color:red}a{color:#f00}', + '.this-class\\\'s-got-an-apostrophe,a{color:red}' + ], + 'escaped quotes in selector name': [ + '.this-class\\\"s-got-an-apostrophes\\\'{color:red}a{color:#f00}', + '.this-class\\\"s-got-an-apostrophes\\\',a{color:red}' + ], 'escaped tab': 'a{content:"\\\t"}' }), 'important comments - one': cssContext({ diff --git a/test/selectors/tokenizer-test.js b/test/selectors/tokenizer-test.js index 32d44806..cc044611 100644 --- a/test/selectors/tokenizer-test.js +++ b/test/selectors/tokenizer-test.js @@ -101,6 +101,14 @@ vows.describe(Tokenizer) body: [{ value: 'color:red' }] }] ], + 'a selector with escaped quote': [ + '.this-class\\\'s-got-an-apostrophe{}', + [{ + kind: 'selector', + value: [{ value: '.this-class\\\'s-got-an-apostrophe' }], + body: [] + }] + ], 'a double selector': [ 'a,\n\ndiv.class > p {color:red}', [{ diff --git a/test/utils/quote-scanner-test.js b/test/utils/quote-scanner-test.js index e3e5ab9f..a1e47091 100644 --- a/test/utils/quote-scanner-test.js +++ b/test/utils/quote-scanner-test.js @@ -73,6 +73,28 @@ vows.describe(QuoteScanner) assert.equal(index, 1); } }, + 'one open-ended quote': { + topic: '.this-class\\\'s-got-an-apostrophe {}', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator() { + index++; + }); + + assert.equal(index, 0); + } + }, + 'many open-ended quotes': { + topic: '.this-class\\\'s-got-many\\\"-apostrophes\\\' {}', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator() { + index++; + }); + + assert.equal(index, 0); + } + }, 'two quotes': { topic: 'text with "one \\"quote" and \'another one\'!', iterator: function (topic) {