Comparing version 1.3.1 to 1.4.0
@@ -33,5 +33,8 @@ #!/usr/bin/env node | ||
.option('-c, --client', 'compile function for client-side runtime.js') | ||
.option('-n, --name <str>', 'The name of the compiled template (requires --client)') | ||
.option('-D, --no-debug', 'compile without debugging (smaller functions)') | ||
.option('-w, --watch', 'watch files for changes and automatically re-render') | ||
.option('--name-after-file', 'Name the template after the last section of the file path (requires --client and overriden by --name)') | ||
program.on('--help', function(){ | ||
@@ -89,2 +92,6 @@ console.log(' Examples:'); | ||
// --name | ||
options.name = program.name; | ||
// left-over args are file paths | ||
@@ -98,4 +105,8 @@ | ||
console.log(); | ||
files.forEach(renderFile); | ||
if (options.watch) { | ||
// keep watching when error occured. | ||
process.on('uncaughtException', function(err) { | ||
console.error(err); | ||
}); | ||
files.forEach(renderFile); | ||
monocle.watchFiles({ | ||
@@ -107,2 +118,4 @@ files: files, | ||
}); | ||
} else { | ||
files.forEach(renderFile); | ||
} | ||
@@ -135,3 +148,3 @@ process.on('exit', function () { | ||
}).resume(); | ||
process.on('SIGINT', function() { | ||
@@ -159,2 +172,5 @@ process.stdout.write('\n'); | ||
options.filename = path; | ||
if (program.nameAfterFile) { | ||
options.name = getNameFromFileName(path); | ||
} | ||
var fn = options.client ? jade.compileClient(str, options) : jade.compile(str, options); | ||
@@ -193,1 +209,14 @@ var extname = options.client ? '.js' : '.html'; | ||
} | ||
/** | ||
* Get a sensible name for a template function from a file path | ||
* | ||
* @param {String} filename | ||
* @returns {String} | ||
*/ | ||
function getNameFromFileName(filename) { | ||
var file = path.basename(filename, '.jade'); | ||
return file.toLowerCase().replace(/[^a-z0-9]+([a-z])/g, function (_, character) { | ||
return character.toUpperCase(); | ||
}) + 'Template'; | ||
} |
@@ -5,3 +5,3 @@ { | ||
"description": "Jade template runtime", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"keywords": [ | ||
@@ -8,0 +8,0 @@ "template" |
@@ -85,3 +85,3 @@ 'use strict'; | ||
* @param {Object} options | ||
* @return {String} | ||
* @return {Object} | ||
* @api private | ||
@@ -126,3 +126,3 @@ */ | ||
return '' | ||
var body = '' | ||
+ 'var buf = [];\n' | ||
@@ -135,2 +135,3 @@ + 'var jade_mixins = {};\n' | ||
+ 'return buf.join("");'; | ||
return {body: body, dependencies: parser.dependencies}; | ||
} | ||
@@ -163,2 +164,3 @@ | ||
var parsed = parse(str, options); | ||
if (options.compileDebug !== false) { | ||
@@ -168,3 +170,3 @@ fn = [ | ||
, 'try {' | ||
, parse(str, options) | ||
, parsed.body | ||
, '} catch (err) {' | ||
@@ -175,3 +177,3 @@ , ' jade.rethrow(err, jade_debug[0].filename, jade_debug[0].lineno' + (options.compileDebug === true ? ',' + JSON.stringify(str) : '') + ');' | ||
} else { | ||
fn = parse(str, options); | ||
fn = parsed.body; | ||
} | ||
@@ -182,3 +184,4 @@ fn = new Function('locals, jade', fn) | ||
res.toString = function () { | ||
var err = new Error('The `client` option is deprecated, use `jade.compileClient`'); | ||
var err = new Error('The `client` option is deprecated, use the `jade.compileClient` method instead'); | ||
err.name = 'Warning'; | ||
console.error(err.stack || err.message); | ||
@@ -188,2 +191,3 @@ return exports.compileClient(str, options); | ||
} | ||
res.dependencies = parsed.dependencies; | ||
return res; | ||
@@ -198,4 +202,5 @@ }; | ||
* - `compileDebug` When it is `true`, the source code is included in | ||
the compiled template for better error messages. | ||
* the compiled template for better error messages. | ||
* - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends | ||
* - `name` the name of the resulting function (defaults to "template") | ||
* | ||
@@ -209,7 +214,6 @@ * @param {String} str | ||
exports.compileClient = function(str, options){ | ||
var options = options || {} | ||
, filename = options.filename | ||
? JSON.stringify(options.filename) | ||
: 'undefined' | ||
, fn; | ||
var options = options || {}; | ||
var name = options.name || 'template'; | ||
var filename = options.filename ? JSON.stringify(options.filename) : 'undefined'; | ||
var fn; | ||
@@ -223,3 +227,3 @@ str = String(str); | ||
, 'try {' | ||
, parse(str, options) | ||
, parse(str, options).body | ||
, '} catch (err) {' | ||
@@ -231,6 +235,6 @@ , ' jade.rethrow(err, jade_debug[0].filename, jade_debug[0].lineno, ' + JSON.stringify(str) + ');' | ||
options.compileDebug = false; | ||
fn = parse(str, options); | ||
fn = parse(str, options).body; | ||
} | ||
return 'function template(locals) {\n' + fn + '\n}'; | ||
return 'function ' + name + '(locals) {\n' + fn + '\n}'; | ||
}; | ||
@@ -237,0 +241,0 @@ |
@@ -190,2 +190,3 @@ 'use strict'; | ||
tok.buffer = '-' != captures[1]; | ||
this.pipeless = true; | ||
return tok; | ||
@@ -240,3 +241,7 @@ } | ||
filter: function() { | ||
return this.scan(/^:([\w\-]+)/, 'filter'); | ||
var tok = this.scan(/^:([\w\-]+)/, 'filter'); | ||
if (tok) { | ||
this.pipeless = true; | ||
return tok; | ||
} | ||
}, | ||
@@ -297,2 +302,3 @@ | ||
dot: function() { | ||
this.pipeless = true; | ||
return this.scan(/^\./, 'dot'); | ||
@@ -392,8 +398,18 @@ }, | ||
var captures; | ||
if (captures = /^include:([\w\-]+) +([^\n]+)/.exec(this.input)) { | ||
if (captures = /^include:([\w\-]+)([\( ])/.exec(this.input)) { | ||
this.consume(captures[0].length - 1); | ||
var filter = captures[1]; | ||
var attrs = captures[2] === '(' ? this.attrs() : null; | ||
if (!(captures[2] === ' ' || this.input[0] === ' ')) { | ||
throw new Error('expected space after include:filter but got ' + JSON.stringify(this.input[0])); | ||
} | ||
captures = /^ *([^\n]+)/.exec(this.input); | ||
if (!captures) { | ||
throw new Error('missing path for include:filter'); | ||
} | ||
this.consume(captures[0].length); | ||
var filter = captures[1]; | ||
var path = captures[2]; | ||
var path = captures[1]; | ||
var tok = this.tok('include', path); | ||
tok.filter = filter; | ||
tok.attrs = attrs; | ||
return tok; | ||
@@ -457,3 +473,3 @@ } | ||
var range = this.bracketExpression(captures[0].length - 1); | ||
if (!/^ *[-\w]+ *=/.test(range.src)) { // not attributes | ||
if (!/^\s*[-\w]+ *=/.test(range.src)) { // not attributes | ||
this.consume(range.end + 1); | ||
@@ -770,3 +786,6 @@ tok.args = range.src; | ||
// blank line | ||
if ('\n' == this.input[0]) return this.tok('newline'); | ||
if ('\n' == this.input[0]) { | ||
this.pipeless = false; | ||
return this.tok('newline'); | ||
} | ||
@@ -789,2 +808,3 @@ // outdent | ||
this.pipeless = false; | ||
return tok; | ||
@@ -800,10 +820,45 @@ } | ||
pipelessText: function() { | ||
if (this.pipeless) { | ||
if ('\n' == this.input[0]) return; | ||
var i = this.input.indexOf('\n'); | ||
if (-1 == i) i = this.input.length; | ||
var str = this.input.substr(0, i); | ||
this.consume(str.length); | ||
return this.tok('text', str); | ||
if (!this.pipeless) return; | ||
var captures, re; | ||
// established regexp | ||
if (this.indentRe) { | ||
captures = this.indentRe.exec(this.input); | ||
// determine regexp | ||
} else { | ||
// tabs | ||
re = /^\n(\t*) */; | ||
captures = re.exec(this.input); | ||
// spaces | ||
if (captures && !captures[1].length) { | ||
re = /^\n( *)/; | ||
captures = re.exec(this.input); | ||
} | ||
// established | ||
if (captures && captures[1].length) this.indentRe = re; | ||
} | ||
var indents = captures && captures[1].length; | ||
if (indents && (this.indentStack.length === 0 || indents > this.indentStack[0])) { | ||
var indent = captures[1]; | ||
var line; | ||
var tokens = []; | ||
var isMatch; | ||
do { | ||
// text has `\n` as a prefix | ||
var i = this.input.substr(1).indexOf('\n'); | ||
if (-1 == i) i = this.input.length - 1; | ||
var str = this.input.substr(1, i); | ||
isMatch = str.substr(0, indent.length) === indent || !str.trim(); | ||
if (isMatch) { | ||
// consume test along with `\n` prefix if match | ||
this.consume(str.length + 1); | ||
tokens.push(str.substr(indent.length)); | ||
} | ||
} while(this.input.length && isMatch); | ||
while (this.input.length === 0 && tokens[tokens.length - 1] === '') tokens.pop(); | ||
return this.tok('pipeless-text', tokens); | ||
} | ||
}, | ||
@@ -810,0 +865,0 @@ |
@@ -31,2 +31,3 @@ 'use strict'; | ||
this.inMixin = false; | ||
this.dependencies = []; | ||
}; | ||
@@ -139,2 +140,23 @@ | ||
if (!this.extending && !this.included && Object.keys(this.blocks).length){ | ||
var blocks = []; | ||
utils.walkAST(block, function (node) { | ||
if (node.type === 'Block' && node.name) { | ||
blocks.push(node.name); | ||
} | ||
}); | ||
Object.keys(this.blocks).forEach(function (name) { | ||
if (blocks.indexOf(name) === -1) { | ||
console.warn('Warning: Unexpected block "' | ||
+ name | ||
+ '" ' | ||
+ ' on line ' | ||
+ this.blocks[name].line | ||
+ ' of ' | ||
+ (this.blocks[name].filename) | ||
+ '. This block is never used. This warning will be an error in v2.0.0'); | ||
} | ||
}.bind(this)); | ||
} | ||
return block; | ||
@@ -241,3 +263,3 @@ }, | ||
var tok = this.expect('text'); | ||
var tokens = this.parseTextWithInlineTags(tok.val); | ||
var tokens = this.parseInlineTagsInText(tok.val); | ||
if (tokens.length === 1) return tokens[0]; | ||
@@ -366,6 +388,5 @@ var node = new nodes.Block; | ||
if ('indent' == this.peek().type) { | ||
this.lexer.pipeless = true; | ||
node = new nodes.BlockComment(tok.val, this.parseTextBlock(), tok.buffer); | ||
this.lexer.pipeless = false; | ||
var block; | ||
if (block = this.parseTextBlock()) { | ||
node = new nodes.BlockComment(tok.val, block, tok.buffer); | ||
} else { | ||
@@ -399,9 +420,3 @@ node = new nodes.Comment(tok.val, tok.buffer); | ||
if ('indent' == this.peek().type) { | ||
this.lexer.pipeless = true; | ||
block = this.parseTextBlock(); | ||
this.lexer.pipeless = false; | ||
} else { | ||
block = new nodes.Block; | ||
} | ||
block = this.parseTextBlock() || new nodes.Block(); | ||
@@ -475,4 +490,6 @@ var options = {}; | ||
this.dependencies.push(path); | ||
var str = fs.readFileSync(path, 'utf8'); | ||
var parser = new this.constructor(str, path, this.options); | ||
parser.dependencies = this.dependencies; | ||
@@ -499,2 +516,3 @@ parser.blocks = this.blocks; | ||
: new nodes.Block(new nodes.Literal('')); | ||
block.name = name; | ||
@@ -544,7 +562,13 @@ var prev = this.blocks[name] || {prepended: [], appended: []} | ||
var path = this.resolvePath(tok.val.trim(), 'include'); | ||
this.dependencies.push(path); | ||
// has-filter | ||
if (tok.filter) { | ||
var str = fs.readFileSync(path, 'utf8').replace(/\r/g, ''); | ||
str = filters(tok.filter, str, { filename: path }); | ||
var options = {filename: path}; | ||
if (tok.attrs) { | ||
tok.attrs.attrs.forEach(function (attribute) { | ||
options[attribute.name] = constantinople.toConstant(attribute.val); | ||
}); | ||
} | ||
str = filters(tok.filter, str, options); | ||
return new nodes.Literal(str); | ||
@@ -561,3 +585,6 @@ } | ||
var parser = new this.constructor(str, path, this.options); | ||
parser.dependencies = this.dependencies; | ||
parser.blocks = utils.merge({}, this.blocks); | ||
parser.included = true; | ||
@@ -620,3 +647,3 @@ parser.mixins = this.mixins; | ||
parseTextWithInlineTags: function (str) { | ||
parseInlineTagsInText: function (str) { | ||
var line = this.line(); | ||
@@ -629,3 +656,3 @@ | ||
text.line = line; | ||
var rest = this.parseTextWithInlineTags(match[2]); | ||
var rest = this.parseInlineTagsInText(match[2]); | ||
if (rest[0].type === 'Text') { | ||
@@ -644,3 +671,3 @@ text.val += rest[0].val; | ||
buffer.push(inner.parse()); | ||
return buffer.concat(this.parseTextWithInlineTags(rest.substr(range.end + 1))); | ||
return buffer.concat(this.parseInlineTagsInText(rest.substr(range.end + 1))); | ||
} | ||
@@ -661,26 +688,8 @@ } else { | ||
block.line = this.line(); | ||
var spaces = this.expect('indent').val; | ||
if (null == this._spaces) this._spaces = spaces; | ||
var indent = Array(spaces - this._spaces + 1).join(' '); | ||
while ('outdent' != this.peek().type) { | ||
switch (this.peek().type) { | ||
case 'newline': | ||
this.advance(); | ||
break; | ||
case 'indent': | ||
this.parseTextBlock(true).nodes.forEach(function(node){ | ||
block.push(node); | ||
}); | ||
break; | ||
default: | ||
var texts = this.parseTextWithInlineTags(indent + this.advance().val); | ||
texts.forEach(function (text) { | ||
block.push(text); | ||
}); | ||
} | ||
} | ||
if (spaces == this._spaces) this._spaces = null; | ||
this.expect('outdent'); | ||
var body = this.peek(); | ||
if (body.type !== 'pipeless-text') return; | ||
this.advance(); | ||
block.nodes = body.val.reduce(function (accumulator, text) { | ||
return accumulator.concat(this.parseInlineTagsInText(text)); | ||
}.bind(this), []); | ||
return block; | ||
@@ -798,2 +807,3 @@ }, | ||
case 'eos': | ||
case 'pipeless-text': | ||
break; | ||
@@ -808,12 +818,8 @@ default: | ||
// block? | ||
if ('indent' == this.peek().type) { | ||
if (tag.textOnly) { | ||
this.lexer.pipeless = true; | ||
tag.block = this.parseTextBlock(); | ||
this.lexer.pipeless = false; | ||
} else { | ||
var block = this.block(); | ||
for (var i = 0, len = block.nodes.length; i < len; ++i) { | ||
tag.block.push(block.nodes[i]); | ||
} | ||
if (tag.textOnly) { | ||
tag.block = this.parseTextBlock(); | ||
} else if ('indent' == this.peek().type) { | ||
var block = this.block(); | ||
for (var i = 0, len = block.nodes.length; i < len; ++i) { | ||
tag.block.push(block.nodes[i]); | ||
} | ||
@@ -820,0 +826,0 @@ } |
@@ -180,3 +180,3 @@ 'use strict'; | ||
try { | ||
str = str || require('fs').readFileSync(filename, 'utf8') | ||
str = str || require('fs').readFileSync(filename, 'utf8') | ||
} catch (ex) { | ||
@@ -183,0 +183,0 @@ rethrow(err, null, lineno) |
@@ -17,1 +17,32 @@ 'use strict'; | ||
exports.walkAST = function walkAST(ast, before, after) { | ||
before && before(ast); | ||
switch (ast.type) { | ||
case 'Block': | ||
ast.nodes.forEach(function (node) { | ||
walkAST(node, before, after); | ||
}); | ||
break; | ||
case 'Case': | ||
case 'Each': | ||
case 'Mixin': | ||
case 'Tag': | ||
case 'When': | ||
ast.block && walkAST(ast.block, before, after); | ||
break; | ||
case 'Attrs': | ||
case 'BlockComment': | ||
case 'Code': | ||
case 'Comment': | ||
case 'Doctype': | ||
case 'Filter': | ||
case 'Literal': | ||
case 'MixinBlock': | ||
case 'Text': | ||
break; | ||
default: | ||
throw new Error('Unexpected node type ' + ast.type); | ||
break; | ||
} | ||
after && after(ast); | ||
}; |
{ | ||
"name": "jade", | ||
"description": "Jade template engine", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"author": "TJ Holowaychuk <tj@vision-media.ca>", | ||
"maintainers": [ | ||
"forbeslindesay <forbes@lindesay.co.uk>", | ||
"bloodyowl <mlbli@me.com", | ||
"jbnicolai <joshua@jbna.nl>" | ||
], | ||
"license": "MIT", | ||
"repository": "git://github.com/visionmedia/jade", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/visionmedia/jade" | ||
}, | ||
"main": "./index.js", | ||
@@ -12,6 +20,5 @@ "bin": { | ||
}, | ||
"man": "./jade.1", | ||
"dependencies": { | ||
"commander": "2.1.0", | ||
"mkdirp": "~0.3.5", | ||
"mkdirp": "~0.5.0", | ||
"transformers": "2.1.0", | ||
@@ -33,3 +40,20 @@ "character-parser": "1.2.0", | ||
"browserify": "*", | ||
"linify": "*" | ||
"linify": "*", | ||
"less-file": "0.0.8", | ||
"express": "~3.4.8", | ||
"browserify-middleware": "~2.4.0", | ||
"twbs": "0.0.6", | ||
"highlight-codemirror": "~3.20.0", | ||
"inconsolata": "0.0.2", | ||
"jade-code-mirror": "~1.0.5", | ||
"code-mirror": "~3.22.0", | ||
"handle": "~1.0.0", | ||
"jade-highlighter": "~1.0.5", | ||
"marked": "~0.3.2", | ||
"stop": "^3.0.0-rc1", | ||
"opener": "^1.3.0", | ||
"github-basic": "^3.0.0", | ||
"pull-request": "^3.0.0", | ||
"lsr": "^1.0.0", | ||
"rimraf": "^2.2.8" | ||
}, | ||
@@ -36,0 +60,0 @@ "component": { |
@@ -65,3 +65,3 @@ # Jade - 模板引擎 | ||
- 命令行下编译jade模板 | ||
- HTML5 模式 (使用 `!!! 5` 文档类型) | ||
- HTML5 模式 (使用 ~~`!!! 5`~~ `doctype html` 文档类型) | ||
- 在内存中缓存(可选) | ||
@@ -68,0 +68,0 @@ - 合并动态和静态标签类 |
@@ -10,5 +10,5 @@ # [![Jade - template engine ](http://i.imgur.com/5zf2aVt.png)](http://jade-lang.com/) | ||
[![Build Status](https://travis-ci.org/visionmedia/jade.png?branch=master)](https://travis-ci.org/visionmedia/jade) | ||
[![Dependency Status](https://gemnasium.com/visionmedia/jade.png)](https://gemnasium.com/visionmedia/jade) | ||
[![NPM version](https://badge.fury.io/js/jade.png)](http://badge.fury.io/js/jade) | ||
[![Build Status](https://img.shields.io/travis/visionmedia/jade/master.svg)](https://travis-ci.org/visionmedia/jade) | ||
[![Dependency Status](https://img.shields.io/gemnasium/visionmedia/jade.svg)](https://gemnasium.com/visionmedia/jade) | ||
[![NPM version](https://img.shields.io/npm/v/jade.svg)](http://badge.fury.io/js/jade) | ||
@@ -127,4 +127,4 @@ ## Installation | ||
- [Jade について。](https://gist.github.com/japboy/5402844) (A Japanese Tutorial) | ||
- [Jade - 模板引擎](https://github.com/visionmedia/jade/blob/master/Readme_zh-cn.md) | ||
Implementations in other languages: | ||
@@ -146,2 +146,3 @@ | ||
- [html2jade](https://github.com/donpark/html2jade) converter | ||
- [Jade Server](https://github.com/ded/jade-server) Ideal for building local prototypes apart from any application | ||
@@ -148,0 +149,0 @@ ## License |
@@ -181,3 +181,3 @@ !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.jade=e()}}(function(){var define,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(_dereq_,module,exports){ | ||
try { | ||
str = str || _dereq_('fs').readFileSync(filename, 'utf8') | ||
str = str || _dereq_('fs').readFileSync(filename, 'utf8') | ||
} catch (ex) { | ||
@@ -184,0 +184,0 @@ rethrow(err, null, lineno) |
Sorry, the diff of this file is not supported yet
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
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
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
664619
40
17178
149
27
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
- Removedmkdirp@0.3.5(transitive)
Updatedmkdirp@~0.5.0