summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2021-11-16 22:06:09 -0500
committerLinus Groh <mail@linusgroh.de>2021-11-17 09:01:32 +0000
commit39ab1a8999bf814565318f57d1305ab836343be6 (patch)
tree169d0f0ad678769a2a6b2a1f868673773f23834c
parentc19c3205ffe0747fa299950a725a57ebd6667e95 (diff)
downloadserenity-39ab1a8999bf814565318f57d1305ab836343be6.zip
LibJS: Implement ECMA-402 Array.prototype.toLocaleString
Turns out the only difference between our existing implementation and the ECMA-402 implementation is we weren't passing the locales and options list to each element.toLocaleString invocation. This also adds spec comments to the definition.
-rw-r--r--Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp41
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js8
2 files changed, 41 insertions, 8 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp
index 81598d904e..90b8d9bac5 100644
--- a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp
@@ -388,9 +388,13 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_string)
return TRY(vm.call(join_function.as_function(), this_object));
}
-// 23.1.3.30 Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-array.prototype.tolocalestring
+// 18.5.1 Array.prototype.toLocaleString ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sup-array.prototype.tolocalestring
JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_locale_string)
{
+ auto locales = vm.argument(0);
+ auto options = vm.argument(1);
+
+ // 1. Let array be ? ToObject(this value).
auto* this_object = TRY(vm.this_value(global_object).to_object(global_object));
if (s_array_join_seen_objects.contains(this_object))
@@ -400,20 +404,41 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_locale_string)
s_array_join_seen_objects.remove(this_object);
};
+ // 2. Let len be ? ToLength(? Get(array, "length")).
auto length = TRY(length_of_array_like(global_object, *this_object));
- String separator = ","; // NOTE: This is implementation-specific.
+ // 3. Let separator be the String value for the list-separator String appropriate for the host environment's current locale (this is derived in an implementation-defined way).
+ constexpr auto separator = ","sv;
+
+ // 4. Let R be the empty String.
StringBuilder builder;
+
+ // 5. Let k be 0.
+ // 6. Repeat, while k < len,
for (size_t i = 0; i < length; ++i) {
- if (i > 0)
+ // a. If k > 0, then
+ if (i > 0) {
+ // i. Set R to the string-concatenation of R and separator.
builder.append(separator);
+ }
+
+ // b. Let nextElement be ? Get(array, ! ToString(k)).
auto value = TRY(this_object->get(i));
- if (value.is_nullish())
- continue;
- auto locale_string_result = TRY(value.invoke(global_object, vm.names.toLocaleString));
- auto string = TRY(locale_string_result.to_string(global_object));
- builder.append(string);
+
+ // c. If nextElement is not undefined or null, then
+ if (!value.is_nullish()) {
+ // i. Let S be ? ToString(? Invoke(nextElement, "toLocaleString", ยซ locales, options ยป)).
+ auto locale_string_result = TRY(value.invoke(global_object, vm.names.toLocaleString, locales, options));
+
+ // ii. Set R to the string-concatenation of R and S.
+ auto string = TRY(locale_string_result.to_string(global_object));
+ builder.append(string);
+ }
+
+ // d. Increase k by 1.
}
+
+ // 7. Return R.
return js_string(vm, builder.to_string());
}
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js b/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js
index 05854a1d0c..8a632ad67e 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.toLocaleString.js
@@ -59,4 +59,12 @@ describe("normal behavior", () => {
// [ "foo", <circular>, [ 1, 2, <circular> ], [ "bar" ] ]
expect(a.toLocaleString()).toBe("foo,,1,2,,bar");
});
+
+ test("with options", () => {
+ expect([12, 34].toLocaleString("en")).toBe("12");
+ expect([12, 34].toLocaleString("ar")).toBe("\u0661\u0662,\u0663\u0664");
+
+ expect([0.234].toLocaleString("en", { style: "percent" })).toBe("23%");
+ expect([0.234].toLocaleString("ar", { style: "percent" })).toBe("\u0662\u0663\u066a\u061c");
+ });
});