From: Jakub Pawlowicz Date: Thu, 25 Sep 2014 12:21:42 +0000 (+0100) Subject: Improves QuoteScanner. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=b0ecf2636cfb341f970fd8de78e395196ce1ee3e;p=clean-css.git Improves QuoteScanner. * Removes module wrapper. * Adds set of tests. --- diff --git a/lib/text/quote-scanner.js b/lib/text/quote-scanner.js index f04e26b8..8981daca 100644 --- a/lib/text/quote-scanner.js +++ b/lib/text/quote-scanner.js @@ -1,91 +1,89 @@ -(function() { - var QuoteScanner = function QuoteScanner(data) { - this.data = data; - }; - - var findQuoteEnd = function(data, matched, cursor, oldCursor) { - var commentStartMark = '/*'; - var commentEndMark = '*/'; - var escapeMark = '\\'; - var blockEndMark = '}'; - var dataPrefix = data.substring(oldCursor, cursor); - var commentEndedAt = dataPrefix.lastIndexOf(commentEndMark, cursor); - var commentStartedAt = dataPrefix.lastIndexOf(commentStartMark, cursor); - var commentStarted = false; - - if (commentEndedAt >= cursor && commentStartedAt > -1) - commentStarted = true; - if (commentStartedAt < cursor && commentStartedAt > commentEndedAt) - commentStarted = true; - - if (commentStarted) { - var commentEndsAt = data.indexOf(commentEndMark, cursor); - if (commentEndsAt > -1) - return commentEndsAt; - - commentEndsAt = data.indexOf(blockEndMark, cursor); - return commentEndsAt > -1 ? commentEndsAt - 1 : data.length; +var QuoteScanner = function QuoteScanner(data) { + this.data = data; +}; + +var findQuoteEnd = function (data, matched, cursor, oldCursor) { + var commentStartMark = '/*'; + var commentEndMark = '*/'; + var escapeMark = '\\'; + var blockEndMark = '}'; + var dataPrefix = data.substring(oldCursor, cursor); + var commentEndedAt = dataPrefix.lastIndexOf(commentEndMark, cursor); + var commentStartedAt = dataPrefix.lastIndexOf(commentStartMark, cursor); + var commentStarted = false; + + if (commentEndedAt >= cursor && commentStartedAt > -1) + commentStarted = true; + if (commentStartedAt < cursor && commentStartedAt > commentEndedAt) + commentStarted = true; + + if (commentStarted) { + var commentEndsAt = data.indexOf(commentEndMark, cursor); + if (commentEndsAt > -1) + return commentEndsAt; + + commentEndsAt = data.indexOf(blockEndMark, cursor); + return commentEndsAt > -1 ? commentEndsAt - 1 : data.length; + } + + while (true) { + if (data[cursor] === undefined) + break; + if (data[cursor] == matched && (data[cursor - 1] != escapeMark || data[cursor - 2] == escapeMark)) + break; + + cursor++; + } + + return cursor; +}; + +QuoteScanner.prototype.each = function (callback) { + var data = this.data; + var tempData = []; + var nextStart = 0; + var nextEnd = 0; + var cursor = 0; + var matchedMark = null; + var singleMark = '\''; + var doubleMark = '"'; + var dataLength = data.length; + + for (; nextEnd < data.length;) { + var nextStartSingle = data.indexOf(singleMark, nextEnd + 1); + var nextStartDouble = data.indexOf(doubleMark, nextEnd + 1); + + if (nextStartSingle == -1) + nextStartSingle = dataLength; + if (nextStartDouble == -1) + nextStartDouble = dataLength; + + if (nextStartSingle < nextStartDouble) { + nextStart = nextStartSingle; + matchedMark = singleMark; + } else { + nextStart = nextStartDouble; + matchedMark = doubleMark; } - while (true) { - if (data[cursor] === undefined) - break; - if (data[cursor] == matched && (data[cursor - 1] != escapeMark || data[cursor - 2] == escapeMark)) - break; + if (nextStart == -1) + break; - cursor++; - } + nextEnd = findQuoteEnd(data, matchedMark, nextStart + 1, cursor); + if (nextEnd == -1) + break; - return cursor; - }; - - QuoteScanner.prototype.each = function(callback) { - var data = this.data; - var tempData = []; - var nextStart = 0; - var nextEnd = 0; - var cursor = 0; - var matchedMark = null; - var singleMark = '\''; - var doubleMark = '"'; - var dataLength = data.length; - - for (; nextEnd < data.length;) { - var nextStartSingle = data.indexOf(singleMark, nextEnd + 1); - var nextStartDouble = data.indexOf(doubleMark, nextEnd + 1); - - if (nextStartSingle == -1) - nextStartSingle = dataLength; - if (nextStartDouble == -1) - nextStartDouble = dataLength; - - if (nextStartSingle < nextStartDouble) { - nextStart = nextStartSingle; - matchedMark = singleMark; - } else { - nextStart = nextStartDouble; - matchedMark = doubleMark; - } - - if (nextStart == -1) - break; - - nextEnd = findQuoteEnd(data, matchedMark, nextStart + 1, cursor); - if (nextEnd == -1) - break; - - var text = data.substring(nextStart, nextEnd + 1); - tempData.push(data.substring(cursor, nextStart)); - if (text.length > 0) - callback(text, tempData, nextStart); - - cursor = nextEnd + 1; - } + var text = data.substring(nextStart, nextEnd + 1); + tempData.push(data.substring(cursor, nextStart)); + if (text.length > 0) + callback(text, tempData, nextStart); + + cursor = nextEnd + 1; + } - return tempData.length > 0 ? - tempData.join('') + data.substring(cursor, data.length) : - data; - }; + return tempData.length > 0 ? + tempData.join('') + data.substring(cursor, data.length) : + data; +}; - module.exports = QuoteScanner; -})(); +module.exports = QuoteScanner; diff --git a/test/text/quote-scanner-test.js b/test/text/quote-scanner-test.js new file mode 100644 index 00000000..9b89f656 --- /dev/null +++ b/test/text/quote-scanner-test.js @@ -0,0 +1,98 @@ +var vows = require('vows'); +var assert = require('assert'); +var QuoteScanner = require('../../lib/text/quote-scanner'); + +vows.describe(QuoteScanner) + .addBatch({ + 'no quotes': { + topic: 'text without quotes', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator() { index++; }); + + assert.equal(0, index); + } + }, + 'one single quote': { + topic: 'text with \'one quote\'!', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { + index++; + + assert.equal('\'one quote\'', match); + assert.deepEqual(['text with '], tokensSoFar); + assert.equal(10, nextStart); + }); + + assert.equal(1, index); + } + }, + 'one double quote': { + topic: 'text with "one quote"!', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { + index++; + + assert.equal('"one quote"', match); + assert.deepEqual(['text with '], tokensSoFar); + assert.equal(10, nextStart); + }); + + assert.equal(1, index); + } + }, + 'mixed quotes': { + topic: 'text with "one \'quote\'"!', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { + index++; + + assert.equal('"one \'quote\'"', match); + assert.deepEqual(['text with '], tokensSoFar); + assert.equal(10, nextStart); + }); + + assert.equal(1, index); + } + }, + 'escaped quotes': { + topic: 'text with "one \\"quote"!', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { + index++; + + assert.equal('"one \\"quote"', match); + assert.deepEqual(['text with '], tokensSoFar); + assert.equal(10, nextStart); + }); + + assert.equal(1, index); + } + }, + 'two quotes': { + topic: 'text with "one \\"quote" and \'another one\'!', + iterator: function (topic) { + var index = 0; + new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { + index++; + + if (index == 1) { + assert.equal('"one \\"quote"', match); + assert.deepEqual(['text with '], tokensSoFar); + assert.equal(10, nextStart); + } else { + assert.equal('\'another one\'', match); + assert.deepEqual(['text with ', ' and '], tokensSoFar); + assert.equal(28, nextStart); + } + }); + + assert.equal(2, index); + } + } + }) + .export(module);