00001 var assignInWith = require('./assignInWith'),
00002 attempt = require('./attempt'),
00003 baseValues = require('./_baseValues'),
00004 customDefaultsAssignIn = require('./_customDefaultsAssignIn'),
00005 escapeStringChar = require('./_escapeStringChar'),
00006 isError = require('./isError'),
00007 isIterateeCall = require('./_isIterateeCall'),
00008 keys = require('./keys'),
00009 reInterpolate = require('./_reInterpolate'),
00010 templateSettings = require('./templateSettings'),
00011 toString = require('./toString');
00012
00014 var reEmptyStringLeading = /\b__p \+= '';/g,
00015 reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
00016 reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
00017
00022 var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
00023
00025 var reNoMatch = /($^)/;
00026
00028 var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
00029
00134 function template(string, options, guard) {
00135 // Based on John Resig's `tmpl` implementation
00136
00137
00138 var settings = templateSettings.imports._.templateSettings || templateSettings;
00139
00140 if (guard && isIterateeCall(string, options, guard)) {
00141 options = undefined;
00142 }
00143 string = toString(string);
00144 options = assignInWith({}, options, settings, customDefaultsAssignIn);
00145
00146 var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
00147 importsKeys = keys(imports),
00148 importsValues = baseValues(imports, importsKeys);
00149
00150 var isEscaping,
00151 isEvaluating,
00152 index = 0,
00153 interpolate = options.interpolate || reNoMatch,
00154 source = "__p += '";
00155
00156
00157 var reDelimiters = RegExp(
00158 (options.escape || reNoMatch).source + '|' +
00159 interpolate.source + '|' +
00160 (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
00161 (options.evaluate || reNoMatch).source + '|$'
00162 , 'g');
00163
00164
00165 var sourceURL = 'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\n' : '';
00166
00167 string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
00168 interpolateValue || (interpolateValue = esTemplateValue);
00169
00170
00171 source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
00172
00173
00174 if (escapeValue) {
00175 isEscaping = true;
00176 source += "' +\n__e(" + escapeValue + ") +\n'";
00177 }
00178 if (evaluateValue) {
00179 isEvaluating = true;
00180 source += "';\n" + evaluateValue + ";\n__p += '";
00181 }
00182 if (interpolateValue) {
00183 source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
00184 }
00185 index = offset + match.length;
00186
00187
00188
00189 return match;
00190 });
00191
00192 source += "';\n";
00193
00194
00195
00196 var variable = options.variable;
00197 if (!variable) {
00198 source = 'with (obj) {\n' + source + '\n}\n';
00199 }
00200
00201 source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
00202 .replace(reEmptyStringMiddle, '$1')
00203 .replace(reEmptyStringTrailing, '$1;');
00204
00205
00206 source = 'function(' + (variable || 'obj') + ') {\n' +
00207 (variable
00208 ? ''
00209 : 'obj || (obj = {});\n'
00210 ) +
00211 "var __t, __p = ''" +
00212 (isEscaping
00213 ? ', __e = _.escape'
00214 : ''
00215 ) +
00216 (isEvaluating
00217 ? ', __j = Array.prototype.join;\n' +
00218 "function print() { __p += __j.call(arguments, '') }\n"
00219 : ';\n'
00220 ) +
00221 source +
00222 'return __p\n}';
00223
00224 var result = attempt(function() {
00225 return Function(importsKeys, sourceURL + 'return ' + source)
00226 .apply(undefined, importsValues);
00227 });
00228
00229
00230
00231 result.source = source;
00232 if (isError(result)) {
00233 throw result;
00234 }
00235 return result;
00236 }
00237
00238 module.exports = template;