guard-templates 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ })();