diff --git a/CHANGELOG.md b/CHANGELOG.md index b44e383e83..2aba263c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ #### :rocket: New Feature - Add `RegExp.flags`. https://github.com/rescript-lang/rescript/pull/7461 +- Add `Array.findLast`, `Array.findLastWithIndex`, `Array.findLastIndex`, `Array.findLastIndexWithIndex` and `Array.findLastIndexOpt`. https://github.com/rescript-lang/rescript/pull/7503 #### :bug: Bug fix diff --git a/lib/es6/Stdlib_Array.js b/lib/es6/Stdlib_Array.js index 5d83e76143..b1bbc32728 100644 --- a/lib/es6/Stdlib_Array.js +++ b/lib/es6/Stdlib_Array.js @@ -106,6 +106,14 @@ function findIndexOpt(array, finder) { } +function findLastIndexOpt(array, finder) { + let index = array.findLastIndex(finder); + if (index !== -1) { + return index; + } + +} + function swapUnsafe(xs, i, j) { let tmp = xs[i]; xs[i] = xs[j]; @@ -182,6 +190,7 @@ export { reduceRight, reduceRightWithIndex, findIndexOpt, + findLastIndexOpt, filterMap, keepSome, toShuffled, diff --git a/lib/js/Stdlib_Array.js b/lib/js/Stdlib_Array.js index 2af73849d4..f5313a3e3b 100644 --- a/lib/js/Stdlib_Array.js +++ b/lib/js/Stdlib_Array.js @@ -106,6 +106,14 @@ function findIndexOpt(array, finder) { } +function findLastIndexOpt(array, finder) { + let index = array.findLastIndex(finder); + if (index !== -1) { + return index; + } + +} + function swapUnsafe(xs, i, j) { let tmp = xs[i]; xs[i] = xs[j]; @@ -181,6 +189,7 @@ exports.reduceWithIndex = reduceWithIndex; exports.reduceRight = reduceRight; exports.reduceRightWithIndex = reduceRightWithIndex; exports.findIndexOpt = findIndexOpt; +exports.findLastIndexOpt = findLastIndexOpt; exports.filterMap = filterMap; exports.keepSome = keepSome; exports.toShuffled = toShuffled; diff --git a/runtime/Stdlib_Array.res b/runtime/Stdlib_Array.res index b34cfa93de..a88869f9a5 100644 --- a/runtime/Stdlib_Array.res +++ b/runtime/Stdlib_Array.res @@ -169,9 +169,15 @@ let lastIndexOfOpt = (arr, item) => @send external find: (array<'a>, 'a => bool) => option<'a> = "find" @send external findWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "find" +@send external findLast: (t<'a>, 'a => bool) => option<'a> = "findLast" +@send external findLastWithIndex: (t<'a>, ('a, int) => bool) => option<'a> = "findLast" + @send external findIndex: (array<'a>, 'a => bool) => int = "findIndex" @send external findIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findIndex" +@send external findLastIndex: (t<'a>, 'a => bool) => int = "findLastIndex" +@send external findLastIndexWithIndex: (t<'a>, ('a, int) => bool) => int = "findLastIndex" + @send external forEach: (array<'a>, 'a => unit) => unit = "forEach" @send external forEachWithIndex: (array<'a>, ('a, int) => unit) => unit = "forEach" @@ -205,6 +211,12 @@ let findIndexOpt = (array: array<'a>, finder: 'a => bool): option => | index => Some(index) } +let findLastIndexOpt = (array: array<'a>, finder: 'a => bool): option => + switch findLastIndex(array, finder) { + | -1 => None + | index => Some(index) + } + let swapUnsafe = (xs, i, j) => { let tmp = getUnsafe(xs, i) setUnsafe(xs, i, getUnsafe(xs, j)) diff --git a/runtime/Stdlib_Array.resi b/runtime/Stdlib_Array.resi index c524b848bc..fff252d987 100644 --- a/runtime/Stdlib_Array.resi +++ b/runtime/Stdlib_Array.resi @@ -720,6 +720,42 @@ array @send external findWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "find" +/** +`findLast(array, checker)` returns the last element of `array` where the provided `checker` function returns true. + +See [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN. + +## Examples + +```rescript +let array = [1, 2, 3] + +array +->Array.findLast(item => item > 0) +->assertEqual(Some(3)) +``` +*/ +@send +external findLast: (array<'a>, 'a => bool) => option<'a> = "findLast" + +/** +`findLastWithIndex(array, checker)` returns the last element of `array` where the provided `checker` function returns true. + +See [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN. + +## Examples + +```rescript +let array = [1, 2, 3] + +array +->Array.findLastWithIndex((item, index) => index < 2 && item > 0) +->assertEqual(Some(2)) +``` +*/ +@send +external findLastWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "findLast" + /** `findIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true. @@ -769,6 +805,55 @@ assertEqual(isTypeScriptFirst, -1) @send external findIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findIndex" +/** +`findLastIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true. + +Returns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`). + +See [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN. + +## Examples + +```rescript +type languages = ReScript | TypeScript | JavaScript + +let array = [ReScript, JavaScript, ReScript] + +array +->Array.findLastIndex(item => item == ReScript) +->assertEqual(2) + +array->Array.findLastIndex(item => item == TypeScript) +->assertEqual(-1) +``` +*/ +@send +external findLastIndex: (array<'a>, 'a => bool) => int = "findLastIndex" + +/** +`findLastIndexWithIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true. + +Returns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`). + +See [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN. + +## Examples + +```rescript +type languages = ReScript | TypeScript | JavaScript + +let array = [ReScript, JavaScript, JavaScript, ReScript] + +let isReScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == ReScript) +let isTypeScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == TypeScript) + +assertEqual(isReScriptLast, 3) +assertEqual(isTypeScriptLast, -1) +``` +*/ +@send +external findLastIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findLastIndex" + /** `forEach(array, fn)` runs the provided `fn` on every element of `array`. @@ -1064,6 +1149,25 @@ array */ let findIndexOpt: (array<'a>, 'a => bool) => option +/** +`findIndexOpt(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true. + +Returns `None` if no item matches. + +See [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN. + +## Examples + +```rescript +let array = ["hello", "world", "!"] + +array +->Array.findLastIndexOpt(item => item->String.includes("o")) +->assertEqual(Some(1)) +``` +*/ +let findLastIndexOpt: (array<'a>, 'a => bool) => option + /** `toReversed(array)` creates a new array with all items from `array` in reversed order. diff --git a/runtime/Stdlib_TypedArray.res b/runtime/Stdlib_TypedArray.res index 759f81cb18..af38e2448f 100644 --- a/runtime/Stdlib_TypedArray.res +++ b/runtime/Stdlib_TypedArray.res @@ -59,9 +59,15 @@ external copyWithin: (t<'a>, ~target: int, ~start: int, ~end: int) => array<'a> @send external find: (t<'a>, 'a => bool) => option<'a> = "find" @send external findWithIndex: (t<'a>, ('a, int) => bool) => option<'a> = "find" +@send external findLast: (t<'a>, 'a => bool) => option<'a> = "findLast" +@send external findLastWithIndex: (t<'a>, ('a, int) => bool) => option<'a> = "findLast" + @send external findIndex: (t<'a>, 'a => bool) => int = "findIndex" @send external findIndexWithIndex: (t<'a>, ('a, int) => bool) => int = "findIndex" +@send external findLastIndex: (t<'a>, 'a => bool) => int = "findLastIndex" +@send external findLastIndexWithIndex: (t<'a>, ('a, int) => bool) => int = "findLastIndex" + @send external forEach: (t<'a>, 'a => unit) => unit = "forEach" @send external forEachWithIndex: (t<'a>, ('a, int) => unit) => unit = "forEach" diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index 3892764aa7..f56854cd77 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -64,6 +64,18 @@ Path Array. "tags": [], "detail": "(array<'a>, 'a => option<'b>) => array<'b>", "documentation": {"kind": "markdown", "value": "\n`filterMap(array, fn)`\n\nCalls `fn` for each element and returns a new array containing results of the `fn` calls which are not `None`.\n\n## Examples\n\n```rescript\n[\"Hello\", \"Hi\", \"Good bye\"]\n->Array.filterMap(item =>\n switch item {\n | \"Hello\" => Some(item->String.length)\n | _ => None\n }\n)\n->assertEqual([5])\n\n[1, 2, 3, 4, 5, 6]\n->Array.filterMap(n => mod(n, 2) == 0 ? Some(n * n) : None)\n->assertEqual([4, 16, 36])\n\nArray.filterMap([1, 2, 3, 4, 5, 6], _ => None)->assertEqual([])\n\nArray.filterMap([], n => mod(n, 2) == 0 ? Some(n * n) : None)->assertEqual([])\n```\n"} + }, { + "label": "findLastWithIndex", + "kind": 12, + "tags": [], + "detail": "(array<'a>, ('a, int) => bool) => option<'a>", + "documentation": {"kind": "markdown", "value": "\n`findLastWithIndex(array, checker)` returns the last element of `array` where the provided `checker` function returns true.\n\nSee [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN.\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3]\n\narray\n->Array.findLastWithIndex((item, index) => index < 2 && item > 0)\n->assertEqual(Some(2))\n```\n"} + }, { + "label": "findLast", + "kind": 12, + "tags": [], + "detail": "(array<'a>, 'a => bool) => option<'a>", + "documentation": {"kind": "markdown", "value": "\n`findLast(array, checker)` returns the last element of `array` where the provided `checker` function returns true.\n\nSee [`Array.findLast`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast) on MDN.\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3]\n\narray\n->Array.findLast(item => item > 0)\n->assertEqual(Some(3))\n```\n"} }, { "label": "shift", "kind": 12, @@ -178,6 +190,12 @@ Path Array. "tags": [], "detail": "(array<'a>, 'a) => bool", "documentation": {"kind": "markdown", "value": "\n`includes(array, item)` checks whether `array` includes `item`, by doing a [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality).\n\nSee [`Array.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) on MDN.\n\n## Examples\n\n```rescript\n[1, 2]->Array.includes(1)->assertEqual(true)\n[1, 2]->Array.includes(3)->assertEqual(false)\n\n[{\"language\": \"ReScript\"}]\n->Array.includes({\"language\": \"ReScript\"})\n->assertEqual(false) // false, because of strict equality\n```\n"} + }, { + "label": "findLastIndex", + "kind": 12, + "tags": [], + "detail": "(array<'a>, 'a => bool) => int", + "documentation": {"kind": "markdown", "value": "\n`findLastIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript, ReScript]\n\narray\n->Array.findLastIndex(item => item == ReScript)\n->assertEqual(2)\n\narray->Array.findLastIndex(item => item == TypeScript)\n->assertEqual(-1)\n```\n"} }, { "label": "fromInitializer", "kind": 12, @@ -298,6 +316,12 @@ Path Array. "tags": [], "detail": "array<'a> => unit", "documentation": {"kind": "markdown", "value": "\n`reverse(array)` reverses the order of the items in `array`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.reverse\n\nsomeArray->assertEqual([\"hello\", \"hi\"])\n```\n"} + }, { + "label": "findLastIndexWithIndex", + "kind": 12, + "tags": [], + "detail": "(array<'a>, ('a, int) => bool) => int", + "documentation": {"kind": "markdown", "value": "\n`findLastIndexWithIndex(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findLastIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript, JavaScript, ReScript]\n\nlet isReScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == ReScript)\nlet isTypeScriptLast = array->Array.findLastIndexWithIndex((item, index) => index === 3 && item == TypeScript)\n\nassertEqual(isReScriptLast, 3)\nassertEqual(isTypeScriptLast, -1)\n```\n"} }, { "label": "getUnsafe", "kind": 12, @@ -520,6 +544,12 @@ Path Array. "tags": [], "detail": "(array<'a>, int) => unit", "documentation": {"kind": "markdown", "value": "\n`removeInPlace(array, index)` removes the item at the specified `index` from `array`.\n\nBeware this will *mutate* the array.\n\n## Examples\n\n```rescript\nlet array = []\narray->Array.removeInPlace(0)\nassertEqual(array, []) // Removing from an empty array does nothing\n\nlet array2 = [\"Hello\", \"Hi\", \"Good bye\"]\narray2->Array.removeInPlace(1)\nassertEqual(array2, [\"Hello\", \"Good bye\"]) // Removes the item at index 1\n```\n "} + }, { + "label": "findLastIndexOpt", + "kind": 12, + "tags": [], + "detail": "(array<'a>, 'a => bool) => option", + "documentation": {"kind": "markdown", "value": "\n`findIndexOpt(array, checker)` returns the index of the last element of `array` where the provided `checker` function returns true.\n\nReturns `None` if no item matches.\n\nSee [`Array.findLastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"hello\", \"world\", \"!\"]\n\narray\n->Array.findLastIndexOpt(item => item->String.includes(\"o\"))\n->assertEqual(Some(1))\n```\n"} }, { "label": "pushMany", "kind": 12,