5 var path = require.resolve(p)
6 , mod = require.modules[path];
7 if (!mod) throw new Error('failed to require "' + p + '"');
10 mod.call(mod.exports, mod, mod.exports, require.relative(path));
17 require.resolve = function (path){
20 , index = path + '/index.js';
21 return require.modules[reg] && reg
22 || require.modules[index] && index
26 require.register = function (path, fn){
27 require.modules[path] = fn;
30 require.relative = function (parent) {
32 if ('.' != p[0]) return require(p);
34 var path = parent.split('/')
35 , segs = p.split('/');
38 for (var i = 0; i < segs.length; i++) {
40 if ('..' == seg) path.pop();
41 else if ('.' != seg) path.push(seg);
44 return require(path.join('/'));
49 require.register("compiler.js", function(module, exports, require){
53 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
58 * Module dependencies.
61 var nodes = require('./nodes')
62 , filters = require('./filters')
63 , doctypes = require('./doctypes')
64 , selfClosing = require('./self-closing')
65 , inlineTags = require('./inline-tags')
66 , utils = require('./utils');
70 Object.keys = function(obj){
72 for (var key in obj) {
73 if (obj.hasOwnProperty(key)) {
81 if (!String.prototype.trimLeft) {
82 String.prototype.trimLeft = function(){
83 return this.replace(/^\s+/, '');
90 * Initialize `Compiler` with the given `node`.
93 * @param {Object} options
97 var Compiler = module.exports = function Compiler(node, options) {
98 this.options = options = options || {};
101 this.hasCompiledDoctype = false;
102 this.hasCompiledTag = false;
103 if (options.doctype) this.setDoctype(options.doctype);
105 this.pp = options.prettyprint || false;
106 this.indentDepth = 0;
110 * Compiler prototype.
113 Compiler.prototype = {
116 * Compile parse tree to JavaScript.
122 this.buf = ['var interp;'];
123 this.visit(this.node);
124 return this.buf.join('\n');
128 * Sets the default doctype `name`. Sets terse mode to `true` when
129 * html 5 is used, causing self-closing tags to end with ">" vs "/>",
130 * and boolean attributes are not mirrored.
132 * @param {string} name
136 setDoctype: function(name){
137 var doctype = doctypes[(name || 'default').toLowerCase()];
138 if (!doctype) throw new Error('unknown doctype "' + name + '"');
139 this.doctype = doctype;
140 this.terse = '5' == name || 'html' == name;
141 this.xml = 0 == this.doctype.indexOf('<?xml');
145 * Buffer the given `str` optionally escaped.
147 * @param {String} str
148 * @param {Boolean} esc
152 buffer: function(str, esc){
153 if (esc) str = utils.escape(str);
154 this.buf.push("buf.push('" + str + "');");
158 * Buffer the given `node`'s lineno.
164 line: function(node){
165 if (node.instrumentLineNumber === false) return;
166 this.buf.push('__.lineno = ' + node.line + ';');
176 visit: function(node){
178 return this.visitNode(node);
188 visitNode: function(node){
189 var name = node.constructor.name
190 || node.constructor.toString().match(/function ([^(\s]+)()/)[1];
191 return this['visit' + name](node);
195 * Visit all nodes in `block`.
197 * @param {Block} block
201 visitBlock: function(block){
202 var len = len = block.nodes.length;
203 for (var i = 0; i < len; ++i) {
204 this.visit(block.nodes[i]);
209 * Visit `doctype`. Sets terse mode to `true` when html 5
210 * is used, causing self-closing tags to end with ">" vs "/>",
211 * and boolean attributes are not mirrored.
213 * @param {Doctype} doctype
217 visitDoctype: function(doctype){
218 if (doctype && (doctype.val || !this.doctype)) {
219 this.setDoctype(doctype.val || 'default');
222 if (this.doctype) this.buffer(this.doctype);
223 this.hasCompiledDoctype = true;
227 * Visit `tag` buffering tag markup, generating
228 * attributes, visiting the `tag`'s code and block.
234 visitTag: function(tag){
238 if (!this.hasCompiledTag) {
239 if (!this.hasCompiledDoctype && 'html' == name) {
242 this.hasCompiledTag = true;
245 if(this.pp && inlineTags.indexOf(name) == -1)
246 this.buffer('\\n' + new Array(this.indentDepth).join(' '));
248 if (~selfClosing.indexOf(name) && !this.xml) {
249 this.buffer('<' + name);
250 this.visitAttributes(tag.attrs);
255 // Optimize attributes buffering
256 if (tag.attrs.length) {
257 this.buffer('<' + name);
258 if (tag.attrs.length) this.visitAttributes(tag.attrs);
261 this.buffer('<' + name + '>');
263 if (tag.code) this.visitCode(tag.code);
264 if (tag.text) this.buffer(utils.text(tag.text.nodes[0].trimLeft()));
265 this.escape = 'pre' == tag.name;
266 this.visit(tag.block);
267 if (this.pp && inlineTags.indexOf(name) == -1 && tag.textOnly == 0) this.buffer('\\n' + new Array(this.indentDepth).join(' '));
268 this.buffer('</' + name + '>');
274 * Visit `filter`, throwing when the filter does not exist.
276 * @param {Filter} filter
280 visitFilter: function(filter){
281 var fn = filters[filter.name];
285 if (filter.isASTFilter) {
286 throw new Error('unknown ast filter "' + filter.name + ':"');
288 throw new Error('unknown filter ":' + filter.name + '"');
291 if (filter.isASTFilter) {
292 this.buf.push(fn(filter.block, this, filter.attrs));
294 var text = filter.block.nodes.join('');
295 this.buffer(utils.text(fn(text, filter.attrs)));
306 visitText: function(text){
307 text = utils.text(text.nodes.join(''));
308 if (this.escape) text = escape(text);
314 * Visit a `comment`, only buffering when the buffer flag is set.
316 * @param {Comment} comment
320 visitComment: function(comment){
321 if (!comment.buffer) return;
322 if (this.pp) this.buffer('\\n' + new Array(this.indentDepth + 1).join(' '));
323 this.buffer('<!--' + utils.escape(comment.val) + '-->');
327 * Visit a `BlockComment`.
329 * @param {Comment} comment
333 visitBlockComment: function(comment){
334 if (0 == comment.val.indexOf('if')) {
335 this.buffer('<!--[' + comment.val + ']>');
336 this.visit(comment.block);
337 this.buffer('<![endif]-->');
339 this.buffer('<!--' + comment.val);
340 this.visit(comment.block);
346 * Visit `code`, respecting buffer / escape flags.
347 * If the code is followed by a block, wrap it in
348 * a self-calling function.
354 visitCode: function(code){
355 // Wrap code blocks with {}.
356 // we only wrap unbuffered code blocks ATM
357 // since they are usually flow control
361 var val = code.val.trimLeft();
362 this.buf.push('var __val__ = ' + val);
363 val = 'null == __val__ ? "" : __val__';
364 if (code.escape) val = 'escape(' + val + ')';
365 this.buf.push("buf.push(" + val + ");");
367 this.buf.push(code.val);
372 if (!code.buffer) this.buf.push('{');
373 this.visit(code.block);
374 if (!code.buffer) this.buf.push('}');
379 * Visit `each` block.
385 visitEach: function(each){
387 + '// iterate ' + each.obj + '\n'
389 + ' if (\'number\' == typeof ' + each.obj + '.length) {\n'
390 + ' for (var ' + each.key + ' = 0, $$l = ' + each.obj + '.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
391 + ' var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
393 this.visit(each.block);
398 + ' for (var ' + each.key + ' in ' + each.obj + ') {\n'
399 + ' if (' + each.obj + '.hasOwnProperty(' + each.key + ')){'
400 + ' var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
402 this.visit(each.block);
404 this.buf.push(' }\n');
406 this.buf.push(' }\n }\n}).call(this);\n');
412 * @param {Array} attrs
416 visitAttributes: function(attrs){
420 if (this.terse) buf.push('terse: true');
422 attrs.forEach(function(attr){
423 if (attr.name == 'class') {
424 classes.push('(' + attr.val + ')');
426 var pair = "'" + attr.name + "':(" + attr.val + ')';
431 if (classes.length) {
432 classes = classes.join(" + ' ' + ");
433 buf.push("class: " + classes);
436 buf = buf.join(', ').replace('class:', '"class":');
438 this.buf.push("buf.push(attrs({ " + buf + " }));");
443 * Escape the given string of `html`.
445 * @param {String} html
450 function escape(html){
452 .replace(/&(?!\w+;)/g, '&')
453 .replace(/</g, '<')
454 .replace(/>/g, '>')
455 .replace(/"/g, '"');
458 }); // module: compiler.js
460 require.register("doctypes.js", function(module, exports, require){
464 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
469 '5': '<!DOCTYPE html>'
470 , 'html': '<!DOCTYPE html>'
471 , 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
472 , 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
473 , 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
474 , 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
475 , 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
476 , '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
477 , 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
478 , 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
480 }); // module: doctypes.js
482 require.register("filters.js", function(module, exports, require){
486 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
493 * Wrap text with CDATA block.
496 cdata: function(str){
497 return '<![CDATA[\\n' + str + '\\n]]>';
501 * Transform sass to css, wrapped in style tags.
505 str = str.replace(/\\n/g, '\n');
506 var sass = require('sass').render(str).replace(/\n/g, '\\n');
507 return '<style>' + sass + '</style>';
511 * Transform stylus to css, wrapped in style tags.
514 stylus: function(str, options){
516 str = str.replace(/\\n/g, '\n');
517 var stylus = require('stylus');
518 stylus(str, options).render(function(err, css){
520 ret = css.replace(/\n/g, '\\n');
522 return '<style>' + ret + '</style>';
526 * Transform sass to css, wrapped in style tags.
531 str = str.replace(/\\n/g, '\n');
532 require('less').render(str, function(err, css){
534 ret = '<style>' + css.replace(/\n/g, '\\n') + '</style>';
540 * Transform markdown to html.
543 markdown: function(str){
546 // support markdown / discount
548 md = require('markdown');
551 md = require('discount');
554 md = require('markdown-js');
556 throw new Error('Cannot find markdown library, install markdown or discount');
561 str = str.replace(/\\n/g, '\n');
562 return md.parse(str).replace(/\n/g, '\\n').replace(/'/g,''');
566 * Transform coffeescript to javascript.
569 coffeescript: function(str){
570 str = str.replace(/\\n/g, '\n');
571 var js = require('coffee-script').compile(str).replace(/\n/g, '\\n');
572 return '<script type="text/javascript">\\n' + js + '</script>';
575 }); // module: filters.js
577 require.register("inline-tags.js", function(module, exports, require){
581 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
606 }); // module: inline-tags.js
608 require.register("jade.js", function(module, exports, require){
612 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
617 * Module dependencies.
620 var Parser = require('./parser')
621 , Compiler = require('./compiler')
627 exports.version = '0.12.1';
630 * Intermediate JavaScript cache.
633 var cache = exports.cache = {};
636 * Expose self closing tags.
639 exports.selfClosing = require('./self-closing');
642 * Default supported doctypes.
645 exports.doctypes = require('./doctypes');
651 exports.filters = require('./filters');
657 exports.utils = require('./utils');
663 exports.Compiler = Compiler;
669 exports.Parser = Parser;
675 exports.nodes = require('./nodes');
678 * Render the given attributes object.
680 * @param {Object} obj
689 var keys = Object.keys(obj)
693 for (var i = 0; i < len; ++i) {
696 if (typeof val === 'boolean' || val === '' || val == null) {
700 : buf.push(key + '="' + key + '"');
703 buf.push(key + '="' + escape(val) + '"');
707 return buf.join(' ');
711 * Escape the given string of `html`.
713 * @param {String} html
718 function escape(html){
720 .replace(/&(?!\w+;)/g, '&')
721 .replace(/</g, '<')
722 .replace(/>/g, '>')
723 .replace(/"/g, '"');
727 * Re-throw the given `err` in context to the
728 * `str` of jade, `filename`, and `lineno`.
731 * @param {String} str
732 * @param {String} filename
733 * @param {String} lineno
737 function rethrow(err, str, filename, lineno){
739 , lines = str.split('\n')
740 , start = Math.max(lineno - context, 0)
741 , end = Math.min(lines.length, lineno + context);
744 var context = lines.slice(start, end).map(function(line, i){
745 var curr = i + start + 1;
746 return (curr == lineno ? ' > ' : ' ')
752 // Alter exception message
754 err.message = (filename || 'Jade') + ':' + lineno
755 + '\n' + context + '\n\n' + err.message;
760 * Parse the given `str` of jade and return a function body.
762 * @param {String} str
763 * @param {Object} options
768 function parse(str, options){
769 var filename = options.filename;
772 var parser = new Parser(str, filename);
773 if (options.debug) parser.debug();
776 var compiler = new (options.compiler || Compiler)(parser.parse(), options)
777 , js = compiler.compile();
781 console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, ' '));
786 + attrs.toString() + '\n\n'
787 + escape.toString() + '\n\n'
790 ? 'var self = locals || {}, __ = __ || locals.__;\n' + js
791 : 'with (locals || {}) {' + js + '}')
792 + 'return buf.join("");';
794 process.compile(js, filename || 'Jade');
798 rethrow(err, str, filename, parser.lexer.lineno);
803 * Compile a `Function` representation of the given jade `str`.
805 * @param {String} str
806 * @param {Options} options
811 exports.compile = function(str, options){
812 var options = options || {}
813 , input = JSON.stringify(str)
814 , filename = options.filename
815 ? JSON.stringify(options.filename)
818 // Reduce closure madness by injecting some locals
820 'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
823 , parse(String(str), options || {})
825 , ' rethrow(err, __.input, __.filename, __.lineno);'
829 return new Function('locals', fn);
833 * Render the given `str` of jade.
837 * - `scope` Evaluation scope (`this`)
838 * - `locals` Local variable object
839 * - `filename` Used in exceptions, and required by `cache`
840 * - `cache` Cache intermediate JavaScript in memory keyed by `filename`
841 * - `compiler` Compiler to replade jade's default
842 * - `doctype` Specify the default doctype
844 * @param {String|Buffer} str
845 * @param {Object} options
850 exports.render = function(str, options){
852 , options = options || {}
853 , filename = options.filename;
861 if (cache[filename]) {
862 fn = cache[filename];
864 fn = cache[filename] = new Function('locals', parse(str, options));
867 throw new Error('filename is required when using the cache option');
870 fn = new Function('locals', parse(str, options));
873 // Render the template
875 var locals = options.locals || {}
876 , meta = { lineno: 1 };
878 return fn.call(options.scope, locals);
880 rethrow(err, str, filename, meta.lineno);
885 * Render jade template at the given `path`.
887 * @param {String} path
888 * @param {Object} options
889 * @param {Function} fn
893 exports.renderFile = function(path, options, fn){
896 if (typeof options === 'function') {
900 options.filename = path;
903 if (options.cache && cache[path]) {
905 ret = exports.render('', options);
911 fs.readFile(path, 'utf8', function(err, str){
912 if (err) return fn(err);
914 ret = exports.render(str, options);
923 }); // module: jade.js
925 require.register("lexer.js", function(module, exports, require){
929 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
934 * Initialize `Lexer` with the given `str`.
936 * @param {String} str
940 var Lexer = module.exports = function Lexer(str) {
941 this.input = str.replace(/\r\n|\r/g, '\n');
942 this.deferredTokens = [];
943 this.lastIndents = 0;
946 this.indentStack = [];
947 this.indentRe = null;
948 this.pipeless = false;
958 * Construct a token with the given `type` and `val`.
960 * @param {String} type
961 * @param {String} val
966 tok: function(type, val){
975 * Consume the given `len` of input.
977 * @param {Number} len
981 consume: function(len){
982 this.input = this.input.substr(len);
986 * Scan for `type` with the given `regexp`.
988 * @param {String} type
989 * @param {RegExp} regexp
994 scan: function(regexp, type){
996 if (captures = regexp.exec(this.input)) {
997 this.consume(captures[0].length);
998 return this.tok(type, captures[1]);
1003 * Defer the given `tok`.
1005 * @param {Object} tok
1009 defer: function(tok){
1010 this.deferredTokens.push(tok);
1014 * Lookahead `n` tokens.
1021 lookahead: function(n){
1022 var fetch = n - this.stash.length;
1023 while (fetch-- > 0) this.stash.push(this.next());
1024 return this.stash[--n];
1028 * Return the indexOf `start` / `end` delimiters.
1030 * @param {String} start
1031 * @param {String} end
1036 indexOfDelimiters: function(start, end){
1037 var str = this.input
1041 for (var i = 0, len = str.length; i < len; ++i) {
1042 if (start == str[i]) {
1044 } else if (end == str[i]) {
1045 if (++nend == nstart) {
1058 stashed: function() {
1059 return this.stash.length
1060 && this.stash.shift();
1067 deferred: function() {
1068 return this.deferredTokens.length
1069 && this.deferredTokens.shift();
1077 if (this.input.length) return;
1078 if (this.indentStack.length) {
1079 this.indentStack.shift();
1080 return this.tok('outdent');
1082 return this.tok('eos');
1090 blockComment: function() {
1092 if (captures = /^\/([^\n]+)/.exec(this.input)) {
1093 this.consume(captures[0].length);
1094 var tok = this.tok('block-comment', captures[1]);
1103 comment: function() {
1105 if (captures = /^ *\/\/(-)?([^\n]+)/.exec(this.input)) {
1106 this.consume(captures[0].length);
1107 var tok = this.tok('comment', captures[2]);
1108 tok.buffer = '-' != captures[1];
1119 if (captures = /^(\w[-:\w]*)/.exec(this.input)) {
1120 this.consume(captures[0].length);
1121 var tok, name = captures[1];
1122 if (':' == name[name.length - 1]) {
1123 name = name.slice(0, -1);
1124 tok = this.tok('tag', name);
1125 this.deferredTokens.push(this.tok(':'));
1126 while (' ' == this.input[0]) this.input = this.input.substr(1);
1128 tok = this.tok('tag', name);
1138 filter: function() {
1139 return this.scan(/^:(\w+)/, 'filter');
1146 doctype: function() {
1147 return this.scan(/^(?:!!!|doctype) *(\w+)?/, 'doctype');
1155 return this.scan(/^#([\w-]+)/, 'id');
1162 className: function() {
1163 return this.scan(/^\.([\w-]+)/, 'class');
1171 return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
1180 if (captures = /^- *each *(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
1181 this.consume(captures[0].length);
1182 var tok = this.tok('each', captures[1]);
1183 tok.key = captures[2] || 'index';
1184 tok.code = captures[3];
1195 if (captures = /^(!?=|-)([^\n]+)/.exec(this.input)) {
1196 this.consume(captures[0].length);
1197 var flags = captures[1];
1198 captures[1] = captures[2];
1199 var tok = this.tok('code', captures[1]);
1200 tok.escape = flags[0] === '=';
1201 tok.buffer = flags[0] === '=' || flags[1] === '=';
1211 if ('(' == this.input[0]) {
1212 var index = this.indexOfDelimiters('(', ')')
1213 , str = this.input.substr(1, index-1)
1214 , tok = this.tok('attrs')
1223 return states[states.length - 1];
1226 function interpolate(attr) {
1227 return attr.replace(/#\{([^}]+)\}/g, function(_, expr){
1228 return quote + " + (" + expr + ") + " + quote;
1232 this.consume(index + 1);
1250 if ('' == key) return;
1251 tok.attrs[key.replace(/^['"]|['"]$/g, '')] = '' == val
1274 if ('val' == state()) states.push('expr');
1278 if ('expr' == state()) states.pop();
1282 if ('val' == state()) states.push('object');
1286 if ('object' == state()) states.pop();
1290 if ('val' == state()) states.push('array');
1294 if ('array' == state()) states.pop();
1301 states.push('key char');
1307 if (c == quote) states.pop();
1311 states.push('string');
1330 for (var i = 0; i < len; ++i) {
1341 * Indent | Outdent | Newline.
1344 indent: function() {
1347 // established regexp
1348 if (this.indentRe) {
1349 captures = this.indentRe.exec(this.input);
1354 captures = re.exec(this.input);
1357 if (captures && !captures[1].length) {
1359 captures = re.exec(this.input);
1363 if (captures && captures[1].length) this.indentRe = re;
1368 , indents = captures[1].length;
1371 this.consume(indents + 1);
1373 if (' ' == this.input[0] || '\t' == this.input[0]) {
1374 throw new Error('Invalid indentation, you can use tabs or spaces but not both');
1378 if ('\n' == this.input[0]) return this.tok('newline');
1381 if (this.indentStack.length && indents < this.indentStack[0]) {
1382 while (this.indentStack.length && this.indentStack[0] > indents) {
1383 this.stash.push(this.tok('outdent'));
1384 this.indentStack.shift();
1386 tok = this.stash.pop();
1388 } else if (indents && indents != this.indentStack[0]) {
1389 this.indentStack.unshift(indents);
1390 tok = this.tok('indent', indents);
1393 tok = this.tok('newline');
1401 * Pipe-less text consumed only when
1405 pipelessText: function() {
1406 if (this.pipeless) {
1407 if ('\n' == this.input[0]) return;
1408 var i = this.input.indexOf('\n');
1409 if (-1 == i) i = this.input.length;
1410 var str = this.input.substr(0, i);
1411 this.consume(str.length);
1412 return this.tok('text', str);
1421 return this.scan(/^: */, ':');
1425 * Return the next token object, or those
1426 * previously stashed by lookahead.
1432 advance: function(){
1433 return this.stashed()
1438 * Return the next token object.
1445 return this.deferred()
1447 || this.pipelessText()
1458 || this.blockComment()
1464 }); // module: lexer.js
1466 require.register("nodes/block-comment.js", function(module, exports, require){
1469 * Jade - nodes - BlockComment
1470 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1475 * Module dependencies.
1478 var Node = require('./node');
1481 * Initialize a `BlockComment` with the given `block`.
1483 * @param {String} val
1484 * @param {Block} block
1488 var BlockComment = module.exports = function BlockComment(val, block) {
1494 * Inherit from `Node`.
1497 BlockComment.prototype = new Node;
1498 BlockComment.prototype.constructor = BlockComment;
1500 }); // module: nodes/block-comment.js
1502 require.register("nodes/block.js", function(module, exports, require){
1505 * Jade - nodes - Block
1506 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1511 * Module dependencies.
1514 var Node = require('./node');
1517 * Initialize a new `Block` with an optional `node`.
1519 * @param {Node} node
1523 var Block = module.exports = function Block(node){
1525 if (node) this.push(node);
1529 * Inherit from `Node`.
1532 Block.prototype = new Node;
1533 Block.prototype.constructor = Block;
1537 * Pust the given `node`.
1539 * @param {Node} node
1544 Block.prototype.push = function(node){
1545 return this.nodes.push(node);
1549 * Unshift the given `node`.
1551 * @param {Node} node
1556 Block.prototype.unshift = function(node){
1557 return this.nodes.unshift(node);
1560 }); // module: nodes/block.js
1562 require.register("nodes/code.js", function(module, exports, require){
1565 * Jade - nodes - Code
1566 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1571 * Module dependencies.
1574 var Node = require('./node');
1577 * Initialize a `Code` node with the given code `val`.
1578 * Code may also be optionally buffered and escaped.
1580 * @param {String} val
1581 * @param {Boolean} buffer
1582 * @param {Boolean} escape
1586 var Code = module.exports = function Code(val, buffer, escape) {
1588 this.buffer = buffer;
1589 this.escape = escape;
1590 if (/^ *else/.test(val)) this.instrumentLineNumber = false;
1594 * Inherit from `Node`.
1597 Code.prototype = new Node;
1598 Code.prototype.constructor = Code;
1600 }); // module: nodes/code.js
1602 require.register("nodes/comment.js", function(module, exports, require){
1605 * Jade - nodes - Comment
1606 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1611 * Module dependencies.
1614 var Node = require('./node');
1617 * Initialize a `Comment` with the given `val`, optionally `buffer`,
1618 * otherwise the comment may render in the output.
1620 * @param {String} val
1621 * @param {Boolean} buffer
1625 var Comment = module.exports = function Comment(val, buffer) {
1627 this.buffer = buffer;
1631 * Inherit from `Node`.
1634 Comment.prototype = new Node;
1635 Comment.prototype.constructor = Comment;
1637 }); // module: nodes/comment.js
1639 require.register("nodes/doctype.js", function(module, exports, require){
1642 * Jade - nodes - Doctype
1643 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1648 * Module dependencies.
1651 var Node = require('./node');
1654 * Initialize a `Doctype` with the given `val`.
1656 * @param {String} val
1660 var Doctype = module.exports = function Doctype(val) {
1665 * Inherit from `Node`.
1668 Doctype.prototype = new Node;
1669 Doctype.prototype.constructor = Doctype;
1671 }); // module: nodes/doctype.js
1673 require.register("nodes/each.js", function(module, exports, require){
1676 * Jade - nodes - Each
1677 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1682 * Module dependencies.
1685 var Node = require('./node');
1688 * Initialize an `Each` node, representing iteration
1690 * @param {String} obj
1691 * @param {String} val
1692 * @param {String} key
1693 * @param {Block} block
1697 var Each = module.exports = function Each(obj, val, key, block) {
1705 * Inherit from `Node`.
1708 Each.prototype = new Node;
1709 Each.prototype.constructor = Each;
1711 }); // module: nodes/each.js
1713 require.register("nodes/filter.js", function(module, exports, require){
1716 * Jade - nodes - Filter
1717 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1722 * Module dependencies.
1725 var Node = require('./node')
1726 , Block = require('./block');
1729 * Initialize a `Filter` node with the given
1730 * filter `name` and `block`.
1732 * @param {String} name
1733 * @param {Block|Node} block
1737 var Filter = module.exports = function Filter(name, block, attrs) {
1741 this.isASTFilter = block instanceof Block;
1745 * Inherit from `Node`.
1748 Filter.prototype = new Node;
1749 Filter.prototype.constructor = Filter;
1751 }); // module: nodes/filter.js
1753 require.register("nodes/index.js", function(module, exports, require){
1757 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1761 exports.Node = require('./node');
1762 exports.Tag = require('./tag');
1763 exports.Code = require('./code');
1764 exports.Each = require('./each');
1765 exports.Text = require('./text');
1766 exports.Block = require('./block');
1767 exports.Filter = require('./filter');
1768 exports.Comment = require('./comment');
1769 exports.BlockComment = require('./block-comment');
1770 exports.Doctype = require('./doctype');
1772 }); // module: nodes/index.js
1774 require.register("nodes/node.js", function(module, exports, require){
1777 * Jade - nodes - Node
1778 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1783 * Initialize a `Node`.
1788 var Node = module.exports = function Node(){};
1789 }); // module: nodes/node.js
1791 require.register("nodes/tag.js", function(module, exports, require){
1794 * Jade - nodes - Tag
1795 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1800 * Module dependencies.
1803 var Node = require('./node'),
1804 Block = require('./block');
1807 * Initialize a `Tag` node with the given tag `name` and optional `block`.
1809 * @param {String} name
1810 * @param {Block} block
1814 var Tag = module.exports = function Tag(name, block) {
1817 this.block = block || new Block;
1821 * Inherit from `Node`.
1824 Tag.prototype = new Node;
1825 Tag.prototype.constructor = Tag;
1829 * Set attribute `name` to `val`, keep in mind these become
1830 * part of a raw js object literal, so to quote a value you must
1831 * '"quote me"', otherwise or example 'user.name' is literal JavaScript.
1833 * @param {String} name
1834 * @param {String} val
1835 * @return {Tag} for chaining
1839 Tag.prototype.setAttribute = function(name, val){
1840 this.attrs.push({ name: name, val: val });
1845 * Remove attribute `name` when present.
1847 * @param {String} name
1851 Tag.prototype.removeAttribute = function(name){
1852 for (var i = 0, len = this.attrs.length; i < len; ++i) {
1853 if (this.attrs[i] && this.attrs[i].name == name) {
1854 delete this.attrs[i];
1860 * Get attribute value by `name`.
1862 * @param {String} name
1867 Tag.prototype.getAttribute = function(name){
1868 for (var i = 0, len = this.attrs.length; i < len; ++i) {
1869 if (this.attrs[i] && this.attrs[i].name == name) {
1870 return this.attrs[i].val;
1875 }); // module: nodes/tag.js
1877 require.register("nodes/text.js", function(module, exports, require){
1880 * Jade - nodes - Text
1881 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1886 * Module dependencies.
1889 var Node = require('./node');
1892 * Initialize a `Text` node with optional `line`.
1894 * @param {String} line
1898 var Text = module.exports = function Text(line) {
1900 if ('string' == typeof line) this.push(line);
1904 * Inherit from `Node`.
1907 Text.prototype = new Node;
1908 Text.prototype.constructor = Text;
1912 * Push the given `node.`
1914 * @param {Node} node
1919 Text.prototype.push = function(node){
1920 return this.nodes.push(node);
1923 }); // module: nodes/text.js
1925 require.register("parser.js", function(module, exports, require){
1929 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1934 * Module dependencies.
1937 var Lexer = require('./lexer')
1938 , nodes = require('./nodes');
1941 * Initialize `Parser` with the given input `str` and `filename`.
1943 * @param {String} str
1944 * @param {String} filename
1948 var Parser = exports = module.exports = function Parser(str, filename){
1950 this.lexer = new Lexer(str);
1951 this.filename = filename;
1955 * Tags that may not contain tags.
1958 var textOnly = exports.textOnly = ['code', 'script', 'textarea', 'style', 'title'];
1964 Parser.prototype = {
1967 * Output parse tree to stdout.
1973 var lexer = new Lexer(this.input)
1974 , tree = require('sys').inspect(this.parse(), false, 12, true);
1975 console.log('\n\x1b[1mParse Tree\x1b[0m:\n');
1981 * Return the next token object.
1987 advance: function(){
1988 return this.lexer.advance();
1992 * Single token lookahead.
1999 return this.lookahead(1);
2003 * Return lexer lineno.
2010 return this.lexer.lineno;
2014 * `n` token lookahead.
2021 lookahead: function(n){
2022 return this.lexer.lookahead(n);
2026 * Parse input returning a string of js for evaluation.
2033 var block = new nodes.Block;
2034 block.line = this.line();
2035 while ('eos' != this.peek().type) {
2036 if ('newline' == this.peek().type) {
2039 block.push(this.parseExpr());
2046 * Expect the given type, or throw an exception.
2048 * @param {String} type
2052 expect: function(type){
2053 if (this.peek().type === type) {
2054 return this.advance();
2056 throw new Error('expected "' + type + '", but got "' + this.peek().type + '"');
2061 * Accept the given `type`.
2063 * @param {String} type
2067 accept: function(type){
2068 if (this.peek().type === type) {
2069 return this.advance();
2085 parseExpr: function(){
2086 switch (this.peek().type) {
2088 return this.parseTag();
2090 return this.parseDoctype();
2092 return this.parseFilter();
2094 return this.parseComment();
2095 case 'block-comment':
2096 return this.parseBlockComment();
2098 return this.parseText();
2100 return this.parseEach();
2102 return this.parseCode();
2105 var tok = this.advance();
2106 this.lexer.defer(this.lexer.tok('tag', 'div'));
2107 this.lexer.defer(tok);
2108 return this.parseExpr();
2110 throw new Error('unexpected token "' + this.peek().type + '"');
2118 parseText: function(){
2119 var tok = this.expect('text')
2120 , node = new nodes.Text(tok.val);
2121 node.line = this.line();
2129 parseCode: function(){
2130 var tok = this.expect('code')
2131 , node = new nodes.Code(tok.val, tok.buffer, tok.escape);
2132 node.line = this.line();
2133 if ('indent' == this.peek().type) {
2134 node.block = this.parseBlock();
2143 parseBlockComment: function(){
2144 var tok = this.expect('block-comment')
2145 , node = new nodes.BlockComment(tok.val, this.parseBlock());
2146 node.line = this.line();
2155 parseComment: function(){
2156 var tok = this.expect('comment')
2157 , node = new nodes.Comment(tok.val, tok.buffer);
2158 node.line = this.line();
2166 parseDoctype: function(){
2167 var tok = this.expect('doctype')
2168 , node = new nodes.Doctype(tok.val);
2169 node.line = this.line();
2174 * filter attrs? text-block
2177 parseFilter: function(){
2179 , tok = this.expect('filter')
2180 , attrs = this.accept('attrs');
2182 this.lexer.pipeless = true;
2183 block = this.parseTextBlock();
2184 this.lexer.pipeless = false;
2186 var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
2187 node.line = this.line();
2192 * tag ':' attrs? block
2195 parseASTFilter: function(){
2197 , tok = this.expect('tag')
2198 , attrs = this.accept('attrs');
2201 block = this.parseBlock();
2203 var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
2204 node.line = this.line();
2212 parseEach: function(){
2213 var tok = this.expect('each')
2214 , node = new nodes.Each(tok.code, tok.val, tok.key, this.parseBlock());
2215 node.line = this.line();
2220 * indent (text | newline)* outdent
2223 parseTextBlock: function(){
2224 var text = new nodes.Text;
2225 text.line = this.line();
2226 var spaces = this.expect('indent').val;
2227 if (null == this._spaces) this._spaces = spaces;
2228 var indent = Array(spaces - this._spaces + 1).join(' ');
2229 while ('outdent' != this.peek().type) {
2230 switch (this.peek().type) {
2237 this.parseTextBlock().nodes.forEach(function(node){
2243 text.push(indent + this.advance().val);
2246 this._spaces = null;
2247 this.expect('outdent');
2252 * indent expr* outdent
2255 parseBlock: function(){
2256 var block = new nodes.Block;
2257 block.line = this.line();
2258 this.expect('indent');
2259 while ('outdent' != this.peek().type) {
2260 if ('newline' == this.peek().type) {
2263 block.push(this.parseExpr());
2266 this.expect('outdent');
2271 * tag (attrs | class | id)* (text | code | ':')? newline* block?
2274 parseTag: function(){
2275 // ast-filter look-ahead
2277 if ('attrs' == this.lookahead(i).type) ++i;
2278 if (':' == this.lookahead(i).type) {
2279 if ('indent' == this.lookahead(++i).type) {
2280 return this.parseASTFilter();
2284 var name = this.advance().val
2285 , tag = new nodes.Tag(name);
2287 tag.line = this.line();
2289 // (attrs | class | id)*
2292 switch (this.peek().type) {
2295 var tok = this.advance();
2296 tag.setAttribute(tok.type, "'" + tok.val + "'");
2299 var obj = this.advance().attrs
2300 , names = Object.keys(obj);
2301 for (var i = 0, len = names.length; i < len; ++i) {
2304 tag.setAttribute(name, val);
2312 // check immediate '.'
2313 if ('.' == this.peek().val) {
2314 tag.textOnly = true;
2318 // (text | code | ':')?
2319 switch (this.peek().type) {
2321 tag.text = this.parseText();
2324 tag.code = this.parseCode();
2328 tag.block = new nodes.Block;
2329 tag.block.push(this.parseTag());
2334 while ('newline' == this.peek().type) this.advance();
2336 tag.textOnly = tag.textOnly || ~textOnly.indexOf(tag.name);
2338 // script special-case
2339 if ('script' == tag.name) {
2340 var type = tag.getAttribute('type');
2341 if (type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
2342 tag.textOnly = false;
2347 if ('indent' == this.peek().type) {
2349 this.lexer.pipeless = true;
2350 tag.block = this.parseTextBlock();
2351 this.lexer.pipeless = false;
2353 var block = this.parseBlock();
2355 for (var i = 0, len = block.nodes.length; i < len; ++i) {
2356 tag.block.push(block.nodes[i]);
2367 }); // module: parser.js
2369 require.register("self-closing.js", function(module, exports, require){
2372 * Jade - self closing tags
2373 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2388 }); // module: self-closing.js
2390 require.register("utils.js", function(module, exports, require){
2394 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2399 * Convert interpolation in the given string to JavaScript.
2401 * @param {String} str
2406 var interpolate = exports.interpolate = function(str){
2407 return str.replace(/(\\)?([#!]){(.*?)}/g, function(str, escape, flag, code){
2411 + ('!' == flag ? '' : 'escape')
2412 + "((interp = " + code.replace(/\\'/g, "'")
2413 + ") == null ? '' : interp) + '";
2418 * Escape single quotes in `str`.
2420 * @param {String} str
2425 var escape = exports.escape = function(str) {
2426 return str.replace(/'/g, "\\'");
2430 * Interpolate, and escape the given `str`.
2432 * @param {String} str
2437 exports.text = function(str){
2438 return interpolate(escape(str));
2440 }); // module: utils.js