Name: js-handler/node_modules/nodeunit/deps/ejs/lib/ejs.js
| 1: | /*! |
| 2: | * EJS |
| 3: | * Copyright(c) 2010 TJ Holowaychuk <[email protected]> |
| 4: | * MIT Licensed |
| 5: | */ |
| 6: | |
| 7: | /** |
| 8: | * Module dependencies. |
| 9: | */ |
| 10: | |
| 11: | var utils = require('./utils'); |
| 12: | |
| 13: | /** |
| 14: | * Library version. |
| 15: | */ |
| 16: | |
| 17: | exports.version = '0.4.3'; |
| 18: | |
| 19: | /** |
| 20: | * Filters. |
| 21: | * |
| 22: | * @type Object |
| 23: | */ |
| 24: | |
| 25: | var filters = exports.filters = require('./filters'); |
| 26: | |
| 27: | /** |
| 28: | * Intermediate js cache. |
| 29: | * |
| 30: | * @type Object |
| 31: | */ |
| 32: | |
| 33: | var cache = {}; |
| 34: | |
| 35: | /** |
| 36: | * Clear intermediate js cache. |
| 37: | * |
| 38: | * @api public |
| 39: | */ |
| 40: | |
| 41: | exports.clearCache = function(){ |
| 42: | cache = {}; |
| 43: | }; |
| 44: | |
| 45: | /** |
| 46: | * Translate filtered code into function calls. |
| 47: | * |
| 48: | * @param {String} js |
| 49: | * @return {String} |
| 50: | * @api private |
| 51: | */ |
| 52: | |
| 53: | function filtered(js) { |
| 54: | return js.substr(1).split('|').reduce(function(js, filter){ |
| 55: | var parts = filter.split(':') |
| 56: | , name = parts.shift() |
| 57: | , args = parts.shift() || ''; |
| 58: | if (args) args = ', ' + args; |
| 59: | return 'filters.' + name + '(' + js + args + ')'; |
| 60: | }); |
| 61: | }; |
| 62: | |
| 63: | /** |
| 64: | * Re-throw the given `err` in context to the |
| 65: | * `str` of ejs, `filename`, and `lineno`. |
| 66: | * |
| 67: | * @param {Error} err |
| 68: | * @param {String} str |
| 69: | * @param {String} filename |
| 70: | * @param {String} lineno |
| 71: | * @api private |
| 72: | */ |
| 73: | |
| 74: | function rethrow(err, str, filename, lineno){ |
| 75: | var lines = str.split('\n') |
| 76: | , start = Math.max(lineno - 3, 0) |
| 77: | , end = Math.min(lines.length, lineno + 3); |
| 78: | |
| 79: | // Error context |
| 80: | var context = lines.slice(start, end).map(function(line, i){ |
| 81: | var curr = i + start + 1; |
| 82: | return (curr == lineno ? ' >> ' : ' ') |
| 83: | + curr |
| 84: | + '| ' |
| 85: | + line; |
| 86: | }).join('\n'); |
| 87: | |
| 88: | // Alter exception message |
| 89: | err.path = filename; |
| 90: | err.message = (filename || 'ejs') + ':' |
| 91: | + lineno + '\n' |
| 92: | + context + '\n\n' |
| 93: | + err.message; |
| 94: | |
| 95: | throw err; |
| 96: | } |
| 97: | |
| 98: | /** |
| 99: | * Parse the given `str` of ejs, returning the function body. |
| 100: | * |
| 101: | * @param {String} str |
| 102: | * @return {String} |
| 103: | * @api public |
| 104: | */ |
| 105: | |
| 106: | var parse = exports.parse = function(str, options){ |
| 107: | var options = options || {} |
| 108: | , open = options.open || exports.open || '<%' |
| 109: | , close = options.close || exports.close || '%>'; |
| 110: | |
| 111: | var buf = [ |
| 112: | "var buf = [];" |
| 113: | , "\nwith (locals) {" |
| 114: | , "\n buf.push('" |
| 115: | ]; |
| 116: | |
| 117: | var lineno = 1; |
| 118: | |
| 119: | for (var i = 0, len = str.length; i < len; ++i) { |
| 120: | if (str.slice(i, open.length + i) == open) { |
| 121: | i += open.length |
| 122: | |
| 123: | var prefix, postfix, line = '__stack.lineno=' + lineno; |
| 124: | switch (str.substr(i, 1)) { |
| 125: | case '=': |
| 126: | prefix = "', escape((" + line + ', '; |
| 127: | postfix = ")), '"; |
| 128: | ++i; |
| 129: | break; |
| 130: | case '-': |
| 131: | prefix = "', (" + line + ', '; |
| 132: | postfix = "), '"; |
| 133: | ++i; |
| 134: | break; |
| 135: | default: |
| 136: | prefix = "');" + line + ';'; |
| 137: | postfix = "; buf.push('"; |
| 138: | } |
| 139: | |
| 140: | var end = str.indexOf(close, i) |
| 141: | , js = str.substring(i, end) |
| 142: | , start = i |
| 143: | , n = 0; |
| 144: | |
| 145: | while (~(n = js.indexOf("\n", n))) n++, lineno++; |
| 146: | if (js.substr(0, 1) == ':') js = filtered(js); |
| 147: | buf.push(prefix, js, postfix); |
| 148: | i += end - start + close.length - 1; |
| 149: | |
| 150: | } else if (str.substr(i, 1) == "\\") { |
| 151: | buf.push("\\\\"); |
| 152: | } else if (str.substr(i, 1) == "'") { |
| 153: | buf.push("\\'"); |
| 154: | } else if (str.substr(i, 1) == "\r") { |
| 155: | buf.push(" "); |
| 156: | } else if (str.substr(i, 1) == "\n") { |
| 157: | buf.push("\\n"); |
| 158: | lineno++; |
| 159: | } else { |
| 160: | buf.push(str.substr(i, 1)); |
| 161: | } |
| 162: | } |
| 163: | |
| 164: | buf.push("');\n}\nreturn buf.join('');"); |
| 165: | return buf.join(''); |
| 166: | }; |
| 167: | |
| 168: | /** |
| 169: | * Compile the given `str` of ejs into a `Function`. |
| 170: | * |
| 171: | * @param {String} str |
| 172: | * @param {Object} options |
| 173: | * @return {Function} |
| 174: | * @api public |
| 175: | */ |
| 176: | |
| 177: | var compile = exports.compile = function(str, options){ |
| 178: | options = options || {}; |
| 179: | |
| 180: | var input = JSON.stringify(str) |
| 181: | , filename = options.filename |
| 182: | ? JSON.stringify(options.filename) |
| 183: | : 'undefined'; |
| 184: | |
| 185: | // Adds the fancy stack trace meta info |
| 186: | str = [ |
| 187: | 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };', |
| 188: | rethrow.toString(), |
| 189: | 'try {', |
| 190: | exports.parse(str, options), |
| 191: | '} catch (err) {', |
| 192: | ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);', |
| 193: | '}' |
| 194: | ].join("\n"); |
| 195: | |
| 196: | if (options.debug) console.log(str); |
| 197: | var fn = new Function('locals, filters, escape', str); |
| 198: | return function(locals){ |
| 199: | return fn.call(this, locals, filters, utils.escape); |
| 200: | } |
| 201: | }; |
| 202: | |
| 203: | /** |
| 204: | * Render the given `str` of ejs. |
| 205: | * |
| 206: | * Options: |
| 207: | * |
| 208: | * - `locals` Local variables object |
| 209: | * - `cache` Compiled functions are cached, requires `filename` |
| 210: | * - `filename` Used by `cache` to key caches |
| 211: | * - `scope` Function execution context |
| 212: | * - `debug` Output generated function body |
| 213: | * - `open` Open tag, defaulting to "<%" |
| 214: | * - `close` Closing tag, defaulting to "%>" |
| 215: | * |
| 216: | * @param {String} str |
| 217: | * @param {Object} options |
| 218: | * @return {String} |
| 219: | * @api public |
| 220: | */ |
| 221: | |
| 222: | exports.render = function(str, options){ |
| 223: | var fn |
| 224: | , options = options || {}; |
| 225: | if (options.cache) { |
| 226: | if (options.filename) { |
| 227: | fn = cache[options.filename] || (cache[options.filename] = compile(str, options)); |
| 228: | } else { |
| 229: | throw new Error('"cache" option requires "filename".'); |
| 230: | } |
| 231: | } else { |
| 232: | fn = compile(str, options); |
| 233: | } |
| 234: | return fn.call(options.scope, options.locals || {}); |
| 235: | }; |
| 236: | |
| 237: | /** |
| 238: | * Expose to require(). |
| 239: | */ |
| 240: | |
| 241: | if (require.extensions) { |
| 242: | require.extensions['.ejs'] = function(module, filename) { |
| 243: | source = require('fs').readFileSync(filename, 'utf-8'); |
| 244: | module._compile(compile(source, {}), filename); |
| 245: | }; |
| 246: | } else if (require.registerExtension) { |
| 247: | require.registerExtension('.ejs', function(src) { |
| 248: | return compile(src, {}); |
| 249: | }); |
| 250: | } |
