summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-01-25 10:41:57 -0500
committerLinus Groh <mail@linusgroh.de>2022-01-25 19:02:59 +0000
commit79fdec85de20c35eba3ef34cdea12ab678c31586 (patch)
treea6bfb02ca57ae63e6e260048c22e6685f728e9eb /Userland
parent0865f71d37943848316791575ac3a2fc3324c938 (diff)
downloadserenity-79fdec85de20c35eba3ef34cdea12ab678c31586.zip
LibJS: Implement a nearly empty Intl.RelativeTimeFormat object
This adds plumbing for the Intl.RelativeTimeFormat object, constructor, and prototype.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibJS/CMakeLists.txt3
-rw-r--r--Userland/Libraries/LibJS/Forward.h3
-rw-r--r--Userland/Libraries/LibJS/Runtime/GlobalObject.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp47
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.h67
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp50
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h28
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.cpp28
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h23
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.@@toStringTag.js3
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.js16
12 files changed, 271 insertions, 1 deletions
diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt
index 9fe951bab9..d1c7e07993 100644
--- a/Userland/Libraries/LibJS/CMakeLists.txt
+++ b/Userland/Libraries/LibJS/CMakeLists.txt
@@ -106,6 +106,9 @@ set(SOURCES
Runtime/Intl/NumberFormatConstructor.cpp
Runtime/Intl/NumberFormatFunction.cpp
Runtime/Intl/NumberFormatPrototype.cpp
+ Runtime/Intl/RelativeTimeFormat.cpp
+ Runtime/Intl/RelativeTimeFormatConstructor.cpp
+ Runtime/Intl/RelativeTimeFormatPrototype.cpp
Runtime/IteratorOperations.cpp
Runtime/IteratorPrototype.cpp
Runtime/JSONObject.cpp
diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h
index 13802349cd..87d743cdf9 100644
--- a/Userland/Libraries/LibJS/Forward.h
+++ b/Userland/Libraries/LibJS/Forward.h
@@ -72,7 +72,8 @@
__JS_ENUMERATE(DisplayNames, display_names, DisplayNamesPrototype, DisplayNamesConstructor) \
__JS_ENUMERATE(ListFormat, list_format, ListFormatPrototype, ListFormatConstructor) \
__JS_ENUMERATE(Locale, locale, LocalePrototype, LocaleConstructor) \
- __JS_ENUMERATE(NumberFormat, number_format, NumberFormatPrototype, NumberFormatConstructor)
+ __JS_ENUMERATE(NumberFormat, number_format, NumberFormatPrototype, NumberFormatConstructor) \
+ __JS_ENUMERATE(RelativeTimeFormat, relative_time_format, RelativeTimeFormatPrototype, RelativeTimeFormatConstructor)
#define JS_ENUMERATE_TEMPORAL_OBJECTS \
__JS_ENUMERATE(Calendar, calendar, CalendarPrototype, CalendarConstructor) \
diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
index 7a18d2b37e..2d015c9b85 100644
--- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
@@ -61,6 +61,8 @@
#include <LibJS/Runtime/Intl/LocalePrototype.h>
#include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
#include <LibJS/Runtime/Intl/NumberFormatPrototype.h>
+#include <LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h>
+#include <LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h>
#include <LibJS/Runtime/IteratorPrototype.h>
#include <LibJS/Runtime/JSONObject.h>
#include <LibJS/Runtime/MapConstructor.h>
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp
index 4c9cf5e20f..38a2dbc8cd 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp
@@ -13,6 +13,7 @@
#include <LibJS/Runtime/Intl/ListFormatConstructor.h>
#include <LibJS/Runtime/Intl/LocaleConstructor.h>
#include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
+#include <LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h>
namespace JS::Intl {
@@ -37,6 +38,7 @@ void Intl::initialize(GlobalObject& global_object)
define_direct_property(vm.names.ListFormat, global_object.intl_list_format_constructor(), attr);
define_direct_property(vm.names.Locale, global_object.intl_locale_constructor(), attr);
define_direct_property(vm.names.NumberFormat, global_object.intl_number_format_constructor(), attr);
+ define_direct_property(vm.names.RelativeTimeFormat, global_object.intl_relative_time_format_constructor(), attr);
define_native_function(vm.names.getCanonicalLocales, get_canonical_locales, 1, attr);
}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp
new file mode 100644
index 0000000000..eed3a02a24
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
+
+namespace JS::Intl {
+
+// 17 RelativeTimeFormat Objects, https://tc39.es/ecma402/#relativetimeformat-objects
+RelativeTimeFormat::RelativeTimeFormat(Object& prototype)
+ : Object(prototype)
+{
+}
+
+void RelativeTimeFormat::visit_edges(Cell::Visitor& visitor)
+{
+ Base::visit_edges(visitor);
+ if (m_number_format)
+ visitor.visit(m_number_format);
+}
+
+void RelativeTimeFormat::set_numeric(StringView numeric)
+{
+ if (numeric == "always"sv) {
+ m_numeric = Numeric::Always;
+ } else if (numeric == "auto"sv) {
+ m_numeric = Numeric::Auto;
+ } else {
+ VERIFY_NOT_REACHED();
+ }
+}
+
+StringView RelativeTimeFormat::numeric_string() const
+{
+ switch (m_numeric) {
+ case Numeric::Always:
+ return "always"sv;
+ case Numeric::Auto:
+ return "auto"sv;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.h b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.h
new file mode 100644
index 0000000000..1622320b83
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Array.h>
+#include <AK/String.h>
+#include <AK/StringView.h>
+#include <LibJS/Runtime/Object.h>
+#include <LibUnicode/Locale.h>
+
+namespace JS::Intl {
+
+class RelativeTimeFormat final : public Object {
+ JS_OBJECT(RelativeTimeFormat, Object);
+
+public:
+ enum class Numeric {
+ Always,
+ Auto,
+ };
+
+ static constexpr auto relevant_extension_keys()
+ {
+ // 17.3.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat-internal-slots
+ // The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
+ return AK::Array { "nu"sv };
+ }
+
+ RelativeTimeFormat(Object& prototype);
+ virtual ~RelativeTimeFormat() override = default;
+
+ String const& locale() const { return m_locale; }
+ void set_locale(String locale) { m_locale = move(locale); }
+
+ String const& data_locale() const { return m_data_locale; }
+ void set_data_locale(String data_locale) { m_data_locale = move(data_locale); }
+
+ String const& numbering_system() const { return m_numbering_system; }
+ void set_numbering_system(String numbering_system) { m_numbering_system = move(numbering_system); }
+
+ Unicode::Style style() const { return m_style; }
+ void set_style(StringView style) { m_style = Unicode::style_from_string(style); }
+ StringView style_string() const { return Unicode::style_to_string(m_style); }
+
+ Numeric numeric() const { return m_numeric; }
+ void set_numeric(StringView numeric);
+ StringView numeric_string() const;
+
+ NumberFormat* number_format() const { return m_number_format; }
+ void set_number_format(NumberFormat* number_format) { m_number_format = number_format; }
+
+private:
+ virtual void visit_edges(Cell::Visitor&) override;
+
+ String m_locale; // [[Locale]]
+ String m_data_locale; // [[DataLocale]]
+ String m_numbering_system; // [[NumberingSystem]]
+ Unicode::Style m_style { Unicode::Style::Long }; // [[Style]]
+ Numeric m_numeric { Numeric::Always }; // [[Numeric]]
+ NumberFormat* m_number_format { nullptr }; // [[NumberFormat]]
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp
new file mode 100644
index 0000000000..76b481da29
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/AbstractOperations.h>
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
+#include <LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h>
+
+namespace JS::Intl {
+
+// 17.2 The Intl.RelativeTimeFormat Constructor, https://tc39.es/ecma402/#sec-intl-relativetimeformat-constructor
+RelativeTimeFormatConstructor::RelativeTimeFormatConstructor(GlobalObject& global_object)
+ : NativeFunction(vm().names.RelativeTimeFormat.as_string(), *global_object.function_prototype())
+{
+}
+
+void RelativeTimeFormatConstructor::initialize(GlobalObject& global_object)
+{
+ NativeFunction::initialize(global_object);
+
+ auto& vm = this->vm();
+
+ // 17.3.1 Intl.RelativeTimeFormat.prototype, https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype
+ define_direct_property(vm.names.prototype, global_object.intl_relative_time_format_prototype(), 0);
+ define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
+}
+
+// 17.2.1 Intl.RelativeTimeFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
+ThrowCompletionOr<Value> RelativeTimeFormatConstructor::call()
+{
+ // 1. If NewTarget is undefined, throw a TypeError exception.
+ return vm().throw_completion<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, "Intl.RelativeTimeFormat");
+}
+
+// 17.2.1 Intl.RelativeTimeFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
+ThrowCompletionOr<Object*> RelativeTimeFormatConstructor::construct(FunctionObject& new_target)
+{
+ auto& global_object = this->global_object();
+
+ // 2. Let relativeTimeFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%RelativeTimeFormat.prototype%", « [[InitializedRelativeTimeFormat]], [[Locale]], [[DataLocale]], [[Style]], [[Numeric]], [[NumberFormat]], [[NumberingSystem]], [[PluralRules]] »).
+ auto* relative_time_format = TRY(ordinary_create_from_constructor<RelativeTimeFormat>(global_object, new_target, &GlobalObject::intl_relative_time_format_prototype));
+
+ // 3. Return ? InitializeRelativeTimeFormat(relativeTimeFormat, locales, options).
+ return relative_time_format;
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h
new file mode 100644
index 0000000000..2fc1b0fdc0
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/NativeFunction.h>
+
+namespace JS::Intl {
+
+class RelativeTimeFormatConstructor final : public NativeFunction {
+ JS_OBJECT(RelativeTimeFormatConstructor, NativeFunction);
+
+public:
+ explicit RelativeTimeFormatConstructor(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~RelativeTimeFormatConstructor() override = default;
+
+ virtual ThrowCompletionOr<Value> call() override;
+ virtual ThrowCompletionOr<Object*> construct(FunctionObject& new_target) override;
+
+private:
+ virtual bool has_constructor() const override { return true; }
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.cpp
new file mode 100644
index 0000000000..bccb8dbf4e
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h>
+
+namespace JS::Intl {
+
+// 17.4 Properties of the Intl.RelativeTimeFormat Prototype Object, https://tc39.es/ecma402/#sec-properties-of-intl-relativetimeformat-prototype-object
+RelativeTimeFormatPrototype::RelativeTimeFormatPrototype(GlobalObject& global_object)
+ : PrototypeObject(*global_object.object_prototype())
+{
+}
+
+void RelativeTimeFormatPrototype::initialize(GlobalObject& global_object)
+{
+ Object::initialize(global_object);
+
+ auto& vm = this->vm();
+
+ // 17.4.2 Intl.RelativeTimeFormat.prototype[ @@toStringTag ], https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype-toStringTag
+ define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Intl.RelativeTimeFormat"sv), Attribute::Configurable);
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h
new file mode 100644
index 0000000000..8d40bc1595
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
+#include <LibJS/Runtime/PrototypeObject.h>
+
+namespace JS::Intl {
+
+class RelativeTimeFormatPrototype final : public PrototypeObject<RelativeTimeFormatPrototype, RelativeTimeFormat> {
+ JS_PROTOTYPE_OBJECT(RelativeTimeFormatPrototype, RelativeTimeFormat, Intl.RelativeTimeFormat);
+
+public:
+ explicit RelativeTimeFormatPrototype(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~RelativeTimeFormatPrototype() override = default;
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.@@toStringTag.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.@@toStringTag.js
new file mode 100644
index 0000000000..ab8844fd58
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.@@toStringTag.js
@@ -0,0 +1,3 @@
+test("basic functionality", () => {
+ expect(Intl.RelativeTimeFormat.prototype[Symbol.toStringTag]).toBe("Intl.RelativeTimeFormat");
+});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.js
new file mode 100644
index 0000000000..e755270127
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/RelativeTimeFormat/RelativeTimeFormat.js
@@ -0,0 +1,16 @@
+describe("errors", () => {
+ test("called without new", () => {
+ expect(() => {
+ Intl.RelativeTimeFormat();
+ }).toThrowWithMessage(
+ TypeError,
+ "Intl.RelativeTimeFormat constructor must be called with 'new'"
+ );
+ });
+});
+
+describe("normal behavior", () => {
+ test("length is 0", () => {
+ expect(Intl.RelativeTimeFormat).toHaveLength(0);
+ });
+});