mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:27:35 +00:00
LibJS: Implement a nearly empty Intl.RelativeTimeFormat object
This adds plumbing for the Intl.RelativeTimeFormat object, constructor, and prototype.
This commit is contained in:
parent
0865f71d37
commit
79fdec85de
12 changed files with 271 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
47
Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp
Normal file
47
Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
67
Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.h
Normal file
67
Userland/Libraries/LibJS/Runtime/Intl/RelativeTimeFormat.h
Normal file
|
@ -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]]
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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; }
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
test("basic functionality", () => {
|
||||
expect(Intl.RelativeTimeFormat.prototype[Symbol.toStringTag]).toBe("Intl.RelativeTimeFormat");
|
||||
});
|
|
@ -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);
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue