From bdbe716547f38e60a5d58facb64c89d1f7a34281 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 19 Jul 2021 16:01:35 -0400 Subject: [PATCH] LibJS: Implement String.prototype.endsWith with UTF-16 code units --- .../LibJS/Runtime/StringPrototype.cpp | 31 ++++++++++--------- .../String/String.prototype.endsWith.js | 8 +++++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp index 68ee2c3a94..8112b7d145 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -304,8 +304,8 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_with) // 22.1.3.6 String.prototype.endsWith ( searchString [ , endPosition ] ), https://tc39.es/ecma262/#sec-string.prototype.endswith JS_DEFINE_NATIVE_FUNCTION(StringPrototype::ends_with) { - auto string = ak_string_from(vm, global_object); - if (!string.has_value()) + auto string = utf16_string_from(vm, global_object); + if (vm.exception()) return {}; auto search_string_value = vm.argument(0); @@ -318,30 +318,33 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::ends_with) return {}; } - auto search_string = search_string_value.to_string(global_object); + auto search_string = search_string_value.to_utf16_string(global_object); if (vm.exception()) return {}; - auto string_length = string->length(); - auto search_string_length = search_string.length(); + Utf16View utf16_string_view { string }; + auto string_length = utf16_string_view.length_in_code_units(); - size_t pos = string_length; + Utf16View utf16_search_view { search_string }; + auto search_length = utf16_search_view.length_in_code_units(); - auto end_position_value = vm.argument(1); - if (!end_position_value.is_undefined()) { - double pos_as_double = end_position_value.to_integer_or_infinity(global_object); + size_t end = string_length; + if (!vm.argument(1).is_undefined()) { + auto position = vm.argument(1).to_integer_or_infinity(global_object); if (vm.exception()) return {}; - pos = clamp(pos_as_double, static_cast(0), static_cast(string_length)); + end = clamp(position, static_cast(0), static_cast(string_length)); } - if (search_string_length == 0) + if (search_length == 0) return Value(true); - if (pos < search_string_length) + if (search_length > end) return Value(false); - auto start = pos - search_string_length; - return Value(string->substring(start, search_string_length) == search_string); + size_t start = end - search_length; + + utf16_string_view = utf16_string_view.substring_view(start, end - start); + return Value(utf16_string_view == utf16_search_view); } // 22.1.3.8 String.prototype.indexOf ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.indexof diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.endsWith.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.endsWith.js index 286cc6b1b2..7d31172f9b 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.endsWith.js +++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.endsWith.js @@ -40,3 +40,11 @@ test("basic functionality", () => { ); expect(s.endsWith("bar", undefined)).toBeTrue(); }); + +test("UTF-16", () => { + var s = "😀"; + expect(s.endsWith("😀")).toBeTrue(); + expect(s.endsWith("\ud83d")).toBeFalse(); + expect(s.endsWith("\ude00")).toBeTrue(); + expect(s.endsWith("a")).toBeFalse(); +});