guard-templates 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3143 @@
1
+ (function() {
2
+
3
+ // CommonJS require()
4
+
5
+ function 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
+
16
+ require.modules = {};
17
+
18
+ require.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
+
27
+ require.register = function (path, fn){
28
+ require.modules[path] = fn;
29
+ };
30
+
31
+ require.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
+
50
+ require.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
+
62
+ var 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
+
98
+ var 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
+
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.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
+
541
+ function 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
+
551
+ require.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
+
559
+ module.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
+
572
+ require.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
+
580
+ module.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
+
673
+ require.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
+
681
+ module.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
+
704
+ require.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
+
715
+ var Parser = require('./parser')
716
+ , Lexer = require('./lexer')
717
+ , Compiler = require('./compiler')
718
+ , runtime = require('./runtime')
719
+
720
+ /**
721
+ * Library version.
722
+ */
723
+
724
+ exports.version = '0.21.0';
725
+
726
+ /**
727
+ * Expose self closing tags.
728
+ */
729
+
730
+ exports.selfClosing = require('./self-closing');
731
+
732
+ /**
733
+ * Default supported doctypes.
734
+ */
735
+
736
+ exports.doctypes = require('./doctypes');
737
+
738
+ /**
739
+ * Text filters.
740
+ */
741
+
742
+ exports.filters = require('./filters');
743
+
744
+ /**
745
+ * Utilities.
746
+ */
747
+
748
+ exports.utils = require('./utils');
749
+
750
+ /**
751
+ * Expose `Compiler`.
752
+ */
753
+
754
+ exports.Compiler = Compiler;
755
+
756
+ /**
757
+ * Expose `Parser`.
758
+ */
759
+
760
+ exports.Parser = Parser;
761
+
762
+ /**
763
+ * Expose `Lexer`.
764
+ */
765
+
766
+ exports.Lexer = Lexer;
767
+
768
+ /**
769
+ * Nodes.
770
+ */
771
+
772
+ exports.nodes = require('./nodes');
773
+
774
+ /**
775
+ * Jade runtime helpers.
776
+ */
777
+
778
+ exports.runtime = runtime;
779
+
780
+ /**
781
+ * Template function cache.
782
+ */
783
+
784
+ exports.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
+
795
+ function 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
+
836
+ exports.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
+
885
+ exports.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
+
916
+ exports.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
+
938
+ exports.__express = exports.renderFile;
939
+
940
+ }); // module: jade.js
941
+
942
+ require.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
+
962
+ var 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
+
979
+ Lexer.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
+
1653
+ require.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
+
1665
+ var 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
+
1676
+ var 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
+
1686
+ BlockComment.prototype = new Node;
1687
+ BlockComment.prototype.constructor = BlockComment;
1688
+
1689
+ }); // module: nodes/block-comment.js
1690
+
1691
+ require.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
+
1703
+ var Node = require('./node');
1704
+
1705
+ /**
1706
+ * Initialize a new `Block` with an optional `node`.
1707
+ *
1708
+ * @param {Node} node
1709
+ * @api public
1710
+ */
1711
+
1712
+ var Block = module.exports = function Block(node){
1713
+ this.nodes = [];
1714
+ if (node) this.push(node);
1715
+ };
1716
+
1717
+ /**
1718
+ * Inherit from `Node`.
1719
+ */
1720
+
1721
+ Block.prototype = new Node;
1722
+ Block.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
+
1733
+ Block.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
+
1745
+ Block.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
+
1756
+ Block.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
+
1768
+ Block.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
+
1779
+ Block.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
+
1797
+ require.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
+
1809
+ var Node = require('./node');
1810
+
1811
+ /**
1812
+ * Initialize a new `Case` with `expr`.
1813
+ *
1814
+ * @param {String} expr
1815
+ * @api public
1816
+ */
1817
+
1818
+ var 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
+
1827
+ Case.prototype = new Node;
1828
+ Case.prototype.constructor = Case;
1829
+
1830
+
1831
+ var 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
+
1841
+ When.prototype = new Node;
1842
+ When.prototype.constructor = When;
1843
+
1844
+
1845
+
1846
+ }); // module: nodes/case.js
1847
+
1848
+ require.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
+
1860
+ var 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
+
1872
+ var 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
+
1883
+ Code.prototype = new Node;
1884
+ Code.prototype.constructor = Code;
1885
+
1886
+ }); // module: nodes/code.js
1887
+
1888
+ require.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
+
1900
+ var 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
+
1911
+ var Comment = module.exports = function Comment(val, buffer) {
1912
+ this.val = val;
1913
+ this.buffer = buffer;
1914
+ };
1915
+
1916
+ /**
1917
+ * Inherit from `Node`.
1918
+ */
1919
+
1920
+ Comment.prototype = new Node;
1921
+ Comment.prototype.constructor = Comment;
1922
+
1923
+ }); // module: nodes/comment.js
1924
+
1925
+ require.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
+
1937
+ var Node = require('./node');
1938
+
1939
+ /**
1940
+ * Initialize a `Doctype` with the given `val`.
1941
+ *
1942
+ * @param {String} val
1943
+ * @api public
1944
+ */
1945
+
1946
+ var Doctype = module.exports = function Doctype(val) {
1947
+ this.val = val;
1948
+ };
1949
+
1950
+ /**
1951
+ * Inherit from `Node`.
1952
+ */
1953
+
1954
+ Doctype.prototype = new Node;
1955
+ Doctype.prototype.constructor = Doctype;
1956
+
1957
+ }); // module: nodes/doctype.js
1958
+
1959
+ require.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
+
1971
+ var 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
+
1983
+ var 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
+
1994
+ Each.prototype = new Node;
1995
+ Each.prototype.constructor = Each;
1996
+
1997
+ }); // module: nodes/each.js
1998
+
1999
+ require.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
+
2011
+ var 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
+
2023
+ var 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
+
2034
+ Filter.prototype = new Node;
2035
+ Filter.prototype.constructor = Filter;
2036
+
2037
+ }); // module: nodes/filter.js
2038
+
2039
+ require.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
+
2047
+ exports.Node = require('./node');
2048
+ exports.Tag = require('./tag');
2049
+ exports.Code = require('./code');
2050
+ exports.Each = require('./each');
2051
+ exports.Case = require('./case');
2052
+ exports.Text = require('./text');
2053
+ exports.Block = require('./block');
2054
+ exports.Mixin = require('./mixin');
2055
+ exports.Filter = require('./filter');
2056
+ exports.Comment = require('./comment');
2057
+ exports.Literal = require('./literal');
2058
+ exports.BlockComment = require('./block-comment');
2059
+ exports.Doctype = require('./doctype');
2060
+
2061
+ }); // module: nodes/index.js
2062
+
2063
+ require.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
+
2075
+ var Node = require('./node');
2076
+
2077
+ /**
2078
+ * Initialize a `Literal` node with the given `str.
2079
+ *
2080
+ * @param {String} str
2081
+ * @api public
2082
+ */
2083
+
2084
+ var 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
+
2095
+ Literal.prototype = new Node;
2096
+ Literal.prototype.constructor = Literal;
2097
+
2098
+
2099
+ }); // module: nodes/literal.js
2100
+
2101
+ require.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
+
2113
+ var 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
+
2124
+ var 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
+
2134
+ Mixin.prototype = new Node;
2135
+ Mixin.prototype.constructor = Mixin;
2136
+
2137
+
2138
+
2139
+ }); // module: nodes/mixin.js
2140
+
2141
+ require.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
+
2155
+ var Node = module.exports = function Node(){};
2156
+ }); // module: nodes/node.js
2157
+
2158
+ require.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
+
2170
+ var 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
+
2181
+ var 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
+
2191
+ Tag.prototype = new Node;
2192
+ Tag.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
+
2206
+ Tag.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
+
2218
+ Tag.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
+
2234
+ Tag.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
+
2244
+ require.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
+
2256
+ var Node = require('./node');
2257
+
2258
+ /**
2259
+ * Initialize a `Text` node with optional `line`.
2260
+ *
2261
+ * @param {String} line
2262
+ * @api public
2263
+ */
2264
+
2265
+ var 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
+
2274
+ Text.prototype = new Node;
2275
+ Text.prototype.constructor = Text;
2276
+
2277
+
2278
+ /**
2279
+ * Push the given `node.`
2280
+ *
2281
+ * @param {Node} node
2282
+ * @return {Number}
2283
+ * @api public
2284
+ */
2285
+
2286
+ Text.prototype.push = function(node){
2287
+ return this.nodes.push(node);
2288
+ };
2289
+
2290
+ }); // module: nodes/text.js
2291
+
2292
+ require.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
+
2304
+ var 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
+
2316
+ var 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
+
2329
+ var textOnly = exports.textOnly = ['script', 'style'];
2330
+
2331
+ /**
2332
+ * Parser prototype.
2333
+ */
2334
+
2335
+ Parser.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
+
2947
+ require.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
+
2959
+ if (!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
+
2969
+ if (!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
+
2989
+ exports.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
+
3024
+ exports.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
+
3042
+ exports.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
+
3069
+ require.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
+
3077
+ module.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
+
3090
+ require.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
+
3106
+ var 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
+
3125
+ var 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
+
3137
+ exports.text = function(str){
3138
+ return interpolate(escape(str));
3139
+ };
3140
+ }); // module: utils.js
3141
+
3142
+ window.jade = require("jade");
3143
+ })();