Inital Commit
[oweals/finalsclub.git] / node_modules / jade / jade.js
1
2 // CommonJS require()
3
4 function require(p){
5     var path = require.resolve(p)
6       , mod = require.modules[path];
7     if (!mod) throw new Error('failed to require "' + p + '"');
8     if (!mod.exports) {
9       mod.exports = {};
10       mod.call(mod.exports, mod, mod.exports, require.relative(path));
11     }
12     return mod.exports;
13   }
14
15 require.modules = {};
16
17 require.resolve = function (path){
18     var orig = path
19       , reg = path + '.js'
20       , index = path + '/index.js';
21     return require.modules[reg] && reg
22       || require.modules[index] && index
23       || orig;
24   };
25
26 require.register = function (path, fn){
27     require.modules[path] = fn;
28   };
29
30 require.relative = function (parent) {
31     return function(p){
32       if ('.' != p[0]) return require(p);
33       
34       var path = parent.split('/')
35         , segs = p.split('/');
36       path.pop();
37       
38       for (var i = 0; i < segs.length; i++) {
39         var seg = segs[i];
40         if ('..' == seg) path.pop();
41         else if ('.' != seg) path.push(seg);
42       }
43
44       return require(path.join('/'));
45     };
46   };
47
48
49 require.register("compiler.js", function(module, exports, require){
50
51 /*!
52  * Jade - Compiler
53  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
54  * MIT Licensed
55  */
56
57 /**
58  * Module dependencies.
59  */
60
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');
67
68  
69  if (!Object.keys) {
70    Object.keys = function(obj){
71      var arr = [];
72      for (var key in obj) {
73        if (obj.hasOwnProperty(key)) {
74          arr.push(obj);
75        }
76      }
77      return arr;
78    } 
79  }
80  
81  if (!String.prototype.trimLeft) {
82    String.prototype.trimLeft = function(){
83      return this.replace(/^\s+/, '');
84    }
85  }
86
87
88
89 /**
90  * Initialize `Compiler` with the given `node`.
91  *
92  * @param {Node} node
93  * @param {Object} options
94  * @api public
95  */
96
97 var Compiler = module.exports = function Compiler(node, options) {
98   this.options = options = options || {};
99   this.node = node;
100
101   this.hasCompiledDoctype = false;
102   this.hasCompiledTag = false;
103   if (options.doctype) this.setDoctype(options.doctype);
104
105   this.pp = options.prettyprint || false;
106   this.indentDepth = 0;
107 };
108
109 /**
110  * Compiler prototype.
111  */
112
113 Compiler.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.visit(this.node);
124     return this.buf.join('\n');
125   },
126
127   /**
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.
131    *
132    * @param {string} name
133    * @api public
134    */
135   
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');
142   },
143   
144   /**
145    * Buffer the given `str` optionally escaped.
146    *
147    * @param {String} str
148    * @param {Boolean} esc
149    * @api public
150    */
151   
152   buffer: function(str, esc){
153     if (esc) str = utils.escape(str);
154     this.buf.push("buf.push('" + str + "');");
155   },
156   
157   /**
158    * Buffer the given `node`'s lineno.
159    *
160    * @param {Node} node
161    * @api public
162    */
163   
164   line: function(node){
165     if (node.instrumentLineNumber === false) return;
166     this.buf.push('__.lineno = ' + node.line + ';');
167   },
168   
169   /**
170    * Visit `node`.
171    *
172    * @param {Node} node
173    * @api public
174    */
175   
176   visit: function(node){
177     this.line(node);
178     return this.visitNode(node);
179   },
180   
181   /**
182    * Visit `node`.
183    *
184    * @param {Node} node
185    * @api public
186    */
187   
188   visitNode: function(node){
189     var name = node.constructor.name
190       || node.constructor.toString().match(/function ([^(\s]+)()/)[1];
191     return this['visit' + name](node);
192   },
193   
194   /**
195    * Visit all nodes in `block`.
196    *
197    * @param {Block} block
198    * @api public
199    */
200
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]);
205     }
206   },
207   
208   /**
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.
212    *
213    * @param {Doctype} doctype
214    * @api public
215    */
216   
217   visitDoctype: function(doctype){
218     if (doctype && (doctype.val || !this.doctype)) {
219       this.setDoctype(doctype.val || 'default');
220     }
221
222     if (this.doctype) this.buffer(this.doctype);
223     this.hasCompiledDoctype = true;
224   },
225   
226   /**
227    * Visit `tag` buffering tag markup, generating
228    * attributes, visiting the `tag`'s code and block.
229    *
230    * @param {Tag} tag
231    * @api public
232    */
233   
234   visitTag: function(tag){
235     this.indentDepth++;
236     var name = tag.name;
237
238     if (!this.hasCompiledTag) {
239       if (!this.hasCompiledDoctype && 'html' == name) {
240         this.visitDoctype();
241       }
242       this.hasCompiledTag = true;
243     }
244
245     if(this.pp && inlineTags.indexOf(name) == -1) 
246       this.buffer('\\n' + new Array(this.indentDepth).join('  '));
247
248     if (~selfClosing.indexOf(name) && !this.xml) {
249       this.buffer('<' + name);
250       this.visitAttributes(tag.attrs);
251       this.terse
252         ? this.buffer('>')
253         : this.buffer('/>');
254     } else {
255       // Optimize attributes buffering
256       if (tag.attrs.length) {
257         this.buffer('<' + name);
258         if (tag.attrs.length) this.visitAttributes(tag.attrs);
259         this.buffer('>');
260       } else {
261         this.buffer('<' + name + '>');
262       }
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 + '>');
269     }
270     this.indentDepth--;
271   },
272   
273   /**
274    * Visit `filter`, throwing when the filter does not exist.
275    *
276    * @param {Filter} filter
277    * @api public
278    */
279   
280   visitFilter: function(filter){
281     var fn = filters[filter.name];
282
283     // unknown filter
284     if (!fn) {
285       if (filter.isASTFilter) {
286         throw new Error('unknown ast filter "' + filter.name + ':"');
287       } else {
288         throw new Error('unknown filter ":' + filter.name + '"');
289       }
290     }
291     if (filter.isASTFilter) {
292       this.buf.push(fn(filter.block, this, filter.attrs));
293     } else {
294       var text = filter.block.nodes.join('');
295       this.buffer(utils.text(fn(text, filter.attrs)));
296     }
297   },
298   
299   /**
300    * Visit `text` node.
301    *
302    * @param {Text} text
303    * @api public
304    */
305   
306   visitText: function(text){
307     text = utils.text(text.nodes.join(''));
308     if (this.escape) text = escape(text);
309     this.buffer(text);
310     this.buffer('\\n');
311   },
312   
313   /**
314    * Visit a `comment`, only buffering when the buffer flag is set.
315    *
316    * @param {Comment} comment
317    * @api public
318    */
319   
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) + '-->');
324   },
325   
326   /**
327    * Visit a `BlockComment`.
328    *
329    * @param {Comment} comment
330    * @api public
331    */
332   
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]-->');
338     } else {
339       this.buffer('<!--' + comment.val);
340       this.visit(comment.block);
341       this.buffer('-->');
342     }
343   },
344   
345   /**
346    * Visit `code`, respecting buffer / escape flags.
347    * If the code is followed by a block, wrap it in
348    * a self-calling function.
349    *
350    * @param {Code} code
351    * @api public
352    */
353   
354   visitCode: function(code){
355     // Wrap code blocks with {}.
356     // we only wrap unbuffered code blocks ATM
357     // since they are usually flow control
358
359     // Buffer code
360     if (code.buffer) {
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 + ");");
366     } else {
367       this.buf.push(code.val);
368     }
369
370     // Block support
371     if (code.block) {
372       if (!code.buffer) this.buf.push('{');
373       this.visit(code.block);
374       if (!code.buffer) this.buf.push('}');
375     }
376   },
377   
378   /**
379    * Visit `each` block.
380    *
381    * @param {Each} each
382    * @api public
383    */
384   
385   visitEach: function(each){
386     this.buf.push(''
387       + '// iterate ' + each.obj + '\n'
388       + '(function(){\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');
392
393     this.visit(each.block);
394
395     this.buf.push(''
396       + '    }\n'
397       + '  } else {\n'
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');
401
402     this.visit(each.block);
403
404      this.buf.push('      }\n');
405
406     this.buf.push('   }\n  }\n}).call(this);\n');
407   },
408   
409   /**
410    * Visit `attrs`.
411    *
412    * @param {Array} attrs
413    * @api public
414    */
415   
416   visitAttributes: function(attrs){
417     var buf = []
418       , classes = [];
419
420     if (this.terse) buf.push('terse: true');
421
422     attrs.forEach(function(attr){
423       if (attr.name == 'class') {
424         classes.push('(' + attr.val + ')');
425       } else {
426         var pair = "'" + attr.name + "':(" + attr.val + ')';
427         buf.push(pair);
428       }
429     });
430
431     if (classes.length) {
432       classes = classes.join(" + ' ' + ");
433       buf.push("class: " + classes);
434     }
435
436     buf = buf.join(', ').replace('class:', '"class":');
437
438     this.buf.push("buf.push(attrs({ " + buf + " }));");
439   }
440 };
441
442 /**
443  * Escape the given string of `html`.
444  *
445  * @param {String} html
446  * @return {String}
447  * @api private
448  */
449
450 function escape(html){
451   return String(html)
452     .replace(/&(?!\w+;)/g, '&amp;')
453     .replace(/</g, '&lt;')
454     .replace(/>/g, '&gt;')
455     .replace(/"/g, '&quot;');
456 }
457
458 }); // module: compiler.js
459
460 require.register("doctypes.js", function(module, exports, require){
461
462 /*!
463  * Jade - doctypes
464  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
465  * MIT Licensed
466  */
467
468 module.exports = {
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">'
479 };
480 }); // module: doctypes.js
481
482 require.register("filters.js", function(module, exports, require){
483
484 /*!
485  * Jade - filters
486  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
487  * MIT Licensed
488  */
489
490 module.exports = {
491   
492   /**
493    * Wrap text with CDATA block.
494    */
495   
496   cdata: function(str){
497     return '<![CDATA[\\n' + str + '\\n]]>';
498   },
499   
500   /**
501    * Transform sass to css, wrapped in style tags.
502    */
503   
504   sass: function(str){
505     str = str.replace(/\\n/g, '\n');
506     var sass = require('sass').render(str).replace(/\n/g, '\\n');
507     return '<style>' + sass + '</style>'; 
508   },
509   
510   /**
511    * Transform stylus to css, wrapped in style tags.
512    */
513   
514   stylus: function(str, options){
515     var ret;
516     str = str.replace(/\\n/g, '\n');
517     var stylus = require('stylus');
518     stylus(str, options).render(function(err, css){
519       if (err) throw err;
520       ret = css.replace(/\n/g, '\\n');
521     });
522     return '<style>' + ret + '</style>'; 
523   },
524   
525   /**
526    * Transform sass to css, wrapped in style tags.
527    */
528   
529   less: function(str){
530     var ret;
531     str = str.replace(/\\n/g, '\n');
532     require('less').render(str, function(err, css){
533       if (err) throw err;
534       ret = '<style>' + css.replace(/\n/g, '\\n') + '</style>';  
535     });
536     return ret;
537   },
538   
539   /**
540    * Transform markdown to html.
541    */
542   
543   markdown: function(str){
544     var md;
545
546     // support markdown / discount
547     try {
548       md = require('markdown');
549     } catch (err){
550       try {
551         md = require('discount');
552       } catch (err) {
553         try {
554           md = require('markdown-js');
555         } catch (err) {
556           throw new Error('Cannot find markdown library, install markdown or discount');
557         }
558       }
559     }
560
561     str = str.replace(/\\n/g, '\n');
562     return md.parse(str).replace(/\n/g, '\\n').replace(/'/g,'&#39;');
563   },
564   
565   /**
566    * Transform coffeescript to javascript.
567    */
568
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>';
573   }
574 };
575 }); // module: filters.js
576
577 require.register("inline-tags.js", function(module, exports, require){
578
579 /*!
580  * Jade - inline tags
581  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
582  * MIT Licensed
583  */
584
585 module.exports = [
586   'a', 
587   'abbr', 
588   'acronym', 
589   'b',   
590   'br', 
591   'code',  
592   'em', 
593   'font', 
594   'i', 
595   'img', 
596   'ins', 
597   'kbd', 
598   'map', 
599   'samp', 
600   'small', 
601   'span', 
602   'strong', 
603   'sub', 
604   'sup'
605 ];
606 }); // module: inline-tags.js
607
608 require.register("jade.js", function(module, exports, require){
609
610 /*!
611  * Jade
612  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
613  * MIT Licensed
614  */
615
616 /**
617  * Module dependencies.
618  */
619
620 var Parser = require('./parser')
621   , Compiler = require('./compiler')
622
623 /**
624  * Library version.
625  */
626
627 exports.version = '0.12.1';
628
629 /**
630  * Intermediate JavaScript cache.
631  */
632
633 var cache = exports.cache = {};
634
635 /**
636  * Expose self closing tags.
637  */
638
639 exports.selfClosing = require('./self-closing');
640
641 /**
642  * Default supported doctypes.
643  */
644
645 exports.doctypes = require('./doctypes');
646
647 /**
648  * Text filters.
649  */
650
651 exports.filters = require('./filters');
652
653 /**
654  * Utilities.
655  */
656
657 exports.utils = require('./utils');
658
659 /**
660  * Expose `Compiler`.
661  */
662
663 exports.Compiler = Compiler;
664
665 /**
666  * Expose `Parser`.
667  */
668
669 exports.Parser = Parser;
670
671 /**
672  * Nodes.
673  */
674
675 exports.nodes = require('./nodes');
676
677 /**
678  * Render the given attributes object.
679  *
680  * @param {Object} obj
681  * @return {String}
682  * @api private
683  */
684
685 function attrs(obj){
686   var buf = []
687     , terse = obj.terse;
688   delete obj.terse;
689   var keys = Object.keys(obj)
690     , len = keys.length;
691   if (len) {
692     buf.push('');
693     for (var i = 0; i < len; ++i) {
694       var key = keys[i]
695         , val = obj[key];
696       if (typeof val === 'boolean' || val === '' || val == null) {
697         if (val) {
698           terse
699             ? buf.push(key)
700             : buf.push(key + '="' + key + '"');
701         }
702       } else {
703         buf.push(key + '="' + escape(val) + '"');
704       }
705     }
706   }
707   return buf.join(' ');
708 }
709
710 /**
711  * Escape the given string of `html`.
712  *
713  * @param {String} html
714  * @return {String}
715  * @api private
716  */
717
718 function escape(html){
719   return String(html)
720     .replace(/&(?!\w+;)/g, '&amp;')
721     .replace(/</g, '&lt;')
722     .replace(/>/g, '&gt;')
723     .replace(/"/g, '&quot;');
724 }
725
726 /**
727  * Re-throw the given `err` in context to the
728  * `str` of jade, `filename`, and `lineno`.
729  *
730  * @param {Error} err
731  * @param {String} str
732  * @param {String} filename
733  * @param {String} lineno
734  * @api private
735  */
736
737 function rethrow(err, str, filename, lineno){
738   var context = 3
739     , lines = str.split('\n')
740     , start = Math.max(lineno - context, 0)
741     , end = Math.min(lines.length, lineno + context); 
742
743   // Error context
744   var context = lines.slice(start, end).map(function(line, i){
745     var curr = i + start + 1;
746     return (curr == lineno ? '  > ' : '    ')
747       + curr
748       + '| '
749       + line;
750   }).join('\n');
751
752   // Alter exception message
753   err.path = filename;
754   err.message = (filename || 'Jade') + ':' + lineno 
755     + '\n' + context + '\n\n' + err.message;
756   throw err;
757 }
758
759 /**
760  * Parse the given `str` of jade and return a function body.
761  *
762  * @param {String} str
763  * @param {Object} options
764  * @return {String}
765  * @api private
766  */
767
768 function parse(str, options){
769   var filename = options.filename;
770   try {
771     // Parse
772     var parser = new Parser(str, filename);
773     if (options.debug) parser.debug();
774
775     // Compile
776     var compiler = new (options.compiler || Compiler)(parser.parse(), options)
777       , js = compiler.compile();
778
779     // Debug compiler
780     if (options.debug) {
781       console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, '  '));
782     }
783
784     try {
785       return ''
786         + attrs.toString() + '\n\n'
787         + escape.toString()  + '\n\n'
788         + 'var buf = [];\n'
789         + (options.self
790           ? 'var self = locals || {}, __ = __ || locals.__;\n' + js
791           : 'with (locals || {}) {' + js + '}')
792         + 'return buf.join("");';
793     } catch (err) {
794       process.compile(js, filename || 'Jade');
795       return;
796     }
797   } catch (err) {
798     rethrow(err, str, filename, parser.lexer.lineno);
799   }
800 }
801
802 /**
803  * Compile a `Function` representation of the given jade `str`.
804  *
805  * @param {String} str
806  * @param {Options} options
807  * @return {Function}
808  * @api public
809  */
810
811 exports.compile = function(str, options){
812   var options = options || {}
813     , input = JSON.stringify(str)
814     , filename = options.filename
815       ? JSON.stringify(options.filename)
816       : 'undefined';
817
818   // Reduce closure madness by injecting some locals
819   var fn = [
820       'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
821     , rethrow.toString()
822     , 'try {'
823     , parse(String(str), options || {})
824     , '} catch (err) {'
825     , '  rethrow(err, __.input, __.filename, __.lineno);'
826     , '}'
827   ].join('\n');
828
829   return new Function('locals', fn);
830 };
831
832 /**
833  * Render the given `str` of jade.
834  *
835  * Options:
836  *
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
843  *
844  * @param {String|Buffer} str
845  * @param {Object} options
846  * @return {String}
847  * @api public
848  */
849
850 exports.render = function(str, options){
851   var fn
852     , options = options || {}
853     , filename = options.filename;
854
855   // Accept Buffers
856   str = String(str);
857
858   // Cache support
859   if (options.cache) {
860     if (filename) {
861       if (cache[filename]) {
862         fn = cache[filename];
863       } else {
864         fn = cache[filename] = new Function('locals', parse(str, options));
865       }
866     } else {
867       throw new Error('filename is required when using the cache option');
868     }
869   } else {
870     fn = new Function('locals', parse(str, options));
871   }
872
873   // Render the template
874   try {
875     var locals = options.locals || {}
876       , meta = { lineno: 1 };
877     locals.__ = meta;
878     return fn.call(options.scope, locals); 
879   } catch (err) {
880     rethrow(err, str, filename, meta.lineno);
881   }
882 };
883
884 /**
885  * Render jade template at the given `path`.
886  *
887  * @param {String} path
888  * @param {Object} options
889  * @param {Function} fn
890  * @api public
891  */
892
893 exports.renderFile = function(path, options, fn){
894   var ret;
895
896   if (typeof options === 'function') {
897     fn = options;
898     options = {};
899   }
900   options.filename = path;
901
902   // Primed cache
903   if (options.cache && cache[path]) {
904     try {
905       ret = exports.render('', options);
906     } catch (err) {
907       return fn(err);
908     }
909     fn(null, ret);
910   } else {
911     fs.readFile(path, 'utf8', function(err, str){
912       if (err) return fn(err);
913       try {
914         ret = exports.render(str, options);
915       } catch (err) {
916         return fn(err);
917       }
918       fn(null, ret);
919     });
920   }
921 };
922
923 }); // module: jade.js
924
925 require.register("lexer.js", function(module, exports, require){
926
927 /*!
928  * Jade - Lexer
929  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
930  * MIT Licensed
931  */
932
933 /**
934  * Initialize `Lexer` with the given `str`.
935  *
936  * @param {String} str
937  * @api private
938  */
939
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;
944   this.lineno = 1;
945   this.stash = [];
946   this.indentStack = [];
947   this.indentRe = null;
948   this.pipeless = false;
949 };
950
951 /**
952  * Lexer prototype.
953  */
954
955 Lexer.prototype = {
956   
957   /**
958    * Construct a token with the given `type` and `val`.
959    *
960    * @param {String} type
961    * @param {String} val
962    * @return {Object}
963    * @api private
964    */
965   
966   tok: function(type, val){
967     return {
968         type: type
969       , line: this.lineno
970       , val: val
971     }
972   },
973   
974   /**
975    * Consume the given `len` of input.
976    *
977    * @param {Number} len
978    * @api private
979    */
980   
981   consume: function(len){
982     this.input = this.input.substr(len);
983   },
984   
985   /**
986    * Scan for `type` with the given `regexp`.
987    *
988    * @param {String} type
989    * @param {RegExp} regexp
990    * @return {Object}
991    * @api private
992    */
993   
994   scan: function(regexp, type){
995     var captures;
996     if (captures = regexp.exec(this.input)) {
997       this.consume(captures[0].length);
998       return this.tok(type, captures[1]);
999     }
1000   },
1001   
1002   /**
1003    * Defer the given `tok`.
1004    *
1005    * @param {Object} tok
1006    * @api private
1007    */
1008   
1009   defer: function(tok){
1010     this.deferredTokens.push(tok);
1011   },
1012   
1013   /**
1014    * Lookahead `n` tokens.
1015    *
1016    * @param {Number} n
1017    * @return {Object}
1018    * @api private
1019    */
1020   
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];
1025   },
1026   
1027   /**
1028    * Return the indexOf `start` / `end` delimiters.
1029    *
1030    * @param {String} start
1031    * @param {String} end
1032    * @return {Number}
1033    * @api private
1034    */
1035   
1036   indexOfDelimiters: function(start, end){
1037     var str = this.input
1038       , nstart = 0
1039       , nend = 0
1040       , pos = 0;
1041     for (var i = 0, len = str.length; i < len; ++i) {
1042       if (start == str[i]) {
1043         ++nstart;
1044       } else if (end == str[i]) {
1045         if (++nend == nstart) {
1046           pos = i;
1047           break;
1048         }
1049       }
1050     }
1051     return pos;
1052   },
1053   
1054   /**
1055    * Stashed token.
1056    */
1057   
1058   stashed: function() {
1059     return this.stash.length
1060       && this.stash.shift();
1061   },
1062   
1063   /**
1064    * Deferred token.
1065    */
1066   
1067   deferred: function() {
1068     return this.deferredTokens.length 
1069       && this.deferredTokens.shift();
1070   },
1071   
1072   /**
1073    * end-of-source.
1074    */
1075   
1076   eos: function() {
1077     if (this.input.length) return;
1078     if (this.indentStack.length) {
1079       this.indentStack.shift();
1080       return this.tok('outdent');
1081     } else {
1082       return this.tok('eos');
1083     }
1084   },
1085
1086   /**
1087    * Block comment
1088    */
1089
1090    blockComment: function() {
1091      var captures;
1092      if (captures = /^\/([^\n]+)/.exec(this.input)) {
1093        this.consume(captures[0].length);
1094        var tok = this.tok('block-comment', captures[1]);
1095        return tok;
1096      }
1097    },
1098   
1099   /**
1100    * Comment.
1101    */
1102   
1103   comment: function() {
1104     var captures;
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];
1109       return tok;
1110     }
1111   },
1112   
1113   /**
1114    * Tag.
1115    */
1116   
1117   tag: function() {
1118     var captures;
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);
1127       } else {
1128         tok = this.tok('tag', name);
1129       }
1130       return tok;
1131     }
1132   },
1133   
1134   /**
1135    * Filter.
1136    */
1137   
1138   filter: function() {
1139     return this.scan(/^:(\w+)/, 'filter');
1140   },
1141   
1142   /**
1143    * Doctype.
1144    */
1145   
1146   doctype: function() {
1147     return this.scan(/^(?:!!!|doctype) *(\w+)?/, 'doctype');
1148   },
1149   
1150   /**
1151    * Id.
1152    */
1153   
1154   id: function() {
1155     return this.scan(/^#([\w-]+)/, 'id');
1156   },
1157   
1158   /**
1159    * Class.
1160    */
1161   
1162   className: function() {
1163     return this.scan(/^\.([\w-]+)/, 'class');
1164   },
1165   
1166   /**
1167    * Text.
1168    */
1169   
1170   text: function() {
1171     return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
1172   },
1173
1174   /**
1175    * Each.
1176    */
1177   
1178   each: function() {
1179     var captures;
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];
1185       return tok;
1186     }
1187   },
1188   
1189   /**
1190    * Code.
1191    */
1192   
1193   code: function() {
1194     var captures;
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] === '=';
1202       return tok;
1203     }
1204   },
1205   
1206   /**
1207    * Attributes.
1208    */
1209   
1210   attrs: function() {
1211     if ('(' == this.input[0]) {
1212       var index = this.indexOfDelimiters('(', ')')
1213         , str = this.input.substr(1, index-1)
1214         , tok = this.tok('attrs')
1215         , len = str.length
1216         , states = ['key']
1217         , key = ''
1218         , val = ''
1219         , quote
1220         , c;
1221
1222       function state(){
1223         return states[states.length - 1];
1224       }
1225
1226       function interpolate(attr) {
1227         return attr.replace(/#\{([^}]+)\}/g, function(_, expr){
1228           return quote + " + (" + expr + ") + " + quote;
1229         });
1230       }
1231
1232       this.consume(index + 1);
1233       tok.attrs = {};
1234
1235       function parse(c) {
1236         switch (c) {
1237           case ',':
1238           case '\n':
1239             switch (state()) {
1240               case 'expr':
1241               case 'array':
1242               case 'string':
1243               case 'object':
1244                 val += c;
1245                 break;
1246               default:
1247                 states.push('key');
1248                 val = val.trim();
1249                 key = key.trim();
1250                 if ('' == key) return;
1251                 tok.attrs[key.replace(/^['"]|['"]$/g, '')] = '' == val
1252                   ? true
1253                   : interpolate(val);
1254                 key = val = '';
1255             }
1256             break;
1257           case '=':
1258             switch (state()) {
1259               case 'key char':
1260                 key += c;
1261                 break;
1262               case 'val':
1263               case 'expr':
1264               case 'array':
1265               case 'string':
1266               case 'object':
1267                 val += c;
1268                 break;
1269               default:
1270                 states.push('val');
1271             }
1272             break;
1273           case '(':
1274             if ('val' == state()) states.push('expr');
1275             val += c;
1276             break;
1277           case ')':
1278             if ('expr' == state()) states.pop();
1279             val += c;
1280             break;
1281           case '{':
1282             if ('val' == state()) states.push('object');
1283             val += c;
1284             break;
1285           case '}':
1286             if ('object' == state()) states.pop();
1287             val += c;
1288             break;
1289           case '[':
1290             if ('val' == state()) states.push('array');
1291             val += c;
1292             break;
1293           case ']':
1294             if ('array' == state()) states.pop();
1295             val += c;
1296             break;
1297           case '"':
1298           case "'":
1299             switch (state()) {
1300               case 'key':
1301                 states.push('key char');
1302                 break;
1303               case 'key char':
1304                 states.pop();
1305                 break;
1306               case 'string':
1307                 if (c == quote) states.pop();
1308                 val += c;
1309                 break;
1310               default:
1311                 states.push('string');
1312                 val += c;
1313                 quote = c;
1314             }
1315             break;
1316           case '':
1317             break;
1318           default:
1319             switch (state()) {
1320               case 'key':
1321               case 'key char':
1322                 key += c;
1323                 break;
1324               default:
1325                 val += c;
1326             }
1327         }
1328       }
1329
1330       for (var i = 0; i < len; ++i) {
1331         parse(str[i]);
1332       }
1333
1334       parse(',');
1335
1336       return tok;
1337     }
1338   },
1339   
1340   /**
1341    * Indent | Outdent | Newline.
1342    */
1343   
1344   indent: function() {
1345     var captures, re;
1346
1347     // established regexp
1348     if (this.indentRe) {
1349       captures = this.indentRe.exec(this.input);
1350     // determine regexp
1351     } else {
1352       // tabs
1353       re = /^\n(\t*) */;
1354       captures = re.exec(this.input);
1355
1356       // spaces
1357       if (captures && !captures[1].length) {
1358         re = /^\n( *)/;
1359         captures = re.exec(this.input);
1360       }
1361
1362       // established
1363       if (captures && captures[1].length) this.indentRe = re;
1364     }
1365
1366     if (captures) {
1367       var tok
1368         , indents = captures[1].length;
1369
1370       ++this.lineno;
1371       this.consume(indents + 1);
1372
1373       if (' ' == this.input[0] || '\t' == this.input[0]) {
1374         throw new Error('Invalid indentation, you can use tabs or spaces but not both');
1375       }
1376
1377       // blank line
1378       if ('\n' == this.input[0]) return this.tok('newline');
1379
1380       // outdent
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();
1385         }
1386         tok = this.stash.pop();
1387       // indent
1388       } else if (indents && indents != this.indentStack[0]) {
1389         this.indentStack.unshift(indents);
1390         tok = this.tok('indent', indents);
1391       // newline
1392       } else {
1393         tok = this.tok('newline');
1394       }
1395
1396       return tok;
1397     }
1398   },
1399
1400   /**
1401    * Pipe-less text consumed only when 
1402    * pipeless is true;
1403    */
1404
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);
1413     }
1414   },
1415
1416   /**
1417    * ':'
1418    */
1419
1420   colon: function() {
1421     return this.scan(/^: */, ':');
1422   },
1423
1424   /**
1425    * Return the next token object, or those
1426    * previously stashed by lookahead.
1427    *
1428    * @return {Object}
1429    * @api private
1430    */
1431   
1432   advance: function(){
1433     return this.stashed()
1434       || this.next();
1435   },
1436   
1437   /**
1438    * Return the next token object.
1439    *
1440    * @return {Object}
1441    * @api private
1442    */
1443   
1444   next: function() {
1445     return this.deferred()
1446       || this.eos()
1447       || this.pipelessText()
1448       || this.doctype()
1449       || this.tag()
1450       || this.filter()
1451       || this.each()
1452       || this.code()
1453       || this.id()
1454       || this.className()
1455       || this.attrs()
1456       || this.indent()
1457       || this.comment()
1458       || this.blockComment()
1459       || this.colon()
1460       || this.text();
1461   }
1462 };
1463
1464 }); // module: lexer.js
1465
1466 require.register("nodes/block-comment.js", function(module, exports, require){
1467
1468 /*!
1469  * Jade - nodes - BlockComment
1470  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1471  * MIT Licensed
1472  */
1473
1474 /**
1475  * Module dependencies.
1476  */
1477
1478 var Node = require('./node');
1479
1480 /**
1481  * Initialize a `BlockComment` with the given `block`.
1482  *
1483  * @param {String} val
1484  * @param {Block} block
1485  * @api public
1486  */
1487
1488 var BlockComment = module.exports = function BlockComment(val, block) {
1489   this.block = block;
1490   this.val = val;
1491 };
1492
1493 /**
1494  * Inherit from `Node`.
1495  */
1496
1497 BlockComment.prototype = new Node;
1498 BlockComment.prototype.constructor = BlockComment;
1499
1500 }); // module: nodes/block-comment.js
1501
1502 require.register("nodes/block.js", function(module, exports, require){
1503
1504 /*!
1505  * Jade - nodes - Block
1506  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1507  * MIT Licensed
1508  */
1509
1510 /**
1511  * Module dependencies.
1512  */
1513
1514 var Node = require('./node');
1515
1516 /**
1517  * Initialize a new `Block` with an optional `node`.
1518  *
1519  * @param {Node} node
1520  * @api public
1521  */
1522
1523 var Block = module.exports = function Block(node){
1524   this.nodes = [];
1525   if (node) this.push(node);
1526 };
1527
1528 /**
1529  * Inherit from `Node`.
1530  */
1531
1532 Block.prototype = new Node;
1533 Block.prototype.constructor = Block;
1534
1535
1536 /**
1537  * Pust the given `node`.
1538  *
1539  * @param {Node} node
1540  * @return {Number}
1541  * @api public
1542  */
1543
1544 Block.prototype.push = function(node){
1545   return this.nodes.push(node);
1546 };
1547
1548 /**
1549  * Unshift the given `node`.
1550  *
1551  * @param {Node} node
1552  * @return {Number}
1553  * @api public
1554  */
1555
1556 Block.prototype.unshift = function(node){
1557   return this.nodes.unshift(node);
1558 };
1559
1560 }); // module: nodes/block.js
1561
1562 require.register("nodes/code.js", function(module, exports, require){
1563
1564 /*!
1565  * Jade - nodes - Code
1566  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1567  * MIT Licensed
1568  */
1569
1570 /**
1571  * Module dependencies.
1572  */
1573
1574 var Node = require('./node');
1575
1576 /**
1577  * Initialize a `Code` node with the given code `val`.
1578  * Code may also be optionally buffered and escaped.
1579  *
1580  * @param {String} val
1581  * @param {Boolean} buffer
1582  * @param {Boolean} escape
1583  * @api public
1584  */
1585
1586 var Code = module.exports = function Code(val, buffer, escape) {
1587   this.val = val;
1588   this.buffer = buffer;
1589   this.escape = escape;
1590   if (/^ *else/.test(val)) this.instrumentLineNumber = false;
1591 };
1592
1593 /**
1594  * Inherit from `Node`.
1595  */
1596
1597 Code.prototype = new Node;
1598 Code.prototype.constructor = Code;
1599
1600 }); // module: nodes/code.js
1601
1602 require.register("nodes/comment.js", function(module, exports, require){
1603
1604 /*!
1605  * Jade - nodes - Comment
1606  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1607  * MIT Licensed
1608  */
1609
1610 /**
1611  * Module dependencies.
1612  */
1613
1614 var Node = require('./node');
1615
1616 /**
1617  * Initialize a `Comment` with the given `val`, optionally `buffer`,
1618  * otherwise the comment may render in the output.
1619  *
1620  * @param {String} val
1621  * @param {Boolean} buffer
1622  * @api public
1623  */
1624
1625 var Comment = module.exports = function Comment(val, buffer) {
1626   this.val = val;
1627   this.buffer = buffer;
1628 };
1629
1630 /**
1631  * Inherit from `Node`.
1632  */
1633
1634 Comment.prototype = new Node;
1635 Comment.prototype.constructor = Comment;
1636
1637 }); // module: nodes/comment.js
1638
1639 require.register("nodes/doctype.js", function(module, exports, require){
1640
1641 /*!
1642  * Jade - nodes - Doctype
1643  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1644  * MIT Licensed
1645  */
1646
1647 /**
1648  * Module dependencies.
1649  */
1650
1651 var Node = require('./node');
1652
1653 /**
1654  * Initialize a `Doctype` with the given `val`. 
1655  *
1656  * @param {String} val
1657  * @api public
1658  */
1659
1660 var Doctype = module.exports = function Doctype(val) {
1661   this.val = val;
1662 };
1663
1664 /**
1665  * Inherit from `Node`.
1666  */
1667
1668 Doctype.prototype = new Node;
1669 Doctype.prototype.constructor = Doctype;
1670
1671 }); // module: nodes/doctype.js
1672
1673 require.register("nodes/each.js", function(module, exports, require){
1674
1675 /*!
1676  * Jade - nodes - Each
1677  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1678  * MIT Licensed
1679  */
1680
1681 /**
1682  * Module dependencies.
1683  */
1684
1685 var Node = require('./node');
1686
1687 /**
1688  * Initialize an `Each` node, representing iteration
1689  *
1690  * @param {String} obj
1691  * @param {String} val
1692  * @param {String} key
1693  * @param {Block} block
1694  * @api public
1695  */
1696
1697 var Each = module.exports = function Each(obj, val, key, block) {
1698   this.obj = obj;
1699   this.val = val;
1700   this.key = key;
1701   this.block = block;
1702 };
1703
1704 /**
1705  * Inherit from `Node`.
1706  */
1707
1708 Each.prototype = new Node;
1709 Each.prototype.constructor = Each;
1710
1711 }); // module: nodes/each.js
1712
1713 require.register("nodes/filter.js", function(module, exports, require){
1714
1715 /*!
1716  * Jade - nodes - Filter
1717  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1718  * MIT Licensed
1719  */
1720
1721 /**
1722  * Module dependencies.
1723  */
1724
1725 var Node = require('./node')
1726   , Block = require('./block');
1727
1728 /**
1729  * Initialize a `Filter` node with the given 
1730  * filter `name` and `block`.
1731  *
1732  * @param {String} name
1733  * @param {Block|Node} block
1734  * @api public
1735  */
1736
1737 var Filter = module.exports = function Filter(name, block, attrs) {
1738   this.name = name;
1739   this.block = block;
1740   this.attrs = attrs;
1741   this.isASTFilter = block instanceof Block;
1742 };
1743
1744 /**
1745  * Inherit from `Node`.
1746  */
1747
1748 Filter.prototype = new Node;
1749 Filter.prototype.constructor = Filter;
1750
1751 }); // module: nodes/filter.js
1752
1753 require.register("nodes/index.js", function(module, exports, require){
1754
1755 /*!
1756  * Jade - nodes
1757  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1758  * MIT Licensed
1759  */
1760
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');
1771
1772 }); // module: nodes/index.js
1773
1774 require.register("nodes/node.js", function(module, exports, require){
1775
1776 /*!
1777  * Jade - nodes - Node
1778  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1779  * MIT Licensed
1780  */
1781
1782 /**
1783  * Initialize a `Node`.
1784  *
1785  * @api public
1786  */
1787
1788 var Node = module.exports = function Node(){};
1789 }); // module: nodes/node.js
1790
1791 require.register("nodes/tag.js", function(module, exports, require){
1792
1793 /*!
1794  * Jade - nodes - Tag
1795  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1796  * MIT Licensed
1797  */
1798
1799 /**
1800  * Module dependencies.
1801  */
1802
1803 var Node = require('./node'),
1804     Block = require('./block');
1805
1806 /**
1807  * Initialize a `Tag` node with the given tag `name` and optional `block`.
1808  *
1809  * @param {String} name
1810  * @param {Block} block
1811  * @api public
1812  */
1813
1814 var Tag = module.exports = function Tag(name, block) {
1815   this.name = name;
1816   this.attrs = [];
1817   this.block = block || new Block;
1818 };
1819
1820 /**
1821  * Inherit from `Node`.
1822  */
1823
1824 Tag.prototype = new Node;
1825 Tag.prototype.constructor = Tag;
1826
1827
1828 /**
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.
1832  *
1833  * @param {String} name
1834  * @param {String} val
1835  * @return {Tag} for chaining
1836  * @api public
1837  */
1838
1839 Tag.prototype.setAttribute = function(name, val){
1840   this.attrs.push({ name: name, val: val });
1841   return this;
1842 };
1843
1844 /**
1845  * Remove attribute `name` when present.
1846  *
1847  * @param {String} name
1848  * @api public
1849  */
1850
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];
1855     }
1856   }
1857 };
1858
1859 /**
1860  * Get attribute value by `name`.
1861  *
1862  * @param {String} name
1863  * @return {String}
1864  * @api public
1865  */
1866
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;
1871     }
1872   }
1873 };
1874
1875 }); // module: nodes/tag.js
1876
1877 require.register("nodes/text.js", function(module, exports, require){
1878
1879 /*!
1880  * Jade - nodes - Text
1881  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1882  * MIT Licensed
1883  */
1884
1885 /**
1886  * Module dependencies.
1887  */
1888
1889 var Node = require('./node');
1890
1891 /**
1892  * Initialize a `Text` node with optional `line`.
1893  *
1894  * @param {String} line
1895  * @api public
1896  */
1897
1898 var Text = module.exports = function Text(line) {
1899   this.nodes = [];
1900   if ('string' == typeof line) this.push(line);
1901 };
1902
1903 /**
1904  * Inherit from `Node`.
1905  */
1906
1907 Text.prototype = new Node;
1908 Text.prototype.constructor = Text;
1909
1910
1911 /**
1912  * Push the given `node.`
1913  *
1914  * @param {Node} node
1915  * @return {Number}
1916  * @api public
1917  */
1918
1919 Text.prototype.push = function(node){
1920   return this.nodes.push(node);
1921 };
1922
1923 }); // module: nodes/text.js
1924
1925 require.register("parser.js", function(module, exports, require){
1926
1927 /*!
1928  * Jade - Parser
1929  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
1930  * MIT Licensed
1931  */
1932
1933 /**
1934  * Module dependencies.
1935  */
1936
1937 var Lexer = require('./lexer')
1938   , nodes = require('./nodes');
1939
1940 /**
1941  * Initialize `Parser` with the given input `str` and `filename`.
1942  *
1943  * @param {String} str
1944  * @param {String} filename
1945  * @api public
1946  */
1947
1948 var Parser = exports = module.exports = function Parser(str, filename){
1949   this.input = str;
1950   this.lexer = new Lexer(str);
1951   this.filename = filename;
1952 };
1953
1954 /**
1955  * Tags that may not contain tags.
1956  */
1957
1958 var textOnly = exports.textOnly = ['code', 'script', 'textarea', 'style', 'title'];
1959
1960 /**
1961  * Parser prototype.
1962  */
1963
1964 Parser.prototype = {
1965   
1966   /**
1967    * Output parse tree to stdout. 
1968    *
1969    * @api public
1970    */
1971   
1972   debug: function(){
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');
1976     console.log(tree);
1977     this.lexer = lexer;
1978   },
1979   
1980   /**
1981    * Return the next token object.
1982    *
1983    * @return {Object}
1984    * @api private
1985    */
1986
1987   advance: function(){
1988     return this.lexer.advance();
1989   },
1990   
1991   /**
1992    * Single token lookahead.
1993    *
1994    * @return {Object}
1995    * @api private
1996    */
1997   
1998   peek: function() {
1999     return this.lookahead(1);
2000   },
2001   
2002   /**
2003    * Return lexer lineno.
2004    *
2005    * @return {Number}
2006    * @api private
2007    */
2008   
2009   line: function() {
2010     return this.lexer.lineno;
2011   },
2012   
2013   /**
2014    * `n` token lookahead.
2015    *
2016    * @param {Number} n
2017    * @return {Object}
2018    * @api private
2019    */
2020   
2021   lookahead: function(n){
2022     return this.lexer.lookahead(n);
2023   },
2024   
2025   /**
2026    * Parse input returning a string of js for evaluation.
2027    *
2028    * @return {String}
2029    * @api public
2030    */
2031   
2032   parse: function(){
2033     var block = new nodes.Block;
2034     block.line = this.line();
2035     while ('eos' != this.peek().type) {
2036       if ('newline' == this.peek().type) {
2037         this.advance();
2038       } else {
2039         block.push(this.parseExpr());
2040       }
2041     }
2042     return block;
2043   },
2044   
2045   /**
2046    * Expect the given type, or throw an exception.
2047    *
2048    * @param {String} type
2049    * @api private
2050    */
2051   
2052   expect: function(type){
2053     if (this.peek().type === type) {
2054       return this.advance();
2055     } else {
2056       throw new Error('expected "' + type + '", but got "' + this.peek().type + '"');
2057     }
2058   },
2059   
2060   /**
2061    * Accept the given `type`.
2062    *
2063    * @param {String} type
2064    * @api private
2065    */
2066   
2067   accept: function(type){
2068     if (this.peek().type === type) {
2069       return this.advance();
2070     }
2071   },
2072   
2073   /**
2074    *   tag
2075    * | doctype
2076    * | filter
2077    * | comment
2078    * | text
2079    * | each
2080    * | code
2081    * | id
2082    * | class
2083    */
2084   
2085   parseExpr: function(){
2086     switch (this.peek().type) {
2087       case 'tag':
2088         return this.parseTag();
2089       case 'doctype':
2090         return this.parseDoctype();
2091       case 'filter':
2092         return this.parseFilter();
2093       case 'comment':
2094         return this.parseComment();
2095       case 'block-comment':
2096         return this.parseBlockComment();
2097       case 'text':
2098         return this.parseText();
2099       case 'each':
2100         return this.parseEach();
2101       case 'code':
2102         return this.parseCode();
2103       case 'id':
2104       case 'class':
2105         var tok = this.advance();
2106         this.lexer.defer(this.lexer.tok('tag', 'div'));
2107         this.lexer.defer(tok);
2108         return this.parseExpr();
2109       default:
2110         throw new Error('unexpected token "' + this.peek().type + '"');
2111     }
2112   },
2113   
2114   /**
2115    * Text
2116    */
2117   
2118   parseText: function(){
2119     var tok = this.expect('text')
2120       , node = new nodes.Text(tok.val);
2121     node.line = this.line();
2122     return node;
2123   },
2124   
2125   /**
2126    * code
2127    */
2128   
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();
2135     }
2136     return node;
2137   },
2138
2139   /**
2140    * block comment
2141    */
2142   
2143   parseBlockComment: function(){
2144     var tok = this.expect('block-comment')
2145       , node = new nodes.BlockComment(tok.val, this.parseBlock());
2146     node.line = this.line();
2147     return node;
2148   },
2149
2150   
2151   /**
2152    * comment
2153    */
2154   
2155   parseComment: function(){
2156     var tok = this.expect('comment')
2157       , node = new nodes.Comment(tok.val, tok.buffer);
2158     node.line = this.line();
2159     return node;
2160   },
2161   
2162   /**
2163    * doctype
2164    */
2165   
2166   parseDoctype: function(){
2167     var tok = this.expect('doctype')
2168       , node = new nodes.Doctype(tok.val);
2169     node.line = this.line();
2170     return node;
2171   },
2172   
2173   /**
2174    * filter attrs? text-block
2175    */
2176   
2177   parseFilter: function(){
2178     var block
2179       , tok = this.expect('filter')
2180       , attrs = this.accept('attrs');
2181
2182     this.lexer.pipeless = true;
2183     block = this.parseTextBlock();
2184     this.lexer.pipeless = false;
2185
2186     var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
2187     node.line = this.line();
2188     return node;
2189   },
2190   
2191   /**
2192    * tag ':' attrs? block
2193    */
2194   
2195   parseASTFilter: function(){
2196     var block
2197       , tok = this.expect('tag')
2198       , attrs = this.accept('attrs');
2199
2200     this.expect(':');
2201     block = this.parseBlock();
2202
2203     var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
2204     node.line = this.line();
2205     return node;
2206   },
2207   
2208   /**
2209    * each block
2210    */
2211   
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();
2216     return node;
2217   },
2218   
2219   /**
2220    * indent (text | newline)* outdent
2221    */
2222
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) {
2231         case 'newline':
2232           text.push('\\n');
2233           this.advance();
2234           break;
2235         case 'indent':
2236           text.push('\\n');
2237           this.parseTextBlock().nodes.forEach(function(node){
2238             text.push(node);
2239           });
2240           text.push('\\n');
2241           break;
2242         default:
2243           text.push(indent + this.advance().val);
2244       }
2245     }
2246     this._spaces = null;
2247     this.expect('outdent');
2248     return text;
2249   },
2250
2251   /**
2252    * indent expr* outdent
2253    */
2254   
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) {
2261         this.advance();
2262       } else {
2263         block.push(this.parseExpr());
2264       }
2265     }
2266     this.expect('outdent');
2267     return block;
2268   },
2269
2270   /**
2271    * tag (attrs | class | id)* (text | code | ':')? newline* block?
2272    */
2273   
2274   parseTag: function(){
2275     // ast-filter look-ahead
2276     var i = 2;
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();
2281       }
2282     }
2283
2284     var name = this.advance().val
2285       , tag = new nodes.Tag(name);
2286
2287     tag.line = this.line();
2288
2289     // (attrs | class | id)*
2290     out:
2291       while (true) {
2292         switch (this.peek().type) {
2293           case 'id':
2294           case 'class':
2295             var tok = this.advance();
2296             tag.setAttribute(tok.type, "'" + tok.val + "'");
2297             continue;
2298           case 'attrs':
2299             var obj = this.advance().attrs
2300               , names = Object.keys(obj);
2301             for (var i = 0, len = names.length; i < len; ++i) {
2302               var name = names[i]
2303                 , val = obj[name];
2304               tag.setAttribute(name, val);
2305             }
2306             continue;
2307           default:
2308             break out;
2309         }
2310       }
2311
2312     // check immediate '.'
2313     if ('.' == this.peek().val) {
2314       tag.textOnly = true;
2315       this.advance();
2316     }
2317
2318     // (text | code | ':')?
2319     switch (this.peek().type) {
2320       case 'text':
2321         tag.text = this.parseText();
2322         break;
2323       case 'code':
2324         tag.code = this.parseCode();
2325         break;
2326       case ':':
2327         this.advance();
2328         tag.block = new nodes.Block;
2329         tag.block.push(this.parseTag());
2330         break;
2331     }
2332
2333     // newline*
2334     while ('newline' == this.peek().type) this.advance();
2335
2336     tag.textOnly = tag.textOnly || ~textOnly.indexOf(tag.name);
2337
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;
2343       }
2344     }
2345
2346     // block?
2347     if ('indent' == this.peek().type) {
2348       if (tag.textOnly) {
2349         this.lexer.pipeless = true;
2350         tag.block = this.parseTextBlock();
2351         this.lexer.pipeless = false;
2352       } else {
2353         var block = this.parseBlock();
2354         if (tag.block) {
2355           for (var i = 0, len = block.nodes.length; i < len; ++i) {
2356             tag.block.push(block.nodes[i]);
2357           }
2358         } else {
2359           tag.block = block;
2360         }
2361       }
2362     }
2363     
2364     return tag;
2365   }
2366 };
2367 }); // module: parser.js
2368
2369 require.register("self-closing.js", function(module, exports, require){
2370
2371 /*!
2372  * Jade - self closing tags
2373  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2374  * MIT Licensed
2375  */
2376
2377 module.exports = [
2378     'meta'
2379   , 'img'
2380   , 'link'
2381   , 'input'
2382   , 'area'
2383   , 'base'
2384   , 'col'
2385   , 'br'
2386   , 'hr'
2387 ];
2388 }); // module: self-closing.js
2389
2390 require.register("utils.js", function(module, exports, require){
2391
2392 /*!
2393  * Jade - utils
2394  * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
2395  * MIT Licensed
2396  */
2397
2398 /**
2399  * Convert interpolation in the given string to JavaScript.
2400  *
2401  * @param {String} str
2402  * @return {String}
2403  * @api private
2404  */
2405
2406 var interpolate = exports.interpolate = function(str){
2407   return str.replace(/(\\)?([#!]){(.*?)}/g, function(str, escape, flag, code){
2408     return escape
2409       ? str
2410       : "' + "
2411         + ('!' == flag ? '' : 'escape')
2412         + "((interp = " + code.replace(/\\'/g, "'")
2413         + ") == null ? '' : interp) + '";
2414   });
2415 };
2416
2417 /**
2418  * Escape single quotes in `str`.
2419  *
2420  * @param {String} str
2421  * @return {String}
2422  * @api private
2423  */
2424
2425 var escape = exports.escape = function(str) {
2426   return str.replace(/'/g, "\\'");
2427 };
2428
2429 /**
2430  * Interpolate, and escape the given `str`.
2431  *
2432  * @param {String} str
2433  * @return {String}
2434  * @api private
2435  */
2436
2437 exports.text = function(str){
2438   return interpolate(escape(str));
2439 };
2440 }); // module: utils.js