{"version":3,"file":"swapIndices.cjs","names":["purry"],"sources":["../src/swapIndices.ts"],"sourcesContent":["import type { And, IsEqual, Join } from \"type-fest\";\nimport type { IterableContainer } from \"./internal/types/IterableContainer\";\nimport { purry } from \"./purry\";\n\ntype Difference<A extends number, B extends number> =\n  TupleOfLength<A> extends [...infer U, ...TupleOfLength<B>]\n    ? U[\"length\"]\n    : never;\n\ntype isLessThan<A extends number, B extends number> =\n  IsEqual<A, B> extends true\n    ? false\n    : 0 extends A\n      ? true\n      : 0 extends B\n        ? false\n        : isLessThan<Difference<A, 1>, Difference<B, 1>>;\n\ntype TupleOfLength<\n  L extends number,\n  T extends IterableContainer = [],\n> = T[\"length\"] extends L ? T : TupleOfLength<L, [...T, unknown]>;\n\ntype IsNonNegative<T extends number> = number extends T\n  ? false\n  : `${T}` extends `-${string}`\n    ? false\n    : true;\n\ntype CharactersTuple<T extends string> = string extends T\n  ? string[]\n  : T extends `${infer C}${infer R}`\n    ? [C, ...CharactersTuple<R>]\n    : [];\n\ntype SwapArrayInternal<\n  T extends IterableContainer,\n  Index1 extends number,\n  Index2 extends number,\n  Position extends readonly unknown[] = [],\n  Original extends IterableContainer = T,\n> = T extends readonly [infer AtPosition, ...infer Rest]\n  ? [\n      Position[\"length\"] extends Index1\n        ? Original[Index2]\n        : Position[\"length\"] extends Index2\n          ? Original[Index1]\n          : AtPosition,\n      ...SwapArrayInternal<\n        Rest,\n        Index1,\n        Index2,\n        [unknown, ...Position],\n        Original\n      >,\n    ]\n  : T;\n\ntype SwapString<T extends string, K1 extends number, K2 extends number> = Join<\n  SwapArray<CharactersTuple<T>, K1, K2>,\n  \"\"\n>;\n\ntype SwapArray<\n  T extends IterableContainer,\n  K1 extends number,\n  K2 extends number,\n> =\n  And<IsNonNegative<K1>, IsNonNegative<K2>> extends true\n    ? And<isLessThan<K1, T[\"length\"]>, isLessThan<K2, T[\"length\"]>> extends true\n      ? SwapArrayInternal<T, K1, K2>\n      : // If the indices are not within the input arrays range the result would\n        // be trivially the same as the input array.\n        T\n    : // TODO [>3]: Because of limitations on the typescript version used in Remeda we can't build a proper Absolute number type so we can't implement proper typing for negative indices and have to opt for a less-strict type instead. Check out the history for the PR that introduced this TODO to see how it could be implemented.\n      T[number][];\n\ntype SwappedIndices<\n  T extends IterableContainer | string,\n  K1 extends number,\n  K2 extends number,\n> = T extends string\n  ? SwapString<T, K1, K2>\n  : T extends IterableContainer\n    ? SwapArray<T, K1, K2>\n    : never;\n\n/**\n * Swaps the positions of two elements in an array or string at the provided indices.\n *\n * Negative indices are supported and would be treated as an offset from the end of the array. The resulting type thought would be less strict than when using positive indices.\n *\n * If either index is out of bounds the result would be a shallow copy of the input, as-is.\n *\n * @param data - The item to be manipulated. This can be an array, or a string.\n * @param index1 - The first index.\n * @param index2 - The second index.\n * @returns Returns the manipulated array or string.\n * @signature\n *   swapIndices(data, index1, index2)\n * @example\n *   swapIndices(['a', 'b', 'c'], 0, 1) // => ['b', 'a', 'c']\n *   swapIndices(['a', 'b', 'c'], 1, -1) // => ['a', 'c', 'b']\n *   swapIndices('abc', 0, 1) // => 'bac'\n * @dataFirst\n * @category Array\n */\nexport function swapIndices<\n  T extends IterableContainer | string,\n  K1 extends number,\n  K2 extends number,\n>(data: T, index1: K1, index2: K2): SwappedIndices<T, K1, K2>;\n\n/**\n * Swaps the positions of two elements in an array or string at the provided indices.\n *\n * Negative indices are supported and would be treated as an offset from the end of the array. The resulting type thought would be less strict than when using positive indices.\n *\n * If either index is out of bounds the result would be a shallow copy of the input, as-is.\n *\n * @param index1 - The first index.\n * @param index2 - The second index.\n * @returns Returns the manipulated array or string.\n * @signature\n *   swapIndices(index1, index2)(data)\n * @example\n *   swapIndices(0, 1)(['a', 'b', 'c']) // => ['b', 'a', 'c']\n *   swapIndices(0, -1)('abc') // => 'cba'\n * @dataLast\n * @category Array\n */\nexport function swapIndices<K1 extends number, K2 extends number>(\n  index1: K1,\n  index2: K2,\n): <T extends IterableContainer | string>(data: T) => SwappedIndices<T, K1, K2>;\n\nexport function swapIndices(...args: readonly unknown[]): unknown {\n  return purry(swapIndicesImplementation, args);\n}\n\nconst swapIndicesImplementation = (\n  data: IterableContainer | string,\n  index1: number,\n  index2: number,\n): unknown =>\n  typeof data === \"string\"\n    ? // eslint-disable-next-line @typescript-eslint/no-misused-spread -- TODO: I'm not sure what the right way to split the string here, there are multiple \"correct\" answers and each one is meaningfully different: https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2521\n      swapArray([...data], index1, index2).join(\"\")\n    : swapArray(data, index1, index2);\n\nfunction swapArray(\n  data: readonly unknown[],\n  index1: number,\n  index2: number,\n): unknown[] {\n  const result = [...data];\n\n  if (Number.isNaN(index1) || Number.isNaN(index2)) {\n    return result;\n  }\n\n  const positiveIndexA = index1 < 0 ? data.length + index1 : index1;\n  const positiveIndexB = index2 < 0 ? data.length + index2 : index2;\n\n  if (positiveIndexA < 0 || positiveIndexA > data.length) {\n    return result;\n  }\n\n  if (positiveIndexB < 0 || positiveIndexB > data.length) {\n    return result;\n  }\n\n  result[positiveIndexA] = data[positiveIndexB];\n  result[positiveIndexB] = data[positiveIndexA];\n\n  return result;\n}\n"],"mappings":"kGAwIA,SAAgB,EAAY,GAAG,EAAmC,CAChE,OAAOA,EAAAA,MAAM,EAA2B,EAAK,CAG/C,MAAM,GACJ,EACA,EACA,IAEA,OAAO,GAAS,SAEZ,EAAU,CAAC,GAAG,EAAK,CAAE,EAAQ,EAAO,CAAC,KAAK,GAAG,CAC7C,EAAU,EAAM,EAAQ,EAAO,CAErC,SAAS,EACP,EACA,EACA,EACW,CACX,IAAM,EAAS,CAAC,GAAG,EAAK,CAExB,GAAI,OAAO,MAAM,EAAO,EAAI,OAAO,MAAM,EAAO,CAC9C,OAAO,EAGT,IAAM,EAAiB,EAAS,EAAI,EAAK,OAAS,EAAS,EACrD,EAAiB,EAAS,EAAI,EAAK,OAAS,EAAS,EAa3D,OAXI,EAAiB,GAAK,EAAiB,EAAK,QAI5C,EAAiB,GAAK,EAAiB,EAAK,OACvC,GAGT,EAAO,GAAkB,EAAK,GAC9B,EAAO,GAAkB,EAAK,GAEvB"}