Skip to content

Commit d22bcf9

Browse files
author
Forbes Lindesay
committed
Move self-closing tags logic back to compiler so it works with xml
[closes pugjs#1448][closes pugjs#1464] Also makes invalid filter-name errors get reported with the correct line numbers and correctly reports errors when we have no idea what line/file the error is in.
1 parent a30c204 commit d22bcf9

File tree

6 files changed

+64
-38
lines changed

6 files changed

+64
-38
lines changed

lib/compiler.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var filters = require('./filters');
55
var doctypes = require('./doctypes');
66
var runtime = require('./runtime');
77
var utils = require('./utils');
8+
var selfClosing = require('./self-closing');
89
var parseJSExpression = require('character-parser').parseMax;
910
var constantinople = require('constantinople');
1011

@@ -14,7 +15,11 @@ function isConstant(src) {
1415
function toConstant(src) {
1516
return constantinople.toConstant(src, {jade: runtime, 'jade_interp': undefined});
1617
}
17-
18+
function errorAtNode(node, error) {
19+
error.line = node.line;
20+
error.filename = node.filename;
21+
return error;
22+
}
1823

1924
/**
2025
* Initialize `Compiler` with the given `node`.
@@ -434,13 +439,21 @@ Compiler.prototype = {
434439
if (pp && !tag.isInline())
435440
this.prettyIndent(0, true);
436441

437-
if (tag.selfClosing && !this.xml) {
442+
if (tag.selfClosing || (!this.xml && selfClosing.indexOf(tag.name) !== -1)) {
438443
this.buffer('<');
439444
bufferName();
440445
this.visitAttributes(tag.attrs, tag.attributeBlocks);
441446
this.terse
442447
? this.buffer('>')
443448
: this.buffer('/>');
449+
// if it is non-empty throw an error
450+
if (tag.block &&
451+
!(tag.block.type === 'Block' && tag.block.nodes.length === 0) &&
452+
tag.block.nodes.some(function (tag) {
453+
return tag.type !== 'Text' || !/^\s*$/.test(tag.val)
454+
})) {
455+
throw errorAtNode(tag, new Error(name + ' is self closing and should not have content.'));
456+
}
444457
} else {
445458
// Optimize attributes buffering
446459
this.buffer('<');
@@ -476,7 +489,11 @@ Compiler.prototype = {
476489
function(node){ return node.val; }
477490
).join('\n');
478491
filter.attrs.filename = this.options.filename;
479-
this.buffer(filters(filter.name, text, filter.attrs), true);
492+
try {
493+
this.buffer(filters(filter.name, text, filter.attrs), true);
494+
} catch (err) {
495+
throw errorAtNode(filter, err);
496+
}
480497
},
481498

482499
/**

lib/jade.js

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -87,39 +87,49 @@ exports.cache = {};
8787
*/
8888

8989
function parse(str, options){
90+
// Parse
91+
var parser = new (options.parser || Parser)(str, options.filename, options);
92+
var tokens;
9093
try {
9194
// Parse
92-
var parser = new (options.parser || Parser)(str, options.filename, options);
93-
94-
// Compile
95-
var compiler = new (options.compiler || Compiler)(parser.parse(), options)
96-
, js = compiler.compile();
97-
98-
// Debug compiler
99-
if (options.debug) {
100-
console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, ' '));
101-
}
102-
103-
var globals = [];
104-
105-
globals.push('jade');
106-
globals.push('jade_mixins');
107-
globals.push('jade_interp');
108-
globals.push('jade_debug');
109-
globals.push('buf');
110-
111-
return ''
112-
+ 'var buf = [];\n'
113-
+ 'var jade_mixins = {};\n'
114-
+ 'var jade_interp;\n'
115-
+ (options.self
116-
? 'var self = locals || {};\n' + js
117-
: addWith('locals || {}', '\n' + js, globals)) + ';'
118-
+ 'return buf.join("");';
95+
tokens = parser.parse();
11996
} catch (err) {
12097
parser = parser.context();
12198
runtime.rethrow(err, parser.filename, parser.lexer.lineno, parser.input);
12299
}
100+
101+
// Compile
102+
var compiler = new (options.compiler || Compiler)(tokens, options);
103+
var js;
104+
try {
105+
js = compiler.compile();
106+
} catch (err) {
107+
if (err.line && (err.filename || !options.filename)) {
108+
runtime.rethrow(err, err.filename, err.line, parser.input);
109+
}
110+
}
111+
112+
// Debug compiler
113+
if (options.debug) {
114+
console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, ' '));
115+
}
116+
117+
var globals = [];
118+
119+
globals.push('jade');
120+
globals.push('jade_mixins');
121+
globals.push('jade_interp');
122+
globals.push('jade_debug');
123+
globals.push('buf');
124+
125+
return ''
126+
+ 'var buf = [];\n'
127+
+ 'var jade_mixins = {};\n'
128+
+ 'var jade_interp;\n'
129+
+ (options.self
130+
? 'var self = locals || {};\n' + js
131+
: addWith('locals || {}', '\n' + js, globals)) + ';'
132+
+ 'return buf.join("");';
123133
}
124134

125135
/**

lib/lexer.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
var utils = require('./utils');
44
var characterParser = require('character-parser');
5-
var selfClosing = require('./self-closing');
65

76

87
/**
@@ -227,7 +226,7 @@ Lexer.prototype = {
227226
} else {
228227
tok = this.tok('tag', name);
229228
}
230-
tok.selfClosing = !!captures[2] || selfClosing.indexOf(name) !== -1;
229+
tok.selfClosing = !!captures[2];
231230
return tok;
232231
}
233232
},

lib/parser.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -765,12 +765,6 @@ Parser.prototype = {
765765
this.advance();
766766
}
767767

768-
if (tag.selfClosing
769-
&& ['newline', 'outdent', 'eos'].indexOf(this.peek().type) === -1
770-
&& (this.peek().type !== 'text' || !/^\s*$/.test(this.peek().val))) {
771-
throw new Error(tag.name + ' is self closing and should not have content.');
772-
}
773-
774768
// (text | code | ':')?
775769
switch (this.peek().type) {
776770
case 'text':

test/cases/xml.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<category term="some term"/>
3+
<link>http://google.com</link>

test/cases/xml.jade

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
doctype xml
2+
category(term='some term')/
3+
link http://google.com

0 commit comments

Comments
 (0)