jade-js-source 0.15.4

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.
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