From d2e63a641f9b0a5f80116e97bf80ea0d18e931a1 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 19 Jul 2021 15:57:05 -0400 Subject: [PATCH] LibJS: Implement String.prototype.startsWith with UTF-16 code units --- .../LibJS/Runtime/StringPrototype.cpp | 27 ++++++++++++------- .../String/String.prototype.startsWith.js | 8 ++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp index e3401dc188..68ee2c3a94 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -258,8 +258,8 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat) // 22.1.3.22 String.prototype.startsWith ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.startswith JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_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); @@ -272,12 +272,16 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_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(); + + Utf16View utf16_search_view { search_string }; + auto search_length = utf16_search_view.length_in_code_units(); + size_t start = 0; if (!vm.argument(1).is_undefined()) { auto position = vm.argument(1).to_integer_or_infinity(global_object); @@ -285,11 +289,16 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_with) return {}; start = clamp(position, static_cast(0), static_cast(string_length)); } - if (start + search_string_length > string_length) - return Value(false); - if (search_string_length == 0) + + if (search_length == 0) return Value(true); - return Value(string->substring(start, search_string_length) == search_string); + + size_t end = start + search_length; + if (end > string_length) + return Value(false); + + utf16_string_view = utf16_string_view.substring_view(start, end - start); + return Value(utf16_string_view == utf16_search_view); } // 22.1.3.6 String.prototype.endsWith ( searchString [ , endPosition ] ), https://tc39.es/ecma262/#sec-string.prototype.endswith diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.startsWith.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.startsWith.js index 5114da78f9..6568bfd4a3 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.startsWith.js +++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.startsWith.js @@ -34,3 +34,11 @@ test("basic functionality", () => { expect(s.startsWith("", -1)).toBeTrue(); expect(s.startsWith("", 42)).toBeTrue(); }); + +test("UTF-16", () => { + var s = "😀"; + expect(s.startsWith("😀")).toBeTrue(); + expect(s.startsWith("\ud83d")).toBeTrue(); + expect(s.startsWith("\ude00")).toBeFalse(); + expect(s.startsWith("a")).toBeFalse(); +});