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
10 /** Used as default options for `_.truncate`. */
11 var DEFAULT_TRUNC_LENGTH = 30,
12 DEFAULT_TRUNC_OMISSION = '...';
14 /** Used as references for various `Number` constants. */
16 MAX_INTEGER = 1.7976931348623157e+308,
19 /** `Object#toString` result references. */
20 var regexpTag = '[object RegExp]',
21 symbolTag = '[object Symbol]';
23 /** Used to match leading and trailing whitespace. */
24 var reTrim = /^\s+|\s+$/g;
26 /** Used to match `RegExp` flags from their coerced string values. */
29 /** Used to detect bad signed hexadecimal string values. */
30 var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
32 /** Used to detect binary string values. */
33 var reIsBinary = /^0b[01]+$/i;
35 /** Used to detect octal string values. */
36 var reIsOctal = /^0o[0-7]+$/i;
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';
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]',
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('|') + ')';
61 /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
62 var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
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 + ']');
67 /** Built-in method references without a dependency on `root`. */
68 var freeParseInt = parseInt;
70 /** Detect free variable `global` from Node.js. */
71 var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
73 /** Detect free variable `self`. */
74 var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
76 /** Used as a reference to the global object. */
77 var root = freeGlobal || freeSelf || Function('return this')();
79 /** Detect free variable `exports`. */
80 var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
82 /** Detect free variable `module`. */
83 var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
85 /** Detect the popular CommonJS extension `module.exports`. */
86 var moduleExports = freeModule && freeModule.exports === freeExports;
88 /** Detect free variable `process` from Node.js. */
89 var freeProcess = moduleExports && freeGlobal.process;
91 /** Used to access faster Node.js helpers. */
92 var nodeUtil = (function() {
94 return freeProcess && freeProcess.binding('util');
98 /* Node.js helper references. */
99 var nodeIsRegExp = nodeUtil && nodeUtil.isRegExp;
102 * Gets the size of an ASCII `string`.
105 * @param {string} string The string inspect.
106 * @returns {number} Returns the string size.
108 var asciiSize = baseProperty('length');
111 * Converts an ASCII `string` to an array.
114 * @param {string} string The string to convert.
115 * @returns {Array} Returns the converted array.
117 function asciiToArray(string) {
118 return string.split('');
122 * The base implementation of `_.property` without support for deep paths.
125 * @param {string} key The key of the property to get.
126 * @returns {Function} Returns the new accessor function.
128 function baseProperty(key) {
129 return function(object) {
130 return object == null ? undefined : object[key];
135 * The base implementation of `_.unary` without support for storing metadata.
138 * @param {Function} func The function to cap arguments for.
139 * @returns {Function} Returns the new capped function.
141 function baseUnary(func) {
142 return function(value) {
148 * Checks if `string` contains Unicode symbols.
151 * @param {string} string The string to inspect.
152 * @returns {boolean} Returns `true` if a symbol is found, else `false`.
154 function hasUnicode(string) {
155 return reHasUnicode.test(string);
159 * Gets the number of symbols in `string`.
162 * @param {string} string The string to inspect.
163 * @returns {number} Returns the string size.
165 function stringSize(string) {
166 return hasUnicode(string)
167 ? unicodeSize(string)
172 * Converts `string` to an array.
175 * @param {string} string The string to convert.
176 * @returns {Array} Returns the converted array.
178 function stringToArray(string) {
179 return hasUnicode(string)
180 ? unicodeToArray(string)
181 : asciiToArray(string);
185 * Gets the size of a Unicode `string`.
188 * @param {string} string The string inspect.
189 * @returns {number} Returns the string size.
191 function unicodeSize(string) {
192 var result = reUnicode.lastIndex = 0;
193 while (reUnicode.test(string)) {
200 * Converts a Unicode `string` to an array.
203 * @param {string} string The string to convert.
204 * @returns {Array} Returns the converted array.
206 function unicodeToArray(string) {
207 return string.match(reUnicode) || [];
210 /** Used for built-in method references. */
211 var objectProto = Object.prototype;
214 * Used to resolve the
215 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
218 var objectToString = objectProto.toString;
220 /** Built-in value references. */
221 var Symbol = root.Symbol;
223 /** Used to convert symbols to primitives and strings. */
224 var symbolProto = Symbol ? Symbol.prototype : undefined,
225 symbolToString = symbolProto ? symbolProto.toString : undefined;
228 * The base implementation of `_.isRegExp` without Node.js optimizations.
231 * @param {*} value The value to check.
232 * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
234 function baseIsRegExp(value) {
235 return isObject(value) && objectToString.call(value) == regexpTag;
239 * The base implementation of `_.slice` without an iteratee call guard.
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`.
247 function baseSlice(array, start, end) {
249 length = array.length;
252 start = -start > length ? 0 : (length + start);
254 end = end > length ? length : end;
258 length = start > end ? 0 : ((end - start) >>> 0);
261 var result = Array(length);
262 while (++index < length) {
263 result[index] = array[index + start];
269 * The base implementation of `_.toString` which doesn't convert nullish
270 * values to empty strings.
273 * @param {*} value The value to process.
274 * @returns {string} Returns the string.
276 function baseToString(value) {
277 // Exit early for strings to avoid a performance hit in some environments.
278 if (typeof value == 'string') {
281 if (isSymbol(value)) {
282 return symbolToString ? symbolToString.call(value) : '';
284 var result = (value + '');
285 return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
289 * Casts `array` to a slice if it's needed.
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.
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);
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('')`)
312 * @param {*} value The value to check.
313 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
319 * _.isObject([1, 2, 3]);
322 * _.isObject(_.noop);
328 function isObject(value) {
329 var type = typeof value;
330 return !!value && (type == 'object' || type == 'function');
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".
341 * @param {*} value The value to check.
342 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
345 * _.isObjectLike({});
348 * _.isObjectLike([1, 2, 3]);
351 * _.isObjectLike(_.noop);
354 * _.isObjectLike(null);
357 function isObjectLike(value) {
358 return !!value && typeof value == 'object';
362 * Checks if `value` is classified as a `RegExp` object.
368 * @param {*} value The value to check.
369 * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
375 * _.isRegExp('/abc/');
378 var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
381 * Checks if `value` is classified as a `Symbol` primitive or object.
387 * @param {*} value The value to check.
388 * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
391 * _.isSymbol(Symbol.iterator);
397 function isSymbol(value) {
398 return typeof value == 'symbol' ||
399 (isObjectLike(value) && objectToString.call(value) == symbolTag);
403 * Converts `value` to a finite number.
409 * @param {*} value The value to convert.
410 * @returns {number} Returns the converted number.
416 * _.toFinite(Number.MIN_VALUE);
419 * _.toFinite(Infinity);
420 * // => 1.7976931348623157e+308
425 function toFinite(value) {
427 return value === 0 ? value : 0;
429 value = toNumber(value);
430 if (value === INFINITY || value === -INFINITY) {
431 var sign = (value < 0 ? -1 : 1);
432 return sign * MAX_INTEGER;
434 return value === value ? value : 0;
438 * Converts `value` to an integer.
440 * **Note:** This method is loosely based on
441 * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
447 * @param {*} value The value to convert.
448 * @returns {number} Returns the converted integer.
454 * _.toInteger(Number.MIN_VALUE);
457 * _.toInteger(Infinity);
458 * // => 1.7976931348623157e+308
460 * _.toInteger('3.2');
463 function toInteger(value) {
464 var result = toFinite(value),
465 remainder = result % 1;
467 return result === result ? (remainder ? result - remainder : result) : 0;
471 * Converts `value` to a number.
477 * @param {*} value The value to process.
478 * @returns {number} Returns the number.
484 * _.toNumber(Number.MIN_VALUE);
487 * _.toNumber(Infinity);
493 function toNumber(value) {
494 if (typeof value == 'number') {
497 if (isSymbol(value)) {
500 if (isObject(value)) {
501 var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
502 value = isObject(other) ? (other + '') : other;
504 if (typeof value != 'string') {
505 return value === 0 ? value : +value;
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);
515 * Converts `value` to a string. An empty string is returned for `null`
516 * and `undefined` values. The sign of `-0` is preserved.
522 * @param {*} value The value to process.
523 * @returns {string} Returns the string.
532 * _.toString([1, 2, 3]);
535 function toString(value) {
536 return value == null ? '' : baseToString(value);
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 "...".
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.
556 * _.truncate('hi-diddly-ho there, neighborino');
557 * // => 'hi-diddly-ho there, neighbo...'
559 * _.truncate('hi-diddly-ho there, neighborino', {
563 * // => 'hi-diddly-ho there,...'
565 * _.truncate('hi-diddly-ho there, neighborino', {
567 * 'separator': /,? +/
569 * // => 'hi-diddly-ho there...'
571 * _.truncate('hi-diddly-ho there, neighborino', {
572 * 'omission': ' [...]'
574 * // => 'hi-diddly-ho there, neig [...]'
576 function truncate(string, options) {
577 var length = DEFAULT_TRUNC_LENGTH,
578 omission = DEFAULT_TRUNC_OMISSION;
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;
585 string = toString(string);
587 var strLength = string.length;
588 if (hasUnicode(string)) {
589 var strSymbols = stringToArray(string);
590 strLength = strSymbols.length;
592 if (length >= strLength) {
595 var end = length - stringSize(omission);
599 var result = strSymbols
600 ? castSlice(strSymbols, 0, end).join('')
601 : string.slice(0, end);
603 if (separator === undefined) {
604 return result + omission;
607 end += (result.length - end);
609 if (isRegExp(separator)) {
610 if (string.slice(end).search(separator)) {
614 if (!separator.global) {
615 separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
617 separator.lastIndex = 0;
618 while ((match = separator.exec(substring))) {
619 var newEnd = match.index;
621 result = result.slice(0, newEnd === undefined ? end : newEnd);
623 } else if (string.indexOf(baseToString(separator), end) != end) {
624 var index = result.lastIndexOf(separator);
626 result = result.slice(0, index);
629 return result + omission;
632 module.exports = truncate;