trunc.js 3.42 KB
define(['../internal/baseToString', '../internal/isIterateeCall', '../lang/isObject', '../lang/isRegExp'], function(baseToString, isIterateeCall, isObject, isRegExp) {

  /** Used as a safe reference for `undefined` in pre-ES5 environments. */
  var undefined;

  /** Used as default options for `_.trunc`. */
  var DEFAULT_TRUNC_LENGTH = 30,
      DEFAULT_TRUNC_OMISSION = '...';

  /** Used to match `RegExp` flags from their coerced string values. */
  var reFlags = /\w*$/;

  /**
   * Truncates `string` if it's longer than the given maximum string length.
   * The last characters of the truncated string are replaced with the omission
   * string which defaults to "...".
   *
   * @static
   * @memberOf _
   * @category String
   * @param {string} [string=''] The string to truncate.
   * @param {Object|number} [options] The options object or maximum string length.
   * @param {number} [options.length=30] The maximum string length.
   * @param {string} [options.omission='...'] The string to indicate text is omitted.
   * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
   * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
   * @returns {string} Returns the truncated string.
   * @example
   *
   * _.trunc('hi-diddly-ho there, neighborino');
   * // => 'hi-diddly-ho there, neighbo...'
   *
   * _.trunc('hi-diddly-ho there, neighborino', 24);
   * // => 'hi-diddly-ho there, n...'
   *
   * _.trunc('hi-diddly-ho there, neighborino', {
   *   'length': 24,
   *   'separator': ' '
   * });
   * // => 'hi-diddly-ho there,...'
   *
   * _.trunc('hi-diddly-ho there, neighborino', {
   *   'length': 24,
   *   'separator': /,? +/
   * });
   * // => 'hi-diddly-ho there...'
   *
   * _.trunc('hi-diddly-ho there, neighborino', {
   *   'omission': ' [...]'
   * });
   * // => 'hi-diddly-ho there, neig [...]'
   */
  function trunc(string, options, guard) {
    if (guard && isIterateeCall(string, options, guard)) {
      options = undefined;
    }
    var length = DEFAULT_TRUNC_LENGTH,
        omission = DEFAULT_TRUNC_OMISSION;

    if (options != null) {
      if (isObject(options)) {
        var separator = 'separator' in options ? options.separator : separator;
        length = 'length' in options ? (+options.length || 0) : length;
        omission = 'omission' in options ? baseToString(options.omission) : omission;
      } else {
        length = +options || 0;
      }
    }
    string = baseToString(string);
    if (length >= string.length) {
      return string;
    }
    var end = length - omission.length;
    if (end < 1) {
      return omission;
    }
    var result = string.slice(0, end);
    if (separator == null) {
      return result + omission;
    }
    if (isRegExp(separator)) {
      if (string.slice(end).search(separator)) {
        var match,
            newEnd,
            substring = string.slice(0, end);

        if (!separator.global) {
          separator = RegExp(separator.source, (reFlags.exec(separator) || '') + 'g');
        }
        separator.lastIndex = 0;
        while ((match = separator.exec(substring))) {
          newEnd = match.index;
        }
        result = result.slice(0, newEnd == null ? end : newEnd);
      }
    } else if (string.indexOf(separator, end) != end) {
      var index = result.lastIndexOf(separator);
      if (index > -1) {
        result = result.slice(0, index);
      }
    }
    return result + omission;
  }

  return trunc;
});