diff --git a/lib/parser.js b/lib/parser.js index 6712b41d..702f3b7c 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -215,16 +215,16 @@ exports.compile = function compile(indent, parentBlock) { this.parent = token.template; } else if (token.name === 'block') { // Make a list of blocks blockname = token.args[0]; - if (!helpers.isValidBlockName(blockname) || token.args.length > 1) { - throw new Error('Invalid block tag syntax on line ' + token.line + '.'); + if (!helpers.isValidBlockName(blockname) || token.args.length !== 1) { + throw new Error('Invalid block tag name "' + blockname + '" on line ' + token.line + '.'); } if (this.type !== TEMPLATE) { - throw new Error('Block tag found inside another tag on line' + token.line + '.'); + throw new Error('Block "' + blockname + '" found nested in another block tag on line' + token.line + '.'); } try { if (this.hasOwnProperty('parent') && this.parent.blocks.hasOwnProperty(blockname)) { this.blocks[blockname] = compile.call(token, indent + ' ', this.parent.blocks[blockname]); - } else { + } else if (this.hasOwnProperty('blocks')) { this.blocks[blockname] = compile.call(token, indent + ' '); } } catch (error) { @@ -276,10 +276,12 @@ exports.compile = function compile(indent, parentBlock) { if (token.name === 'block') { if (this.type !== TEMPLATE) { - throw new Error('Block tag found nested in another block tag on line ' + token.line + '.'); + throw new Error('Block "' + token.args[0] + '" found nested in another block tag on line ' + token.line + '.'); } - code += this.blocks[token.args[0]]; // Blocks are already compiled in the precompile part + if (this.hasOwnProperty('blocks')) { + code += this.blocks[token.args[0]]; // Blocks are already compiled in the precompile part + } } else if (token.name === 'parent') { code += indent + ' ' + parentBlock; } else { diff --git a/tests/parser.test.js b/tests/parser.test.js index 20319c3c..268af3e7 100644 --- a/tests/parser.test.js +++ b/tests/parser.test.js @@ -1,4 +1,5 @@ var testCase = require('nodeunit').testCase, + tags = require('../lib/tags'), parser = require('../lib/parser'); exports.Tags = testCase({ @@ -148,5 +149,61 @@ exports.Variable = testCase({ }); exports.Compiling = testCase({ - // TODO: fill in tests for compiling + basic: function (test) { + var template = { tokens: [{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [], escape: false, args: null }] }; + test.doesNotThrow(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'broken compilation will throw (from template object)'); + + template = { tokens: parser.parse('{% if foo %}blah{% endif %}', tags) }; + + test.doesNotThrow(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'broken compilation will throw (fromt parsed string)'); + + test.done(); + }, + + 'throws if bad extends': function (test) { + var template = { tokens: parser.parse('{% extends foobar %}', tags) }; + test.throws(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'extend must throw if given variable argument'); + + template = { tokens: parser.parse('{% extends "foo" "bar" %}', tags) }; + test.throws(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'extend must throw if given multiple arguments'); + + test.done(); + }, + + 'throws if extends is not first token': function (test) { + var template = { tokens: parser.parse('blah!{% extends foobar %}', tags) }; + test.throws(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'extend must throw if it is not first token'); + test.done(); + }, + + 'block name requirements': function (test) { + var template = { tokens: parser.parse('{% block foobar %}{% endblock %}', tags), type: parser.TEMPLATE }; + test.doesNotThrow(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'block name must be alpha'); + + template = { tokens: parser.parse('{% block 123 %}{% endblock %}', tags), type: parser.TEMPLATE }; + test.throws(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'block must throw if its name is not alpha'); + test.done(); + }, + + 'block nesting': function (test) { + var template = { tokens: parser.parse('{% block foobar %}{% block barfoo %}{% endblock %}{% endblock %}', tags) }; + test.throws(function () { + eval('var __output = "";' + parser.compile.call(template, '')); + }, 'block should throw if nested'); + test.done(); + } });