// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.

/**
 * Options for joinToString
 */
export type JoinToStringOptions = {
  separator?: string;
  prefix?: string;
  suffix?: string;
  limit?: number;
  truncated?: string;
};

/**
 * Transforms the elements in the given array to strings using the given selector.
 * Joins the produced strings into one using the given `separator` and applying the given `prefix` and `suffix` to the whole string afterwards.
 * If the array could be huge, you can specify a non-negative value of `limit`, in which case only the first `limit` elements will be appended, followed by the `truncated` string.
 * Returns the resulting string.
 *
 * Example:
 *
 * ```ts
 * import { joinToString } from "https://deno.land/std@$STD_VERSION/collections/mod.ts";
 * import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
 *
 * const users = [
 *   { name: "Kim" },
 *   { name: "Anna" },
 *   { name: "Tim" },
 * ];
 *
 *  const message = joinToString(users, (it) => it.name, {
 *   suffix: " are winners",
 *   prefix: "result: ",
 *   separator: " and ",
 *   limit: 1,
 *   truncated: "others",
 * });
 *
 * assertEquals(message, "result: Kim and others are winners");
 * ```
 */
export function joinToString<T>(
  array: readonly T[],
  selector: (el: T) => string,
  {
    separator = ",",
    prefix = "",
    suffix = "",
    limit = -1,
    truncated = "...",
  }: Readonly<JoinToStringOptions> = {},
): string {
  let result = "";

  let index = -1;
  while (++index < array.length) {
    const el = array[index];

    if (index > 0) {
      result += separator;
    }

    if (limit > -1 && index >= limit) {
      result += truncated;
      break;
    }

    result += selector(el);
  }

  result = prefix + result + suffix;

  return result;
}
