index.js
1 /** 2 * lodash (Custom Build) <https://lodash.com/> 3 * Build: `lodash modularize exports="npm" -o ./` 4 * Copyright jQuery Foundation and other contributors <https://jquery.org/> 5 * Released under MIT license <https://lodash.com/license> 6 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> 7 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 8 */ 9 10 /** Used as default options for `_.truncate`. */ 11 var DEFAULT_TRUNC_LENGTH = 30, 12 DEFAULT_TRUNC_OMISSION = '...'; 13 14 /** Used as references for various `Number` constants. */ 15 var INFINITY = 1 / 0, 16 MAX_INTEGER = 1.7976931348623157e+308, 17 NAN = 0 / 0; 18 19 /** `Object#toString` result references. */ 20 var regexpTag = '[object RegExp]', 21 symbolTag = '[object Symbol]'; 22 23 /** Used to match leading and trailing whitespace. */ 24 var reTrim = /^\s+|\s+$/g; 25 26 /** Used to match `RegExp` flags from their coerced string values. */ 27 var reFlags = /\w*$/; 28 29 /** Used to detect bad signed hexadecimal string values. */ 30 var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; 31 32 /** Used to detect binary string values. */ 33 var reIsBinary = /^0b[01]+$/i; 34 35 /** Used to detect octal string values. */ 36 var reIsOctal = /^0o[0-7]+$/i; 37 38 /** Used to compose unicode character classes. */ 39 var rsAstralRange = '\\ud800-\\udfff', 40 rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23', 41 rsComboSymbolsRange = '\\u20d0-\\u20f0', 42 rsVarRange = '\\ufe0e\\ufe0f'; 43 44 /** Used to compose unicode capture groups. */ 45 var rsAstral = '[' + rsAstralRange + ']', 46 rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']', 47 rsFitz = '\\ud83c[\\udffb-\\udfff]', 48 rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', 49 rsNonAstral = '[^' + rsAstralRange + ']', 50 rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', 51 rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', 52 rsZWJ = '\\u200d'; 53 54 /** Used to compose unicode regexes. */ 55 var reOptMod = rsModifier + '?', 56 rsOptVar = '[' + rsVarRange + ']?', 57 rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', 58 rsSeq = rsOptVar + reOptMod + rsOptJoin, 59 rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; 60 61 /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ 62 var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); 63 64 /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ 65 var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboMarksRange + rsComboSymbolsRange + rsVarRange + ']'); 66 67 /** Built-in method references without a dependency on `root`. */ 68 var freeParseInt = parseInt; 69 70 /** Detect free variable `global` from Node.js. */ 71 var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; 72 73 /** Detect free variable `self`. */ 74 var freeSelf = typeof self == 'object' && self && self.Object === Object && self; 75 76 /** Used as a reference to the global object. */ 77 var root = freeGlobal || freeSelf || Function('return this')(); 78 79 /** Detect free variable `exports`. */ 80 var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; 81 82 /** Detect free variable `module`. */ 83 var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; 84 85 /** Detect the popular CommonJS extension `module.exports`. */ 86 var moduleExports = freeModule && freeModule.exports === freeExports; 87 88 /** Detect free variable `process` from Node.js. */ 89 var freeProcess = moduleExports && freeGlobal.process; 90 91 /** Used to access faster Node.js helpers. */ 92 var nodeUtil = (function() { 93 try { 94 return freeProcess && freeProcess.binding('util'); 95 } catch (e) {} 96 }()); 97 98 /* Node.js helper references. */ 99 var nodeIsRegExp = nodeUtil && nodeUtil.isRegExp; 100 101 /** 102 * Gets the size of an ASCII `string`. 103 * 104 * @private 105 * @param {string} string The string inspect. 106 * @returns {number} Returns the string size. 107 */ 108 var asciiSize = baseProperty('length'); 109 110 /** 111 * Converts an ASCII `string` to an array. 112 * 113 * @private 114 * @param {string} string The string to convert. 115 * @returns {Array} Returns the converted array. 116 */ 117 function asciiToArray(string) { 118 return string.split(''); 119 } 120 121 /** 122 * The base implementation of `_.property` without support for deep paths. 123 * 124 * @private 125 * @param {string} key The key of the property to get. 126 * @returns {Function} Returns the new accessor function. 127 */ 128 function baseProperty(key) { 129 return function(object) { 130 return object == null ? undefined : object[key]; 131 }; 132 } 133 134 /** 135 * The base implementation of `_.unary` without support for storing metadata. 136 * 137 * @private 138 * @param {Function} func The function to cap arguments for. 139 * @returns {Function} Returns the new capped function. 140 */ 141 function baseUnary(func) { 142 return function(value) { 143 return func(value); 144 }; 145 } 146 147 /** 148 * Checks if `string` contains Unicode symbols. 149 * 150 * @private 151 * @param {string} string The string to inspect. 152 * @returns {boolean} Returns `true` if a symbol is found, else `false`. 153 */ 154 function hasUnicode(string) { 155 return reHasUnicode.test(string); 156 } 157 158 /** 159 * Gets the number of symbols in `string`. 160 * 161 * @private 162 * @param {string} string The string to inspect. 163 * @returns {number} Returns the string size. 164 */ 165 function stringSize(string) { 166 return hasUnicode(string) 167 ? unicodeSize(string) 168 : asciiSize(string); 169 } 170 171 /** 172 * Converts `string` to an array. 173 * 174 * @private 175 * @param {string} string The string to convert. 176 * @returns {Array} Returns the converted array. 177 */ 178 function stringToArray(string) { 179 return hasUnicode(string) 180 ? unicodeToArray(string) 181 : asciiToArray(string); 182 } 183 184 /** 185 * Gets the size of a Unicode `string`. 186 * 187 * @private 188 * @param {string} string The string inspect. 189 * @returns {number} Returns the string size. 190 */ 191 function unicodeSize(string) { 192 var result = reUnicode.lastIndex = 0; 193 while (reUnicode.test(string)) { 194 result++; 195 } 196 return result; 197 } 198 199 /** 200 * Converts a Unicode `string` to an array. 201 * 202 * @private 203 * @param {string} string The string to convert. 204 * @returns {Array} Returns the converted array. 205 */ 206 function unicodeToArray(string) { 207 return string.match(reUnicode) || []; 208 } 209 210 /** Used for built-in method references. */ 211 var objectProto = Object.prototype; 212 213 /** 214 * Used to resolve the 215 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) 216 * of values. 217 */ 218 var objectToString = objectProto.toString; 219 220 /** Built-in value references. */ 221 var Symbol = root.Symbol; 222 223 /** Used to convert symbols to primitives and strings. */ 224 var symbolProto = Symbol ? Symbol.prototype : undefined, 225 symbolToString = symbolProto ? symbolProto.toString : undefined; 226 227 /** 228 * The base implementation of `_.isRegExp` without Node.js optimizations. 229 * 230 * @private 231 * @param {*} value The value to check. 232 * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. 233 */ 234 function baseIsRegExp(value) { 235 return isObject(value) && objectToString.call(value) == regexpTag; 236 } 237 238 /** 239 * The base implementation of `_.slice` without an iteratee call guard. 240 * 241 * @private 242 * @param {Array} array The array to slice. 243 * @param {number} [start=0] The start position. 244 * @param {number} [end=array.length] The end position. 245 * @returns {Array} Returns the slice of `array`. 246 */ 247 function baseSlice(array, start, end) { 248 var index = -1, 249 length = array.length; 250 251 if (start < 0) { 252 start = -start > length ? 0 : (length + start); 253 } 254 end = end > length ? length : end; 255 if (end < 0) { 256 end += length; 257 } 258 length = start > end ? 0 : ((end - start) >>> 0); 259 start >>>= 0; 260 261 var result = Array(length); 262 while (++index < length) { 263 result[index] = array[index + start]; 264 } 265 return result; 266 } 267 268 /** 269 * The base implementation of `_.toString` which doesn't convert nullish 270 * values to empty strings. 271 * 272 * @private 273 * @param {*} value The value to process. 274 * @returns {string} Returns the string. 275 */ 276 function baseToString(value) { 277 // Exit early for strings to avoid a performance hit in some environments. 278 if (typeof value == 'string') { 279 return value; 280 } 281 if (isSymbol(value)) { 282 return symbolToString ? symbolToString.call(value) : ''; 283 } 284 var result = (value + ''); 285 return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 286 } 287 288 /** 289 * Casts `array` to a slice if it's needed. 290 * 291 * @private 292 * @param {Array} array The array to inspect. 293 * @param {number} start The start position. 294 * @param {number} [end=array.length] The end position. 295 * @returns {Array} Returns the cast slice. 296 */ 297 function castSlice(array, start, end) { 298 var length = array.length; 299 end = end === undefined ? length : end; 300 return (!start && end >= length) ? array : baseSlice(array, start, end); 301 } 302 303 /** 304 * Checks if `value` is the 305 * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) 306 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 307 * 308 * @static 309 * @memberOf _ 310 * @since 0.1.0 311 * @category Lang 312 * @param {*} value The value to check. 313 * @returns {boolean} Returns `true` if `value` is an object, else `false`. 314 * @example 315 * 316 * _.isObject({}); 317 * // => true 318 * 319 * _.isObject([1, 2, 3]); 320 * // => true 321 * 322 * _.isObject(_.noop); 323 * // => true 324 * 325 * _.isObject(null); 326 * // => false 327 */ 328 function isObject(value) { 329 var type = typeof value; 330 return !!value && (type == 'object' || type == 'function'); 331 } 332 333 /** 334 * Checks if `value` is object-like. A value is object-like if it's not `null` 335 * and has a `typeof` result of "object". 336 * 337 * @static 338 * @memberOf _ 339 * @since 4.0.0 340 * @category Lang 341 * @param {*} value The value to check. 342 * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 343 * @example 344 * 345 * _.isObjectLike({}); 346 * // => true 347 * 348 * _.isObjectLike([1, 2, 3]); 349 * // => true 350 * 351 * _.isObjectLike(_.noop); 352 * // => false 353 * 354 * _.isObjectLike(null); 355 * // => false 356 */ 357 function isObjectLike(value) { 358 return !!value && typeof value == 'object'; 359 } 360 361 /** 362 * Checks if `value` is classified as a `RegExp` object. 363 * 364 * @static 365 * @memberOf _ 366 * @since 0.1.0 367 * @category Lang 368 * @param {*} value The value to check. 369 * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. 370 * @example 371 * 372 * _.isRegExp(/abc/); 373 * // => true 374 * 375 * _.isRegExp('/abc/'); 376 * // => false 377 */ 378 var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; 379 380 /** 381 * Checks if `value` is classified as a `Symbol` primitive or object. 382 * 383 * @static 384 * @memberOf _ 385 * @since 4.0.0 386 * @category Lang 387 * @param {*} value The value to check. 388 * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. 389 * @example 390 * 391 * _.isSymbol(Symbol.iterator); 392 * // => true 393 * 394 * _.isSymbol('abc'); 395 * // => false 396 */ 397 function isSymbol(value) { 398 return typeof value == 'symbol' || 399 (isObjectLike(value) && objectToString.call(value) == symbolTag); 400 } 401 402 /** 403 * Converts `value` to a finite number. 404 * 405 * @static 406 * @memberOf _ 407 * @since 4.12.0 408 * @category Lang 409 * @param {*} value The value to convert. 410 * @returns {number} Returns the converted number. 411 * @example 412 * 413 * _.toFinite(3.2); 414 * // => 3.2 415 * 416 * _.toFinite(Number.MIN_VALUE); 417 * // => 5e-324 418 * 419 * _.toFinite(Infinity); 420 * // => 1.7976931348623157e+308 421 * 422 * _.toFinite('3.2'); 423 * // => 3.2 424 */ 425 function toFinite(value) { 426 if (!value) { 427 return value === 0 ? value : 0; 428 } 429 value = toNumber(value); 430 if (value === INFINITY || value === -INFINITY) { 431 var sign = (value < 0 ? -1 : 1); 432 return sign * MAX_INTEGER; 433 } 434 return value === value ? value : 0; 435 } 436 437 /** 438 * Converts `value` to an integer. 439 * 440 * **Note:** This method is loosely based on 441 * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). 442 * 443 * @static 444 * @memberOf _ 445 * @since 4.0.0 446 * @category Lang 447 * @param {*} value The value to convert. 448 * @returns {number} Returns the converted integer. 449 * @example 450 * 451 * _.toInteger(3.2); 452 * // => 3 453 * 454 * _.toInteger(Number.MIN_VALUE); 455 * // => 0 456 * 457 * _.toInteger(Infinity); 458 * // => 1.7976931348623157e+308 459 * 460 * _.toInteger('3.2'); 461 * // => 3 462 */ 463 function toInteger(value) { 464 var result = toFinite(value), 465 remainder = result % 1; 466 467 return result === result ? (remainder ? result - remainder : result) : 0; 468 } 469 470 /** 471 * Converts `value` to a number. 472 * 473 * @static 474 * @memberOf _ 475 * @since 4.0.0 476 * @category Lang 477 * @param {*} value The value to process. 478 * @returns {number} Returns the number. 479 * @example 480 * 481 * _.toNumber(3.2); 482 * // => 3.2 483 * 484 * _.toNumber(Number.MIN_VALUE); 485 * // => 5e-324 486 * 487 * _.toNumber(Infinity); 488 * // => Infinity 489 * 490 * _.toNumber('3.2'); 491 * // => 3.2 492 */ 493 function toNumber(value) { 494 if (typeof value == 'number') { 495 return value; 496 } 497 if (isSymbol(value)) { 498 return NAN; 499 } 500 if (isObject(value)) { 501 var other = typeof value.valueOf == 'function' ? value.valueOf() : value; 502 value = isObject(other) ? (other + '') : other; 503 } 504 if (typeof value != 'string') { 505 return value === 0 ? value : +value; 506 } 507 value = value.replace(reTrim, ''); 508 var isBinary = reIsBinary.test(value); 509 return (isBinary || reIsOctal.test(value)) 510 ? freeParseInt(value.slice(2), isBinary ? 2 : 8) 511 : (reIsBadHex.test(value) ? NAN : +value); 512 } 513 514 /** 515 * Converts `value` to a string. An empty string is returned for `null` 516 * and `undefined` values. The sign of `-0` is preserved. 517 * 518 * @static 519 * @memberOf _ 520 * @since 4.0.0 521 * @category Lang 522 * @param {*} value The value to process. 523 * @returns {string} Returns the string. 524 * @example 525 * 526 * _.toString(null); 527 * // => '' 528 * 529 * _.toString(-0); 530 * // => '-0' 531 * 532 * _.toString([1, 2, 3]); 533 * // => '1,2,3' 534 */ 535 function toString(value) { 536 return value == null ? '' : baseToString(value); 537 } 538 539 /** 540 * Truncates `string` if it's longer than the given maximum string length. 541 * The last characters of the truncated string are replaced with the omission 542 * string which defaults to "...". 543 * 544 * @static 545 * @memberOf _ 546 * @since 4.0.0 547 * @category String 548 * @param {string} [string=''] The string to truncate. 549 * @param {Object} [options={}] The options object. 550 * @param {number} [options.length=30] The maximum string length. 551 * @param {string} [options.omission='...'] The string to indicate text is omitted. 552 * @param {RegExp|string} [options.separator] The separator pattern to truncate to. 553 * @returns {string} Returns the truncated string. 554 * @example 555 * 556 * _.truncate('hi-diddly-ho there, neighborino'); 557 * // => 'hi-diddly-ho there, neighbo...' 558 * 559 * _.truncate('hi-diddly-ho there, neighborino', { 560 * 'length': 24, 561 * 'separator': ' ' 562 * }); 563 * // => 'hi-diddly-ho there,...' 564 * 565 * _.truncate('hi-diddly-ho there, neighborino', { 566 * 'length': 24, 567 * 'separator': /,? +/ 568 * }); 569 * // => 'hi-diddly-ho there...' 570 * 571 * _.truncate('hi-diddly-ho there, neighborino', { 572 * 'omission': ' [...]' 573 * }); 574 * // => 'hi-diddly-ho there, neig [...]' 575 */ 576 function truncate(string, options) { 577 var length = DEFAULT_TRUNC_LENGTH, 578 omission = DEFAULT_TRUNC_OMISSION; 579 580 if (isObject(options)) { 581 var separator = 'separator' in options ? options.separator : separator; 582 length = 'length' in options ? toInteger(options.length) : length; 583 omission = 'omission' in options ? baseToString(options.omission) : omission; 584 } 585 string = toString(string); 586 587 var strLength = string.length; 588 if (hasUnicode(string)) { 589 var strSymbols = stringToArray(string); 590 strLength = strSymbols.length; 591 } 592 if (length >= strLength) { 593 return string; 594 } 595 var end = length - stringSize(omission); 596 if (end < 1) { 597 return omission; 598 } 599 var result = strSymbols 600 ? castSlice(strSymbols, 0, end).join('') 601 : string.slice(0, end); 602 603 if (separator === undefined) { 604 return result + omission; 605 } 606 if (strSymbols) { 607 end += (result.length - end); 608 } 609 if (isRegExp(separator)) { 610 if (string.slice(end).search(separator)) { 611 var match, 612 substring = result; 613 614 if (!separator.global) { 615 separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g'); 616 } 617 separator.lastIndex = 0; 618 while ((match = separator.exec(substring))) { 619 var newEnd = match.index; 620 } 621 result = result.slice(0, newEnd === undefined ? end : newEnd); 622 } 623 } else if (string.indexOf(baseToString(separator), end) != end) { 624 var index = result.lastIndexOf(separator); 625 if (index > -1) { 626 result = result.slice(0, index); 627 } 628 } 629 return result + omission; 630 } 631 632 module.exports = truncate;