diff --git a/lib/parse/index.js b/lib/parse/index.js index 053f0596..d88c23f3 100644 --- a/lib/parse/index.js +++ b/lib/parse/index.js @@ -11,6 +11,7 @@ module.exports = function(css, options){ var lineno = 1; var column = 1; + var nestinglevel = 0 /** * Update lineno and column based on `str`. @@ -95,7 +96,9 @@ module.exports = function(css, options){ */ function open() { - return match(/^{\s*/); + var hasopenbrace = match(/^{\s*/); + if (hasopenbrace) nestinglevel++ + return hasopenbrace } /** @@ -103,7 +106,9 @@ module.exports = function(css, options){ */ function close() { - return match(/^}/); + var hasclosebrace = match(/^}/); + if (hasclosebrace) nestinglevel-- + return hasclosebrace } /** @@ -119,6 +124,7 @@ module.exports = function(css, options){ if (node !== false) { rules.push(node); comments(rules); + incorrectclosingbrace(); } } return rules; @@ -188,6 +194,22 @@ module.exports = function(css, options){ }); } + /** + * Parse incorrect closing brace. + */ + + function incorrectclosingbrace() { + if (css.length && nestinglevel === 0 && css.charAt(0) == '}') { + error('Extra closing brace') + // remove the closing brace so parsing can continue + css = css.slice(1); + updatePosition('}'); + whitespace(); + // catch multiple incorrect closing braces in a row + incorrectclosingbrace(); + } + } + /** * Parse selector. */ diff --git a/test/parse.js b/test/parse.js index b39b6ee2..fbeabbae 100644 --- a/test/parse.js +++ b/test/parse.js @@ -76,6 +76,22 @@ describe('parse(str)', function() { }); + it('should handle invalid extra closing brace', function() { + var result = parse('foo { color: red; }} bar { color: blue; }', { + silent: true, + source: 'foo.css' + }); + + var rules = result.stylesheet.rules; + rules.length.should.equal(2); + + var errors = result.stylesheet.parsingErrors; + errors.length.should.equal(1); + + errors[0].line.should.equal(1); + errors[0].column.should.equal(20); + }); + it('should set parent property', function() { var result = parse( 'thing { test: value; }\n' +