UNPKG

64.8 kBJavaScriptView Raw
1(function() {
2
3// CommonJS require()
4
5function require(p){
6 var path = require.resolve(p)
7 , mod = require.modules[path];
8 if (!mod) throw new Error('failed to require "' + p + '"');
9 if (!mod.exports) {
10 mod.exports = {};
11 mod.call(mod.exports, mod, mod.exports, require.relative(path));
12 }
13 return mod.exports;
14 }
15
16require.modules = {};
17
18require.resolve = function (path){
19 var orig = path
20 , reg = path + '.js'
21 , index = path + '/index.js';
22 return require.modules[reg] && reg
23 || require.modules[index] && index
24 || orig;
25 };
26
27require.register = function (path, fn){
28 require.modules[path] = fn;
29 };
30
31require.relative = function (parent) {
32 return function(p){
33 if ('.' != p.charAt(0)) return require(p);
34
35 var path = parent.split('/')
36 , segs = p.split('/');
37 path.pop();
38
39 for (var i = 0; i < segs.length; i++) {
40 var seg = segs[i];
41 if ('..' == seg) path.pop();
42 else if ('.' != seg) path.push(seg);
43 }
44
45 return require(path.join('/'));
46 };
47 };
48
49
50require.register("compiler.js", function(module, exports, require){
51
52/*!
53 * Jade - Compiler
54 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
55 * MIT Licensed
56 */
57
58/**
59 * Module dependencies.
60 */
61
62var nodes = require('./nodes')
63 , filters = require('./filters')
64 , doctypes = require('./doctypes')
65 , selfClosing = require('./self-closing')
66 , inlineTags = require('./inline-tags')
67 , utils = require('./utils');
68
69
70 if (!Object.keys) {
71 Object.keys = function(obj){
72 var arr = [];
73 for (var key in obj) {
74 if (obj.hasOwnProperty(key)) {
75 arr.push(key);
76 }
77 }
78 return arr;
79 }
80 }
81
82 if (!String.prototype.trimLeft) {
83 String.prototype.trimLeft = function(){
84 return this.replace(/^\s+/, '');
85 }
86 }
87
88
89
90/**
91 * Initialize `Compiler` with the given `node`.
92 *
93 * @param {Node} node
94 * @param {Object} options
95 * @api public
96 */
97
98var Compiler = module.exports = function Compiler(node, options) {
99 this.options = options = options || {};
100 this.node = node;
101 this.hasCompiledDoctype = false;
102 this.hasCompiledTag = false;
103 this.pp = options.pretty || false;
104 this.debug = false !== options.compileDebug;
105 this.indents = 0;
106 if (options.doctype) this.setDoctype(options.doctype);
107};
108
109/**
110 * Compiler prototype.
111 */
112
113Compiler.prototype = {
114
115 /**
116 * Compile parse tree to JavaScript.
117 *
118 * @api public
119 */
120
121 compile: function(){
122 this.buf = ['var interp;'];
123 this.lastBufferedIdx = -1;
124 this.visit(this.node);
125 return this.buf.join('\n');
126 },
127
128 /**
129 * Sets the default doctype `name`. Sets terse mode to `true` when
130 * html 5 is used, causing self-closing tags to end with ">" vs "/>",
131 * and boolean attributes are not mirrored.
132 *
133 * @param {string} name
134 * @api public
135 */
136
137 setDoctype: function(name){
138 var doctype = doctypes[(name || 'default').toLowerCase()];
139 doctype = doctype || '<!DOCTYPE ' + name + '>';
140 this.doctype = doctype;
141 this.terse = '5' == name || 'html' == name;
142 this.xml = 0 == this.doctype.indexOf('<?xml');
143 },
144
145 /**
146 * Buffer the given `str` optionally escaped.
147 *
148 * @param {String} str
149 * @param {Boolean} esc
150 * @api public
151 */
152
153 buffer: function(str, esc){
154 if (esc) str = utils.escape(str);
155
156 if (this.lastBufferedIdx == this.buf.length) {
157 this.lastBuffered += str;
158 this.buf[this.lastBufferedIdx - 1] = "buf.push('" + this.lastBuffered + "');"
159 } else {
160 this.buf.push("buf.push('" + str + "');");
161 this.lastBuffered = str;
162 this.lastBufferedIdx = this.buf.length;
163 }
164 },
165
166 /**
167 * Visit `node`.
168 *
169 * @param {Node} node
170 * @api public
171 */
172
173 visit: function(node){
174 var debug = this.debug;
175
176 if (debug) {
177 this.buf.push('__jade.unshift({ lineno: ' + node.line
178 + ', filename: ' + (node.filename
179 ? '"' + node.filename + '"'
180 : '__jade[0].filename')
181 + ' });');
182 }
183
184 // Massive hack to fix our context
185 // stack for - else[ if] etc
186 if (false === node.debug && this.debug) {
187 this.buf.pop();
188 this.buf.pop();
189 }
190
191 this.visitNode(node);
192
193 if (debug) this.buf.push('__jade.shift();');
194 },
195
196 /**
197 * Visit `node`.
198 *
199 * @param {Node} node
200 * @api public
201 */
202
203 visitNode: function(node){
204 var name = node.constructor.name
205 || node.constructor.toString().match(/function ([^(\s]+)()/)[1];
206 return this['visit' + name](node);
207 },
208
209 /**
210 * Visit case `node`.
211 *
212 * @param {Literal} node
213 * @api public
214 */
215
216 visitCase: function(node){
217 var _ = this.withinCase;
218 this.withinCase = true;
219 this.buf.push('switch (' + node.expr + '){');
220 this.visit(node.block);
221 this.buf.push('}');
222 this.withinCase = _;
223 },
224
225 /**
226 * Visit when `node`.
227 *
228 * @param {Literal} node
229 * @api public
230 */
231
232 visitWhen: function(node){
233 if ('default' == node.expr) {
234 this.buf.push('default:');
235 } else {
236 this.buf.push('case ' + node.expr + ':');
237 }
238 this.visit(node.block);
239 this.buf.push(' break;');
240 },
241
242 /**
243 * Visit literal `node`.
244 *
245 * @param {Literal} node
246 * @api public
247 */
248
249 visitLiteral: function(node){
250 var str = node.str.replace(/\n/g, '\\\\n');
251 this.buffer(str);
252 },
253
254 /**
255 * Visit all nodes in `block`.
256 *
257 * @param {Block} block
258 * @api public
259 */
260
261 visitBlock: function(block){
262 var len = block.nodes.length;
263 for (var i = 0; i < len; ++i) {
264 this.visit(block.nodes[i]);
265 }
266 },
267
268 /**
269 * Visit `doctype`. Sets terse mode to `true` when html 5
270 * is used, causing self-closing tags to end with ">" vs "/>",
271 * and boolean attributes are not mirrored.
272 *
273 * @param {Doctype} doctype
274 * @api public
275 */
276
277 visitDoctype: function(doctype){
278 if (doctype && (doctype.val || !this.doctype)) {
279 this.setDoctype(doctype.val || 'default');
280 }
281
282 if (this.doctype) this.buffer(this.doctype);
283 this.hasCompiledDoctype = true;
284 },
285
286 /**
287 * Visit `mixin`, generating a function that
288 * may be called within the template.
289 *
290 * @param {Mixin} mixin
291 * @api public
292 */
293
294 visitMixin: function(mixin){
295 var name = mixin.name.replace(/-/g, '_') + '_mixin'
296 , args = mixin.args || '';
297
298 if (mixin.block) {
299 this.buf.push('var ' + name + ' = function(' + args + '){');
300 this.visit(mixin.block);
301 this.buf.push('}');
302 } else {
303 this.buf.push(name + '(' + args + ');');
304 }
305 },
306
307 /**
308 * Visit `tag` buffering tag markup, generating
309 * attributes, visiting the `tag`'s code and block.
310 *
311 * @param {Tag} tag
312 * @api public
313 */
314
315 visitTag: function(tag){
316 this.indents++;
317 var name = tag.name;
318
319 if (!this.hasCompiledTag) {
320 if (!this.hasCompiledDoctype && 'html' == name) {
321 this.visitDoctype();
322 }
323 this.hasCompiledTag = true;
324 }
325
326 // pretty print
327 if (this.pp && inlineTags.indexOf(name) == -1) {
328 this.buffer('\\n' + Array(this.indents).join(' '));
329 }
330
331 if (~selfClosing.indexOf(name) && !this.xml) {
332 this.buffer('<' + name);
333 this.visitAttributes(tag.attrs);
334 this.terse
335 ? this.buffer('>')
336 : this.buffer('/>');
337 } else {
338 // Optimize attributes buffering
339 if (tag.attrs.length) {
340 this.buffer('<' + name);
341 if (tag.attrs.length) this.visitAttributes(tag.attrs);
342 this.buffer('>');
343 } else {
344 this.buffer('<' + name + '>');
345 }
346 if (tag.code) this.visitCode(tag.code);
347 if (tag.text) this.buffer(utils.text(tag.text.nodes[0].trimLeft()));
348 this.escape = 'pre' == tag.name;
349 this.visit(tag.block);
350
351 // pretty print
352 if (this.pp && !~inlineTags.indexOf(name) && !tag.textOnly) {
353 this.buffer('\\n' + Array(this.indents).join(' '));
354 }
355
356 this.buffer('</' + name + '>');
357 }
358 this.indents--;
359 },
360
361 /**
362 * Visit `filter`, throwing when the filter does not exist.
363 *
364 * @param {Filter} filter
365 * @api public
366 */
367
368 visitFilter: function(filter){
369 var fn = filters[filter.name];
370
371 // unknown filter
372 if (!fn) {
373 if (filter.isASTFilter) {
374 throw new Error('unknown ast filter "' + filter.name + ':"');
375 } else {
376 throw new Error('unknown filter ":' + filter.name + '"');
377 }
378 }
379 if (filter.isASTFilter) {
380 this.buf.push(fn(filter.block, this, filter.attrs));
381 } else {
382 var text = filter.block.nodes.join('');
383 filter.attrs = filter.attrs || {};
384 filter.attrs.filename = this.options.filename;
385 this.buffer(utils.text(fn(text, filter.attrs)));
386 }
387 },
388
389 /**
390 * Visit `text` node.
391 *
392 * @param {Text} text
393 * @api public
394 */
395
396 visitText: function(text){
397 text = utils.text(text.nodes.join(''));
398 if (this.escape) text = escape(text);
399 this.buffer(text);
400 this.buffer('\\n');
401 },
402
403 /**
404 * Visit a `comment`, only buffering when the buffer flag is set.
405 *
406 * @param {Comment} comment
407 * @api public
408 */
409
410 visitComment: function(comment){
411 if (!comment.buffer) return;
412 if (this.pp) this.buffer('\\n' + Array(this.indents + 1).join(' '));
413 this.buffer('<!--' + utils.escape(comment.val) + '-->');
414 },
415
416 /**
417 * Visit a `BlockComment`.
418 *
419 * @param {Comment} comment
420 * @api public
421 */
422
423 visitBlockComment: function(comment){
424 if (!comment.buffer) return;
425 if (0 == comment.val.trim().indexOf('if')) {
426 this.buffer('<!--[' + comment.val.trim() + ']>');
427 this.visit(comment.block);
428 this.buffer('<![endif]-->');
429 } else {
430 this.buffer('<!--' + comment.val);
431 this.visit(comment.block);
432 this.buffer('-->');
433 }
434 },
435
436 /**
437 * Visit `code`, respecting buffer / escape flags.
438 * If the code is followed by a block, wrap it in
439 * a self-calling function.
440 *
441 * @param {Code} code
442 * @api public
443 */
444
445 visitCode: function(code){
446 // Wrap code blocks with {}.
447 // we only wrap unbuffered code blocks ATM
448 // since they are usually flow control
449
450 // Buffer code
451 if (code.buffer) {
452 var val = code.val.trimLeft();
453 this.buf.push('var __val__ = ' + val);
454 val = 'null == __val__ ? "" : __val__';
455 if (code.escape) val = 'escape(' + val + ')';
456 this.buf.push("buf.push(" + val + ");");
457 } else {
458 this.buf.push(code.val);
459 }
460
461 // Block support
462 if (code.block) {
463 if (!code.buffer) this.buf.push('{');
464 this.visit(code.block);
465 if (!code.buffer) this.buf.push('}');
466 }
467 },
468
469 /**
470 * Visit `each` block.
471 *
472 * @param {Each} each
473 * @api public
474 */
475
476 visitEach: function(each){
477 this.buf.push(''
478 + '// iterate ' + each.obj + '\n'
479 + '(function(){\n'
480 + ' if (\'number\' == typeof ' + each.obj + '.length) {\n'
481 + ' for (var ' + each.key + ' = 0, $$l = ' + each.obj + '.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
482 + ' var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
483
484 this.visit(each.block);
485
486 this.buf.push(''
487 + ' }\n'
488 + ' } else {\n'
489 + ' for (var ' + each.key + ' in ' + each.obj + ') {\n'
490 + ' if (' + each.obj + '.hasOwnProperty(' + each.key + ')){'
491 + ' var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
492
493 this.visit(each.block);
494
495 this.buf.push(' }\n');
496
497 this.buf.push(' }\n }\n}).call(this);\n');
498 },
499
500 /**
501 * Visit `attrs`.
502 *
503 * @param {Array} attrs
504 * @api public
505 */
506
507 visitAttributes: function(attrs){
508 var buf = []
509 , classes = [];
510
511 if (this.terse) buf.push('terse: true');
512
513 attrs.forEach(function(attr){
514 if (attr.name == 'class') {
515 classes.push('(' + attr.val + ')');
516 } else {
517 var pair = "'" + attr.name + "':(" + attr.val + ')';
518 buf.push(pair);
519 }
520 });
521
522 if (classes.length) {
523 classes = classes.join(" + ' ' + ");
524 buf.push("class: " + classes);
525 }
526
527 buf = buf.join(', ').replace('class:', '"class":');
528
529 this.buf.push("buf.push(attrs({ " + buf + " }));");
530 }
531};
532
533/**
534 * Escape the given string of `html`.
535 *
536 * @param {String} html
537 * @return {String}
538 * @api private
539 */
540
541function escape(html){
542 return String(html)
543 .replace(/&(?!\w+;)/g, '&amp;')
544 .replace(/</g, '&lt;')
545 .replace(/>/g, '&gt;')
546 .replace(/"/g, '&quot;');
547}
548
549}); // module: compiler.js
550
551require.register("doctypes.js", function(module, exports, require){
552
553/*!
554 * Jade - doctypes
555 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
556 * MIT Licensed
557 */
558
559module.exports = {
560 '5': '<!DOCTYPE html>'
561 , 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
562 , 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
563 , 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
564 , 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
565 , 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
566 , '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
567 , 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
568 , 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
569};
570}); // module: doctypes.js
571
572require.register("filters.js", function(module, exports, require){
573
574/*!
575 * Jade - filters
576 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
577 * MIT Licensed
578 */
579
580module.exports = {
581
582 /**
583 * Wrap text with CDATA block.
584 */
585
586 cdata: function(str){
587 return '<![CDATA[\\n' + str + '\\n]]>';
588 },
589
590 /**
591 * Transform sass to css, wrapped in style tags.
592 */
593
594 sass: function(str){
595 str = str.replace(/\\n/g, '\n');
596 var sass = require('sass').render(str).replace(/\n/g, '\\n');
597 return '<style type="text/css">' + sass + '</style>';
598 },
599
600 /**
601 * Transform stylus to css, wrapped in style tags.
602 */
603
604 stylus: function(str, options){
605 var ret;
606 str = str.replace(/\\n/g, '\n');
607 var stylus = require('stylus');
608 stylus(str, options).render(function(err, css){
609 if (err) throw err;
610 ret = css.replace(/\n/g, '\\n');
611 });
612 return '<style type="text/css">' + ret + '</style>';
613 },
614
615 /**
616 * Transform less to css, wrapped in style tags.
617 */
618
619 less: function(str){
620 var ret;
621 str = str.replace(/\\n/g, '\n');
622 require('less').render(str, function(err, css){
623 if (err) throw err;
624 ret = '<style type="text/css">' + css.replace(/\n/g, '\\n') + '</style>';
625 });
626 return ret;
627 },
628
629 /**
630 * Transform markdown to html.
631 */
632
633 markdown: function(str){
634 var md;
635
636 // support markdown / discount
637 try {
638 md = require('markdown');
639 } catch (err){
640 try {
641 md = require('discount');
642 } catch (err) {
643 try {
644 md = require('markdown-js');
645 } catch (err) {
646 try {
647 md = require('marked');
648 } catch (err) {
649 throw new
650 Error('Cannot find markdown library, install markdown, discount, or marked.');
651 }
652 }
653 }
654 }
655
656 str = str.replace(/\\n/g, '\n');
657 return md.parse(str).replace(/\n/g, '\\n').replace(/'/g,'&#39;');
658 },
659
660 /**
661 * Transform coffeescript to javascript.
662 */
663
664 coffeescript: function(str){
665 str = str.replace(/\\n/g, '\n');
666 var js = require('coffee-script').compile(str).replace(/\n/g, '\\n');
667 return '<script type="text/javascript">\\n' + js + '</script>';
668 }
669};
670
671}); // module: filters.js
672
673require.register("inline-tags.js", function(module, exports, require){
674
675/*!
676 * Jade - inline tags
677 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
678 * MIT Licensed
679 */
680
681module.exports = [
682 'a'
683 , 'abbr'
684 , 'acronym'
685 , 'b'
686 , 'br'
687 , 'code'
688 , 'em'
689 , 'font'
690 , 'i'
691 , 'img'
692 , 'ins'
693 , 'kbd'
694 , 'map'
695 , 'samp'
696 , 'small'
697 , 'span'
698 , 'strong'
699 , 'sub'
700 , 'sup'
701];
702}); // module: inline-tags.js
703
704require.register("jade.js", function(module, exports, require){
705/*!
706 * Jade
707 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
708 * MIT Licensed
709 */
710
711/**
712 * Module dependencies.
713 */
714
715var Parser = require('./parser')
716 , Lexer = require('./lexer')
717 , Compiler = require('./compiler')
718 , runtime = require('./runtime')
719
720/**
721 * Library version.
722 */
723
724exports.version = '0.21.0';
725
726/**
727 * Expose self closing tags.
728 */
729
730exports.selfClosing = require('./self-closing');
731
732/**
733 * Default supported doctypes.
734 */
735
736exports.doctypes = require('./doctypes');
737
738/**
739 * Text filters.
740 */
741
742exports.filters = require('./filters');
743
744/**
745 * Utilities.
746 */
747
748exports.utils = require('./utils');
749
750/**
751 * Expose `Compiler`.
752 */
753
754exports.Compiler = Compiler;
755
756/**
757 * Expose `Parser`.
758 */
759
760exports.Parser = Parser;
761
762/**
763 * Expose `Lexer`.
764 */
765
766exports.Lexer = Lexer;
767
768/**
769 * Nodes.
770 */
771
772exports.nodes = require('./nodes');
773
774/**
775 * Jade runtime helpers.
776 */
777
778exports.runtime = runtime;
779
780/**
781 * Template function cache.
782 */
783
784exports.cache = {};
785
786/**
787 * Parse the given `str` of jade and return a function body.
788 *
789 * @param {String} str
790 * @param {Object} options
791 * @return {String}
792 * @api private
793 */
794
795function parse(str, options){
796 try {
797 // Parse
798 var parser = new Parser(str, options.filename, options);
799
800 // Compile
801 var compiler = new (options.compiler || Compiler)(parser.parse(), options)
802 , js = compiler.compile();
803
804 // Debug compiler
805 if (options.debug) {
806 console.error('\nCompiled Function:\n\n\033[90m%s\033[0m', js.replace(/^/gm, ' '));
807 }
808
809 return ''
810 + 'var buf = [];\n'
811 + (options.self
812 ? 'var self = locals || {};\n' + js
813 : 'with (locals || {}) {\n' + js + '\n}\n')
814 + 'return buf.join("");';
815 } catch (err) {
816 parser = parser.context();
817 runtime.rethrow(err, parser.filename, parser.lexer.lineno);
818 }
819}
820
821/**
822 * Compile a `Function` representation of the given jade `str`.
823 *
824 * Options:
825 *
826 * - `compileDebug` when `false` debugging code is stripped from the compiled template
827 * - `client` when `true` the helper functions `escape()` etc will reference `jade.escape()`
828 * for use with the Jade client-side runtime.js
829 *
830 * @param {String} str
831 * @param {Options} options
832 * @return {Function}
833 * @api public
834 */
835
836exports.compile = function(str, options){
837 var options = options || {}
838 , client = options.client
839 , filename = options.filename
840 ? JSON.stringify(options.filename)
841 : 'undefined'
842 , fn;
843
844 if (options.compileDebug !== false) {
845 fn = [
846 'var __jade = [{ lineno: 1, filename: ' + filename + ' }];'
847 , 'try {'
848 , parse(String(str), options)
849 , '} catch (err) {'
850 , ' rethrow(err, __jade[0].filename, __jade[0].lineno);'
851 , '}'
852 ].join('\n');
853 } else {
854 fn = parse(String(str), options);
855 }
856
857 if (client) {
858 fn = 'var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;\n' + fn;
859 }
860
861 fn = new Function('locals, attrs, escape, rethrow', fn);
862
863 if (client) return fn;
864
865 return function(locals){
866 return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow);
867 };
868};
869
870/**
871 * Render the given `str` of jade and invoke
872 * the callback `fn(err, str)`.
873 *
874 * Options:
875 *
876 * - `cache` enable template caching
877 * - `filename` filename required for `include` / `extends` and caching
878 *
879 * @param {String} str
880 * @param {Object|Function} options or fn
881 * @param {Function} fn
882 * @api public
883 */
884
885exports.render = function(str, options, fn){
886 // swap args
887 if ('function' == typeof options) {
888 fn = options, options = {};
889 }
890
891 // cache requires .filename
892 if (options.cache && !options.filename) {
893 return fn(new Error('the "filename" option is required for caching'));
894 }
895
896 try {
897 var path = options.filename;
898 var tmpl = options.cache
899 ? exports.cache[path] || (exports.cache[path] = exports.compile(str, options))
900 : exports.compile(str, options);
901 fn(null, tmpl(options));
902 } catch (err) {
903 fn(err);
904 }
905};
906
907/**
908 * Render a Jade file at the given `path` and callback `fn(err, str)`.
909 *
910 * @param {String} path
911 * @param {Object|Function} options or callback
912 * @param {Function} fn
913 * @api public
914 */
915
916exports.renderFile = function(path, options, fn){
917 var key = path + ':string';
918
919 if ('function' == typeof options) {
920 fn = options, options = {};
921 }
922
923 try {
924 options.filename = path;
925 var str = options.cache
926 ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
927 : fs.readFileSync(path, 'utf8');
928 exports.render(str, options, fn);
929 } catch (err) {
930 fn(err);
931 }
932};
933
934/**
935 * Express support.
936 */
937
938exports.__express = exports.renderFile;
939
940}); // module: jade.js
941
942require.register("lexer.js", function(module, exports, require){
943
944/*!
945 * Jade - Lexer
946 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
947 * MIT Licensed
948 */
949
950/**
951 * Initialize `Lexer` with the given `str`.
952 *
953 * Options:
954 *
955 * - `colons` allow colons for attr delimiters
956 *
957 * @param {String} str
958 * @param {Object} options
959 * @api private
960 */
961
962var Lexer = module.exports = function Lexer(str, options) {
963 options = options || {};
964 this.input = str.replace(/\r\n|\r/g, '\n');
965 this.colons = options.colons;
966 this.deferredTokens = [];
967 this.lastIndents = 0;
968 this.lineno = 1;
969 this.stash = [];
970 this.indentStack = [];
971 this.indentRe = null;
972 this.pipeless = false;
973};
974
975/**
976 * Lexer prototype.
977 */
978
979Lexer.prototype = {
980
981 /**
982 * Construct a token with the given `type` and `val`.
983 *
984 * @param {String} type
985 * @param {String} val
986 * @return {Object}
987 * @api private
988 */
989
990 tok: function(type, val){
991 return {
992 type: type
993 , line: this.lineno
994 , val: val
995 }
996 },
997
998 /**
999 * Consume the given `len` of input.
1000 *
1001 * @param {Number} len
1002 * @api private
1003 */
1004
1005 consume: function(len){
1006 this.input = this.input.substr(len);
1007 },
1008
1009 /**
1010 * Scan for `type` with the given `regexp`.
1011 *
1012 * @param {String} type
1013 * @param {RegExp} regexp
1014 * @return {Object}
1015 * @api private
1016 */
1017
1018 scan: function(regexp, type){
1019 var captures;
1020 if (captures = regexp.exec(this.input)) {
1021 this.consume(captures[0].length);
1022 return this.tok(type, captures[1]);
1023 }
1024 },
1025
1026 /**
1027 * Defer the given `tok`.
1028 *
1029 * @param {Object} tok
1030 * @api private
1031 */
1032
1033 defer: function(tok){
1034 this.deferredTokens.push(tok);
1035 },
1036
1037 /**
1038 * Lookahead `n` tokens.
1039 *
1040 * @param {Number} n
1041 * @return {Object}
1042 * @api private
1043 */
1044
1045 lookahead: function(n){
1046 var fetch = n - this.stash.length;
1047 while (fetch-- > 0) this.stash.push(this.next());
1048 return this.stash[--n];
1049 },
1050
1051 /**
1052 * Return the indexOf `start` / `end` delimiters.
1053 *
1054 * @param {String} start
1055 * @param {String} end
1056 * @return {Number}
1057 * @api private
1058 */
1059
1060 indexOfDelimiters: function(start, end){
1061 var str = this.input
1062 , nstart = 0
1063 , nend = 0
1064 , pos = 0;
1065 for (var i = 0, len = str.length; i < len; ++i) {
1066 if (start == str.charAt(i)) {
1067 ++nstart;
1068 } else if (end == str.charAt(i)) {
1069 if (++nend == nstart) {
1070 pos = i;
1071 break;
1072 }
1073 }
1074 }
1075 return pos;
1076 },
1077
1078 /**
1079 * Stashed token.
1080 */
1081
1082 stashed: function() {
1083 return this.stash.length
1084 && this.stash.shift();
1085 },
1086
1087 /**
1088 * Deferred token.
1089 */
1090
1091 deferred: function() {
1092 return this.deferredTokens.length
1093 && this.deferredTokens.shift();
1094 },
1095
1096 /**
1097 * end-of-source.
1098 */
1099
1100 eos: function() {
1101 if (this.input.length) return;
1102 if (this.indentStack.length) {
1103 this.indentStack.shift();
1104 return this.tok('outdent');
1105 } else {
1106 return this.tok('eos');
1107 }
1108 },
1109
1110 /**
1111 * Comment.
1112 */
1113
1114 comment: function() {
1115 var captures;
1116 if (captures = /^ *\/\/(-)?([^\n]*)/.exec(this.input)) {
1117 this.consume(captures[0].length);
1118 var tok = this.tok('comment', captures[2]);
1119 tok.buffer = '-' != captures[1];
1120 return tok;
1121 }
1122 },
1123
1124 /**
1125 * Tag.
1126 */
1127
1128 tag: function() {
1129 var captures;
1130 if (captures = /^(\w[-:\w]*)/.exec(this.input)) {
1131 this.consume(captures[0].length);
1132 var tok, name = captures[1];
1133 if (':' == name[name.length - 1]) {
1134 name = name.slice(0, -1);
1135 tok = this.tok('tag', name);
1136 this.defer(this.tok(':'));
1137 while (' ' == this.input[0]) this.input = this.input.substr(1);
1138 } else {
1139 tok = this.tok('tag', name);
1140 }
1141 return tok;
1142 }
1143 },
1144
1145 /**
1146 * Filter.
1147 */
1148
1149 filter: function() {
1150 return this.scan(/^:(\w+)/, 'filter');
1151 },
1152
1153 /**
1154 * Doctype.
1155 */
1156
1157 doctype: function() {
1158 return this.scan(/^(?:!!!|doctype) *([^\n]+)?/, 'doctype');
1159 },
1160
1161 /**
1162 * Id.
1163 */
1164
1165 id: function() {
1166 return this.scan(/^#([\w-]+)/, 'id');
1167 },
1168
1169 /**
1170 * Class.
1171 */
1172
1173 className: function() {
1174 return this.scan(/^\.([\w-]+)/, 'class');
1175 },
1176
1177 /**
1178 * Text.
1179 */
1180
1181 text: function() {
1182 return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
1183 },
1184
1185 /**
1186 * Extends.
1187 */
1188
1189 "extends": function() {
1190 return this.scan(/^extends? +([^\n]+)/, 'extends');
1191 },
1192
1193 /**
1194 * Block prepend.
1195 */
1196
1197 prepend: function() {
1198 var captures;
1199 if (captures = /^prepend +([^\n]+)/.exec(this.input)) {
1200 this.consume(captures[0].length);
1201 var mode = 'prepend'
1202 , name = captures[1]
1203 , tok = this.tok('block', name);
1204 tok.mode = mode;
1205 return tok;
1206 }
1207 },
1208
1209 /**
1210 * Block append.
1211 */
1212
1213 append: function() {
1214 var captures;
1215 if (captures = /^append +([^\n]+)/.exec(this.input)) {
1216 this.consume(captures[0].length);
1217 var mode = 'append'
1218 , name = captures[1]
1219 , tok = this.tok('block', name);
1220 tok.mode = mode;
1221 return tok;
1222 }
1223 },
1224
1225 /**
1226 * Block.
1227 */
1228
1229 block: function() {
1230 var captures;
1231 if (captures = /^block +(?:(prepend|append) +)?([^\n]+)/.exec(this.input)) {
1232 this.consume(captures[0].length);
1233 var mode = captures[1] || 'replace'
1234 , name = captures[2]
1235 , tok = this.tok('block', name);
1236 tok.mode = mode;
1237 return tok;
1238 }
1239 },
1240
1241 /**
1242 * Yield.
1243 */
1244
1245 yield: function() {
1246 return this.scan(/^yield */, 'yield');
1247 },
1248
1249 /**
1250 * Include.
1251 */
1252
1253 include: function() {
1254 return this.scan(/^include +([^\n]+)/, 'include');
1255 },
1256
1257 /**
1258 * Case.
1259 */
1260
1261 "case": function() {
1262 return this.scan(/^case +([^\n]+)/, 'case');
1263 },
1264
1265 /**
1266 * When.
1267 */
1268
1269 when: function() {
1270 return this.scan(/^when +([^:\n]+)/, 'when');
1271 },
1272
1273 /**
1274 * Default.
1275 */
1276
1277 "default": function() {
1278 return this.scan(/^default */, 'default');
1279 },
1280
1281 /**
1282 * Assignment.
1283 */
1284
1285 assignment: function() {
1286 var captures;
1287 if (captures = /^(\w+) += *([^;\n]+)( *;? *)/.exec(this.input)) {
1288 this.consume(captures[0].length);
1289 var name = captures[1]
1290 , val = captures[2];
1291 return this.tok('code', 'var ' + name + ' = (' + val + ');');
1292 }
1293 },
1294
1295 /**
1296 * Mixin.
1297 */
1298
1299 mixin: function(){
1300 var captures;
1301 if (captures = /^mixin +([-\w]+)(?: *\((.*)\))?/.exec(this.input)) {
1302 this.consume(captures[0].length);
1303 var tok = this.tok('mixin', captures[1]);
1304 tok.args = captures[2];
1305 return tok;
1306 }
1307 },
1308
1309 /**
1310 * Conditional.
1311 */
1312
1313 conditional: function() {
1314 var captures;
1315 if (captures = /^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)) {
1316 this.consume(captures[0].length);
1317 var type = captures[1]
1318 , js = captures[2];
1319
1320 switch (type) {
1321 case 'if': js = 'if (' + js + ')'; break;
1322 case 'unless': js = 'if (!(' + js + '))'; break;
1323 case 'else if': js = 'else if (' + js + ')'; break;
1324 case 'else': js = 'else'; break;
1325 }
1326
1327 return this.tok('code', js);
1328 }
1329 },
1330
1331 /**
1332 * While.
1333 */
1334
1335 "while": function() {
1336 var captures;
1337 if (captures = /^while +([^\n]+)/.exec(this.input)) {
1338 this.consume(captures[0].length);
1339 return this.tok('code', 'while (' + captures[1] + ')');
1340 }
1341 },
1342
1343 /**
1344 * Each.
1345 */
1346
1347 each: function() {
1348 var captures;
1349 if (captures = /^(?:- *)?(?:each|for) +(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
1350 this.consume(captures[0].length);
1351 var tok = this.tok('each', captures[1]);
1352 tok.key = captures[2] || '$index';
1353 tok.code = captures[3];
1354 return tok;
1355 }
1356 },
1357
1358 /**
1359 * Code.
1360 */
1361
1362 code: function() {
1363 var captures;
1364 if (captures = /^(!?=|-)([^\n]+)/.exec(this.input)) {
1365 this.consume(captures[0].length);
1366 var flags = captures[1];
1367 captures[1] = captures[2];
1368 var tok = this.tok('code', captures[1]);
1369 tok.escape = flags[0] === '=';
1370 tok.buffer = flags[0] === '=' || flags[1] === '=';
1371 return tok;
1372 }
1373 },
1374
1375 /**
1376 * Attributes.
1377 */
1378
1379 attrs: function() {
1380 if ('(' == this.input.charAt(0)) {
1381 var index = this.indexOfDelimiters('(', ')')
1382 , str = this.input.substr(1, index-1)
1383 , tok = this.tok('attrs')
1384 , len = str.length
1385 , colons = this.colons
1386 , states = ['key']
1387 , key = ''
1388 , val = ''
1389 , quote
1390 , c;
1391
1392 function state(){
1393 return states[states.length - 1];
1394 }
1395
1396 function interpolate(attr) {
1397 return attr.replace(/#\{([^}]+)\}/g, function(_, expr){
1398 return quote + " + (" + expr + ") + " + quote;
1399 });
1400 }
1401
1402 this.consume(index + 1);
1403 tok.attrs = {};
1404
1405 function parse(c) {
1406 var real = c;
1407 // TODO: remove when people fix ":"
1408 if (colons && ':' == c) c = '=';
1409 switch (c) {
1410 case ',':
1411 case '\n':
1412 switch (state()) {
1413 case 'expr':
1414 case 'array':
1415 case 'string':
1416 case 'object':
1417 val += c;
1418 break;
1419 default:
1420 states.push('key');
1421 val = val.trim();
1422 key = key.trim();
1423 if ('' == key) return;
1424 tok.attrs[key.replace(/^['"]|['"]$/g, '')] = '' == val
1425 ? true
1426 : interpolate(val);
1427 key = val = '';
1428 }
1429 break;
1430 case '=':
1431 switch (state()) {
1432 case 'key char':
1433 key += real;
1434 break;
1435 case 'val':
1436 case 'expr':
1437 case 'array':
1438 case 'string':
1439 case 'object':
1440 val += real;
1441 break;
1442 default:
1443 states.push('val');
1444 }
1445 break;
1446 case '(':
1447 if ('val' == state()
1448 || 'expr' == state()) states.push('expr');
1449 val += c;
1450 break;
1451 case ')':
1452 if ('expr' == state()
1453 || 'val' == state()) states.pop();
1454 val += c;
1455 break;
1456 case '{':
1457 if ('val' == state()) states.push('object');
1458 val += c;
1459 break;
1460 case '}':
1461 if ('object' == state()) states.pop();
1462 val += c;
1463 break;
1464 case '[':
1465 if ('val' == state()) states.push('array');
1466 val += c;
1467 break;
1468 case ']':
1469 if ('array' == state()) states.pop();
1470 val += c;
1471 break;
1472 case '"':
1473 case "'":
1474 switch (state()) {
1475 case 'key':
1476 states.push('key char');
1477 break;
1478 case 'key char':
1479 states.pop();
1480 break;
1481 case 'string':
1482 if (c == quote) states.pop();
1483 val += c;
1484 break;
1485 default:
1486 states.push('string');
1487 val += c;
1488 quote = c;
1489 }
1490 break;
1491 case '':
1492 break;
1493 default:
1494 switch (state()) {
1495 case 'key':
1496 case 'key char':
1497 key += c;
1498 break;
1499 default:
1500 val += c;
1501 }
1502 }
1503 }
1504
1505 for (var i = 0; i < len; ++i) {
1506 parse(str.charAt(i));
1507 }
1508
1509 parse(',');
1510
1511 return tok;
1512 }
1513 },
1514
1515 /**
1516 * Indent | Outdent | Newline.
1517 */
1518
1519 indent: function() {
1520 var captures, re;
1521
1522 // established regexp
1523 if (this.indentRe) {
1524 captures = this.indentRe.exec(this.input);
1525 // determine regexp
1526 } else {
1527 // tabs
1528 re = /^\n(\t*) */;
1529 captures = re.exec(this.input);
1530
1531 // spaces
1532 if (captures && !captures[1].length) {
1533 re = /^\n( *)/;
1534 captures = re.exec(this.input);
1535 }
1536
1537 // established
1538 if (captures && captures[1].length) this.indentRe = re;
1539 }
1540
1541 if (captures) {
1542 var tok
1543 , indents = captures[1].length;
1544
1545 ++this.lineno;
1546 this.consume(indents + 1);
1547
1548 if (' ' == this.input[0] || '\t' == this.input[0]) {
1549 throw new Error('Invalid indentation, you can use tabs or spaces but not both');
1550 }
1551
1552 // blank line
1553 if ('\n' == this.input[0]) return this.tok('newline');
1554
1555 // outdent
1556 if (this.indentStack.length && indents < this.indentStack[0]) {
1557 while (this.indentStack.length && this.indentStack[0] > indents) {
1558 this.stash.push(this.tok('outdent'));
1559 this.indentStack.shift();
1560 }
1561 tok = this.stash.pop();
1562 // indent
1563 } else if (indents && indents != this.indentStack[0]) {
1564 this.indentStack.unshift(indents);
1565 tok = this.tok('indent', indents);
1566 // newline
1567 } else {
1568 tok = this.tok('newline');
1569 }
1570
1571 return tok;
1572 }
1573 },
1574
1575 /**
1576 * Pipe-less text consumed only when
1577 * pipeless is true;
1578 */
1579
1580 pipelessText: function() {
1581 if (this.pipeless) {
1582 if ('\n' == this.input[0]) return;
1583 var i = this.input.indexOf('\n');
1584 if (-1 == i) i = this.input.length;
1585 var str = this.input.substr(0, i);
1586 this.consume(str.length);
1587 return this.tok('text', str);
1588 }
1589 },
1590
1591 /**
1592 * ':'
1593 */
1594
1595 colon: function() {
1596 return this.scan(/^: */, ':');
1597 },
1598
1599 /**
1600 * Return the next token object, or those
1601 * previously stashed by lookahead.
1602 *
1603 * @return {Object}
1604 * @api private
1605 */
1606
1607 advance: function(){
1608 return this.stashed()
1609 || this.next();
1610 },
1611
1612 /**
1613 * Return the next token object.
1614 *
1615 * @return {Object}
1616 * @api private
1617 */
1618
1619 next: function() {
1620 return this.deferred()
1621 || this.eos()
1622 || this.pipelessText()
1623 || this.yield()
1624 || this.doctype()
1625 || this["case"]()
1626 || this.when()
1627 || this["default"]()
1628 || this["extends"]()
1629 || this.append()
1630 || this.prepend()
1631 || this.block()
1632 || this.include()
1633 || this.mixin()
1634 || this.conditional()
1635 || this.each()
1636 || this["while"]()
1637 || this.assignment()
1638 || this.tag()
1639 || this.filter()
1640 || this.code()
1641 || this.id()
1642 || this.className()
1643 || this.attrs()
1644 || this.indent()
1645 || this.comment()
1646 || this.colon()
1647 || this.text();
1648 }
1649};
1650
1651}); // module: lexer.js
1652
1653require.register("nodes/block-comment.js", function(module, exports, require){
1654
1655/*!
1656 * Jade - nodes - BlockComment
1657 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1658 * MIT Licensed
1659 */
1660
1661/**
1662 * Module dependencies.
1663 */
1664
1665var Node = require('./node');
1666
1667/**
1668 * Initialize a `BlockComment` with the given `block`.
1669 *
1670 * @param {String} val
1671 * @param {Block} block
1672 * @param {Boolean} buffer
1673 * @api public
1674 */
1675
1676var BlockComment = module.exports = function BlockComment(val, block, buffer) {
1677 this.block = block;
1678 this.val = val;
1679 this.buffer = buffer;
1680};
1681
1682/**
1683 * Inherit from `Node`.
1684 */
1685
1686BlockComment.prototype = new Node;
1687BlockComment.prototype.constructor = BlockComment;
1688
1689}); // module: nodes/block-comment.js
1690
1691require.register("nodes/block.js", function(module, exports, require){
1692
1693/*!
1694 * Jade - nodes - Block
1695 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1696 * MIT Licensed
1697 */
1698
1699/**
1700 * Module dependencies.
1701 */
1702
1703var Node = require('./node');
1704
1705/**
1706 * Initialize a new `Block` with an optional `node`.
1707 *
1708 * @param {Node} node
1709 * @api public
1710 */
1711
1712var Block = module.exports = function Block(node){
1713 this.nodes = [];
1714 if (node) this.push(node);
1715};
1716
1717/**
1718 * Inherit from `Node`.
1719 */
1720
1721Block.prototype = new Node;
1722Block.prototype.constructor = Block;
1723
1724
1725/**
1726 * Replace the nodes in `other` with the nodes
1727 * in `this` block.
1728 *
1729 * @param {Block} other
1730 * @api private
1731 */
1732
1733Block.prototype.replace = function(other){
1734 other.nodes = this.nodes;
1735};
1736
1737/**
1738 * Pust the given `node`.
1739 *
1740 * @param {Node} node
1741 * @return {Number}
1742 * @api public
1743 */
1744
1745Block.prototype.push = function(node){
1746 return this.nodes.push(node);
1747};
1748
1749/**
1750 * Check if this block is empty.
1751 *
1752 * @return {Boolean}
1753 * @api public
1754 */
1755
1756Block.prototype.isEmpty = function(){
1757 return 0 == this.nodes.length;
1758};
1759
1760/**
1761 * Unshift the given `node`.
1762 *
1763 * @param {Node} node
1764 * @return {Number}
1765 * @api public
1766 */
1767
1768Block.prototype.unshift = function(node){
1769 return this.nodes.unshift(node);
1770};
1771
1772/**
1773 * Return the "last" block, or the first `yield` node.
1774 *
1775 * @return {Block}
1776 * @api private
1777 */
1778
1779Block.prototype.includeBlock = function(){
1780 var ret = this
1781 , node;
1782
1783 for (var i = 0, len = this.nodes.length; i < len; ++i) {
1784 node = this.nodes[i];
1785 if (node.yield) return node;
1786 else if (node.textOnly) continue;
1787 else if (node.includeBlock) ret = node.includeBlock();
1788 else if (node.block && !node.block.isEmpty()) ret = node.block.includeBlock();
1789 }
1790
1791 return ret;
1792};
1793
1794
1795}); // module: nodes/block.js
1796
1797require.register("nodes/case.js", function(module, exports, require){
1798
1799/*!
1800 * Jade - nodes - Case
1801 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1802 * MIT Licensed
1803 */
1804
1805/**
1806 * Module dependencies.
1807 */
1808
1809var Node = require('./node');
1810
1811/**
1812 * Initialize a new `Case` with `expr`.
1813 *
1814 * @param {String} expr
1815 * @api public
1816 */
1817
1818var Case = exports = module.exports = function Case(expr, block){
1819 this.expr = expr;
1820 this.block = block;
1821};
1822
1823/**
1824 * Inherit from `Node`.
1825 */
1826
1827Case.prototype = new Node;
1828Case.prototype.constructor = Case;
1829
1830
1831var When = exports.When = function When(expr, block){
1832 this.expr = expr;
1833 this.block = block;
1834 this.debug = false;
1835};
1836
1837/**
1838 * Inherit from `Node`.
1839 */
1840
1841When.prototype = new Node;
1842When.prototype.constructor = When;
1843
1844
1845
1846}); // module: nodes/case.js
1847
1848require.register("nodes/code.js", function(module, exports, require){
1849
1850/*!
1851 * Jade - nodes - Code
1852 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1853 * MIT Licensed
1854 */
1855
1856/**
1857 * Module dependencies.
1858 */
1859
1860var Node = require('./node');
1861
1862/**
1863 * Initialize a `Code` node with the given code `val`.
1864 * Code may also be optionally buffered and escaped.
1865 *
1866 * @param {String} val
1867 * @param {Boolean} buffer
1868 * @param {Boolean} escape
1869 * @api public
1870 */
1871
1872var Code = module.exports = function Code(val, buffer, escape) {
1873 this.val = val;
1874 this.buffer = buffer;
1875 this.escape = escape;
1876 if (val.match(/^ *else/)) this.debug = false;
1877};
1878
1879/**
1880 * Inherit from `Node`.
1881 */
1882
1883Code.prototype = new Node;
1884Code.prototype.constructor = Code;
1885
1886}); // module: nodes/code.js
1887
1888require.register("nodes/comment.js", function(module, exports, require){
1889
1890/*!
1891 * Jade - nodes - Comment
1892 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1893 * MIT Licensed
1894 */
1895
1896/**
1897 * Module dependencies.
1898 */
1899
1900var Node = require('./node');
1901
1902/**
1903 * Initialize a `Comment` with the given `val`, optionally `buffer`,
1904 * otherwise the comment may render in the output.
1905 *
1906 * @param {String} val
1907 * @param {Boolean} buffer
1908 * @api public
1909 */
1910
1911var Comment = module.exports = function Comment(val, buffer) {
1912 this.val = val;
1913 this.buffer = buffer;
1914};
1915
1916/**
1917 * Inherit from `Node`.
1918 */
1919
1920Comment.prototype = new Node;
1921Comment.prototype.constructor = Comment;
1922
1923}); // module: nodes/comment.js
1924
1925require.register("nodes/doctype.js", function(module, exports, require){
1926
1927/*!
1928 * Jade - nodes - Doctype
1929 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1930 * MIT Licensed
1931 */
1932
1933/**
1934 * Module dependencies.
1935 */
1936
1937var Node = require('./node');
1938
1939/**
1940 * Initialize a `Doctype` with the given `val`.
1941 *
1942 * @param {String} val
1943 * @api public
1944 */
1945
1946var Doctype = module.exports = function Doctype(val) {
1947 this.val = val;
1948};
1949
1950/**
1951 * Inherit from `Node`.
1952 */
1953
1954Doctype.prototype = new Node;
1955Doctype.prototype.constructor = Doctype;
1956
1957}); // module: nodes/doctype.js
1958
1959require.register("nodes/each.js", function(module, exports, require){
1960
1961/*!
1962 * Jade - nodes - Each
1963 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1964 * MIT Licensed
1965 */
1966
1967/**
1968 * Module dependencies.
1969 */
1970
1971var Node = require('./node');
1972
1973/**
1974 * Initialize an `Each` node, representing iteration
1975 *
1976 * @param {String} obj
1977 * @param {String} val
1978 * @param {String} key
1979 * @param {Block} block
1980 * @api public
1981 */
1982
1983var Each = module.exports = function Each(obj, val, key, block) {
1984 this.obj = obj;
1985 this.val = val;
1986 this.key = key;
1987 this.block = block;
1988};
1989
1990/**
1991 * Inherit from `Node`.
1992 */
1993
1994Each.prototype = new Node;
1995Each.prototype.constructor = Each;
1996
1997}); // module: nodes/each.js
1998
1999require.register("nodes/filter.js", function(module, exports, require){
2000
2001/*!
2002 * Jade - nodes - Filter
2003 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2004 * MIT Licensed
2005 */
2006
2007/**
2008 * Module dependencies.
2009 */
2010
2011var Node = require('./node')
2012 , Block = require('./block');
2013
2014/**
2015 * Initialize a `Filter` node with the given
2016 * filter `name` and `block`.
2017 *
2018 * @param {String} name
2019 * @param {Block|Node} block
2020 * @api public
2021 */
2022
2023var Filter = module.exports = function Filter(name, block, attrs) {
2024 this.name = name;
2025 this.block = block;
2026 this.attrs = attrs;
2027 this.isASTFilter = block instanceof Block;
2028};
2029
2030/**
2031 * Inherit from `Node`.
2032 */
2033
2034Filter.prototype = new Node;
2035Filter.prototype.constructor = Filter;
2036
2037}); // module: nodes/filter.js
2038
2039require.register("nodes/index.js", function(module, exports, require){
2040
2041/*!
2042 * Jade - nodes
2043 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2044 * MIT Licensed
2045 */
2046
2047exports.Node = require('./node');
2048exports.Tag = require('./tag');
2049exports.Code = require('./code');
2050exports.Each = require('./each');
2051exports.Case = require('./case');
2052exports.Text = require('./text');
2053exports.Block = require('./block');
2054exports.Mixin = require('./mixin');
2055exports.Filter = require('./filter');
2056exports.Comment = require('./comment');
2057exports.Literal = require('./literal');
2058exports.BlockComment = require('./block-comment');
2059exports.Doctype = require('./doctype');
2060
2061}); // module: nodes/index.js
2062
2063require.register("nodes/literal.js", function(module, exports, require){
2064
2065/*!
2066 * Jade - nodes - Literal
2067 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2068 * MIT Licensed
2069 */
2070
2071/**
2072 * Module dependencies.
2073 */
2074
2075var Node = require('./node');
2076
2077/**
2078 * Initialize a `Literal` node with the given `str.
2079 *
2080 * @param {String} str
2081 * @api public
2082 */
2083
2084var Literal = module.exports = function Literal(str) {
2085 this.str = str
2086 .replace(/\\/g, "\\\\")
2087 .replace(/\n|\r\n/g, "\\n")
2088 .replace(/'/g, "\\'");
2089};
2090
2091/**
2092 * Inherit from `Node`.
2093 */
2094
2095Literal.prototype = new Node;
2096Literal.prototype.constructor = Literal;
2097
2098
2099}); // module: nodes/literal.js
2100
2101require.register("nodes/mixin.js", function(module, exports, require){
2102
2103/*!
2104 * Jade - nodes - Mixin
2105 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2106 * MIT Licensed
2107 */
2108
2109/**
2110 * Module dependencies.
2111 */
2112
2113var Node = require('./node');
2114
2115/**
2116 * Initialize a new `Mixin` with `name` and `block`.
2117 *
2118 * @param {String} name
2119 * @param {String} args
2120 * @param {Block} block
2121 * @api public
2122 */
2123
2124var Mixin = module.exports = function Mixin(name, args, block){
2125 this.name = name;
2126 this.args = args;
2127 this.block = block;
2128};
2129
2130/**
2131 * Inherit from `Node`.
2132 */
2133
2134Mixin.prototype = new Node;
2135Mixin.prototype.constructor = Mixin;
2136
2137
2138
2139}); // module: nodes/mixin.js
2140
2141require.register("nodes/node.js", function(module, exports, require){
2142
2143/*!
2144 * Jade - nodes - Node
2145 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2146 * MIT Licensed
2147 */
2148
2149/**
2150 * Initialize a `Node`.
2151 *
2152 * @api public
2153 */
2154
2155var Node = module.exports = function Node(){};
2156}); // module: nodes/node.js
2157
2158require.register("nodes/tag.js", function(module, exports, require){
2159
2160/*!
2161 * Jade - nodes - Tag
2162 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2163 * MIT Licensed
2164 */
2165
2166/**
2167 * Module dependencies.
2168 */
2169
2170var Node = require('./node'),
2171 Block = require('./block');
2172
2173/**
2174 * Initialize a `Tag` node with the given tag `name` and optional `block`.
2175 *
2176 * @param {String} name
2177 * @param {Block} block
2178 * @api public
2179 */
2180
2181var Tag = module.exports = function Tag(name, block) {
2182 this.name = name;
2183 this.attrs = [];
2184 this.block = block || new Block;
2185};
2186
2187/**
2188 * Inherit from `Node`.
2189 */
2190
2191Tag.prototype = new Node;
2192Tag.prototype.constructor = Tag;
2193
2194
2195/**
2196 * Set attribute `name` to `val`, keep in mind these become
2197 * part of a raw js object literal, so to quote a value you must
2198 * '"quote me"', otherwise or example 'user.name' is literal JavaScript.
2199 *
2200 * @param {String} name
2201 * @param {String} val
2202 * @return {Tag} for chaining
2203 * @api public
2204 */
2205
2206Tag.prototype.setAttribute = function(name, val){
2207 this.attrs.push({ name: name, val: val });
2208 return this;
2209};
2210
2211/**
2212 * Remove attribute `name` when present.
2213 *
2214 * @param {String} name
2215 * @api public
2216 */
2217
2218Tag.prototype.removeAttribute = function(name){
2219 for (var i = 0, len = this.attrs.length; i < len; ++i) {
2220 if (this.attrs[i] && this.attrs[i].name == name) {
2221 delete this.attrs[i];
2222 }
2223 }
2224};
2225
2226/**
2227 * Get attribute value by `name`.
2228 *
2229 * @param {String} name
2230 * @return {String}
2231 * @api public
2232 */
2233
2234Tag.prototype.getAttribute = function(name){
2235 for (var i = 0, len = this.attrs.length; i < len; ++i) {
2236 if (this.attrs[i] && this.attrs[i].name == name) {
2237 return this.attrs[i].val;
2238 }
2239 }
2240};
2241
2242}); // module: nodes/tag.js
2243
2244require.register("nodes/text.js", function(module, exports, require){
2245
2246/*!
2247 * Jade - nodes - Text
2248 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2249 * MIT Licensed
2250 */
2251
2252/**
2253 * Module dependencies.
2254 */
2255
2256var Node = require('./node');
2257
2258/**
2259 * Initialize a `Text` node with optional `line`.
2260 *
2261 * @param {String} line
2262 * @api public
2263 */
2264
2265var Text = module.exports = function Text(line) {
2266 this.nodes = [];
2267 if ('string' == typeof line) this.push(line);
2268};
2269
2270/**
2271 * Inherit from `Node`.
2272 */
2273
2274Text.prototype = new Node;
2275Text.prototype.constructor = Text;
2276
2277
2278/**
2279 * Push the given `node.`
2280 *
2281 * @param {Node} node
2282 * @return {Number}
2283 * @api public
2284 */
2285
2286Text.prototype.push = function(node){
2287 return this.nodes.push(node);
2288};
2289
2290}); // module: nodes/text.js
2291
2292require.register("parser.js", function(module, exports, require){
2293
2294/*!
2295 * Jade - Parser
2296 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2297 * MIT Licensed
2298 */
2299
2300/**
2301 * Module dependencies.
2302 */
2303
2304var Lexer = require('./lexer')
2305 , nodes = require('./nodes');
2306
2307/**
2308 * Initialize `Parser` with the given input `str` and `filename`.
2309 *
2310 * @param {String} str
2311 * @param {String} filename
2312 * @param {Object} options
2313 * @api public
2314 */
2315
2316var Parser = exports = module.exports = function Parser(str, filename, options){
2317 this.input = str;
2318 this.lexer = new Lexer(str, options);
2319 this.filename = filename;
2320 this.blocks = {};
2321 this.options = options;
2322 this.contexts = [this];
2323};
2324
2325/**
2326 * Tags that may not contain tags.
2327 */
2328
2329var textOnly = exports.textOnly = ['script', 'style'];
2330
2331/**
2332 * Parser prototype.
2333 */
2334
2335Parser.prototype = {
2336
2337 /**
2338 * Push `parser` onto the context stack,
2339 * or pop and return a `Parser`.
2340 */
2341
2342 context: function(parser){
2343 if (parser) {
2344 this.contexts.push(parser);
2345 } else {
2346 return this.contexts.pop();
2347 }
2348 },
2349
2350 /**
2351 * Return the next token object.
2352 *
2353 * @return {Object}
2354 * @api private
2355 */
2356
2357 advance: function(){
2358 return this.lexer.advance();
2359 },
2360
2361 /**
2362 * Skip `n` tokens.
2363 *
2364 * @param {Number} n
2365 * @api private
2366 */
2367
2368 skip: function(n){
2369 while (n--) this.advance();
2370 },
2371
2372 /**
2373 * Single token lookahead.
2374 *
2375 * @return {Object}
2376 * @api private
2377 */
2378
2379 peek: function() {
2380 return this.lookahead(1);
2381 },
2382
2383 /**
2384 * Return lexer lineno.
2385 *
2386 * @return {Number}
2387 * @api private
2388 */
2389
2390 line: function() {
2391 return this.lexer.lineno;
2392 },
2393
2394 /**
2395 * `n` token lookahead.
2396 *
2397 * @param {Number} n
2398 * @return {Object}
2399 * @api private
2400 */
2401
2402 lookahead: function(n){
2403 return this.lexer.lookahead(n);
2404 },
2405
2406 /**
2407 * Parse input returning a string of js for evaluation.
2408 *
2409 * @return {String}
2410 * @api public
2411 */
2412
2413 parse: function(){
2414 var block = new nodes.Block, parser;
2415 block.line = this.line();
2416
2417 while ('eos' != this.peek().type) {
2418 if ('newline' == this.peek().type) {
2419 this.advance();
2420 } else {
2421 block.push(this.parseExpr());
2422 }
2423 }
2424
2425 if (parser = this.extending) {
2426 this.context(parser);
2427 var ast = parser.parse();
2428 this.context();
2429 return ast;
2430 }
2431
2432 return block;
2433 },
2434
2435 /**
2436 * Expect the given type, or throw an exception.
2437 *
2438 * @param {String} type
2439 * @api private
2440 */
2441
2442 expect: function(type){
2443 if (this.peek().type === type) {
2444 return this.advance();
2445 } else {
2446 throw new Error('expected "' + type + '", but got "' + this.peek().type + '"');
2447 }
2448 },
2449
2450 /**
2451 * Accept the given `type`.
2452 *
2453 * @param {String} type
2454 * @api private
2455 */
2456
2457 accept: function(type){
2458 if (this.peek().type === type) {
2459 return this.advance();
2460 }
2461 },
2462
2463 /**
2464 * tag
2465 * | doctype
2466 * | mixin
2467 * | include
2468 * | filter
2469 * | comment
2470 * | text
2471 * | each
2472 * | code
2473 * | yield
2474 * | id
2475 * | class
2476 */
2477
2478 parseExpr: function(){
2479 switch (this.peek().type) {
2480 case 'tag':
2481 return this.parseTag();
2482 case 'mixin':
2483 return this.parseMixin();
2484 case 'block':
2485 return this.parseBlock();
2486 case 'case':
2487 return this.parseCase();
2488 case 'when':
2489 return this.parseWhen();
2490 case 'default':
2491 return this.parseDefault();
2492 case 'extends':
2493 return this.parseExtends();
2494 case 'include':
2495 return this.parseInclude();
2496 case 'doctype':
2497 return this.parseDoctype();
2498 case 'filter':
2499 return this.parseFilter();
2500 case 'comment':
2501 return this.parseComment();
2502 case 'text':
2503 return this.parseText();
2504 case 'each':
2505 return this.parseEach();
2506 case 'code':
2507 return this.parseCode();
2508 case 'yield':
2509 this.advance();
2510 var block = new nodes.Block;
2511 block.yield = true;
2512 return block;
2513 case 'id':
2514 case 'class':
2515 var tok = this.advance();
2516 this.lexer.defer(this.lexer.tok('tag', 'div'));
2517 this.lexer.defer(tok);
2518 return this.parseExpr();
2519 default:
2520 throw new Error('unexpected token "' + this.peek().type + '"');
2521 }
2522 },
2523
2524 /**
2525 * Text
2526 */
2527
2528 parseText: function(){
2529 var tok = this.expect('text')
2530 , node = new nodes.Text(tok.val);
2531 node.line = this.line();
2532 return node;
2533 },
2534
2535 /**
2536 * ':' expr
2537 * | block
2538 */
2539
2540 parseBlockExpansion: function(){
2541 if (':' == this.peek().type) {
2542 this.advance();
2543 return new nodes.Block(this.parseExpr());
2544 } else {
2545 return this.block();
2546 }
2547 },
2548
2549 /**
2550 * case
2551 */
2552
2553 parseCase: function(){
2554 var val = this.expect('case').val
2555 , node = new nodes.Case(val);
2556 node.line = this.line();
2557 node.block = this.block();
2558 return node;
2559 },
2560
2561 /**
2562 * when
2563 */
2564
2565 parseWhen: function(){
2566 var val = this.expect('when').val
2567 return new nodes.Case.When(val, this.parseBlockExpansion());
2568 },
2569
2570 /**
2571 * default
2572 */
2573
2574 parseDefault: function(){
2575 this.expect('default');
2576 return new nodes.Case.When('default', this.parseBlockExpansion());
2577 },
2578
2579 /**
2580 * code
2581 */
2582
2583 parseCode: function(){
2584 var tok = this.expect('code')
2585 , node = new nodes.Code(tok.val, tok.buffer, tok.escape)
2586 , block
2587 , i = 1;
2588 node.line = this.line();
2589 while (this.lookahead(i) && 'newline' == this.lookahead(i).type) ++i;
2590 block = 'indent' == this.lookahead(i).type;
2591 if (block) {
2592 this.skip(i-1);
2593 node.block = this.block();
2594 }
2595 return node;
2596 },
2597
2598 /**
2599 * comment
2600 */
2601
2602 parseComment: function(){
2603 var tok = this.expect('comment')
2604 , node;
2605
2606 if ('indent' == this.peek().type) {
2607 node = new nodes.BlockComment(tok.val, this.block(), tok.buffer);
2608 } else {
2609 node = new nodes.Comment(tok.val, tok.buffer);
2610 }
2611
2612 node.line = this.line();
2613 return node;
2614 },
2615
2616 /**
2617 * doctype
2618 */
2619
2620 parseDoctype: function(){
2621 var tok = this.expect('doctype')
2622 , node = new nodes.Doctype(tok.val);
2623 node.line = this.line();
2624 return node;
2625 },
2626
2627 /**
2628 * filter attrs? text-block
2629 */
2630
2631 parseFilter: function(){
2632 var block
2633 , tok = this.expect('filter')
2634 , attrs = this.accept('attrs');
2635
2636 this.lexer.pipeless = true;
2637 block = this.parseTextBlock();
2638 this.lexer.pipeless = false;
2639
2640 var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
2641 node.line = this.line();
2642 return node;
2643 },
2644
2645 /**
2646 * tag ':' attrs? block
2647 */
2648
2649 parseASTFilter: function(){
2650 var block
2651 , tok = this.expect('tag')
2652 , attrs = this.accept('attrs');
2653
2654 this.expect(':');
2655 block = this.block();
2656
2657 var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
2658 node.line = this.line();
2659 return node;
2660 },
2661
2662 /**
2663 * each block
2664 */
2665
2666 parseEach: function(){
2667 var tok = this.expect('each')
2668 , node = new nodes.Each(tok.code, tok.val, tok.key);
2669 node.line = this.line();
2670 node.block = this.block();
2671 return node;
2672 },
2673
2674 /**
2675 * 'extends' name
2676 */
2677
2678 parseExtends: function(){
2679 var path = require('path')
2680 , fs = require('fs')
2681 , dirname = path.dirname
2682 , basename = path.basename
2683 , join = path.join;
2684
2685 if (!this.filename)
2686 throw new Error('the "filename" option is required to extend templates');
2687
2688 var path = this.expect('extends').val.trim()
2689 , dir = dirname(this.filename);
2690
2691 var path = join(dir, path + '.jade')
2692 , str = fs.readFileSync(path, 'utf8')
2693 , parser = new Parser(str, path, this.options);
2694
2695 parser.blocks = this.blocks;
2696 parser.contexts = this.contexts;
2697 this.extending = parser;
2698
2699 // TODO: null node
2700 return new nodes.Literal('');
2701 },
2702
2703 /**
2704 * 'block' name block
2705 */
2706
2707 parseBlock: function(){
2708 var block = this.expect('block')
2709 , mode = block.mode
2710 , name = block.val.trim();
2711
2712 block = 'indent' == this.peek().type
2713 ? this.block()
2714 : new nodes.Block(new nodes.Literal(''));
2715
2716 var prev = this.blocks[name];
2717
2718 if (prev) {
2719 switch (prev.mode) {
2720 case 'append':
2721 block.nodes = block.nodes.concat(prev.nodes);
2722 prev = block;
2723 break;
2724 case 'prepend':
2725 block.nodes = prev.nodes.concat(block.nodes);
2726 prev = block;
2727 break;
2728 }
2729 }
2730
2731 block.mode = mode;
2732 return this.blocks[name] = prev || block;
2733 },
2734
2735 /**
2736 * include block?
2737 */
2738
2739 parseInclude: function(){
2740 var path = require('path')
2741 , fs = require('fs')
2742 , dirname = path.dirname
2743 , basename = path.basename
2744 , join = path.join;
2745
2746 var path = this.expect('include').val.trim()
2747 , dir = dirname(this.filename);
2748
2749 if (!this.filename)
2750 throw new Error('the "filename" option is required to use includes');
2751
2752 // no extension
2753 if (!~basename(path).indexOf('.')) {
2754 path += '.jade';
2755 }
2756
2757 // non-jade
2758 if ('.jade' != path.substr(-5)) {
2759 var path = join(dir, path)
2760 , str = fs.readFileSync(path, 'utf8');
2761 return new nodes.Literal(str);
2762 }
2763
2764 var path = join(dir, path)
2765 , str = fs.readFileSync(path, 'utf8')
2766 , parser = new Parser(str, path, this.options);
2767
2768 this.context(parser);
2769 var ast = parser.parse();
2770 this.context();
2771 ast.filename = path;
2772
2773 if ('indent' == this.peek().type) {
2774 ast.includeBlock().push(this.block());
2775 }
2776
2777 return ast;
2778 },
2779
2780 /**
2781 * mixin block
2782 */
2783
2784 parseMixin: function(){
2785 var tok = this.expect('mixin')
2786 , name = tok.val
2787 , args = tok.args;
2788 var block = 'indent' == this.peek().type
2789 ? this.block()
2790 : null;
2791 return new nodes.Mixin(name, args, block);
2792 },
2793
2794 /**
2795 * indent (text | newline)* outdent
2796 */
2797
2798 parseTextBlock: function(){
2799 var text = new nodes.Text;
2800 text.line = this.line();
2801 var spaces = this.expect('indent').val;
2802 if (null == this._spaces) this._spaces = spaces;
2803 var indent = Array(spaces - this._spaces + 1).join(' ');
2804 while ('outdent' != this.peek().type) {
2805 switch (this.peek().type) {
2806 case 'newline':
2807 text.push('\\n');
2808 this.advance();
2809 break;
2810 case 'indent':
2811 text.push('\\n');
2812 this.parseTextBlock().nodes.forEach(function(node){
2813 text.push(node);
2814 });
2815 text.push('\\n');
2816 break;
2817 default:
2818 text.push(indent + this.advance().val);
2819 }
2820 }
2821
2822 if (spaces == this._spaces) this._spaces = null;
2823 this.expect('outdent');
2824 return text;
2825 },
2826
2827 /**
2828 * indent expr* outdent
2829 */
2830
2831 block: function(){
2832 var block = new nodes.Block;
2833 block.line = this.line();
2834 this.expect('indent');
2835 while ('outdent' != this.peek().type) {
2836 if ('newline' == this.peek().type) {
2837 this.advance();
2838 } else {
2839 block.push(this.parseExpr());
2840 }
2841 }
2842 this.expect('outdent');
2843 return block;
2844 },
2845
2846 /**
2847 * tag (attrs | class | id)* (text | code | ':')? newline* block?
2848 */
2849
2850 parseTag: function(){
2851 // ast-filter look-ahead
2852 var i = 2;
2853 if ('attrs' == this.lookahead(i).type) ++i;
2854 if (':' == this.lookahead(i).type) {
2855 if ('indent' == this.lookahead(++i).type) {
2856 return this.parseASTFilter();
2857 }
2858 }
2859
2860 var name = this.advance().val
2861 , tag = new nodes.Tag(name)
2862 , dot;
2863
2864 tag.line = this.line();
2865
2866 // (attrs | class | id)*
2867 out:
2868 while (true) {
2869 switch (this.peek().type) {
2870 case 'id':
2871 case 'class':
2872 var tok = this.advance();
2873 tag.setAttribute(tok.type, "'" + tok.val + "'");
2874 continue;
2875 case 'attrs':
2876 var obj = this.advance().attrs
2877 , names = Object.keys(obj);
2878 for (var i = 0, len = names.length; i < len; ++i) {
2879 var name = names[i]
2880 , val = obj[name];
2881 tag.setAttribute(name, val);
2882 }
2883 continue;
2884 default:
2885 break out;
2886 }
2887 }
2888
2889 // check immediate '.'
2890 if ('.' == this.peek().val) {
2891 dot = tag.textOnly = true;
2892 this.advance();
2893 }
2894
2895 // (text | code | ':')?
2896 switch (this.peek().type) {
2897 case 'text':
2898 tag.text = this.parseText();
2899 break;
2900 case 'code':
2901 tag.code = this.parseCode();
2902 break;
2903 case ':':
2904 this.advance();
2905 tag.block = new nodes.Block;
2906 tag.block.push(this.parseExpr());
2907 break;
2908 }
2909
2910 // newline*
2911 while ('newline' == this.peek().type) this.advance();
2912
2913 tag.textOnly = tag.textOnly || ~textOnly.indexOf(tag.name);
2914
2915 // script special-case
2916 if ('script' == tag.name) {
2917 var type = tag.getAttribute('type');
2918 if (!dot && type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
2919 tag.textOnly = false;
2920 }
2921 }
2922
2923 // block?
2924 if ('indent' == this.peek().type) {
2925 if (tag.textOnly) {
2926 this.lexer.pipeless = true;
2927 tag.block = this.parseTextBlock();
2928 this.lexer.pipeless = false;
2929 } else {
2930 var block = this.block();
2931 if (tag.block) {
2932 for (var i = 0, len = block.nodes.length; i < len; ++i) {
2933 tag.block.push(block.nodes[i]);
2934 }
2935 } else {
2936 tag.block = block;
2937 }
2938 }
2939 }
2940
2941 return tag;
2942 }
2943};
2944
2945}); // module: parser.js
2946
2947require.register("runtime.js", function(module, exports, require){
2948
2949/*!
2950 * Jade - runtime
2951 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2952 * MIT Licensed
2953 */
2954
2955/**
2956 * Lame Array.isArray() polyfill for now.
2957 */
2958
2959if (!Array.isArray) {
2960 Array.isArray = function(arr){
2961 return '[object Array]' == Object.prototype.toString.call(arr);
2962 };
2963}
2964
2965/**
2966 * Lame Object.keys() polyfill for now.
2967 */
2968
2969if (!Object.keys) {
2970 Object.keys = function(obj){
2971 var arr = [];
2972 for (var key in obj) {
2973 if (obj.hasOwnProperty(key)) {
2974 arr.push(key);
2975 }
2976 }
2977 return arr;
2978 }
2979}
2980
2981/**
2982 * Render the given attributes object.
2983 *
2984 * @param {Object} obj
2985 * @return {String}
2986 * @api private
2987 */
2988
2989exports.attrs = function attrs(obj){
2990 var buf = []
2991 , terse = obj.terse;
2992 delete obj.terse;
2993 var keys = Object.keys(obj)
2994 , len = keys.length;
2995 if (len) {
2996 buf.push('');
2997 for (var i = 0; i < len; ++i) {
2998 var key = keys[i]
2999 , val = obj[key];
3000 if ('boolean' == typeof val || null == val) {
3001 if (val) {
3002 terse
3003 ? buf.push(key)
3004 : buf.push(key + '="' + key + '"');
3005 }
3006 } else if ('class' == key && Array.isArray(val)) {
3007 buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
3008 } else {
3009 buf.push(key + '="' + exports.escape(val) + '"');
3010 }
3011 }
3012 }
3013 return buf.join(' ');
3014};
3015
3016/**
3017 * Escape the given string of `html`.
3018 *
3019 * @param {String} html
3020 * @return {String}
3021 * @api private
3022 */
3023
3024exports.escape = function escape(html){
3025 return String(html)
3026 .replace(/&(?!\w+;)/g, '&amp;')
3027 .replace(/</g, '&lt;')
3028 .replace(/>/g, '&gt;')
3029 .replace(/"/g, '&quot;');
3030};
3031
3032/**
3033 * Re-throw the given `err` in context to the
3034 * the jade in `filename` at the given `lineno`.
3035 *
3036 * @param {Error} err
3037 * @param {String} filename
3038 * @param {String} lineno
3039 * @api private
3040 */
3041
3042exports.rethrow = function rethrow(err, filename, lineno){
3043 if (!filename) throw err;
3044
3045 var context = 3
3046 , str = require('fs').readFileSync(filename, 'utf8')
3047 , lines = str.split('\n')
3048 , start = Math.max(lineno - context, 0)
3049 , end = Math.min(lines.length, lineno + context);
3050
3051 // Error context
3052 var context = lines.slice(start, end).map(function(line, i){
3053 var curr = i + start + 1;
3054 return (curr == lineno ? ' > ' : ' ')
3055 + curr
3056 + '| '
3057 + line;
3058 }).join('\n');
3059
3060 // Alter exception message
3061 err.path = filename;
3062 err.message = (filename || 'Jade') + ':' + lineno
3063 + '\n' + context + '\n\n' + err.message;
3064 throw err;
3065};
3066
3067}); // module: runtime.js
3068
3069require.register("self-closing.js", function(module, exports, require){
3070
3071/*!
3072 * Jade - self closing tags
3073 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
3074 * MIT Licensed
3075 */
3076
3077module.exports = [
3078 'meta'
3079 , 'img'
3080 , 'link'
3081 , 'input'
3082 , 'area'
3083 , 'base'
3084 , 'col'
3085 , 'br'
3086 , 'hr'
3087];
3088}); // module: self-closing.js
3089
3090require.register("utils.js", function(module, exports, require){
3091
3092/*!
3093 * Jade - utils
3094 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
3095 * MIT Licensed
3096 */
3097
3098/**
3099 * Convert interpolation in the given string to JavaScript.
3100 *
3101 * @param {String} str
3102 * @return {String}
3103 * @api private
3104 */
3105
3106var interpolate = exports.interpolate = function(str){
3107 return str.replace(/(\\)?([#!]){(.*?)}/g, function(str, escape, flag, code){
3108 return escape
3109 ? str
3110 : "' + "
3111 + ('!' == flag ? '' : 'escape')
3112 + "((interp = " + code.replace(/\\'/g, "'")
3113 + ") == null ? '' : interp) + '";
3114 });
3115};
3116
3117/**
3118 * Escape single quotes in `str`.
3119 *
3120 * @param {String} str
3121 * @return {String}
3122 * @api private
3123 */
3124
3125var escape = exports.escape = function(str) {
3126 return str.replace(/'/g, "\\'");
3127};
3128
3129/**
3130 * Interpolate, and escape the given `str`.
3131 *
3132 * @param {String} str
3133 * @return {String}
3134 * @api private
3135 */
3136
3137exports.text = function(str){
3138 return interpolate(escape(str));
3139};
3140}); // module: utils.js
3141
3142window.jade = require("jade");
3143})();