diff --git a/CHANGELOG.md b/CHANGELOG.md index e32c672d8a..4ed301bbf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Add `Dict.has` and double `Dict.forEachWithKey`/`Dict.mapValues` performance. https://github.com/rescript-lang/rescript/pull/7316 - Add popover attributes to JsxDOM.domProps. https://github.com/rescript-lang/rescript/pull/7317 +- Add `Array.removeInPlace` helper based on `splice`. https://github.com/rescript-lang/rescript/pull/7321 - Add `inert` attribute to `JsxDOM.domProps`. https://github.com/rescript-lang/rescript/pull/7326 #### :boom: Breaking Change diff --git a/runtime/Stdlib_Array.res b/runtime/Stdlib_Array.res index 011d1cf564..d6536de0ba 100644 --- a/runtime/Stdlib_Array.res +++ b/runtime/Stdlib_Array.res @@ -108,6 +108,9 @@ external splice: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => u external toSpliced: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => array<'a> = "toSpliced" +@send +external removeInPlace: (array<'a>, int, @as(1) _) => unit = "splice" + @send external with: (array<'a>, int, 'a) => array<'a> = "with" @send external unshift: (array<'a>, 'a) => unit = "unshift" diff --git a/runtime/Stdlib_Array.resi b/runtime/Stdlib_Array.resi index e2bb72b1e6..aba4d2f4fd 100644 --- a/runtime/Stdlib_Array.resi +++ b/runtime/Stdlib_Array.resi @@ -302,6 +302,26 @@ external splice: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => u external toSpliced: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => array<'a> = "toSpliced" +/** +`removeInPlace(array, index)` removes the item at the specified `index` from `array`. + +Beware this will *mutate* the array. + +## Examples + +```rescript +let array = [] +array->Array.removeInPlace(0) +assertEqual(array, []) // Removing from an empty array does nothing + +let array2 = ["Hello", "Hi", "Good bye"] +array2->Array.removeInPlace(1) +assertEqual(array2, ["Hello", "Good bye"]) // Removes the item at index 1 +``` + */ +@send +external removeInPlace: (array<'a>, int, @as(1) _) => unit = "splice" + @send external with: (array<'a>, int, 'a) => array<'a> = "with" /** diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index d8fafb4a77..db60cbe0e2 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -508,6 +508,12 @@ Path Array. "tags": [], "detail": "(array<'a>, int) => option<'a>", "documentation": {"kind": "markdown", "value": "\n`get(array, index)` returns the element at `index` of `array`.\n\nReturns `None` if the index does not exist in the array. Equivalent to doing `array[index]` in JavaScript.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray\n->Array.get(0)\n->assertEqual(Some(\"Hello\"))\n\narray\n->Array.get(3)\n->assertEqual(None)\n```\n"} + }, { + "label": "removeInPlace", + "kind": 12, + "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": "pushMany", "kind": 12, diff --git a/tests/analysis_tests/tests/test.sh b/tests/analysis_tests/tests/test.sh index a30bc3af9d..0d57d897aa 100755 --- a/tests/analysis_tests/tests/test.sh +++ b/tests/analysis_tests/tests/test.sh @@ -22,9 +22,9 @@ reset='\033[0m' diff=$(git ls-files --modified src/expected) if [[ $diff = "" ]]; then - printf "${successGreen}✅ No unstaged tests difference.${reset}\n" + printf "${successGreen}✅ No analysis_tests snapshot changes detected.${reset}\n" else - printf "${warningYellow}⚠️ There are unstaged differences in tests/! Did you break a test?\n${diff}\n${reset}" + printf "${warningYellow}⚠️ The analysis_tests snapshot doesn't match. Double check that the output is correct, run 'make analysis_tests' and stage the diff.\n${diff}\n${reset}" git --no-pager diff src/expected exit 1 fi diff --git a/tests/tests/src/core/Core_ArrayTests.mjs b/tests/tests/src/core/Core_ArrayTests.mjs index 9f528d119c..88de742280 100644 --- a/tests/tests/src/core/Core_ArrayTests.mjs +++ b/tests/tests/src/core/Core_ArrayTests.mjs @@ -457,6 +457,44 @@ Test.run([ "last - empty" ], Stdlib_Array.last([]), eq, undefined); +let array = []; + +array.splice(1, 0, "foo"); + +Test.run([ + [ + "Core_ArrayTests.res", + 116, + 22, + 49 + ], + "splice - Insert no delete" +], array, eq, ["foo"]); + +let array$1 = [ + "bar", + "baz" +]; + +Test.run([ + [ + "Core_ArrayTests.res", + 122, + 15, + 43 + ], + "splice - Insert and delete" +], [ + (array$1.splice(1, 1, "foo"), undefined), + array$1 +], eq, [ + undefined, + [ + "bar", + "foo" + ] +]); + export { eq, } diff --git a/tests/tests/src/core/Core_ArrayTests.res b/tests/tests/src/core/Core_ArrayTests.res index 01fdf39c34..2ec0031dd0 100644 --- a/tests/tests/src/core/Core_ArrayTests.res +++ b/tests/tests/src/core/Core_ArrayTests.res @@ -109,3 +109,24 @@ Test.run( Test.run(__POS_OF__("last - with items"), [1, 2, 3]->Array.last, eq, Some(3)) Test.run(__POS_OF__("last - empty"), []->Array.last, eq, None) + +{ + let array = [] + array->Array.splice(~start=1, ~remove=0, ~insert=["foo"]) + Test.run(__POS_OF__("splice - Insert no delete"), array, eq, ["foo"]) +} + +{ + let array = ["bar", "baz"] + Test.run( + __POS_OF__("splice - Insert and delete"), + (array->Array.splice(~start=1, ~remove=1, ~insert=["foo"]), array), + eq, + ( + // Even though original .splice returns an array with the removed items, + // the binding returns unit so there's no confusion about it mutating the original array. + (), + ["bar", "foo"], + ), + ) +}