diff options
Diffstat (limited to 'dgbuilder/dgeflows/node_modules/ejs/lib/ejs.js')
-rw-r--r-- | dgbuilder/dgeflows/node_modules/ejs/lib/ejs.js | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/dgbuilder/dgeflows/node_modules/ejs/lib/ejs.js b/dgbuilder/dgeflows/node_modules/ejs/lib/ejs.js new file mode 100644 index 00000000..a0d4ae54 --- /dev/null +++ b/dgbuilder/dgeflows/node_modules/ejs/lib/ejs.js @@ -0,0 +1,525 @@ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +'use strict'; + +var fs = require('fs') + , utils = require('./utils') + , jsCache = {} + , _VERSION_STRING = require('../package.json').version + , _DEFAULT_DELIMITER = '%' + , _DEFAULT_LOCALS_NAME = 'locals' + , _REGEX_STRING = '(<%%|<%=|<%-|<%#|<%|%>|-%>)' + , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context' + , 'debug', 'compileDebug', 'client', '_with' + ] + , _TRAILING_SEMCOL = /;\s*$/; + +exports.localsName = _DEFAULT_LOCALS_NAME; + +exports.resolveInclude = function(name, filename) { + var path = require('path') + , dirname = path.dirname + , extname = path.extname + , resolve = path.resolve + , includePath = resolve(dirname(filename), name) + , ext = extname(name); + if (!ext) { + includePath += '.ejs'; + } + return includePath; +} + + +// Returns a possibly cached template function, set by options.cache. +// `template` is the string of EJS to compile. +// If template is undefined then the file specified in options.filename is +// read. +function handleCache(options, template) { + var fn + , path = options.filename + , hasTemplate = template !== undefined; + + if (options.cache) { + if (!path) { + throw new Error('cache option requires a filename'); + } + fn = jsCache[path]; + if (fn) { + return fn; + } + if (!hasTemplate) { + template = fs.readFileSync(path, {encoding: 'utf8'}); + } + } + else if (!hasTemplate) { + if (!path) { + throw new Error('Internal EJS error: no file name or template ' + + 'provided'); + } + template = fs.readFileSync(path, {encoding: 'utf8'}); + } + fn = exports.compile(template.trim(), options); + if (options.cache) { + jsCache[path] = fn; + } + return fn; +} + +function includeFile(path, options) { + var opts = utils.shallowCopy({}, options || /* istanbul ignore next */ {}); + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + opts.filename = exports.resolveInclude(path, opts.filename); + return handleCache(opts); +} + +function includeSource(path, options) { + var opts = utils.shallowCopy({}, options || {}) + , includePath + , template; + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + includePath = exports.resolveInclude(path, opts.filename); + template = fs.readFileSync(includePath).toString().trim(); + + opts.filename = includePath; + var templ = new Template(template, opts); + templ.generateSource(); + return templ.source; +} + +function rethrow(err, str, filename, lineno){ + var lines = str.split('\n') + , start = Math.max(lineno - 3, 0) + , end = Math.min(lines.length, lineno + 3); + + // Error context + var context = lines.slice(start, end).map(function (line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' >> ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'ejs') + ':' + + lineno + '\n' + + context + '\n\n' + + err.message; + + throw err; +} + +function cpOptsInData(data, opts) { + _OPTS.forEach(function (p) { + if (typeof data[p] != 'undefined') { + opts[p] = data[p]; + } + }); + delete data.__expressRender__; +} + +function compile(template, opts) { + var templ; + + // v1 compat + // 'scope' is 'context' + // FIXME: Remove this in a future version + if (opts && opts.scope) { + if (!opts.context) { + opts.context = opts.scope; + } + delete opts.scope; + } + templ = new Template(template, opts); + return templ.compile(); +} +exports.compile = compile; + +// template, [data], [opts] +// Have to include an empty data object if you want opts and no data +exports.render = function (template, data, opts) { + data = data || {}; + opts = opts || {}; + var fn; + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 2) { + cpOptsInData(data, opts); + } + + fn = handleCache(opts, template); + return fn.call(opts.context, data); +}; + +// path, [data], [opts], cb +// Have to include an empty data object if you want opts and no data +exports.renderFile = function () { + var args = Array.prototype.slice.call(arguments) + , path = args.shift() + , cb = args.pop() + , data = args.shift() || {} + , opts = args.pop() || {} + , result + , failed = false; + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 3) { + cpOptsInData(data, opts); + } + opts.filename = path; + + try { + result = handleCache(opts)(data); + } + catch(err) { + return process.nextTick(function () { + cb(err); + }); + } + process.nextTick(function () { + cb(null, result); + }); +}; + +exports.clearCache = function () { + jsCache = {}; +}; + +function Template(text, opts) { + opts = opts || {}; + var options = {}; + this.templateText = text; + this.mode = null; + this.truncate = false; + this.currentLine = 1; + this.source = ''; + options.client = opts.client || false; + options.escapeFunction = opts.escape || utils.escapeXML; + options.compileDebug = opts.compileDebug !== false; + options.debug = !!opts.debug; + options.filename = opts.filename; + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER; + options._with = typeof opts._with != 'undefined' ? opts._with : true; + options.cache = opts.cache || false; + this.opts = options; + + this.regex = this.createRegex(); +} + +Template.modes = { + EVAL: 'eval' + , ESCAPED: 'escaped' + , RAW: 'raw' + , COMMENT: 'comment' + , LITERAL: 'literal' +}; + +Template.prototype = new function () { + this.createRegex = function () { + var str = _REGEX_STRING + , delim = utils.escapeRegExpChars(this.opts.delimiter); + str = str.replace(/%/g, delim); + return new RegExp(str); + }; + + this.compile = function () { + var src + , fn + , opts = this.opts + , escape = opts.escapeFunction; + + if (!this.source) { + this.generateSource(); + var prepended = 'var __output = [];'; + if (opts._with !== false) { + prepended += ' with (' + exports.localsName + ' || {}) { '; + } + this.source = prepended + this.source; + if (opts._with !== false) { + this.source += '}'; + } + this.source += ';return __output.join("").trim();'; + } + + if (opts.compileDebug) { + src = 'var __line = 1' + + ', __lines = ' + JSON.stringify(this.templateText) + + ', __filename = ' + (opts.filename ? + JSON.stringify(opts.filename) : 'undefined') + + '; try {' + + this.source + '} catch (e) { rethrow(e, __lines, __filename, __line); }'; + } + else { + src = this.source; + } + + if (opts.debug) { + console.log(src); + } + + if (opts.client) { + if (escape !== utils.escapeXML) { + src = 'escape = escape || ' + escape.toString() + ';\n' + src; + } + else { + src = utils.escapeFuncStr + + 'escape = escape || ' + + escape.toString() + ';\n' + + src; + } + if (opts.compileDebug) { + src = 'rethrow = rethrow || ' + rethrow.toString() + ';\n' + src; + } + } + + try { + fn = new Function(exports.localsName + ', escape, include, rethrow', src); + } + catch(e) { + if (e instanceof SyntaxError) { + if (opts.filename) { + e.message += ' in ' + opts.filename; + } + e.message += ' while compiling ejs'; + throw e; + } + } + + if (opts.client) { + return fn; + } + + // Return a callable function which will execute the function + // created by the source-code, with the passed data as locals + return function (data) { + var include = function (path, includeData) { + var d = utils.shallowCopy({}, data); + if (includeData) { + d = utils.shallowCopy(d, includeData); + } + return includeFile(path, opts)(d); + }; + return fn(data || {}, escape, include, rethrow); + }; + + }; + + this.generateSource = function () { + var self = this + , matches = this.parseTemplateText() + , d = this.opts.delimiter; + + if (matches && matches.length) { + matches.forEach(function (line, index) { + var closing + , include + , includeOpts + , includeSrc; + // If this is an opening tag, check for closing tags + // FIXME: May end up with some false positives here + // Better to store modes as k/v with '<' + delimiter as key + // Then this can simply check against the map + if ( line.indexOf('<' + d) === 0 // If it is a tag + && line.indexOf('<' + d + d) !== 0) { // and is not escaped + closing = matches[index + 2]; + if (!(closing == d + '>' || closing == '-' + d + '>')) { + throw new Error('Could not find matching close tag for "' + line + '".'); + } + } + // HACK: backward-compat `include` preprocessor directives + if ((include = line.match(/^\s*include\s+(\S+)/))) { + includeOpts = utils.shallowCopy({}, self.opts); + includeSrc = includeSource(include[1], includeOpts); + includeSrc = ';(function(){' + includeSrc + '})();'; + self.source += includeSrc; + } + else { + self.scanLine(line); + } + }); + } + + }; + + this.parseTemplateText = function () { + var str = this.templateText + , pat = this.regex + , result = pat.exec(str) + , arr = [] + , firstPos + , lastPos; + + while (result) { + firstPos = result.index; + lastPos = pat.lastIndex; + + if (firstPos !== 0) { + arr.push(str.substring(0, firstPos)); + str = str.slice(firstPos); + } + + arr.push(result[0]); + str = str.slice(result[0].length); + result = pat.exec(str); + } + + if (str) { + arr.push(str); + } + + return arr; + }; + + this.scanLine = function (line) { + var self = this + , d = this.opts.delimiter + , newLineCount = 0; + + function _addOutput() { + if (self.truncate) { + line = line.replace('\n', ''); + } + + // Preserve literal slashes + line = line.replace(/\\/g, '\\\\'); + + // Convert linebreaks + line = line.replace(/\n/g, '\\n'); + line = line.replace(/\r/g, '\\r'); + + // Escape double-quotes + // - this will be the delimiter during execution + line = line.replace(/"/g, '\\"'); + self.source += ';__output.push("' + line + '");'; + } + + newLineCount = (line.split('\n').length - 1); + + switch (line) { + case '<' + d: + this.mode = Template.modes.EVAL; + break; + case '<' + d + '=': + this.mode = Template.modes.ESCAPED; + break; + case '<' + d + '-': + this.mode = Template.modes.RAW; + break; + case '<' + d + '#': + this.mode = Template.modes.COMMENT; + break; + case '<' + d + d: + this.mode = Template.modes.LITERAL; + this.source += ';__output.push("' + line.replace('<' + d + d, '<' + d) + '");'; + break; + case d + '>': + case '-' + d + '>': + if (this.mode == Template.modes.LITERAL) { + _addOutput(); + } + + this.mode = null; + this.truncate = line.indexOf('-') === 0; + break; + default: + // In script mode, depends on type of tag + if (this.mode) { + // If '//' is found without a line break, add a line break. + switch (this.mode) { + case Template.modes.EVAL: + case Template.modes.ESCAPED: + case Template.modes.RAW: + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) { + line += '\n'; + } + } + switch (this.mode) { + // Just executing code + case Template.modes.EVAL: + this.source += ';' + line; + break; + // Exec, esc, and output + case Template.modes.ESCAPED: + // Add the exec'd, escaped result to the output + // Have to prevent the string-coercion of `undefined` and `null` + // in the `escape` function -- making a `join` call like below unnecessary + this.source += ';__output.push(escape(' + + line.replace(_TRAILING_SEMCOL, '').trim() + '))'; + break; + // Exec and output + case Template.modes.RAW: + // Add the exec'd result to the output + // Using `join` here prevents string-coercion of `undefined` and `null` + // without filtering out falsey values like zero + this.source += ';__output.push(' + + line.replace(_TRAILING_SEMCOL, '').trim() + ')'; + break; + case Template.modes.COMMENT: + // Do nothing + break; + // Literal <%% mode, append as raw output + case Template.modes.LITERAL: + _addOutput(); + break; + } + } + // In string mode, just add the output + else { + _addOutput(); + } + } + + if (self.opts.compileDebug && newLineCount) { + this.currentLine += newLineCount; + this.source += ';__line = ' + this.currentLine + ';'; + } + }; +}; + +// Express support +exports.__express = exports.renderFile; + +// Add require support +/* istanbul ignore else */ +if (require.extensions) { + require.extensions['.ejs'] = function (module, filename) { + filename = filename || /* istanbul ignore next */ module.filename; + var options = { + filename: filename + , client: true + } + , template = fs.readFileSync(filename).toString().trim() + , fn = compile(template, options); + module._compile('module.exports = ' + fn.toString() + ';', filename); + }; +} + +exports.VERSION = _VERSION_STRING; + +/* istanbul ignore if */ +if (typeof window != 'undefined') { + window.ejs = exports; +} |