-(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;
--- /dev/null
+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);