jade-js-source 0.15.4 → 0.16.2

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.
data/lib/jade_js/jade.js CHANGED
@@ -135,7 +135,7 @@ Compiler.prototype = {
135
135
 
136
136
  setDoctype: function(name){
137
137
  var doctype = doctypes[(name || 'default').toLowerCase()];
138
- if (!doctype) throw new Error('unknown doctype "' + name + '"');
138
+ doctype = doctype || '<!DOCTYPE ' + name + '>';
139
139
  this.doctype = doctype;
140
140
  this.terse = '5' == name || 'html' == name;
141
141
  this.xml = 0 == this.doctype.indexOf('<?xml');
@@ -162,18 +162,6 @@ Compiler.prototype = {
162
162
  }
163
163
  },
164
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
165
  /**
178
166
  * Visit `node`.
179
167
  *
@@ -182,8 +170,26 @@ Compiler.prototype = {
182
170
  */
183
171
 
184
172
  visit: function(node){
185
- if (this.debug) this.line(node);
186
- return this.visitNode(node);
173
+ var debug = this.debug;
174
+
175
+ if (debug) {
176
+ this.buf.push('__.unshift({ lineno: ' + node.line
177
+ + ', filename: ' + (node.filename
178
+ ? '"' + node.filename + '"'
179
+ : '__[0].filename')
180
+ + ' });');
181
+ }
182
+
183
+ // Massive hack to fix our context
184
+ // stack for - else[ if] etc
185
+ if (false === node.debug && this.debug) {
186
+ this.buf.pop();
187
+ this.buf.pop();
188
+ }
189
+
190
+ this.visitNode(node);
191
+
192
+ if (debug) this.buf.push('__.shift();');
187
193
  },
188
194
 
189
195
  /**
@@ -516,7 +522,6 @@ require.register("doctypes.js", function(module, exports, require){
516
522
 
517
523
  module.exports = {
518
524
  '5': '<!DOCTYPE html>'
519
- , 'html': '<!DOCTYPE html>'
520
525
  , 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
521
526
  , 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
522
527
  , 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
@@ -553,7 +558,7 @@ module.exports = {
553
558
  sass: function(str){
554
559
  str = str.replace(/\\n/g, '\n');
555
560
  var sass = require('sass').render(str).replace(/\n/g, '\\n');
556
- return '<style>' + sass + '</style>';
561
+ return '<style type="text/css">' + sass + '</style>';
557
562
  },
558
563
 
559
564
  /**
@@ -568,11 +573,11 @@ module.exports = {
568
573
  if (err) throw err;
569
574
  ret = css.replace(/\n/g, '\\n');
570
575
  });
571
- return '<style>' + ret + '</style>';
576
+ return '<style type="text/css">' + ret + '</style>';
572
577
  },
573
578
 
574
579
  /**
575
- * Transform sass to css, wrapped in style tags.
580
+ * Transform less to css, wrapped in style tags.
576
581
  */
577
582
 
578
583
  less: function(str){
@@ -580,7 +585,7 @@ module.exports = {
580
585
  str = str.replace(/\\n/g, '\n');
581
586
  require('less').render(str, function(err, css){
582
587
  if (err) throw err;
583
- ret = '<style>' + css.replace(/\n/g, '\\n') + '</style>';
588
+ ret = '<style type="text/css">' + css.replace(/\n/g, '\\n') + '</style>';
584
589
  });
585
590
  return ret;
586
591
  },
@@ -621,6 +626,7 @@ module.exports = {
621
626
  return '<script type="text/javascript">\\n' + js + '</script>';
622
627
  }
623
628
  };
629
+
624
630
  }); // module: filters.js
625
631
 
626
632
  require.register("inline-tags.js", function(module, exports, require){
@@ -667,6 +673,7 @@ require.register("jade.js", function(module, exports, require){
667
673
  */
668
674
 
669
675
  var Parser = require('./parser')
676
+ , Lexer = require('./lexer')
670
677
  , Compiler = require('./compiler')
671
678
  , runtime = require('./runtime')
672
679
 
@@ -674,13 +681,7 @@ var Parser = require('./parser')
674
681
  * Library version.
675
682
  */
676
683
 
677
- exports.version = '0.15.4';
678
-
679
- /**
680
- * Intermediate JavaScript cache.
681
- */
682
-
683
- var cache = exports.cache = {};
684
+ exports.version = '0.16.1';
684
685
 
685
686
  /**
686
687
  * Expose self closing tags.
@@ -718,6 +719,12 @@ exports.Compiler = Compiler;
718
719
 
719
720
  exports.Parser = Parser;
720
721
 
722
+ /**
723
+ * Expose `Lexer`.
724
+ */
725
+
726
+ exports.Lexer = Lexer;
727
+
721
728
  /**
722
729
  * Nodes.
723
730
  */
@@ -730,6 +737,12 @@ exports.nodes = require('./nodes');
730
737
 
731
738
  exports.runtime = runtime;
732
739
 
740
+ /**
741
+ * Template function cache.
742
+ */
743
+
744
+ exports.cache = {};
745
+
733
746
  /**
734
747
  * Parse the given `str` of jade and return a function body.
735
748
  *
@@ -740,11 +753,9 @@ exports.runtime = runtime;
740
753
  */
741
754
 
742
755
  function parse(str, options){
743
- var filename = options.filename;
744
-
745
756
  try {
746
757
  // Parse
747
- var parser = new Parser(str, filename, options);
758
+ var parser = new Parser(str, options.filename, options);
748
759
 
749
760
  // Compile
750
761
  var compiler = new (options.compiler || Compiler)(parser.parse(), options)
@@ -752,23 +763,18 @@ function parse(str, options){
752
763
 
753
764
  // Debug compiler
754
765
  if (options.debug) {
755
- console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, ' '));
766
+ console.error('\nCompiled Function:\n\n\033[90m%s\033[0m', js.replace(/^/gm, ' '));
756
767
  }
757
768
 
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
- }
769
+ return ''
770
+ + 'var buf = [];\n'
771
+ + (options.self
772
+ ? 'var self = locals || {};\n' + js
773
+ : 'with (locals || {}) {\n' + js + '\n}\n')
774
+ + 'return buf.join("");';
770
775
  } catch (err) {
771
- runtime.rethrow(err, str, filename, parser.lexer.lineno);
776
+ parser = parser.context();
777
+ runtime.rethrow(err, parser.filename, parser.lexer.lineno);
772
778
  }
773
779
  }
774
780
 
@@ -789,7 +795,6 @@ function parse(str, options){
789
795
 
790
796
  exports.compile = function(str, options){
791
797
  var options = options || {}
792
- , input = JSON.stringify(str)
793
798
  , client = options.client
794
799
  , filename = options.filename
795
800
  ? JSON.stringify(options.filename)
@@ -798,11 +803,11 @@ exports.compile = function(str, options){
798
803
 
799
804
  if (options.compileDebug !== false) {
800
805
  fn = [
801
- 'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
806
+ 'var __ = [{ lineno: 1, filename: ' + filename + ' }];'
802
807
  , 'try {'
803
808
  , parse(String(str), options || {})
804
809
  , '} catch (err) {'
805
- , ' rethrow(err, __.input, __.filename, __.lineno);'
810
+ , ' rethrow(err, __[0].filename, __[0].lineno);'
806
811
  , '}'
807
812
  ].join('\n');
808
813
  } else {
@@ -822,6 +827,42 @@ exports.compile = function(str, options){
822
827
  };
823
828
  };
824
829
 
830
+ /**
831
+ * Render the given `str` of jade and invoke
832
+ * the callback `fn(err, str)`.
833
+ *
834
+ * Options:
835
+ *
836
+ * - `cache` enable template caching
837
+ * - `filename` filename required for `include` / `extends` and caching
838
+ *
839
+ * @param {String} str
840
+ * @param {Object|Function} options or fn
841
+ * @param {Function} fn
842
+ * @api public
843
+ */
844
+
845
+ exports.render = function(str, options, fn){
846
+ // swap args
847
+ if ('function' == typeof options) {
848
+ fn = options, options = {};
849
+ }
850
+
851
+ // cache requires .filename
852
+ if (options.cache && !options.filename) {
853
+ return fn(new Error('the "filename" option is required for caching'));
854
+ }
855
+
856
+ try {
857
+ var path = options.filename;
858
+ var tmpl = options.cache
859
+ ? exports.cache[path] || (exports.cache[path] = exports.compile(str, options))
860
+ : exports.compile(str, options);
861
+ fn(null, tmpl(options));
862
+ } catch (err) {
863
+ fn(err);
864
+ }
865
+ };
825
866
  }); // module: jade.js
826
867
 
827
868
  require.register("lexer.js", function(module, exports, require){
@@ -1018,7 +1059,7 @@ Lexer.prototype = {
1018
1059
  if (':' == name[name.length - 1]) {
1019
1060
  name = name.slice(0, -1);
1020
1061
  tok = this.tok('tag', name);
1021
- this.deferredTokens.push(this.tok(':'));
1062
+ this.defer(this.tok(':'));
1022
1063
  while (' ' == this.input[0]) this.input = this.input.substr(1);
1023
1064
  } else {
1024
1065
  tok = this.tok('tag', name);
@@ -1040,7 +1081,7 @@ Lexer.prototype = {
1040
1081
  */
1041
1082
 
1042
1083
  doctype: function() {
1043
- return this.scan(/^(?:!!!|doctype) *(\w+)?/, 'doctype');
1084
+ return this.scan(/^(?:!!!|doctype) *([^\n]+)?/, 'doctype');
1044
1085
  },
1045
1086
 
1046
1087
  /**
@@ -1067,6 +1108,22 @@ Lexer.prototype = {
1067
1108
  return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
1068
1109
  },
1069
1110
 
1111
+ /**
1112
+ * Extends.
1113
+ */
1114
+
1115
+ extends: function() {
1116
+ return this.scan(/^extends +([^\n]+)/, 'extends');
1117
+ },
1118
+
1119
+ /**
1120
+ * Block.
1121
+ */
1122
+
1123
+ block: function() {
1124
+ return this.scan(/^block +([^\n]+)/, 'block');
1125
+ },
1126
+
1070
1127
  /**
1071
1128
  * Include.
1072
1129
  */
@@ -1075,6 +1132,20 @@ Lexer.prototype = {
1075
1132
  return this.scan(/^include +([^\n]+)/, 'include');
1076
1133
  },
1077
1134
 
1135
+ /**
1136
+ * Assignment.
1137
+ */
1138
+
1139
+ assignment: function() {
1140
+ var captures;
1141
+ if (captures = /^(\w+) += *([^\n]+)/.exec(this.input)) {
1142
+ this.consume(captures[0].length);
1143
+ var name = captures[1]
1144
+ , val = captures[2];
1145
+ return this.tok('code', 'var ' + name + ' = (' + val + ')');
1146
+ }
1147
+ },
1148
+
1078
1149
  /**
1079
1150
  * Mixin.
1080
1151
  */
@@ -1111,6 +1182,18 @@ Lexer.prototype = {
1111
1182
  }
1112
1183
  },
1113
1184
 
1185
+ /**
1186
+ * While.
1187
+ */
1188
+
1189
+ while: function() {
1190
+ var captures;
1191
+ if (captures = /^while +([^\n]+)/.exec(this.input)) {
1192
+ this.consume(captures[0].length);
1193
+ return this.tok('code', 'while (' + captures[1] + ')');
1194
+ }
1195
+ },
1196
+
1114
1197
  /**
1115
1198
  * Each.
1116
1199
  */
@@ -1120,7 +1203,7 @@ Lexer.prototype = {
1120
1203
  if (captures = /^(?:- *)?(?:each|for) +(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
1121
1204
  this.consume(captures[0].length);
1122
1205
  var tok = this.tok('each', captures[1]);
1123
- tok.key = captures[2] || 'index';
1206
+ tok.key = captures[2] || '$index';
1124
1207
  tok.code = captures[3];
1125
1208
  return tok;
1126
1209
  }
@@ -1215,11 +1298,13 @@ Lexer.prototype = {
1215
1298
  }
1216
1299
  break;
1217
1300
  case '(':
1218
- if ('val' == state()) states.push('expr');
1301
+ if ('val' == state()
1302
+ || 'expr' == state()) states.push('expr');
1219
1303
  val += c;
1220
1304
  break;
1221
1305
  case ')':
1222
- if ('expr' == state()) states.pop();
1306
+ if ('expr' == state()
1307
+ || 'val' == state()) states.pop();
1223
1308
  val += c;
1224
1309
  break;
1225
1310
  case '{':
@@ -1390,10 +1475,14 @@ Lexer.prototype = {
1390
1475
  || this.eos()
1391
1476
  || this.pipelessText()
1392
1477
  || this.doctype()
1478
+ || this.extends()
1479
+ || this.block()
1393
1480
  || this.include()
1394
1481
  || this.mixin()
1395
1482
  || this.conditional()
1396
1483
  || this.each()
1484
+ || this.while()
1485
+ || this.assignment()
1397
1486
  || this.tag()
1398
1487
  || this.filter()
1399
1488
  || this.code()
@@ -1481,6 +1570,18 @@ Block.prototype = new Node;
1481
1570
  Block.prototype.constructor = Block;
1482
1571
 
1483
1572
 
1573
+ /**
1574
+ * Replace the nodes in `other` with the nodes
1575
+ * in `this` block.
1576
+ *
1577
+ * @param {Block} other
1578
+ * @api private
1579
+ */
1580
+
1581
+ Block.prototype.replace = function(other){
1582
+ other.nodes = this.nodes;
1583
+ };
1584
+
1484
1585
  /**
1485
1586
  * Pust the given `node`.
1486
1587
  *
@@ -1493,6 +1594,17 @@ Block.prototype.push = function(node){
1493
1594
  return this.nodes.push(node);
1494
1595
  };
1495
1596
 
1597
+ /**
1598
+ * Check if this block is empty.
1599
+ *
1600
+ * @return {Boolean}
1601
+ * @api public
1602
+ */
1603
+
1604
+ Block.prototype.isEmpty = function(){
1605
+ return 0 == this.nodes.length;
1606
+ };
1607
+
1496
1608
  /**
1497
1609
  * Unshift the given `node`.
1498
1610
  *
@@ -1505,6 +1617,25 @@ Block.prototype.unshift = function(node){
1505
1617
  return this.nodes.unshift(node);
1506
1618
  };
1507
1619
 
1620
+ /**
1621
+ * Return the "last" block.
1622
+ *
1623
+ * @return {Block}
1624
+ * @api private
1625
+ */
1626
+
1627
+ Block.prototype.lastBlock = function(){
1628
+ var last = this
1629
+ , node;
1630
+ for (var i = 0, len = this.nodes.length; i < len; ++i) {
1631
+ node = this.nodes[i];
1632
+ if (node.nodes) last = node.lastBlock();
1633
+ else if (node.block && !node.block.isEmpty()) last = node.block.lastBlock();
1634
+ }
1635
+ return last;
1636
+ };
1637
+
1638
+
1508
1639
  }); // module: nodes/block.js
1509
1640
 
1510
1641
  require.register("nodes/code.js", function(module, exports, require){
@@ -1535,7 +1666,7 @@ var Code = module.exports = function Code(val, buffer, escape) {
1535
1666
  this.val = val;
1536
1667
  this.buffer = buffer;
1537
1668
  this.escape = escape;
1538
- if (/^ *else/.test(val)) this.instrumentLineNumber = false;
1669
+ if (val.match(/^ *else/)) this.debug = false;
1539
1670
  };
1540
1671
 
1541
1672
  /**
@@ -1975,6 +2106,9 @@ var Parser = exports = module.exports = function Parser(str, filename, options){
1975
2106
  this.input = str;
1976
2107
  this.lexer = new Lexer(str, options);
1977
2108
  this.filename = filename;
2109
+ this.blocks = {};
2110
+ this.options = options;
2111
+ this.contexts = [this];
1978
2112
  };
1979
2113
 
1980
2114
  /**
@@ -1988,7 +2122,20 @@ var textOnly = exports.textOnly = ['code', 'script', 'textarea', 'style', 'title
1988
2122
  */
1989
2123
 
1990
2124
  Parser.prototype = {
1991
-
2125
+
2126
+ /**
2127
+ * Push `parser` onto the context stack,
2128
+ * or pop and return a `Parser`.
2129
+ */
2130
+
2131
+ context: function(parser){
2132
+ if (parser) {
2133
+ this.contexts.push(parser);
2134
+ } else {
2135
+ return this.contexts.pop();
2136
+ }
2137
+ },
2138
+
1992
2139
  /**
1993
2140
  * Return the next token object.
1994
2141
  *
@@ -2053,8 +2200,9 @@ Parser.prototype = {
2053
2200
  */
2054
2201
 
2055
2202
  parse: function(){
2056
- var block = new nodes.Block;
2203
+ var block = new nodes.Block, parser;
2057
2204
  block.line = this.line();
2205
+
2058
2206
  while ('eos' != this.peek().type) {
2059
2207
  if ('newline' == this.peek().type) {
2060
2208
  this.advance();
@@ -2062,6 +2210,14 @@ Parser.prototype = {
2062
2210
  block.push(this.parseExpr());
2063
2211
  }
2064
2212
  }
2213
+
2214
+ if (parser = this.extending) {
2215
+ this.context(parser);
2216
+ var ast = parser.parse();
2217
+ this.context();
2218
+ return ast;
2219
+ }
2220
+
2065
2221
  return block;
2066
2222
  },
2067
2223
 
@@ -2113,6 +2269,10 @@ Parser.prototype = {
2113
2269
  return this.parseTag();
2114
2270
  case 'mixin':
2115
2271
  return this.parseMixin();
2272
+ case 'block':
2273
+ return this.parseBlock();
2274
+ case 'extends':
2275
+ return this.parseExtends();
2116
2276
  case 'include':
2117
2277
  return this.parseInclude();
2118
2278
  case 'doctype':
@@ -2163,7 +2323,7 @@ Parser.prototype = {
2163
2323
  block = 'indent' == this.lookahead(i).type;
2164
2324
  if (block) {
2165
2325
  this.skip(i-1);
2166
- node.block = this.parseBlock();
2326
+ node.block = this.block();
2167
2327
  }
2168
2328
  return node;
2169
2329
  },
@@ -2177,7 +2337,7 @@ Parser.prototype = {
2177
2337
  , node;
2178
2338
 
2179
2339
  if ('indent' == this.peek().type) {
2180
- node = new nodes.BlockComment(tok.val, this.parseBlock(), tok.buffer);
2340
+ node = new nodes.BlockComment(tok.val, this.block(), tok.buffer);
2181
2341
  } else {
2182
2342
  node = new nodes.Comment(tok.val, tok.buffer);
2183
2343
  }
@@ -2225,7 +2385,7 @@ Parser.prototype = {
2225
2385
  , attrs = this.accept('attrs');
2226
2386
 
2227
2387
  this.expect(':');
2228
- block = this.parseBlock();
2388
+ block = this.block();
2229
2389
 
2230
2390
  var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
2231
2391
  node.line = this.line();
@@ -2238,16 +2398,16 @@ Parser.prototype = {
2238
2398
 
2239
2399
  parseEach: function(){
2240
2400
  var tok = this.expect('each')
2241
- , node = new nodes.Each(tok.code, tok.val, tok.key, this.parseBlock());
2401
+ , node = new nodes.Each(tok.code, tok.val, tok.key, this.block());
2242
2402
  node.line = this.line();
2243
2403
  return node;
2244
2404
  },
2245
2405
 
2246
2406
  /**
2247
- * include
2407
+ * 'extends' name
2248
2408
  */
2249
2409
 
2250
- parseInclude: function(){
2410
+ parseExtends: function(){
2251
2411
  var path = require('path')
2252
2412
  , fs = require('fs')
2253
2413
  , dirname = path.dirname
@@ -2255,11 +2415,52 @@ Parser.prototype = {
2255
2415
  , join = path.join;
2256
2416
 
2257
2417
  if (!this.filename)
2258
- throw new Error('the "filename" option is required to use includes');
2418
+ throw new Error('the "filename" option is required to extend templates');
2419
+
2420
+ var path = name = this.expect('extends').val.trim()
2421
+ , dir = dirname(this.filename);
2422
+
2423
+ var path = join(dir, path + '.jade')
2424
+ , str = fs.readFileSync(path, 'utf8')
2425
+ , parser = new Parser(str, path, this.options);
2426
+
2427
+ parser.blocks = this.blocks;
2428
+ parser.contexts = this.contexts;
2429
+ this.extending = parser;
2430
+
2431
+ // TODO: null node
2432
+ return new nodes.Literal('');
2433
+ },
2434
+
2435
+ /**
2436
+ * 'block' name block
2437
+ */
2438
+
2439
+ parseBlock: function(){
2440
+ var name = this.expect('block').val.trim();
2441
+ var block = 'indent' == this.peek().type
2442
+ ? this.block()
2443
+ : new nodes.Block(new nodes.Literal(''));
2444
+ return this.blocks[name] = this.blocks[name] || block;
2445
+ },
2446
+
2447
+ /**
2448
+ * include block?
2449
+ */
2450
+
2451
+ parseInclude: function(){
2452
+ var path = require('path')
2453
+ , fs = require('fs')
2454
+ , dirname = path.dirname
2455
+ , basename = path.basename
2456
+ , join = path.join;
2259
2457
 
2260
2458
  var path = name = this.expect('include').val.trim()
2261
2459
  , dir = dirname(this.filename);
2262
2460
 
2461
+ if (!this.filename)
2462
+ throw new Error('the "filename" option is required to use includes');
2463
+
2263
2464
  // non-jade
2264
2465
  if (~basename(path).indexOf('.')) {
2265
2466
  var path = join(dir, path)
@@ -2269,8 +2470,16 @@ Parser.prototype = {
2269
2470
 
2270
2471
  var path = join(dir, path + '.jade')
2271
2472
  , str = fs.readFileSync(path, 'utf8')
2272
- , parser = new Parser(str, path)
2273
- , ast = parser.parse();
2473
+ , parser = new Parser(str, path, this.options);
2474
+
2475
+ this.context(parser);
2476
+ var ast = parser.parse();
2477
+ this.context();
2478
+ ast.filename = path;
2479
+
2480
+ if ('indent' == this.peek().type) {
2481
+ ast.lastBlock().push(this.block());
2482
+ }
2274
2483
 
2275
2484
  return ast;
2276
2485
  },
@@ -2284,7 +2493,7 @@ Parser.prototype = {
2284
2493
  , name = tok.val
2285
2494
  , args = tok.args;
2286
2495
  var block = 'indent' == this.peek().type
2287
- ? this.parseBlock()
2496
+ ? this.block()
2288
2497
  : null;
2289
2498
  return new nodes.Mixin(name, args, block);
2290
2499
  },
@@ -2326,7 +2535,7 @@ Parser.prototype = {
2326
2535
  * indent expr* outdent
2327
2536
  */
2328
2537
 
2329
- parseBlock: function(){
2538
+ block: function(){
2330
2539
  var block = new nodes.Block;
2331
2540
  block.line = this.line();
2332
2541
  this.expect('indent');
@@ -2425,7 +2634,7 @@ Parser.prototype = {
2425
2634
  tag.block = this.parseTextBlock();
2426
2635
  this.lexer.pipeless = false;
2427
2636
  } else {
2428
- var block = this.parseBlock();
2637
+ var block = this.block();
2429
2638
  if (tag.block) {
2430
2639
  for (var i = 0, len = block.nodes.length; i < len; ++i) {
2431
2640
  tag.block.push(block.nodes[i]);
@@ -2456,7 +2665,7 @@ require.register("runtime.js", function(module, exports, require){
2456
2665
 
2457
2666
  if (!Array.isArray) {
2458
2667
  Array.isArray = function(arr){
2459
- return '[object Array]' == toString.call(arr);
2668
+ return '[object Array]' == Object.prototype.toString.call(arr);
2460
2669
  };
2461
2670
  }
2462
2671
 
@@ -2469,7 +2678,7 @@ if (!Object.keys) {
2469
2678
  var arr = [];
2470
2679
  for (var key in obj) {
2471
2680
  if (obj.hasOwnProperty(key)) {
2472
- arr.push(obj);
2681
+ arr.push(key);
2473
2682
  }
2474
2683
  }
2475
2684
  return arr;
@@ -2529,17 +2738,19 @@ exports.escape = function escape(html){
2529
2738
 
2530
2739
  /**
2531
2740
  * Re-throw the given `err` in context to the
2532
- * `str` of jade, `filename`, and `lineno`.
2741
+ * the jade in `filename` at the given `lineno`.
2533
2742
  *
2534
2743
  * @param {Error} err
2535
- * @param {String} str
2536
2744
  * @param {String} filename
2537
2745
  * @param {String} lineno
2538
2746
  * @api private
2539
2747
  */
2540
2748
 
2541
- exports.rethrow = function rethrow(err, str, filename, lineno){
2749
+ exports.rethrow = function rethrow(err, filename, lineno){
2750
+ if (!filename) throw err;
2751
+
2542
2752
  var context = 3
2753
+ , str = require('fs').readFileSync(filename, 'utf8')
2543
2754
  , lines = str.split('\n')
2544
2755
  , start = Math.max(lineno - context, 0)
2545
2756
  , end = Math.min(lines.length, lineno + context);
@@ -0,0 +1,123 @@
1
+
2
+ var jade = (function(exports){
3
+ /*!
4
+ * Jade - runtime
5
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
6
+ * MIT Licensed
7
+ */
8
+
9
+ /**
10
+ * Lame Array.isArray() polyfill for now.
11
+ */
12
+
13
+ if (!Array.isArray) {
14
+ Array.isArray = function(arr){
15
+ return '[object Array]' == Object.prototype.toString.call(arr);
16
+ };
17
+ }
18
+
19
+ /**
20
+ * Lame Object.keys() polyfill for now.
21
+ */
22
+
23
+ if (!Object.keys) {
24
+ Object.keys = function(obj){
25
+ var arr = [];
26
+ for (var key in obj) {
27
+ if (obj.hasOwnProperty(key)) {
28
+ arr.push(key);
29
+ }
30
+ }
31
+ return arr;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Render the given attributes object.
37
+ *
38
+ * @param {Object} obj
39
+ * @return {String}
40
+ * @api private
41
+ */
42
+
43
+ exports.attrs = function attrs(obj){
44
+ var buf = []
45
+ , terse = obj.terse;
46
+ delete obj.terse;
47
+ var keys = Object.keys(obj)
48
+ , len = keys.length;
49
+ if (len) {
50
+ buf.push('');
51
+ for (var i = 0; i < len; ++i) {
52
+ var key = keys[i]
53
+ , val = obj[key];
54
+ if ('boolean' == typeof val || null == val) {
55
+ if (val) {
56
+ terse
57
+ ? buf.push(key)
58
+ : buf.push(key + '="' + key + '"');
59
+ }
60
+ } else if ('class' == key && Array.isArray(val)) {
61
+ buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
62
+ } else {
63
+ buf.push(key + '="' + exports.escape(val) + '"');
64
+ }
65
+ }
66
+ }
67
+ return buf.join(' ');
68
+ };
69
+
70
+ /**
71
+ * Escape the given string of `html`.
72
+ *
73
+ * @param {String} html
74
+ * @return {String}
75
+ * @api private
76
+ */
77
+
78
+ exports.escape = function escape(html){
79
+ return String(html)
80
+ .replace(/&(?!\w+;)/g, '&amp;')
81
+ .replace(/</g, '&lt;')
82
+ .replace(/>/g, '&gt;')
83
+ .replace(/"/g, '&quot;');
84
+ };
85
+
86
+ /**
87
+ * Re-throw the given `err` in context to the
88
+ * the jade in `filename` at the given `lineno`.
89
+ *
90
+ * @param {Error} err
91
+ * @param {String} filename
92
+ * @param {String} lineno
93
+ * @api private
94
+ */
95
+
96
+ exports.rethrow = function rethrow(err, filename, lineno){
97
+ if (!filename) throw err;
98
+
99
+ var context = 3
100
+ , str = require('fs').readFileSync(filename, 'utf8')
101
+ , lines = str.split('\n')
102
+ , start = Math.max(lineno - context, 0)
103
+ , end = Math.min(lines.length, lineno + context);
104
+
105
+ // Error context
106
+ var context = lines.slice(start, end).map(function(line, i){
107
+ var curr = i + start + 1;
108
+ return (curr == lineno ? ' > ' : ' ')
109
+ + curr
110
+ + '| '
111
+ + line;
112
+ }).join('\n');
113
+
114
+ // Alter exception message
115
+ err.path = filename;
116
+ err.message = (filename || 'Jade') + ':' + lineno
117
+ + '\n' + context + '\n\n' + err.message;
118
+ throw err;
119
+ };
120
+
121
+ return exports;
122
+
123
+ })({});
@@ -3,5 +3,8 @@ module JadeJs
3
3
  def self.bundled_path
4
4
  File.expand_path("../jade.js", __FILE__)
5
5
  end
6
+ def self.bundled_runtime_path
7
+ File.expand_path("../runtime.js", __FILE__)
8
+ end
6
9
  end
7
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jade-js-source
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.4
4
+ version: 0.16.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,8 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-09-07 00:00:00.000000000 -04:00
14
- default_executable:
13
+ date: 2011-10-07 00:00:00.000000000Z
15
14
  dependencies: []
16
15
  description: ! " Jade is a high performance template engine heavily influenced
17
16
  by Haml \n and implemented with JavaScript for node.\n"
@@ -21,8 +20,8 @@ extensions: []
21
20
  extra_rdoc_files: []
22
21
  files:
23
22
  - lib/jade_js/jade.js
23
+ - lib/jade_js/runtime.js
24
24
  - lib/jade_js/source.rb
25
- has_rdoc: true
26
25
  homepage: https://github.com/visionmedia/jade
27
26
  licenses: []
28
27
  post_install_message:
@@ -43,7 +42,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
42
  version: '0'
44
43
  requirements: []
45
44
  rubyforge_project: jade-js-source
46
- rubygems_version: 1.6.2
45
+ rubygems_version: 1.8.10
47
46
  signing_key:
48
47
  specification_version: 3
49
48
  summary: Jade - template engine