diff options
author | Timothy Flynn <trflynn89@pm.me> | 2021-07-19 09:03:52 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-22 09:10:44 +0200 |
commit | 2bba20d1239b75c710f9058c1b1c8802249ecf29 (patch) | |
tree | 472346ebd0ad276efc4bb347a498e389b4e8395a | |
parent | 0c42aece362edfbd71f3b149601c065b5c675e80 (diff) | |
download | serenity-2bba20d1239b75c710f9058c1b1c8802249ecf29.zip |
LibJS: Report string properties using UTF-16 code units
String length is reported as the number of UTF-16 code units, and string
indices are reported as the UTF-16 code units themselves.
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/StringObject.cpp | 14 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Tests/builtins/String/String.js | 26 |
2 files changed, 33 insertions, 7 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/StringObject.cpp b/Userland/Libraries/LibJS/Runtime/StringObject.cpp index a941744060..fd8d950604 100644 --- a/Userland/Libraries/LibJS/Runtime/StringObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringObject.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include <AK/Utf8View.h> +#include <AK/Utf16View.h> #include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/PrimitiveString.h> @@ -34,7 +34,7 @@ void StringObject::initialize(GlobalObject& global_object) { auto& vm = this->vm(); Object::initialize(global_object); - define_direct_property(vm.names.length, Value(Utf8View(m_string.string()).length()), 0); + define_direct_property(vm.names.length, Value(m_string.utf16_string_view().length_in_code_units()), 0); } void StringObject::visit_edges(Cell::Visitor& visitor) @@ -70,17 +70,17 @@ static Optional<PropertyDescriptor> string_get_own_property(GlobalObject& global // 8. Let str be S.[[StringData]]. // 9. Assert: Type(str) is String. - auto& str = string.primitive_string().string(); + auto str = string.primitive_string().utf16_string_view(); // 10. Let len be the length of str. - auto length = str.length(); + auto length = str.length_in_code_units(); // 11. If ℝ(index) < 0 or len ≤ ℝ(index), return undefined. if (index.as_double() < 0 || length <= index.as_double()) return {}; // 12. Let resultStr be the String value of length 1, containing one code unit from str, specifically the code unit at index ℝ(index). - auto result_str = js_string(string.vm(), str.substring(index.as_double(), 1)); + auto result_str = js_string(string.vm(), str.substring_view(index.as_double(), 1)); // 13. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }. return PropertyDescriptor { @@ -138,12 +138,12 @@ MarkedValueList StringObject::internal_own_property_keys() const auto keys = MarkedValueList { heap() }; // 2. Let str be O.[[StringData]]. - auto& str = m_string.string(); + auto str = m_string.utf16_string_view(); // 3. Assert: Type(str) is String. // 4. Let len be the length of str. - auto length = str.length(); + auto length = str.length_in_code_units(); // 5. For each integer i starting with 0 such that i < len, in ascending order, do for (size_t i = 0; i < length; ++i) { diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.js index ba076bd5b4..5050f17333 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/String/String.js +++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.js @@ -13,4 +13,30 @@ test("length", () => { expect(new String("a").length).toBe(1); expect(new String("\u180E").length).toBe(1); expect(new String("\uDBFF\uDFFF").length).toBe(2); + + // Issue #2280 + expect("⛳".length).toBe(1); + expect("🔥".length).toBe(2); + expect("🔥🔥🔥".length).toBe(6); + expect("👨👩👦".length).toBe(8); + expect("👩❤️💋👩".length).toBe(11); +}); + +test("indices", () => { + expect("abc"[0]).toBe("a"); + expect("abc"[1]).toBe("b"); + expect("abc"[2]).toBe("c"); + expect("abc"[3]).toBeUndefined(); + + expect("😀"[0]).toBe("\ud83d"); + expect("😀"[1]).toBe("\ude00"); + expect("😀"[2]).toBeUndefined(); +}); + +test("properties", () => { + expect(Object.getOwnPropertyNames("")).toEqual(["length"]); + expect(Object.getOwnPropertyNames("a")).toEqual(["0", "length"]); + expect(Object.getOwnPropertyNames("ab")).toEqual(["0", "1", "length"]); + expect(Object.getOwnPropertyNames("abc")).toEqual(["0", "1", "2", "length"]); + expect(Object.getOwnPropertyNames("😀")).toEqual(["0", "1", "length"]); }); |