|
12 | 12 | var undefined; |
13 | 13 |
|
14 | 14 | /** Used as the semantic version number. */ |
15 | | - var VERSION = '4.17.20'; |
| 15 | + var VERSION = '4.17.21'; |
16 | 16 |
|
17 | 17 | /** Used as the size to enable large array optimizations. */ |
18 | 18 | var LARGE_ARRAY_SIZE = 200; |
19 | 19 |
|
20 | 20 | /** Error message constants. */ |
21 | 21 | var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', |
22 | | - FUNC_ERROR_TEXT = 'Expected a function'; |
| 22 | + FUNC_ERROR_TEXT = 'Expected a function', |
| 23 | + INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`'; |
23 | 24 |
|
24 | 25 | /** Used to stand-in for `undefined` hash values. */ |
25 | 26 | var HASH_UNDEFINED = '__lodash_hash_undefined__'; |
|
152 | 153 | var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, |
153 | 154 | reHasRegExpChar = RegExp(reRegExpChar.source); |
154 | 155 |
|
155 | | - /** Used to match leading and trailing whitespace. */ |
156 | | - var reTrim = /^\s+|\s+$/g, |
157 | | - reTrimStart = /^\s+/, |
158 | | - reTrimEnd = /\s+$/; |
| 156 | + /** Used to match leading whitespace. */ |
| 157 | + var reTrimStart = /^\s+/; |
| 158 | + |
| 159 | + /** Used to match a single whitespace character. */ |
| 160 | + var reWhitespace = /\s/; |
159 | 161 |
|
160 | 162 | /** Used to match wrap detail comments. */ |
161 | 163 | var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, |
|
165 | 167 | /** Used to match words composed of alphanumeric characters. */ |
166 | 168 | var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; |
167 | 169 |
|
| 170 | + /** |
| 171 | + * Used to validate the `validate` option in `_.template` variable. |
| 172 | + * |
| 173 | + * Forbids characters which could potentially change the meaning of the function argument definition: |
| 174 | + * - "()," (modification of function parameters) |
| 175 | + * - "=" (default value) |
| 176 | + * - "[]{}" (destructuring of function parameters) |
| 177 | + * - "/" (beginning of a comment) |
| 178 | + * - whitespace |
| 179 | + */ |
| 180 | + var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/; |
| 181 | + |
168 | 182 | /** Used to match backslashes in property paths. */ |
169 | 183 | var reEscapeChar = /\\(\\)?/g; |
170 | 184 |
|
|
993 | 1007 | }); |
994 | 1008 | } |
995 | 1009 |
|
| 1010 | + /** |
| 1011 | + * The base implementation of `_.trim`. |
| 1012 | + * |
| 1013 | + * @private |
| 1014 | + * @param {string} string The string to trim. |
| 1015 | + * @returns {string} Returns the trimmed string. |
| 1016 | + */ |
| 1017 | + function baseTrim(string) { |
| 1018 | + return string |
| 1019 | + ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') |
| 1020 | + : string; |
| 1021 | + } |
| 1022 | + |
996 | 1023 | /** |
997 | 1024 | * The base implementation of `_.unary` without support for storing metadata. |
998 | 1025 | * |
|
1326 | 1353 | : asciiToArray(string); |
1327 | 1354 | } |
1328 | 1355 |
|
| 1356 | + /** |
| 1357 | + * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace |
| 1358 | + * character of `string`. |
| 1359 | + * |
| 1360 | + * @private |
| 1361 | + * @param {string} string The string to inspect. |
| 1362 | + * @returns {number} Returns the index of the last non-whitespace character. |
| 1363 | + */ |
| 1364 | + function trimmedEndIndex(string) { |
| 1365 | + var index = string.length; |
| 1366 | + |
| 1367 | + while (index-- && reWhitespace.test(string.charAt(index))) {} |
| 1368 | + return index; |
| 1369 | + } |
| 1370 | + |
1329 | 1371 | /** |
1330 | 1372 | * Used by `_.unescape` to convert HTML entities to characters. |
1331 | 1373 | * |
|
12494 | 12536 | if (typeof value != 'string') { |
12495 | 12537 | return value === 0 ? value : +value; |
12496 | 12538 | } |
12497 | | - value = value.replace(reTrim, ''); |
| 12539 | + value = baseTrim(value); |
12498 | 12540 | var isBinary = reIsBinary.test(value); |
12499 | 12541 | return (isBinary || reIsOctal.test(value)) |
12500 | 12542 | ? freeParseInt(value.slice(2), isBinary ? 2 : 8) |
|
14866 | 14908 | if (!variable) { |
14867 | 14909 | source = 'with (obj) {\n' + source + '\n}\n'; |
14868 | 14910 | } |
| 14911 | + // Throw an error if a forbidden character was found in `variable`, to prevent |
| 14912 | + // potential command injection attacks. |
| 14913 | + else if (reForbiddenIdentifierChars.test(variable)) { |
| 14914 | + throw new Error(INVALID_TEMPL_VAR_ERROR_TEXT); |
| 14915 | + } |
| 14916 | + |
14869 | 14917 | // Cleanup code by stripping empty strings. |
14870 | 14918 | source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) |
14871 | 14919 | .replace(reEmptyStringMiddle, '$1') |
|
14979 | 15027 | function trim(string, chars, guard) { |
14980 | 15028 | string = toString(string); |
14981 | 15029 | if (string && (guard || chars === undefined)) { |
14982 | | - return string.replace(reTrim, ''); |
| 15030 | + return baseTrim(string); |
14983 | 15031 | } |
14984 | 15032 | if (!string || !(chars = baseToString(chars))) { |
14985 | 15033 | return string; |
|
15014 | 15062 | function trimEnd(string, chars, guard) { |
15015 | 15063 | string = toString(string); |
15016 | 15064 | if (string && (guard || chars === undefined)) { |
15017 | | - return string.replace(reTrimEnd, ''); |
| 15065 | + return string.slice(0, trimmedEndIndex(string) + 1); |
15018 | 15066 | } |
15019 | 15067 | if (!string || !(chars = baseToString(chars))) { |
15020 | 15068 | return string; |
|
0 commit comments