summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-07-05 12:10:24 -0400
committerLinus Groh <mail@linusgroh.de>2022-07-06 16:56:42 +0200
commite9bc35d805f931746aedfb183a2d155feedd1375 (patch)
treecef5d3b6a9cac570e449d127f053098e703c899f
parent028a6b90b1cba4fc94004de1ec1b712ad3ec2f35 (diff)
downloadserenity-e9bc35d805f931746aedfb183a2d155feedd1375.zip
LibJS: Implement Intl.Locale.prototype.calendars property
-rw-r--r--Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp39
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/Locale.h5
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp17
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h3
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.calendars.js29
6 files changed, 90 insertions, 4 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
index 5b9bf6d7b0..d35634c8c9 100644
--- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
+++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
@@ -83,6 +83,7 @@ namespace JS {
P(byteOffset) \
P(calendar) \
P(calendarName) \
+ P(calendars) \
P(call) \
P(callee) \
P(caller) \
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp
index ab3b9abbd0..f014be677f 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2022, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/Locale.h>
#include <LibUnicode/Locale.h>
@@ -50,4 +51,40 @@ Locale::Locale(Unicode::LocaleID const& locale_id, Object& prototype)
}
}
+// 1.1.1 CreateArrayFromListOrRestricted ( list , restricted )
+static Array* create_array_from_list_or_restricted(GlobalObject& global_object, Vector<StringView> list, Optional<String> restricted)
+{
+ auto& vm = global_object.vm();
+
+ // 1. If restricted is not undefined, then
+ if (restricted.has_value()) {
+ // a. Set list to ยซ restricted ยป.
+ list = { *restricted };
+ }
+
+ // 2. Return ! CreateArrayFromList( list ).
+ return Array::create_from<StringView>(global_object, list, [&vm](auto value) {
+ return js_string(vm, value);
+ });
+}
+
+// 1.1.2 CalendarsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-calendars-of-locale
+Array* calendars_of_locale(GlobalObject& global_object, Locale const& locale_object)
+{
+ // 1. Let restricted be loc.[[Calendar]].
+ Optional<String> restricted = locale_object.has_calendar() ? locale_object.calendar() : Optional<String> {};
+
+ // 2. Let locale be loc.[[Locale]].
+ auto const& locale = locale_object.locale();
+
+ // 3. Assert: locale matches the unicode_locale_id production.
+ VERIFY(Unicode::parse_unicode_locale_id(locale).has_value());
+
+ // 4. Let list be a List of 1 or more unique canonical calendar identifiers, which must be lower case String values conforming to the type sequence from UTS 35 Unicode Locale Identifier, section 3.2, sorted in descending preference of those in common use for date and time formatting in locale.
+ auto list = Unicode::get_keywords_for_locale(locale, "ca"sv);
+
+ // 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
+ return create_array_from_list_or_restricted(global_object, move(list), move(restricted));
+}
+
}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Locale.h b/Userland/Libraries/LibJS/Runtime/Intl/Locale.h
index ac77f7134c..f9157c09a9 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/Locale.h
+++ b/Userland/Libraries/LibJS/Runtime/Intl/Locale.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2022, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -10,6 +10,7 @@
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Vector.h>
+#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/Value.h>
#include <LibUnicode/Forward.h>
@@ -73,4 +74,6 @@ private:
bool m_numeric { false }; // [[Numeric]]
};
+Array* calendars_of_locale(GlobalObject& global_object, Locale const& locale);
+
}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp
index f7966071aa..52bc2ca6e6 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp
@@ -1,10 +1,11 @@
/*
- * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2022, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TypeCasts.h>
+#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/Locale.h>
#include <LibJS/Runtime/Intl/LocalePrototype.h>
@@ -34,6 +35,7 @@ void LocalePrototype::initialize(GlobalObject& global_object)
define_native_accessor(vm.names.baseName, base_name, {}, Attribute::Configurable);
define_native_accessor(vm.names.calendar, calendar, {}, Attribute::Configurable);
+ define_native_accessor(vm.names.calendars, calendars, {}, Attribute::Configurable);
define_native_accessor(vm.names.caseFirst, case_first, {}, Attribute::Configurable);
define_native_accessor(vm.names.collation, collation, {}, Attribute::Configurable);
define_native_accessor(vm.names.hourCycle, hour_cycle, {}, Attribute::Configurable);
@@ -199,4 +201,17 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
return js_string(vm, *locale->language_id.region);
}
+#define JS_ENUMERATE_LOCALE_INFO_PROPERTIES \
+ __JS_ENUMERATE(calendars)
+
+// 1.4.16 get Intl.Locale.prototype.calendars, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.calendars
+#define __JS_ENUMERATE(keyword) \
+ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::keyword) \
+ { \
+ auto* locale_object = TRY(typed_this_object(global_object)); \
+ return keyword##_of_locale(global_object, *locale_object); \
+ }
+JS_ENUMERATE_LOCALE_INFO_PROPERTIES
+#undef __JS_ENUMERATE
+
}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h
index 48c079969b..e59442f4d3 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h
+++ b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
+ * Copyright (c) 2021-2022, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -26,6 +26,7 @@ private:
JS_DECLARE_NATIVE_FUNCTION(base_name);
JS_DECLARE_NATIVE_FUNCTION(calendar);
+ JS_DECLARE_NATIVE_FUNCTION(calendars);
JS_DECLARE_NATIVE_FUNCTION(case_first);
JS_DECLARE_NATIVE_FUNCTION(collation);
JS_DECLARE_NATIVE_FUNCTION(hour_cycle);
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.calendars.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.calendars.js
new file mode 100644
index 0000000000..e1f2c08f0f
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.calendars.js
@@ -0,0 +1,29 @@
+describe("errors", () => {
+ test("called on non-Locale object", () => {
+ expect(() => {
+ Intl.Locale.prototype.calendars;
+ }).toThrowWithMessage(TypeError, "Not an object of type Intl.Locale");
+ });
+});
+
+describe("normal behavior", () => {
+ test("basic functionality", () => {
+ expect(Array.isArray(new Intl.Locale("en").calendars)).toBeTrue();
+ expect(new Intl.Locale("en").calendars).toEqual(["gregory"]);
+
+ expect(Array.isArray(new Intl.Locale("ar").calendars)).toBeTrue();
+ expect(new Intl.Locale("ar").calendars).toEqual(["gregory"]);
+ });
+
+ test("extension keyword overrides default data", () => {
+ expect(new Intl.Locale("en-u-ca-islamicc").calendars).toEqual(["islamic-civil"]);
+ expect(new Intl.Locale("en", { calendar: "dangi" }).calendars).toEqual(["dangi"]);
+
+ expect(new Intl.Locale("ar-u-ca-ethiopic-amete-alem").calendars).toEqual(["ethioaa"]);
+ expect(new Intl.Locale("ar", { calendar: "hebrew" }).calendars).toEqual(["hebrew"]);
+
+ // Invalid calendars also take precedence.
+ expect(new Intl.Locale("en-u-ca-ladybird").calendars).toEqual(["ladybird"]);
+ expect(new Intl.Locale("en", { calendar: "ladybird" }).calendars).toEqual(["ladybird"]);
+ });
+});