A Twitch.tv viewer reward and games system.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

323 lines
7.0 KiB

  1. 'use strict';
  2. /*!
  3. * Jade
  4. * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
  5. * MIT Licensed
  6. */
  7. /**
  8. * Module dependencies.
  9. */
  10. var Parser = require('./parser')
  11. , Lexer = require('./lexer')
  12. , Compiler = require('./compiler')
  13. , runtime = require('./runtime')
  14. , addWith = require('with')
  15. , fs = require('fs');
  16. /**
  17. * Expose self closing tags.
  18. */
  19. exports.selfClosing = require('./self-closing');
  20. /**
  21. * Default supported doctypes.
  22. */
  23. exports.doctypes = require('./doctypes');
  24. /**
  25. * Text filters.
  26. */
  27. exports.filters = require('./filters');
  28. /**
  29. * Utilities.
  30. */
  31. exports.utils = require('./utils');
  32. /**
  33. * Expose `Compiler`.
  34. */
  35. exports.Compiler = Compiler;
  36. /**
  37. * Expose `Parser`.
  38. */
  39. exports.Parser = Parser;
  40. /**
  41. * Expose `Lexer`.
  42. */
  43. exports.Lexer = Lexer;
  44. /**
  45. * Nodes.
  46. */
  47. exports.nodes = require('./nodes');
  48. /**
  49. * Jade runtime helpers.
  50. */
  51. exports.runtime = runtime;
  52. /**
  53. * Template function cache.
  54. */
  55. exports.cache = {};
  56. /**
  57. * Parse the given `str` of jade and return a function body.
  58. *
  59. * @param {String} str
  60. * @param {Object} options
  61. * @return {String}
  62. * @api private
  63. */
  64. function parse(str, options){
  65. try {
  66. // Parse
  67. var parser = new (options.parser || Parser)(str, options.filename, options);
  68. // Compile
  69. var compiler = new (options.compiler || Compiler)(parser.parse(), options)
  70. , js = compiler.compile();
  71. // Debug compiler
  72. if (options.debug) {
  73. console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, ' '));
  74. }
  75. var globals = options.globals && Array.isArray(options.globals) ? options.globals : [];
  76. globals.push('jade');
  77. globals.push('jade_mixins');
  78. globals.push('jade_debug');
  79. globals.push('buf');
  80. return ''
  81. + 'var buf = [];\n'
  82. + 'var jade_mixins = {};\n'
  83. + (options.self
  84. ? 'var self = locals || {};\n' + js
  85. : addWith('locals || {}', '\n' + js, globals)) + ';'
  86. + 'return buf.join("");';
  87. } catch (err) {
  88. parser = parser.context();
  89. runtime.rethrow(err, parser.filename, parser.lexer.lineno, parser.input);
  90. }
  91. }
  92. /**
  93. * Compile a `Function` representation of the given jade `str`.
  94. *
  95. * Options:
  96. *
  97. * - `compileDebug` when `false` debugging code is stripped from the compiled
  98. template, when it is explicitly `true`, the source code is included in
  99. the compiled template for better accuracy.
  100. * - `filename` used to improve errors when `compileDebug` is not `false` and to resolve imports/extends
  101. *
  102. * @param {String} str
  103. * @param {Options} options
  104. * @return {Function}
  105. * @api public
  106. */
  107. exports.compile = function(str, options){
  108. var options = options || {}
  109. , filename = options.filename
  110. ? JSON.stringify(options.filename)
  111. : 'undefined'
  112. , fn;
  113. str = String(str);
  114. if (options.compileDebug !== false) {
  115. fn = [
  116. 'var jade_debug = [{ lineno: 1, filename: ' + filename + ' }];'
  117. , 'try {'
  118. , parse(str, options)
  119. , '} catch (err) {'
  120. , ' jade.rethrow(err, jade_debug[0].filename, jade_debug[0].lineno' + (options.compileDebug === true ? ',' + JSON.stringify(str) : '') + ');'
  121. , '}'
  122. ].join('\n');
  123. } else {
  124. fn = parse(str, options);
  125. }
  126. fn = new Function('locals, jade', fn)
  127. var res = function(locals){ return fn(locals, Object.create(runtime)) };
  128. if (options.client) {
  129. res.toString = function () {
  130. var err = new Error('The `client` option is deprecated, use `jade.compileClient`');
  131. console.error(err.stack || err.message);
  132. return exports.compileClient(str, options);
  133. };
  134. }
  135. return res;
  136. };
  137. /**
  138. * Compile a JavaScript source representation of the given jade `str`.
  139. *
  140. * Options:
  141. *
  142. * - `compileDebug` When it is `true`, the source code is included in
  143. the compiled template for better error messages.
  144. * - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends
  145. *
  146. * @param {String} str
  147. * @param {Options} options
  148. * @return {String}
  149. * @api public
  150. */
  151. exports.compileClient = function(str, options){
  152. var options = options || {}
  153. , filename = options.filename
  154. ? JSON.stringify(options.filename)
  155. : 'undefined'
  156. , fn;
  157. str = String(str);
  158. if (options.compileDebug) {
  159. options.compileDebug = true;
  160. fn = [
  161. 'var jade_debug = [{ lineno: 1, filename: ' + filename + ' }];'
  162. , 'try {'
  163. , parse(str, options)
  164. , '} catch (err) {'
  165. , ' jade.rethrow(err, jade_debug[0].filename, jade_debug[0].lineno, ' + JSON.stringify(str) + ');'
  166. , '}'
  167. ].join('\n');
  168. } else {
  169. options.compileDebug = false;
  170. fn = parse(str, options);
  171. }
  172. return 'function template(locals) {\n' + fn + '\n}';
  173. };
  174. /**
  175. * Render the given `str` of jade.
  176. *
  177. * Options:
  178. *
  179. * - `cache` enable template caching
  180. * - `filename` filename required for `include` / `extends` and caching
  181. *
  182. * @param {String} str
  183. * @param {Object|Function} options or fn
  184. * @param {Function|undefined} fn
  185. * @returns {String}
  186. * @api public
  187. */
  188. exports.render = function(str, options, fn){
  189. // support callback API
  190. if ('function' == typeof options) {
  191. fn = options, options = undefined;
  192. }
  193. if (typeof fn === 'function') {
  194. var res
  195. try {
  196. res = exports.render(str, options);
  197. } catch (ex) {
  198. return fn(ex);
  199. }
  200. return fn(null, res);
  201. }
  202. options = options || {};
  203. // cache requires .filename
  204. if (options.cache && !options.filename) {
  205. throw new Error('the "filename" option is required for caching');
  206. }
  207. var path = options.filename;
  208. var tmpl = options.cache
  209. ? exports.cache[path] || (exports.cache[path] = exports.compile(str, options))
  210. : exports.compile(str, options);
  211. return tmpl(options);
  212. };
  213. /**
  214. * Render a Jade file at the given `path`.
  215. *
  216. * @param {String} path
  217. * @param {Object|Function} options or callback
  218. * @param {Function|undefined} fn
  219. * @returns {String}
  220. * @api public
  221. */
  222. exports.renderFile = function(path, options, fn){
  223. // support callback API
  224. if ('function' == typeof options) {
  225. fn = options, options = undefined;
  226. }
  227. if (typeof fn === 'function') {
  228. var res
  229. try {
  230. res = exports.renderFile(path, options);
  231. } catch (ex) {
  232. return fn(ex);
  233. }
  234. return fn(null, res);
  235. }
  236. options = options || {};
  237. var key = path + ':string';
  238. options.filename = path;
  239. var str = options.cache
  240. ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
  241. : fs.readFileSync(path, 'utf8');
  242. return exports.render(str, options);
  243. };
  244. /**
  245. * Compile a Jade file at the given `path` for use on the client.
  246. *
  247. * @param {String} path
  248. * @param {Object} options
  249. * @returns {String}
  250. * @api public
  251. */
  252. exports.compileFileClient = function(path, options){
  253. options = options || {};
  254. var key = path + ':string';
  255. options.filename = path;
  256. var str = options.cache
  257. ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
  258. : fs.readFileSync(path, 'utf8');
  259. return exports.compileClient(str, options);
  260. };
  261. /**
  262. * Express support.
  263. */
  264. exports.__express = exports.renderFile;