/** * lodash 3.6.2 (Custom Build) <https://lodash.com/> * Build: `lodash modern modularize exports="npm" -o ./` * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license <https://lodash.com/license> */ var baseCopy = require('lodash._basecopy'), baseToString = require('lodash._basetostring'), baseValues = require('lodash._basevalues'), isIterateeCall = require('lodash._isiterateecall'), reInterpolate = require('lodash._reinterpolate'), keys = require('lodash.keys'), restParam = require('lodash.restparam'), templateSettings = require('lodash.templatesettings'); /** `Object#toString` result references. */ var errorTag = '[object Error]'; /** Used to match empty string literals in compiled template source. */ var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; /** Used to ensure capturing order of template delimiters. */ var reNoMatch = /($^)/; /** Used to match unescaped characters in compiled string literals. */ var reUnescapedString = /['\n\r\u2028\u2029\\]/g; /** Used to escape characters for inclusion in compiled string literals. */ var stringEscapes = { '\\': '\\', "'": "'", '\n': 'n', '\r': 'r', '\u2028': 'u2028', '\u2029': 'u2029' }; /** * Used by `_.template` to escape characters for inclusion in compiled string literals. * * @private * @param {string} chr The matched character to escape. * @returns {string} Returns the escaped character. */ function escapeStringChar(chr) { return '\\' + stringEscapes[chr]; } /** * Checks if `value` is object-like. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. */ function isObjectLike(value) { return !!value && typeof value == 'object'; } /** Used for native method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objToString = objectProto.toString; /** * Used by `_.template` to customize its `_.assign` use. * * **Note:** This function is like `assignDefaults` except that it ignores * inherited property values when checking if a property is `undefined`. * * @private * @param {*} objectValue The destination object property value. * @param {*} sourceValue The source object property value. * @param {string} key The key associated with the object and source values. * @param {Object} object The destination object. * @returns {*} Returns the value to assign to the destination object. */ function assignOwnDefaults(objectValue, sourceValue, key, object) { return (objectValue === undefined || !hasOwnProperty.call(object, key)) ? sourceValue : objectValue; } /** * A specialized version of `_.assign` for customizing assigned values without * support for argument juggling, multiple sources, and `this` binding `customizer` * functions. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @param {Function} customizer The function to customize assigned values. * @returns {Object} Returns `object`. */ function assignWith(object, source, customizer) { var index = -1, props = keys(source), length = props.length; while (++index < length) { var key = props[index], value = object[key], result = customizer(value, source[key], key, object, source); if ((result === result ? (result !== value) : (value === value)) || (value === undefined && !(key in object))) { object[key] = result; } } return object; } /** * The base implementation of `_.assign` without support for argument juggling, * multiple sources, and `customizer` functions. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @returns {Object} Returns `object`. */ function baseAssign(object, source) { return source == null ? object : baseCopy(source, keys(source), object); } /** * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, * `SyntaxError`, `TypeError`, or `URIError` object. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an error object, else `false`. * @example * * _.isError(new Error); * // => true * * _.isError(Error); * // => false */ function isError(value) { return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag; } /** * Creates a compiled template function that can interpolate data properties * in "interpolate" delimiters, HTML-escape interpolated data properties in * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data * properties may be accessed as free variables in the template. If a setting * object is provided it takes precedence over `_.templateSettings` values. * * **Note:** In the development build `_.template` utilizes * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) * for easier debugging. * * For more information on precompiling templates see * [lodash's custom builds documentation](https://lodash.com/custom-builds). * * For more information on Chrome extension sandboxes see * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). * * @static * @memberOf _ * @category String * @param {string} [string=''] The template string. * @param {Object} [options] The options object. * @param {RegExp} [options.escape] The HTML "escape" delimiter. * @param {RegExp} [options.evaluate] The "evaluate" delimiter. * @param {Object} [options.imports] An object to import into the template as free variables. * @param {RegExp} [options.interpolate] The "interpolate" delimiter. * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. * @param {string} [options.variable] The data object variable name. * @param- {Object} [otherOptions] Enables the legacy `options` param signature. * @returns {Function} Returns the compiled template function. * @example * * // using the "interpolate" delimiter to create a compiled template * var compiled = _.template('hello <%= user %>!'); * compiled({ 'user': 'fred' }); * // => 'hello fred!' * * // using the HTML "escape" delimiter to escape data property values * var compiled = _.template('<b><%- value %></b>'); * compiled({ 'value': '<script>' }); * // => '<b><script></b>' * * // using the "evaluate" delimiter to execute JavaScript and generate HTML * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>'); * compiled({ 'users': ['fred', 'barney'] }); * // => '<li>fred</li><li>barney</li>' * * // using the internal `print` function in "evaluate" delimiters * var compiled = _.template('<% print("hello " + user); %>!'); * compiled({ 'user': 'barney' }); * // => 'hello barney!' * * // using the ES delimiter as an alternative to the default "interpolate" delimiter * var compiled = _.template('hello ${ user }!'); * compiled({ 'user': 'pebbles' }); * // => 'hello pebbles!' * * // using custom template delimiters * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g; * var compiled = _.template('hello {{ user }}!'); * compiled({ 'user': 'mustache' }); * // => 'hello mustache!' * * // using backslashes to treat delimiters as plain text * var compiled = _.template('<%= "\\<%- value %\\>" %>'); * compiled({ 'value': 'ignored' }); * // => '<%- value %>' * * // using the `imports` option to import `jQuery` as `jq` * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>'; * var compiled = _.template(text, { 'imports': { 'jq': jQuery } }); * compiled({ 'users': ['fred', 'barney'] }); * // => '<li>fred</li><li>barney</li>' * * // using the `sourceURL` option to specify a custom sourceURL for the template * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' }); * compiled(data); * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector * * // using the `variable` option to ensure a with-statement isn't used in the compiled template * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' }); * compiled.source; * // => function(data) { * // var __t, __p = ''; * // __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!'; * // return __p; * // } * * // using the `source` property to inline compiled templates for meaningful * // line numbers in error messages and a stack trace * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ * var JST = {\ * "main": ' + _.template(mainText).source + '\ * };\ * '); */ function template(string, options, otherOptions) { // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/) // and Laura Doktorova's doT.js (https://github.com/olado/doT). var settings = templateSettings.imports._.templateSettings || templateSettings; if (otherOptions && isIterateeCall(string, options, otherOptions)) { options = otherOptions = undefined; } string = baseToString(string); options = assignWith(baseAssign({}, otherOptions || options), settings, assignOwnDefaults); var imports = assignWith(baseAssign({}, options.imports), settings.imports, assignOwnDefaults), importsKeys = keys(imports), importsValues = baseValues(imports, importsKeys); var isEscaping, isEvaluating, index = 0, interpolate = options.interpolate || reNoMatch, source = "__p += '"; // Compile the regexp to match each delimiter. var reDelimiters = RegExp( (options.escape || reNoMatch).source + '|' + interpolate.source + '|' + (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' + (options.evaluate || reNoMatch).source + '|$' , 'g'); // Use a sourceURL for easier debugging. var sourceURL = 'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\n' : ''; string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) { interpolateValue || (interpolateValue = esTemplateValue); // Escape characters that can't be included in string literals. source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar); // Replace delimiters with snippets. if (escapeValue) { isEscaping = true; source += "' +\n__e(" + escapeValue + ") +\n'"; } if (evaluateValue) { isEvaluating = true; source += "';\n" + evaluateValue + ";\n__p += '"; } if (interpolateValue) { source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'"; } index = offset + match.length; // The JS engine embedded in Adobe products requires returning the `match` // string in order to produce the correct `offset` value. return match; }); source += "';\n"; // If `variable` is not specified wrap a with-statement around the generated // code to add the data object to the top of the scope chain. var variable = options.variable; if (!variable) { source = 'with (obj) {\n' + source + '\n}\n'; } // Cleanup code by stripping empty strings. source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) .replace(reEmptyStringMiddle, '$1') .replace(reEmptyStringTrailing, '$1;'); // Frame code as the function body. source = 'function(' + (variable || 'obj') + ') {\n' + (variable ? '' : 'obj || (obj = {});\n' ) + "var __t, __p = ''" + (isEscaping ? ', __e = _.escape' : '' ) + (isEvaluating ? ', __j = Array.prototype.join;\n' + "function print() { __p += __j.call(arguments, '') }\n" : ';\n' ) + source + 'return __p\n}'; var result = attempt(function() { return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues); }); // Provide the compiled function's source by its `toString` method or // the `source` property as a convenience for inlining compiled templates. result.source = source; if (isError(result)) { throw result; } return result; } /** * Attempts to invoke `func`, returning either the result or the caught error * object. Any additional arguments are provided to `func` when it is invoked. * * @static * @memberOf _ * @category Utility * @param {Function} func The function to attempt. * @returns {*} Returns the `func` result or error object. * @example * * // avoid throwing errors for invalid selectors * var elements = _.attempt(function(selector) { * return document.querySelectorAll(selector); * }, '>_>'); * * if (_.isError(elements)) { * elements = []; * } */ var attempt = restParam(function(func, args) { try { return func.apply(undefined, args); } catch(e) { return isError(e) ? e : new Error(e); } }); module.exports = template;