Skip to content
Commits on Source (21)
......@@ -7,7 +7,8 @@ node_js:
# Use faster Docker architecture on Travis.
sudo: false
script: "npm test && npm run coveralls"
script: npm test
after_success: npm run coveralls
notifications:
webhooks:
......
1.11.0 / 2015-06-12
==================
* Added block code support ([@alephyud](https://github.com/alephyud))
* Improved runtime performance of mixins significantly ([Andreas Lubbe](https://github.com/alubbe))
* Improved runtime performance of jade's string escaping ([Andreas Lubbe](https://github.com/alubbe)) and ([@ForbesLindesay](http://www.forbeslindesay.co.uk/))
* Better line number counting for pipeless text ([@alephyud](https://github.com/alephyud))
1.10.0 / 2015-05-25
==================
......
......@@ -2,7 +2,7 @@
"name": "jade",
"repo": "visionmedia/jade",
"description": "Jade template runtime",
"version": "1.10.0",
"version": "1.11.0",
"keywords": [
"template"
],
......
......@@ -38,7 +38,7 @@ block content
dd.description If set to true, the tokens and function body is logged to stdout
dt compileDebug:
dd.type.boolean boolean
dd.description Set this to false to disable debugging instrumentation (recommended in production). Set it to true to include the function source in the compiled template for better error messages (sometimes useful in development).
dd.description If set to true, the function source will be included in the compiled template for better error messages (sometimes useful in development). It is enabled by default unless used with express in production mode.
dt cache:
dd.type.boolean boolean
dd.description If set to true, compiled functions are cached. #[code filename] must be set as the cache key.
......@@ -133,11 +133,11 @@ block content
// Render the function
var html = fn(locals);
// => 'function template(locals) { return "<string>of jade</string>"; }'
h3 jade.compileClientWithDependenciesTracked(source, options)
p See #[code jade.compileClient] except that this method returns an object of the form:
+js
:jssrc
{
......
......@@ -21,6 +21,27 @@ block documentation
<li>item</li>
<li>item</li>
<li>item</li>
p Jade also supports block unbuffered code:
.row(data-control='interactive')
.col-lg-6
+jade
:jadesrc
-
list = ["Uno", "Dos", "Tres",
"Cuatro", "Cinco", "Seis"]
each item in list
li= item
.col-lg-6
+html
:htmlsrc
<li>Uno</li>
<li>Dos</li>
<li>Tres</li>
<li>Cuatro</li>
<li>Cinco</li>
<li>Seis</li>
h2 Buffered Code
......@@ -72,7 +93,7 @@ block documentation
.col-lg-6
+jade
:jadesrc
p!= 'This code is <strong>not</strong> escaped!'
p!= 'This code is' + ' <strong>not</strong> escaped!'
.col-lg-6
+html
:htmlsrc
......
- var title = "Things"
-
var subtitle = ["Really", "long",
"list", "of",
"words"]
h1= title
h2= subtitle.join(" ")
ul#users
each user, name in users
......
This diff is collapsed.
......@@ -404,7 +404,9 @@ Compiler.prototype = {
if (args.length && /^\.\.\./.test(args[args.length - 1].trim())) {
rest = args.pop().trim().replace(/^\.\.\./, '');
}
this.buf.push(name + ' = function(' + args.join(',') + '){');
// we need use jade_interp here for v8: https://code.google.com/p/v8/issues/detail?id=4165
// once fixed, use this: this.buf.push(name + ' = function(' + args.join(',') + '){');
this.buf.push(name + ' = jade_interp = function(' + args.join(',') + '){');
this.buf.push('var block = (this && this.block), attributes = (this && this.attributes) || {};');
if (rest) {
this.buf.push('var ' + rest + ' = [];');
......
......@@ -586,6 +586,21 @@ Lexer.prototype = {
}
},
/**
* Block code.
*/
blockCode: function() {
var captures;
if (captures = /^-\n/.exec(this.input)) {
this.consume(captures[0].length - 1);
var tok = this.tok('blockCode');
this.pipeless = true;
return tok;
}
},
/**
* Attributes.
*/
......@@ -845,6 +860,7 @@ Lexer.prototype = {
if (isMatch) {
// consume test along with `\n` prefix if match
this.consume(str.length + 1);
++this.lineno;
tokens.push(str.substr(indent.length));
}
} while(this.input.length && isMatch);
......@@ -916,6 +932,7 @@ Lexer.prototype = {
|| this["while"]()
|| this.tag()
|| this.filter()
|| this.blockCode()
|| this.code()
|| this.id()
|| this.className()
......
......@@ -233,6 +233,8 @@ Parser.prototype = {
return this.parseEach();
case 'code':
return this.parseCode();
case 'blockCode':
return this.parseBlockCode();
case 'call':
return this.parseCall();
case 'interpolation':
......@@ -376,6 +378,25 @@ Parser.prototype = {
return node;
},
/**
* block code
*/
parseBlockCode: function(){
var tok = this.expect('blockCode');
var node;
var body = this.peek();
var text;
if (body.type === 'pipeless-text') {
this.advance();
text = body.val.join('\n');
} else {
text = '';
}
node = new nodes.Code(text, false, false);
return node;
},
/**
* comment
*/
......
......@@ -179,12 +179,21 @@ exports.attrs = function attrs(obj, terse){
* @api private
*/
exports.escape = function escape(html){
var result = String(html)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
var jade_encode_html_rules = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;'
};
var jade_match_html = /[&<>"]/g;
function jade_encode_char(c) {
return jade_encode_html_rules[c] || c;
}
exports.escape = jade_escape;
function jade_escape(html){
var result = String(html).replace(jade_match_html, jade_encode_char);
if (result === '' + html) return html;
else return result;
};
......
{
"name": "jade",
"description": "A clean, whitespace-sensitive template language for writing HTML",
"version": "1.10.0",
"version": "1.11.0",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"maintainers": [
"Forbes Lindesay <forbes@lindesay.co.uk>",
......
......@@ -180,12 +180,21 @@ exports.attrs = function attrs(obj, terse){
* @api private
*/
exports.escape = function escape(html){
var result = String(html)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
var jade_encode_html_rules = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;'
};
var jade_match_html = /[&<>"]/g;
function jade_encode_char(c) {
return jade_encode_html_rules[c] || c;
}
exports.escape = jade_escape;
function jade_escape(html){
var result = String(html).replace(jade_match_html, jade_encode_char);
if (result === '' + html) return html;
else return result;
};
......
<li>Uno</li>
<li>Dos</li>
<li>Tres</li>
<li>Cuatro</li>
<li>Cinco</li>
<li>Seis</li>
-
list = ["uno", "dos", "tres",
"cuatro", "cinco", "seis"];
//- Without a block, the element is accepted and no code is generated
-
each item in list
-
string = item.charAt(0)
.toUpperCase() +
item.slice(1);
li= string
......@@ -681,6 +681,19 @@ describe('jade', function(){
].join('');
assert.equal(html, jade.render(str));
var str = [
'-',
' var a =',
' 5;',
'p= a'
].join('\n')
var html = [
'<p>5</p>'
].join('');
assert.equal(html, jade.render(str));
});
it('should support - each', function(){
......@@ -881,6 +894,32 @@ describe('jade', function(){
assert.equal("<p>foo\u2028bar</p>", jade.render("p foo\u2028bar"));
assert.equal("<p>foo\u2029bar</p>", jade.render("p foo\u2029bar"));
});
it('should display error line number correctly up to token level', function() {
var str = [
'p.',
' Lorem ipsum dolor sit amet, consectetur',
' adipisicing elit, sed do eiusmod tempor',
' incididunt ut labore et dolore magna aliqua.',
'p.',
' Ut enim ad minim veniam, quis nostrud',
' exercitation ullamco laboris nisi ut aliquip',
' ex ea commodo consequat.',
'p.',
' Duis aute irure dolor in reprehenderit',
' in voluptate velit esse cillum dolore eu',
' fugiat nulla pariatur.',
'a(href="#" Next',
].join('\n');
var errorLocation = function(str) {
try {
jade.render(str);
} catch (err) {
return err.message.split('\n')[0];
}
};
assert.equal(errorLocation(str), "Jade:13");
});
});
describe('.compileFile()', function () {
......