Comparing version 0.34.1 to 0.35.0
@@ -5,3 +5,3 @@ { | ||
"description": "Jade template runtime", | ||
"version": "0.34.1", | ||
"version": "0.35.0", | ||
"keywords": [ | ||
@@ -8,0 +8,0 @@ "template" |
@@ -140,4 +140,5 @@ /*! | ||
bufferExpression: function (src) { | ||
var fn = Function('', 'return (' + src + ');'); | ||
if (isConstant(src)) { | ||
return this.buffer(toConstant(src), false) | ||
return this.buffer(fn(), false) | ||
} | ||
@@ -144,0 +145,0 @@ if (this.lastBufferedIdx == this.buf.length) { |
@@ -114,16 +114,2 @@ /*! | ||
/** | ||
* Strip any UTF-8 BOM off of the start of `str`, if it exists. | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function stripBOM(str){ | ||
return 0xFEFF == str.charCodeAt(0) | ||
? str.substring(1) | ||
: str; | ||
} | ||
/** | ||
* Compile a `Function` representation of the given jade `str`. | ||
@@ -151,3 +137,3 @@ * | ||
str = stripBOM(String(str)); | ||
str = String(str); | ||
@@ -154,0 +140,0 @@ if (options.compileDebug !== false) { |
256
lib/lexer.js
@@ -8,4 +8,5 @@ /*! | ||
var utils = require('./utils'); | ||
var parseJSExpression = require('character-parser').parseMax; | ||
var characterParser = require('character-parser'); | ||
/** | ||
@@ -36,2 +37,16 @@ * Initialize `Lexer` with the given `str`. | ||
function assertExpression(exp) { | ||
//this verifies that a JavaScript expression is valid | ||
Function('', 'return (' + exp + ')'); | ||
} | ||
function assertNestingCorrect(exp) { | ||
//this verifies that code is properly nested, but allows | ||
//invalid JavaScript such as the contents of `attributes` | ||
var res = characterParser(exp) | ||
if (res.isNesting()) { | ||
throw new Error('Nesting must match on expression `' + exp + '`') | ||
} | ||
} | ||
/** | ||
@@ -125,3 +140,3 @@ * Lexer prototype. | ||
var end = ({'(': ')', '{': '}', '[': ']'})[start]; | ||
var range = parseJSExpression(this.input, {start: skip + 1}); | ||
var range = characterParser.parseMax(this.input, {start: skip + 1}); | ||
if (this.input[range.end] !== end) throw new Error('start character ' + start + ' does not match end character ' + this.input[range.end]); | ||
@@ -435,6 +450,20 @@ return range; | ||
switch (type) { | ||
case 'if': js = 'if (' + js + ')'; break; | ||
case 'unless': js = 'if (!(' + js + '))'; break; | ||
case 'else if': js = 'else if (' + js + ')'; break; | ||
case 'else': js = 'else'; break; | ||
case 'if': | ||
assertExpression(js) | ||
js = 'if (' + js + ')'; | ||
break; | ||
case 'unless': | ||
assertExpression(js) | ||
js = 'if (!(' + js + '))'; | ||
break; | ||
case 'else if': | ||
assertExpression(js) | ||
js = 'else if (' + js + ')'; | ||
break; | ||
case 'else': | ||
if (js && js.trim()) { | ||
throw new Error('`else` cannot have a condition, perhaps you meant `else if`'); | ||
} | ||
js = 'else'; | ||
break; | ||
} | ||
@@ -454,2 +483,3 @@ | ||
this.consume(captures[0].length); | ||
assertExpression(captures[1]) | ||
return this.tok('code', 'while (' + captures[1] + ')'); | ||
@@ -469,2 +499,3 @@ } | ||
tok.key = captures[2] || '$index'; | ||
assertExpression(captures[3]) | ||
tok.code = captures[3]; | ||
@@ -488,2 +519,3 @@ return tok; | ||
tok.buffer = flags.charAt(0) === '=' || flags.charAt(1) === '='; | ||
if (tok.buffer) assertExpression(captures[1]) | ||
return tok; | ||
@@ -502,16 +534,11 @@ } | ||
, tok = this.tok('attrs') | ||
, len = str.length | ||
, colons = this.colons | ||
, states = ['key'] | ||
, escapedAttr | ||
, key = '' | ||
, val = '' | ||
, quote | ||
, c | ||
, p; | ||
, equals = this.colons ? ':' : '='; | ||
function state(){ | ||
return states[states.length - 1]; | ||
if (equals === ':') { | ||
console.warn('`:` in jade is deprecated, please use `=`'); | ||
} | ||
assertNestingCorrect(str); | ||
var quote = ''; | ||
function interpolate(attr) { | ||
@@ -521,4 +548,5 @@ return attr.replace(/(\\)?#\{(.+)/g, function(_, escape, expr){ | ||
try { | ||
var range = parseJSExpression(expr); | ||
var range = characterParser.parseMax(expr); | ||
if (expr[range.end] !== '}') return _.substr(0, 2) + interpolate(_.substr(2)); | ||
assertExpression(range.src) | ||
return quote + " + (" + range.src + ") + " + quote + interpolate(expr.substr(range.end + 1)); | ||
@@ -535,112 +563,96 @@ } catch (ex) { | ||
function parse(c) { | ||
var real = c; | ||
// TODO: remove when people fix ":" | ||
if (colons && ':' == c) c = '='; | ||
switch (c) { | ||
case ',': | ||
case '\n': | ||
switch (state()) { | ||
case 'expr': | ||
case 'array': | ||
case 'string': | ||
case 'object': | ||
val += c; | ||
break; | ||
default: | ||
states.push('key'); | ||
val = val.trim(); | ||
key = key.trim(); | ||
if ('' == key) return; | ||
key = key.replace(/^['"]|['"]$/g, '').replace('!', ''); | ||
tok.escaped[key] = escapedAttr; | ||
tok.attrs[key] = '' == val | ||
? true | ||
: interpolate(val); | ||
key = val = ''; | ||
var escapedAttr = true | ||
var key = ''; | ||
var val = ''; | ||
var interpolatable = ''; | ||
var state = characterParser.defaultState(); | ||
var loc = 'key'; | ||
function isEndOfAttribute(i) { | ||
if (key.trim() === '') return false; | ||
if (i === str.length) return true; | ||
if (loc === 'key') { | ||
if (str[i] === ' ' || str[i] === '\n') { | ||
for (var x = i; x < str.length; x++) { | ||
if (str[x] != ' ' && str[x] != '\n') { | ||
if (str[x] === '=' || str[x] === '!' || str[x] === ',') return false; | ||
else return true; | ||
} | ||
} | ||
break; | ||
case '=': | ||
switch (state()) { | ||
case 'key char': | ||
key += real; | ||
break; | ||
case 'val': | ||
case 'expr': | ||
case 'array': | ||
case 'string': | ||
case 'object': | ||
val += real; | ||
break; | ||
default: | ||
escapedAttr = '!' != p; | ||
states.push('val'); | ||
} | ||
return str[i] === ',' | ||
} else if (loc === 'value' && !state.isNesting()) { | ||
try { | ||
Function('', 'return (' + val + ');'); | ||
if (str[i] === ' ' || str[i] === '\n') { | ||
for (var x = i; x < str.length; x++) { | ||
if (str[x] != ' ' && str[x] != '\n') { | ||
if (characterParser.isPunctuator(str[x]) && str[x] != '"' && str[x] != "'") return false; | ||
else return true; | ||
} | ||
} | ||
} | ||
break; | ||
case '(': | ||
if ('val' == state() | ||
|| 'expr' == state()) states.push('expr'); | ||
val += c; | ||
break; | ||
case ')': | ||
if ('expr' == state() | ||
|| 'val' == state()) states.pop(); | ||
val += c; | ||
break; | ||
case '{': | ||
if ('val' == state()) states.push('object'); | ||
val += c; | ||
break; | ||
case '}': | ||
if ('object' == state()) states.pop(); | ||
val += c; | ||
break; | ||
case '[': | ||
if ('val' == state()) states.push('array'); | ||
val += c; | ||
break; | ||
case ']': | ||
if ('array' == state()) states.pop(); | ||
val += c; | ||
break; | ||
case '"': | ||
case "'": | ||
switch (state()) { | ||
case 'key': | ||
states.push('key char'); | ||
break; | ||
case 'key char': | ||
states.pop(); | ||
break; | ||
case 'string': | ||
if (c == quote) states.pop(); | ||
val += c; | ||
break; | ||
default: | ||
states.push('string'); | ||
val += c; | ||
quote = c; | ||
} | ||
break; | ||
case '': | ||
break; | ||
default: | ||
switch (state()) { | ||
case 'key': | ||
case 'key char': | ||
key += c; | ||
break; | ||
default: | ||
val += c; | ||
} | ||
return str[i] === ','; | ||
} catch (ex) { | ||
return false; | ||
} | ||
} | ||
p = c; | ||
} | ||
for (var i = 0; i < len; ++i) { | ||
parse(str.charAt(i)); | ||
for (var i = 0; i <= str.length; i++) { | ||
if (isEndOfAttribute(i)) { | ||
val = val.trim(); | ||
if (val) assertExpression(val) | ||
key = key.trim(); | ||
key = key.replace(/^['"]|['"]$/g, ''); | ||
tok.escaped[key] = escapedAttr; | ||
tok.attrs[key] = '' == val ? true : val; | ||
key = val = ''; | ||
loc = 'key'; | ||
escapedAttr = false; | ||
} else { | ||
switch (loc) { | ||
case 'key-char': | ||
if (str[i] === quote) { | ||
loc = 'key'; | ||
if (i + 1 < str.length && [' ', ',', '!', equals, '\n'].indexOf(str[i + 1]) === -1) | ||
throw new Error('Unexpected character ' + str[i + 1] + ' expected ` `, `\\n`, `,`, `!` or `=`'); | ||
} else if (loc === 'key-char') { | ||
key += str[i]; | ||
} | ||
break; | ||
case 'key': | ||
if (key === '' && (str[i] === '"' || str[i] === "'")) { | ||
loc = 'key-char'; | ||
quote = str[i]; | ||
} else if (str[i] === '!' || str[i] === equals) { | ||
escapedAttr = str[i] !== '!'; | ||
if (str[i] === '!') i++; | ||
if (str[i] !== equals) throw new Error('Unexpected character ' + str[i] + ' expected `=`'); | ||
loc = 'value'; | ||
state = characterParser.defaultState(); | ||
} else { | ||
key += str[i] | ||
} | ||
break; | ||
case 'value': | ||
state = characterParser.parseChar(str[i], state); | ||
if (state.isString()) { | ||
loc = 'string'; | ||
quote = str[i]; | ||
interpolatable = str[i]; | ||
} else { | ||
val += str[i]; | ||
} | ||
break; | ||
case 'string': | ||
state = characterParser.parseChar(str[i], state); | ||
interpolatable += str[i]; | ||
if (!state.isString()) { | ||
loc = 'value'; | ||
val += interpolate(interpolatable); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
parse(','); | ||
if ('/' == this.input.charAt(0)) { | ||
@@ -647,0 +659,0 @@ this.consume(1); |
@@ -29,3 +29,5 @@ | ||
Attrs.prototype.__proto__ = Node.prototype; | ||
Attrs.prototype = Object.create(Node.prototype); | ||
Attrs.prototype.constructor = Attrs; | ||
Attrs.prototype.constructor.name = 'Attrs'; // prevent the minifiers removing this | ||
@@ -32,0 +34,0 @@ /** |
@@ -33,2 +33,4 @@ | ||
BlockComment.prototype.__proto__ = Node.prototype; | ||
BlockComment.prototype = Object.create(Node.prototype); | ||
BlockComment.prototype.constructor = BlockComment; | ||
BlockComment.prototype.constructor.name = 'BlockComment'; // prevent the minifiers removing this |
@@ -30,4 +30,7 @@ | ||
Block.prototype.__proto__ = Node.prototype; | ||
Block.prototype = Object.create(Node.prototype); | ||
Block.prototype.constructor = Block; | ||
Block.prototype.constructor.name = 'Block'; // prevent the minifiers removing this | ||
/** | ||
@@ -34,0 +37,0 @@ * Block flag. |
@@ -30,3 +30,5 @@ | ||
Case.prototype.__proto__ = Node.prototype; | ||
Case.prototype = Object.create(Node.prototype); | ||
Case.prototype.constructor = Case; | ||
Case.prototype.constructor.name = 'Case'; // prevent the minifiers removing this | ||
@@ -43,3 +45,4 @@ var When = exports.When = function When(expr, block){ | ||
When.prototype.__proto__ = Node.prototype; | ||
When.prototype = Object.create(Node.prototype); | ||
When.prototype.constructor = When; | ||
When.prototype.constructor.name = 'When'; // prevent the minifiers removing this |
@@ -35,2 +35,4 @@ | ||
Code.prototype.__proto__ = Node.prototype; | ||
Code.prototype = Object.create(Node.prototype); | ||
Code.prototype.constructor = Code; | ||
Code.prototype.constructor.name = 'Code'; // prevent the minifiers removing this |
@@ -32,2 +32,4 @@ | ||
Comment.prototype.__proto__ = Node.prototype; | ||
Comment.prototype = Object.create(Node.prototype); | ||
Comment.prototype.constructor = Comment; | ||
Comment.prototype.constructor.name = 'Comment'; // prevent the minifiers removing this |
@@ -29,2 +29,4 @@ | ||
Doctype.prototype.__proto__ = Node.prototype; | ||
Doctype.prototype = Object.create(Node.prototype); | ||
Doctype.prototype.constructor = Doctype; | ||
Doctype.prototype.constructor.name = 'Doctype'; // prevent the minifiers removing this |
@@ -35,2 +35,4 @@ | ||
Each.prototype.__proto__ = Node.prototype; | ||
Each.prototype = Object.create(Node.prototype); | ||
Each.prototype.constructor = Each; | ||
Each.prototype.constructor.name = 'Each'; // prevent the minifiers removing this |
@@ -34,2 +34,4 @@ | ||
Filter.prototype.__proto__ = Node.prototype; | ||
Filter.prototype = Object.create(Node.prototype); | ||
Filter.prototype.constructor = Filter; | ||
Filter.prototype.constructor.name = 'Filter'; // prevent the minifiers removing this |
@@ -29,2 +29,4 @@ | ||
Literal.prototype.__proto__ = Node.prototype; | ||
Literal.prototype = Object.create(Node.prototype); | ||
Literal.prototype.constructor = Literal; | ||
Literal.prototype.constructor.name = 'Literal'; // prevent the minifiers removing this |
@@ -35,3 +35,4 @@ | ||
Mixin.prototype.__proto__ = Attrs.prototype; | ||
Mixin.prototype = Object.create(Attrs.prototype); | ||
Mixin.prototype.constructor = Mixin; | ||
Mixin.prototype.constructor.name = 'Mixin'; // prevent the minifiers removing this |
@@ -34,3 +34,5 @@ | ||
Tag.prototype.__proto__ = Attrs.prototype; | ||
Tag.prototype = Object.create(Attrs.prototype); | ||
Tag.prototype.constructor = Tag; | ||
Tag.prototype.constructor.name = 'Tag'; // prevent the minifiers removing this | ||
@@ -37,0 +39,0 @@ /** |
@@ -30,3 +30,5 @@ | ||
Text.prototype.__proto__ = Node.prototype; | ||
Text.prototype = Object.create(Node.prototype); | ||
Text.prototype.constructor = Text; | ||
Text.prototype.constructor.name = 'Text'; // prevent the minifiers removing this | ||
@@ -33,0 +35,0 @@ /** |
@@ -28,4 +28,5 @@ /*! | ||
var Parser = exports = module.exports = function Parser(str, filename, options){ | ||
this.input = str; | ||
this.lexer = new Lexer(str, options); | ||
//Strip any UTF-8 BOM off of the start of `str`, if it exists. | ||
this.input = str.replace(/^\uFEFF/, ''); | ||
this.lexer = new Lexer(this.input, options); | ||
this.filename = filename; | ||
@@ -32,0 +33,0 @@ this.blocks = {}; |
{ | ||
"name": "jade", | ||
"description": "Jade template engine", | ||
"version": "0.34.1", | ||
"version": "0.35.0", | ||
"author": "TJ Holowaychuk <tj@vision-media.ca>", | ||
@@ -13,7 +13,7 @@ "repository": "git://github.com/visionmedia/jade", | ||
"dependencies": { | ||
"commander": "1.3.2", | ||
"commander": "2.0.0", | ||
"mkdirp": "0.3.x", | ||
"transformers": "2.1.0", | ||
"character-parser": "1.0.2", | ||
"monocle": "0.1.50", | ||
"character-parser": "1.2.0", | ||
"monocle": "1.1.50", | ||
"with": "~1.1.0", | ||
@@ -20,0 +20,0 @@ "constantinople": "~1.0.1" |
(function(e){if("function"==typeof bootstrap)bootstrap("jade",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeJade=e}else"undefined"!=typeof window?window.jade=e():global.jade=e()})(function(){var define,ses,bootstrap,module,exports; | ||
return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){ | ||
return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
@@ -4,0 +4,0 @@ /*! |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
614803
15577
16
+ Addedcharacter-parser@1.2.0(transitive)
+ Addedcommander@2.0.0(transitive)
+ Addedmonocle@1.1.50(transitive)
- Removedcharacter-parser@1.0.2(transitive)
- Removedcommander@1.3.2(transitive)
- Removedkeypress@0.1.0(transitive)
- Removedmonocle@0.1.50(transitive)
Updatedcharacter-parser@1.2.0
Updatedcommander@2.0.0
Updatedmonocle@1.1.50