index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /**
  2. * lodash 3.6.2 (Custom Build) <https://lodash.com/>
  3. * Build: `lodash modern modularize exports="npm" -o ./`
  4. * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
  5. * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
  6. * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
  7. * Available under MIT license <https://lodash.com/license>
  8. */
  9. var baseCopy = require('lodash._basecopy'),
  10. baseToString = require('lodash._basetostring'),
  11. baseValues = require('lodash._basevalues'),
  12. isIterateeCall = require('lodash._isiterateecall'),
  13. reInterpolate = require('lodash._reinterpolate'),
  14. keys = require('lodash.keys'),
  15. restParam = require('lodash.restparam'),
  16. templateSettings = require('lodash.templatesettings');
  17. /** `Object#toString` result references. */
  18. var errorTag = '[object Error]';
  19. /** Used to match empty string literals in compiled template source. */
  20. var reEmptyStringLeading = /\b__p \+= '';/g,
  21. reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
  22. reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
  23. /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */
  24. var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
  25. /** Used to ensure capturing order of template delimiters. */
  26. var reNoMatch = /($^)/;
  27. /** Used to match unescaped characters in compiled string literals. */
  28. var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
  29. /** Used to escape characters for inclusion in compiled string literals. */
  30. var stringEscapes = {
  31. '\\': '\\',
  32. "'": "'",
  33. '\n': 'n',
  34. '\r': 'r',
  35. '\u2028': 'u2028',
  36. '\u2029': 'u2029'
  37. };
  38. /**
  39. * Used by `_.template` to escape characters for inclusion in compiled string literals.
  40. *
  41. * @private
  42. * @param {string} chr The matched character to escape.
  43. * @returns {string} Returns the escaped character.
  44. */
  45. function escapeStringChar(chr) {
  46. return '\\' + stringEscapes[chr];
  47. }
  48. /**
  49. * Checks if `value` is object-like.
  50. *
  51. * @private
  52. * @param {*} value The value to check.
  53. * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
  54. */
  55. function isObjectLike(value) {
  56. return !!value && typeof value == 'object';
  57. }
  58. /** Used for native method references. */
  59. var objectProto = Object.prototype;
  60. /** Used to check objects for own properties. */
  61. var hasOwnProperty = objectProto.hasOwnProperty;
  62. /**
  63. * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
  64. * of values.
  65. */
  66. var objToString = objectProto.toString;
  67. /**
  68. * Used by `_.template` to customize its `_.assign` use.
  69. *
  70. * **Note:** This function is like `assignDefaults` except that it ignores
  71. * inherited property values when checking if a property is `undefined`.
  72. *
  73. * @private
  74. * @param {*} objectValue The destination object property value.
  75. * @param {*} sourceValue The source object property value.
  76. * @param {string} key The key associated with the object and source values.
  77. * @param {Object} object The destination object.
  78. * @returns {*} Returns the value to assign to the destination object.
  79. */
  80. function assignOwnDefaults(objectValue, sourceValue, key, object) {
  81. return (objectValue === undefined || !hasOwnProperty.call(object, key))
  82. ? sourceValue
  83. : objectValue;
  84. }
  85. /**
  86. * A specialized version of `_.assign` for customizing assigned values without
  87. * support for argument juggling, multiple sources, and `this` binding `customizer`
  88. * functions.
  89. *
  90. * @private
  91. * @param {Object} object The destination object.
  92. * @param {Object} source The source object.
  93. * @param {Function} customizer The function to customize assigned values.
  94. * @returns {Object} Returns `object`.
  95. */
  96. function assignWith(object, source, customizer) {
  97. var index = -1,
  98. props = keys(source),
  99. length = props.length;
  100. while (++index < length) {
  101. var key = props[index],
  102. value = object[key],
  103. result = customizer(value, source[key], key, object, source);
  104. if ((result === result ? (result !== value) : (value === value)) ||
  105. (value === undefined && !(key in object))) {
  106. object[key] = result;
  107. }
  108. }
  109. return object;
  110. }
  111. /**
  112. * The base implementation of `_.assign` without support for argument juggling,
  113. * multiple sources, and `customizer` functions.
  114. *
  115. * @private
  116. * @param {Object} object The destination object.
  117. * @param {Object} source The source object.
  118. * @returns {Object} Returns `object`.
  119. */
  120. function baseAssign(object, source) {
  121. return source == null
  122. ? object
  123. : baseCopy(source, keys(source), object);
  124. }
  125. /**
  126. * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
  127. * `SyntaxError`, `TypeError`, or `URIError` object.
  128. *
  129. * @static
  130. * @memberOf _
  131. * @category Lang
  132. * @param {*} value The value to check.
  133. * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
  134. * @example
  135. *
  136. * _.isError(new Error);
  137. * // => true
  138. *
  139. * _.isError(Error);
  140. * // => false
  141. */
  142. function isError(value) {
  143. return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag;
  144. }
  145. /**
  146. * Creates a compiled template function that can interpolate data properties
  147. * in "interpolate" delimiters, HTML-escape interpolated data properties in
  148. * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
  149. * properties may be accessed as free variables in the template. If a setting
  150. * object is provided it takes precedence over `_.templateSettings` values.
  151. *
  152. * **Note:** In the development build `_.template` utilizes
  153. * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
  154. * for easier debugging.
  155. *
  156. * For more information on precompiling templates see
  157. * [lodash's custom builds documentation](https://lodash.com/custom-builds).
  158. *
  159. * For more information on Chrome extension sandboxes see
  160. * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
  161. *
  162. * @static
  163. * @memberOf _
  164. * @category String
  165. * @param {string} [string=''] The template string.
  166. * @param {Object} [options] The options object.
  167. * @param {RegExp} [options.escape] The HTML "escape" delimiter.
  168. * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
  169. * @param {Object} [options.imports] An object to import into the template as free variables.
  170. * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
  171. * @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
  172. * @param {string} [options.variable] The data object variable name.
  173. * @param- {Object} [otherOptions] Enables the legacy `options` param signature.
  174. * @returns {Function} Returns the compiled template function.
  175. * @example
  176. *
  177. * // using the "interpolate" delimiter to create a compiled template
  178. * var compiled = _.template('hello <%= user %>!');
  179. * compiled({ 'user': 'fred' });
  180. * // => 'hello fred!'
  181. *
  182. * // using the HTML "escape" delimiter to escape data property values
  183. * var compiled = _.template('<b><%- value %></b>');
  184. * compiled({ 'value': '<script>' });
  185. * // => '<b>&lt;script&gt;</b>'
  186. *
  187. * // using the "evaluate" delimiter to execute JavaScript and generate HTML
  188. * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
  189. * compiled({ 'users': ['fred', 'barney'] });
  190. * // => '<li>fred</li><li>barney</li>'
  191. *
  192. * // using the internal `print` function in "evaluate" delimiters
  193. * var compiled = _.template('<% print("hello " + user); %>!');
  194. * compiled({ 'user': 'barney' });
  195. * // => 'hello barney!'
  196. *
  197. * // using the ES delimiter as an alternative to the default "interpolate" delimiter
  198. * var compiled = _.template('hello ${ user }!');
  199. * compiled({ 'user': 'pebbles' });
  200. * // => 'hello pebbles!'
  201. *
  202. * // using custom template delimiters
  203. * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
  204. * var compiled = _.template('hello {{ user }}!');
  205. * compiled({ 'user': 'mustache' });
  206. * // => 'hello mustache!'
  207. *
  208. * // using backslashes to treat delimiters as plain text
  209. * var compiled = _.template('<%= "\\<%- value %\\>" %>');
  210. * compiled({ 'value': 'ignored' });
  211. * // => '<%- value %>'
  212. *
  213. * // using the `imports` option to import `jQuery` as `jq`
  214. * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
  215. * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
  216. * compiled({ 'users': ['fred', 'barney'] });
  217. * // => '<li>fred</li><li>barney</li>'
  218. *
  219. * // using the `sourceURL` option to specify a custom sourceURL for the template
  220. * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
  221. * compiled(data);
  222. * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
  223. *
  224. * // using the `variable` option to ensure a with-statement isn't used in the compiled template
  225. * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
  226. * compiled.source;
  227. * // => function(data) {
  228. * // var __t, __p = '';
  229. * // __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
  230. * // return __p;
  231. * // }
  232. *
  233. * // using the `source` property to inline compiled templates for meaningful
  234. * // line numbers in error messages and a stack trace
  235. * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
  236. * var JST = {\
  237. * "main": ' + _.template(mainText).source + '\
  238. * };\
  239. * ');
  240. */
  241. function template(string, options, otherOptions) {
  242. // Based on John Resig's `tmpl` implementation (http://ejohn.org/blog/javascript-micro-templating/)
  243. // and Laura Doktorova's doT.js (https://github.com/olado/doT).
  244. var settings = templateSettings.imports._.templateSettings || templateSettings;
  245. if (otherOptions && isIterateeCall(string, options, otherOptions)) {
  246. options = otherOptions = undefined;
  247. }
  248. string = baseToString(string);
  249. options = assignWith(baseAssign({}, otherOptions || options), settings, assignOwnDefaults);
  250. var imports = assignWith(baseAssign({}, options.imports), settings.imports, assignOwnDefaults),
  251. importsKeys = keys(imports),
  252. importsValues = baseValues(imports, importsKeys);
  253. var isEscaping,
  254. isEvaluating,
  255. index = 0,
  256. interpolate = options.interpolate || reNoMatch,
  257. source = "__p += '";
  258. // Compile the regexp to match each delimiter.
  259. var reDelimiters = RegExp(
  260. (options.escape || reNoMatch).source + '|' +
  261. interpolate.source + '|' +
  262. (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
  263. (options.evaluate || reNoMatch).source + '|$'
  264. , 'g');
  265. // Use a sourceURL for easier debugging.
  266. var sourceURL = 'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\n' : '';
  267. string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
  268. interpolateValue || (interpolateValue = esTemplateValue);
  269. // Escape characters that can't be included in string literals.
  270. source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
  271. // Replace delimiters with snippets.
  272. if (escapeValue) {
  273. isEscaping = true;
  274. source += "' +\n__e(" + escapeValue + ") +\n'";
  275. }
  276. if (evaluateValue) {
  277. isEvaluating = true;
  278. source += "';\n" + evaluateValue + ";\n__p += '";
  279. }
  280. if (interpolateValue) {
  281. source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
  282. }
  283. index = offset + match.length;
  284. // The JS engine embedded in Adobe products requires returning the `match`
  285. // string in order to produce the correct `offset` value.
  286. return match;
  287. });
  288. source += "';\n";
  289. // If `variable` is not specified wrap a with-statement around the generated
  290. // code to add the data object to the top of the scope chain.
  291. var variable = options.variable;
  292. if (!variable) {
  293. source = 'with (obj) {\n' + source + '\n}\n';
  294. }
  295. // Cleanup code by stripping empty strings.
  296. source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
  297. .replace(reEmptyStringMiddle, '$1')
  298. .replace(reEmptyStringTrailing, '$1;');
  299. // Frame code as the function body.
  300. source = 'function(' + (variable || 'obj') + ') {\n' +
  301. (variable
  302. ? ''
  303. : 'obj || (obj = {});\n'
  304. ) +
  305. "var __t, __p = ''" +
  306. (isEscaping
  307. ? ', __e = _.escape'
  308. : ''
  309. ) +
  310. (isEvaluating
  311. ? ', __j = Array.prototype.join;\n' +
  312. "function print() { __p += __j.call(arguments, '') }\n"
  313. : ';\n'
  314. ) +
  315. source +
  316. 'return __p\n}';
  317. var result = attempt(function() {
  318. return Function(importsKeys, sourceURL + 'return ' + source).apply(undefined, importsValues);
  319. });
  320. // Provide the compiled function's source by its `toString` method or
  321. // the `source` property as a convenience for inlining compiled templates.
  322. result.source = source;
  323. if (isError(result)) {
  324. throw result;
  325. }
  326. return result;
  327. }
  328. /**
  329. * Attempts to invoke `func`, returning either the result or the caught error
  330. * object. Any additional arguments are provided to `func` when it is invoked.
  331. *
  332. * @static
  333. * @memberOf _
  334. * @category Utility
  335. * @param {Function} func The function to attempt.
  336. * @returns {*} Returns the `func` result or error object.
  337. * @example
  338. *
  339. * // avoid throwing errors for invalid selectors
  340. * var elements = _.attempt(function(selector) {
  341. * return document.querySelectorAll(selector);
  342. * }, '>_>');
  343. *
  344. * if (_.isError(elements)) {
  345. * elements = [];
  346. * }
  347. */
  348. var attempt = restParam(function(func, args) {
  349. try {
  350. return func.apply(undefined, args);
  351. } catch(e) {
  352. return isError(e) ? e : new Error(e);
  353. }
  354. });
  355. module.exports = template;