{"version":3,"file":"findLast.cjs","names":["purry"],"sources":["../src/findLast.ts"],"sourcesContent":["import type { LastArrayElement } from \"type-fest\";\nimport type { Assignability } from \"./internal/types/Assignability\";\nimport type { IterableContainer } from \"./internal/types/IterableContainer\";\nimport type { Narrowed } from \"./internal/types/Narrowed\";\nimport type { TupleParts } from \"./internal/types/TupleParts\";\nimport { purry } from \"./purry\";\n\ntype FoundLast<T extends IterableContainer, Condition> =\n  // We distribute the array type to support unions of arrays/tuples.\n  T extends unknown\n    ? FoundLastInFixedTuple<\n        TupleParts<T>[\"suffix\"],\n        Condition,\n        // When the suffix part doesn't have any item that would always match\n        // we fall back to the optional parts of the tuple which might match.\n        | Narrowed<TupleParts<T>[\"item\"], Condition>\n        | Narrowed<TupleParts<T>[\"optional\"][number], Condition>\n        // The required part is always present, but it precedes every other\n        // part of the tuple, so any match in it is only the last one when the\n        // parts after it have none; this makes it the fallback of them all.\n        | FoundLastInFixedTuple<\n            TupleParts<T>[\"required\"],\n            Condition,\n            // When an item isn't found we need to return `undefined`, but\n            // because it might still always exist in the required part we set\n            // this return value as the fallback of the required part, this way\n            // if the required part has a match the fallback isn't reached and\n            // we don't add the `undefined`, and in any other case the fallback\n            // would make sure we cover this case too.\n            undefined\n          >\n      >\n    : never;\n\n// This type only works under the assumption that T is a simple fixed tuple (no\n// optional items and no rest items)!\ntype FoundLastInFixedTuple<T, Condition, Fallback> = T extends readonly [\n  ...infer Rest,\n  infer Last,\n]\n  ? Assignability<\n      Last,\n      Condition,\n      {\n        full: Last;\n\n        // Because the match isn't full we need to also consider the rest of the\n        // items too because in runtime we might skip the current item.\n        partial:\n          | Narrowed<Last, Condition>\n          | FoundLastInFixedTuple<Rest, Condition, Fallback>;\n        none: FoundLastInFixedTuple<Rest, Condition, Fallback>;\n      }\n    >\n  : Fallback;\n\n// For non-type-narrowing predicates, we can only provide more refined type when\n// we know the predicate returns a constant literal boolean value.\ntype FoundLastNonRefined<\n  T extends IterableContainer,\n  IsItemIncluded extends boolean,\n> = boolean extends IsItemIncluded\n  ? T[number] | undefined\n  : IsItemIncluded extends true\n    ? // `findLast(data, constant(true))` is equivalent to `last(data)`.\n      LastArrayElement<T>\n    : undefined;\n\n/**\n * Iterates the array in reverse order and returns the value of the first\n * element that satisfies the provided testing function. If no elements satisfy\n * the testing function, undefined is returned.\n *\n * Similar functions:\n * * `find` - If you need the first element that satisfies the provided testing function.\n * * `findLastIndex` - If you need the index of the found element in the array.\n * * `lastIndexOf` - If you need to find the index of a value.\n * * `includes` - If you need to find if a value exists in an array.\n * * `some` - If you need to find if any element satisfies the provided testing function.\n * * `filter` - If you need to find all elements that satisfy the provided testing function.\n *\n * @param data - The items to search in.\n * @param predicate - A function to execute for each element in the array. It\n * should return `true` to indicate a matching element has been found, and\n * `false` otherwise. A type-predicate can also be used to narrow the result.\n * @returns The last (highest-index) element in the array that satisfies the\n * provided testing function; undefined if no matching element is found.\n * @signature\n *    findLast(data, predicate)\n * @example\n *    findLast([1, 3, 4, 6], n => n % 2 === 1) // => 3\n * @dataFirst\n * @category Array\n */\nexport function findLast<T extends IterableContainer, Condition>(\n  data: T,\n  predicate: (value: T[number], index: number, data: T) => value is Condition,\n): FoundLast<T, Condition>;\n\nexport function findLast<\n  T extends IterableContainer,\n  IsItemIncluded extends boolean,\n>(\n  data: T,\n  predicate: (value: T[number], index: number, data: T) => IsItemIncluded,\n): FoundLastNonRefined<T, IsItemIncluded>;\n\n/**\n * Iterates the array in reverse order and returns the value of the first\n * element that satisfies the provided testing function. If no elements satisfy\n * the testing function, undefined is returned.\n *\n * Similar functions:\n * * `find` - If you need the first element that satisfies the provided testing function.\n * * `findLastIndex` - If you need the index of the found element in the array.\n * * `lastIndexOf` - If you need to find the index of a value.\n * * `includes` - If you need to find if a value exists in an array.\n * * `some` - If you need to find if any element satisfies the provided testing function.\n * * `filter` - If you need to find all elements that satisfy the provided testing function.\n *\n * @param predicate - A function to execute for each element in the array. It\n * should return `true` to indicate a matching element has been found, and\n * `false` otherwise. A type-predicate can also be used to narrow the result.\n * @returns The last (highest-index) element in the array that satisfies the\n * provided testing function; undefined if no matching element is found.\n * @signature\n *    findLast(predicate)(data)\n * @example\n *    pipe(\n *      [1, 3, 4, 6],\n *      findLast(n => n % 2 === 1)\n *    ) // => 3\n * @dataLast\n * @category Array\n */\nexport function findLast<T extends IterableContainer, Condition>(\n  predicate: (value: T[number], index: number, data: T) => value is Condition,\n): (data: T) => FoundLast<T, Condition>;\n\nexport function findLast<\n  T extends IterableContainer,\n  IsItemIncluded extends boolean,\n>(\n  predicate: (value: T[number], index: number, data: T) => IsItemIncluded,\n): (data: T) => FoundLastNonRefined<T, IsItemIncluded>;\n\nexport function findLast(...args: readonly unknown[]): unknown {\n  return purry(findLastImplementation, args);\n}\n\nconst findLastImplementation = <T, S extends T>(\n  data: readonly T[],\n  predicate: (value: T, index: number, data: readonly T[]) => value is S,\n): S | undefined => {\n  // TODO [>2]: When node 18 reaches end-of-life bump target lib to ES2023+ and use `Array.prototype.findLast` here.\n\n  for (let i = data.length - 1; i >= 0; i--) {\n    const item = data[i]!;\n    if (predicate(item, i, data)) {\n      return item;\n    }\n  }\n\n  return undefined;\n};\n"],"mappings":"kGAkJA,SAAgB,EAAS,GAAG,EAAmC,CAC7D,OAAOA,EAAAA,MAAM,EAAwB,CAAI,CAC3C,CAEA,MAAM,GACJ,EACA,IACkB,CAGlB,IAAK,IAAI,EAAI,EAAK,OAAS,EAAG,GAAK,EAAG,IAAK,CACzC,IAAM,EAAO,EAAK,GAClB,GAAI,EAAU,EAAM,EAAG,CAAI,EACzB,OAAO,CAEX,CAGF"}