runtime.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. jade = (function(exports){
  2. /*!
  3. * Jade - runtime
  4. * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
  5. * MIT Licensed
  6. */
  7. /**
  8. * Lame Array.isArray() polyfill for now.
  9. */
  10. if (!Array.isArray) {
  11. Array.isArray = function(arr){
  12. return '[object Array]' == Object.prototype.toString.call(arr);
  13. };
  14. }
  15. /**
  16. * Lame Object.keys() polyfill for now.
  17. */
  18. if (!Object.keys) {
  19. Object.keys = function(obj){
  20. var arr = [];
  21. for (var key in obj) {
  22. if (obj.hasOwnProperty(key)) {
  23. arr.push(key);
  24. }
  25. }
  26. return arr;
  27. }
  28. }
  29. /**
  30. * Merge two attribute objects giving precedence
  31. * to values in object `b`. Classes are special-cased
  32. * allowing for arrays and merging/joining appropriately
  33. * resulting in a string.
  34. *
  35. * @param {Object} a
  36. * @param {Object} b
  37. * @return {Object} a
  38. * @api private
  39. */
  40. exports.merge = function merge(a, b) {
  41. var ac = a['class'];
  42. var bc = b['class'];
  43. if (ac || bc) {
  44. ac = ac || [];
  45. bc = bc || [];
  46. if (!Array.isArray(ac)) ac = [ac];
  47. if (!Array.isArray(bc)) bc = [bc];
  48. ac = ac.filter(nulls);
  49. bc = bc.filter(nulls);
  50. a['class'] = ac.concat(bc).join(' ');
  51. }
  52. for (var key in b) {
  53. if (key != 'class') {
  54. a[key] = b[key];
  55. }
  56. }
  57. return a;
  58. };
  59. /**
  60. * Filter null `val`s.
  61. *
  62. * @param {Mixed} val
  63. * @return {Mixed}
  64. * @api private
  65. */
  66. function nulls(val) {
  67. return val != null;
  68. }
  69. /**
  70. * Render the given attributes object.
  71. *
  72. * @param {Object} obj
  73. * @param {Object} escaped
  74. * @return {String}
  75. * @api private
  76. */
  77. exports.attrs = function attrs(obj, escaped){
  78. var buf = []
  79. , terse = obj.terse;
  80. delete obj.terse;
  81. var keys = Object.keys(obj)
  82. , len = keys.length;
  83. if (len) {
  84. buf.push('');
  85. for (var i = 0; i < len; ++i) {
  86. var key = keys[i]
  87. , val = obj[key];
  88. if ('boolean' == typeof val || null == val) {
  89. if (val) {
  90. terse
  91. ? buf.push(key)
  92. : buf.push(key + '="' + key + '"');
  93. }
  94. } else if (0 == key.indexOf('data') && 'string' != typeof val) {
  95. buf.push(key + "='" + JSON.stringify(val) + "'");
  96. } else if ('class' == key && Array.isArray(val)) {
  97. buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
  98. } else if (escaped && escaped[key]) {
  99. buf.push(key + '="' + exports.escape(val) + '"');
  100. } else {
  101. buf.push(key + '="' + val + '"');
  102. }
  103. }
  104. }
  105. return buf.join(' ');
  106. };
  107. /**
  108. * Escape the given string of `html`.
  109. *
  110. * @param {String} html
  111. * @return {String}
  112. * @api private
  113. */
  114. exports.escape = function escape(html){
  115. return String(html)
  116. .replace(/&(?!(\w+|\#\d+);)/g, '&amp;')
  117. .replace(/</g, '&lt;')
  118. .replace(/>/g, '&gt;')
  119. .replace(/"/g, '&quot;');
  120. };
  121. /**
  122. * Re-throw the given `err` in context to the
  123. * the jade in `filename` at the given `lineno`.
  124. *
  125. * @param {Error} err
  126. * @param {String} filename
  127. * @param {String} lineno
  128. * @api private
  129. */
  130. exports.rethrow = function rethrow(err, filename, lineno){
  131. if (!filename) throw err;
  132. var context = 3
  133. , str = require('fs').readFileSync(filename, 'utf8')
  134. , lines = str.split('\n')
  135. , start = Math.max(lineno - context, 0)
  136. , end = Math.min(lines.length, lineno + context);
  137. // Error context
  138. var context = lines.slice(start, end).map(function(line, i){
  139. var curr = i + start + 1;
  140. return (curr == lineno ? ' > ' : ' ')
  141. + curr
  142. + '| '
  143. + line;
  144. }).join('\n');
  145. // Alter exception message
  146. err.path = filename;
  147. err.message = (filename || 'Jade') + ':' + lineno
  148. + '\n' + context + '\n\n' + err.message;
  149. throw err;
  150. };
  151. return exports;
  152. })({});