jade-js-source 0.15.4

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