diff --git a/src/parser.js b/src/parser.js index 9fa3959..8413ae6 100644 --- a/src/parser.js +++ b/src/parser.js @@ -1,11 +1,8 @@ function createParseContext(raw, options) { - var index = 0, line = 1, column = 1; - var nextReadIncrementsLine = false; + var index = 0; var context = { text: { - value: '', - line: 0, - column: 0 + value: '' }, peek: function(count) { count = count || 1; @@ -16,22 +13,11 @@ function createParseContext(raw, options) { return ''; } count = count || 1; - if (nextReadIncrementsLine) { - line++; - column = 0; - nextReadIncrementsLine = false; - } - var next = this.peek(count); - if (next) { - column++; - - if (next === '\n') { - nextReadIncrementsLine = true; - } - } - index += count; + if (index > this.length) { + index = this.length; + } return next; }, readUntilNonWhitespace: function() { @@ -51,14 +37,6 @@ function createParseContext(raw, options) { }, readRegex: function(regex) { var value = (regex.exec(this.raw.substring(this.index)) || [''])[0]; - var lineBreaks = value.replace(/[^\n]/g, '').length; - line += lineBreaks; - if (lineBreaks) { - column = value.substring(Math.max(value.lastIndexOf('\n'), 0)).length; - } else { - column += value.length; - } - index += value.length; return value; }, @@ -91,12 +69,6 @@ function createParseContext(raw, options) { context.__defineGetter__('index', function() { return index; }); - context.__defineGetter__('line', function() { - return line; - }); - context.__defineGetter__('column', function() { - return column; - }); context.__defineGetter__('substring', function() { return this.raw.substring(this.index); }); @@ -115,16 +87,8 @@ var regexes = { regexes.attributeName = regexes.elementName; -function createCallbackContext(context) { - return { - line: context.line, - column: context.column - }; -} - function parseOpenElement(context) { function readAttribute() { - var cbContext = createCallbackContext(context); var name = context.readRegex(regexes.attributeName); var value = null; if (context.current === '=' || context.peekIgnoreWhitespace() === '=') { @@ -139,15 +103,11 @@ function parseOpenElement(context) { context.read(match[0].length); } - context.callbacks.attribute(name, value, cbContext); + context.callbacks.attribute(name, value); } - var line = context.line, column = context.column; var name = context.readRegex(regexes.elementName); - context.callbacks.openElement(name, { - line: line, - column: column - }); + context.callbacks.openElement(name); //read attributes var next = context.current; @@ -166,60 +126,39 @@ function parseOpenElement(context) { } function parseEndElement(context) { - var line = context.line, column = context.column; var name = context.readRegex(regexes.elementName); - context.callbacks.closeElement(name, { - line: line, - column: column - }); - + context.callbacks.closeElement(name); context.readRegex(/.*?(?:>|$)/); } function parseCData(context) { - var cbContext = createCallbackContext(context); - - //we already read the "<" - cbContext.column--; - //read "![CDATA[" context.read(8); var match = /^([\s\S]*?)(?:$|]]>)/.exec(context.substring); var value = match[1]; context.read(value.length + match[0].length); - context.callbacks.cdata(value, cbContext); + context.callbacks.cdata(value); } function parseComment(context) { - var cbContext = createCallbackContext(context); - - //we already read the "<" - cbContext.column--; - //read "!--" context.read(3); var match = /^([\s\S]*?)(?:$|-->)/.exec(context.substring); var value = match[1]; context.read(value.length + match[0].length); - context.callbacks.comment(value, cbContext); + context.callbacks.comment(value); } function appendText(value, context) { - if (!context.text.value) { - context.text.line = context.line; - context.text.column = context.column; - } context.text.value += value; } function callbackText(context) { if (context.text.value) { - context.callbacks.text(context.text.value, createCallbackContext(context.text)); + context.callbacks.text(context.text.value); context.text.value = ''; - context.text.line = 0; - context.text.column = 0; } } diff --git a/tests/attribute-tests.js b/tests/attribute-tests.js index 1a58bae..3f001f2 100644 --- a/tests/attribute-tests.js +++ b/tests/attribute-tests.js @@ -5,16 +5,14 @@ describe('attributes', function() { it('with value, without quotes', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal('bar'); value.should.equal('baz'); - helpers.verifyContext(1, 6, context); attrCount++; } }); @@ -26,16 +24,14 @@ describe('attributes', function() { it('with value, with double quotes', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal('bar'); value.should.equal('baz'); - helpers.verifyContext(1, 6, context); attrCount++; } }); @@ -47,16 +43,14 @@ describe('attributes', function() { it('with value, with single quotes', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal('bar'); value.should.equal('baz'); - helpers.verifyContext(1, 6, context); attrCount++; } }); @@ -68,16 +62,14 @@ describe('attributes', function() { it('without value', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal(attrCount === 0 ? 'bar' : 'baz'); should.not.exist(value); - helpers.verifyContext(1, (attrCount === 0 ? 6 : 10), context); attrCount++; } }); @@ -89,16 +81,14 @@ describe('attributes', function() { it('with value, without quotes should be terminated by line break', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal('bar'); should.not.exist(value); - helpers.verifyContext(1, 6, context); attrCount++; } }); @@ -110,16 +100,14 @@ describe('attributes', function() { it('with and without quotes in same element', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal(attrCount === 0 ? 'width' : 'height'); value.should.equal(attrCount === 0 ? '0' : '12'); - helpers.verifyContext(1, (attrCount === 0 ? 6 : 13), context); attrCount++; } }); @@ -131,16 +119,14 @@ describe('attributes', function() { it('with value and funky whitespace', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal('bar'); value.should.equal('baz'); - helpers.verifyContext(1, 6, context); attrCount++; } }); @@ -152,16 +138,14 @@ describe('attributes', function() { it('with value on different lines', function() { var openCount = 0, attrCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - attribute: function(name, value, context) { + attribute: function(name, value) { name.should.equal('bar'); value.should.equal('baz'); - helpers.verifyContext(1, 6, context); attrCount++; } }); diff --git a/tests/cdata-tests.js b/tests/cdata-tests.js index e335266..92b3d63 100644 --- a/tests/cdata-tests.js +++ b/tests/cdata-tests.js @@ -5,9 +5,8 @@ describe('CDATA', function() { it('inside tags', function() { var cdataCount = 0; helpers.parseString('', { - cdata: function(value, context) { + cdata: function(value) { value.should.equal(' this is cdata '); - helpers.verifyContext(1, 6, context); cdataCount++; } }); @@ -18,9 +17,8 @@ describe('CDATA', function() { it('does not parse elements or entities', function() { var cdataCount = 0; helpers.parseString(' & ]]>', { - cdata: function(value, context) { + cdata: function(value) { value.should.equal(' & '); - helpers.verifyContext(1, 1, context); cdataCount++; } }); @@ -31,9 +29,8 @@ describe('CDATA', function() { it('does not parse as text', function() { var cdataCount = 0, textCount = 0; helpers.parseString('', { - cdata: function(value, context) { + cdata: function(value) { value.should.equal(' foo '); - helpers.verifyContext(1, 1, context); cdataCount++; }, @@ -49,9 +46,8 @@ describe('CDATA', function() { it('respects line breaks', function() { var cdataCount = 0; helpers.parseString('', { - cdata: function(value, context) { + cdata: function(value) { value.should.equal(' \nlol '); - helpers.verifyContext(1, 1, context); cdataCount++; } }); @@ -62,9 +58,8 @@ describe('CDATA', function() { it('reads to end if no ]]> is found', function() { var cdataCount = 0; helpers.parseString('', { - cdata: function(value, context) { + cdata: function(value) { textCount.should.equal(1); value.should.equal('bar'); - helpers.verifyContext(1, 4, context); cdataCount++; }, - text: function(value, context) { + text: function(value) { value.should.equal('foo'); - helpers.verifyContext(1, 1, context); textCount++; } }); diff --git a/tests/comment-tests.js b/tests/comment-tests.js index 882590e..c66796b 100644 --- a/tests/comment-tests.js +++ b/tests/comment-tests.js @@ -5,9 +5,8 @@ describe('Comments', function() { it('inside tags', function() { var commentCount = 0; helpers.parseString('', { - comment: function(value, context) { + comment: function(value) { value.should.equal(' foo bar '); - helpers.verifyContext(1, 6, context); commentCount++; } }); @@ -18,9 +17,8 @@ describe('Comments', function() { it('spanning multiple lines', function() { var commentCount = 0; helpers.parseString('', { - comment: function(value, context) { + comment: function(value) { value.should.equal(' foo \nbar '); - helpers.verifyContext(1, 1, context); commentCount++; } }); @@ -31,9 +29,8 @@ describe('Comments', function() { it('allow tags and entities', function() { var commentCount = 0; helpers.parseString('', { - comment: function(value, context) { + comment: function(value) { value.should.equal(' foo & '); - helpers.verifyContext(1, 1, context); commentCount++; } }); @@ -44,9 +41,8 @@ describe('Comments', function() { it('read to EOF if --> is not given', function() { var commentCount = 0; helpers.parseString('', { - text: function(value, context) { + text: function(value) { value.should.equal('foo'); - helpers.verifyContext(1, 1, context); textCount++; }, - comment: function(value, context) { + comment: function(value) { textCount.should.equal(1); value.should.equal(' bar '); - helpers.verifyContext(1, 4, context); commentCount++; } }); diff --git a/tests/helpers.js b/tests/helpers.js index 4ffac95..f69b2f9 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -4,9 +4,4 @@ exports.parser = htmlParser; exports.parseString = function(string, options) { htmlParser.parse(string, options); -}; - -exports.verifyContext = function(line, column, context) { - context.should.have.property('line').equal(line); - context.should.have.property('column').equal(column); }; \ No newline at end of file diff --git a/tests/malformed-tests.js b/tests/malformed-tests.js index aab1dcf..3dbefed 100644 --- a/tests/malformed-tests.js +++ b/tests/malformed-tests.js @@ -5,7 +5,7 @@ describe('Malformed HTML', function() { it('unescaped < in text should not be an open tag', function() { var openCount = 0, textCount = 0; helpers.parseString('5 < 4 == false', { - openElement: function(name, context) { + openElement: function(name) { openCount++; }, @@ -22,12 +22,12 @@ describe('Malformed HTML', function() { it('< followed by a letter without a following > is still a tag', function() { var openCount = 0, textCount = 0; helpers.parseString('< foo', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); openCount++; }, - text: function(value, context) { + text: function(value) { textCount++; } }); diff --git a/tests/open-and-close-tag-tests.js b/tests/open-and-close-tag-tests.js index 65a34ad..e6c9d65 100644 --- a/tests/open-and-close-tag-tests.js +++ b/tests/open-and-close-tag-tests.js @@ -5,9 +5,8 @@ describe('opening and closing tags', function() { it('element without a closing tag', function() { var count = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); count++; } }); @@ -18,14 +17,12 @@ describe('opening and closing tags', function() { it('element with a closing tag', function() { var openCount = 0, closeCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - closeElement: function(name, context) { + closeElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 8, context); closeCount++; } }); @@ -37,14 +34,12 @@ describe('opening and closing tags', function() { it('tag names can start with _', function() { var openCount = 0, closeCount = 0; helpers.parseString('<_foo>', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('_foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - closeElement: function(name, context) { + closeElement: function(name) { name.should.equal('_foo'); - helpers.verifyContext(1, 9, context); closeCount++; } }); @@ -56,14 +51,29 @@ describe('opening and closing tags', function() { it('opening and closing tag mismatch', function() { var openCount = 0, closeCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 2, context); openCount++; }, - closeElement: function(name, context) { + closeElement: function(name) { + name.should.equal('bar'); + closeCount++; + } + }); + + openCount.should.equal(1); + closeCount.should.equal(1); + }); + + it('tag names with weird whitespace', function() { + var openCount = 0, closeCount = 0; + helpers.parseString('< foo\n>', { + openElement: function(name) { + name.should.equal('foo'); + openCount++; + }, + closeElement: function(name) { name.should.equal('bar'); - helpers.verifyContext(1, 8, context); closeCount++; } }); @@ -75,14 +85,12 @@ describe('opening and closing tags', function() { it('element with a closing tag that doesn\'t end', function() { var openCount = 0, closeCount = 0; helpers.parseString('', { - openElement: function(name, context) { + openElement: function(name) { textCount.should.equal(1); name.should.equal('bar'); - helpers.verifyContext(1, 5, context); openCount++; }, - text: function(name, context) { + text: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 1, context); textCount++; } }); @@ -114,15 +120,13 @@ describe('opening and closing tags', function() { it('outputs buffered text node before close element', function() { var closeCount = 0, textCount = 0; helpers.parseString('foo', { - closeElement: function(name, context) { + closeElement: function(name) { textCount.should.equal(1); name.should.equal('bar'); - helpers.verifyContext(1, 6, context); closeCount++; }, - text: function(name, context) { + text: function(name) { name.should.equal('foo'); - helpers.verifyContext(1, 1, context); textCount++; } }); diff --git a/tests/text-tests.js b/tests/text-tests.js index 039e8ad..ff8836b 100644 --- a/tests/text-tests.js +++ b/tests/text-tests.js @@ -4,9 +4,8 @@ describe('text', function() { it('outside of everything', function() { var textCount = 0; helpers.parseString('foo', { - text: function(text, context) { + text: function(text) { text.should.equal('foo'); - helpers.verifyContext(1, 1, context); textCount++; } }); @@ -17,9 +16,8 @@ describe('text', function() { it('inside a tag', function() { var textCount = 0; helpers.parseString('bar and such', { - text: function(text, context) { + text: function(text) { text.should.equal('bar and such'); - helpers.verifyContext(1, 6, context); textCount++; } });