diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index d1c7e079938..a7bf6d0ba81 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/PluralRules.cpp + Runtime/Intl/PluralRulesConstructor.cpp + Runtime/Intl/PluralRulesPrototype.cpp Runtime/Intl/RelativeTimeFormat.cpp Runtime/Intl/RelativeTimeFormatConstructor.cpp Runtime/Intl/RelativeTimeFormatPrototype.cpp diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index 87d743cdf9e..3b21d3e5488 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -73,6 +73,7 @@ __JS_ENUMERATE(ListFormat, list_format, ListFormatPrototype, ListFormatConstructor) \ __JS_ENUMERATE(Locale, locale, LocalePrototype, LocaleConstructor) \ __JS_ENUMERATE(NumberFormat, number_format, NumberFormatPrototype, NumberFormatConstructor) \ + __JS_ENUMERATE(PluralRules, plural_rules, PluralRulesPrototype, PluralRulesConstructor) \ __JS_ENUMERATE(RelativeTimeFormat, relative_time_format, RelativeTimeFormatPrototype, RelativeTimeFormatConstructor) #define JS_ENUMERATE_TEMPORAL_OBJECTS \ diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp index 2d015c9b85d..34452aa99ba 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp index 38a2dbc8cd6..06ea3a82d9f 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace JS::Intl { @@ -38,6 +39,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.PluralRules, global_object.intl_plural_rules_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/PluralRules.cpp b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.cpp new file mode 100644 index 00000000000..25e89517e88 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace JS::Intl { + +// 16 PluralRules Objects, https://tc39.es/ecma402/#pluralrules-objects +PluralRules::PluralRules(Object& prototype) + : NumberFormatBase(prototype) +{ +} + +void PluralRules::set_type(StringView type) +{ + if (type == "cardinal"sv) { + m_type = Type::Cardinal; + } else if (type == "ordinal"sv) { + m_type = Type::Ordinal; + } else { + VERIFY_NOT_REACHED(); + } +} + +StringView PluralRules::type_string() const +{ + switch (m_type) { + case Type::Cardinal: + return "cardinal"sv; + case Type::Ordinal: + return "ordinal"sv; + default: + VERIFY_NOT_REACHED(); + } +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h new file mode 100644 index 00000000000..9321a8824b4 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace JS::Intl { + +class PluralRules final : public NumberFormatBase { + JS_OBJECT(PluralRules, NumberFormatBase); + +public: + enum class Type { + Cardinal, + Ordinal, + }; + + PluralRules(Object& prototype); + virtual ~PluralRules() override = default; + + Type type() const { return m_type; } + StringView type_string() const; + void set_type(StringView type); + +private: + Type m_type { Type::Cardinal }; // [[Type]] +}; + +} diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp new file mode 100644 index 00000000000..161c7469388 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace JS::Intl { + +// 16.2 The Intl.PluralRules Constructor, https://tc39.es/ecma402/#sec-intl-pluralrules-constructor +PluralRulesConstructor::PluralRulesConstructor(GlobalObject& global_object) + : NativeFunction(vm().names.PluralRules.as_string(), *global_object.function_prototype()) +{ +} + +void PluralRulesConstructor::initialize(GlobalObject& global_object) +{ + NativeFunction::initialize(global_object); + + auto& vm = this->vm(); + + // 16.3.1 Intl.PluralRules.prototype, https://tc39.es/ecma402/#sec-intl.pluralrules.prototype + define_direct_property(vm.names.prototype, global_object.intl_plural_rules_prototype(), 0); + define_direct_property(vm.names.length, Value(0), Attribute::Configurable); +} + +// 16.2.1 Intl.PluralRules ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.pluralrules +ThrowCompletionOr PluralRulesConstructor::call() +{ + // 1. If NewTarget is undefined, throw a TypeError exception. + return vm().throw_completion(global_object(), ErrorType::ConstructorWithoutNew, "Intl.PluralRules"); +} + +// 16.2.1 Intl.PluralRules ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.pluralrules +ThrowCompletionOr PluralRulesConstructor::construct(FunctionObject& new_target) +{ + auto& global_object = this->global_object(); + + // 2. Let pluralRules be ? OrdinaryCreateFromConstructor(NewTarget, "%PluralRules.prototype%", « [[InitializedPluralRules]], [[Locale]], [[Type]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]] »). + auto* plural_rules = TRY(ordinary_create_from_constructor(global_object, new_target, &GlobalObject::intl_plural_rules_prototype)); + + // 3. Return ? InitializePluralRules(pluralRules, locales, options). + return plural_rules; +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.h b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.h new file mode 100644 index 00000000000..4aef86b23b6 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS::Intl { + +class PluralRulesConstructor final : public NativeFunction { + JS_OBJECT(PluralRulesConstructor, NativeFunction); + +public: + explicit PluralRulesConstructor(GlobalObject&); + virtual void initialize(GlobalObject&) override; + virtual ~PluralRulesConstructor() override = default; + + virtual ThrowCompletionOr call() override; + virtual ThrowCompletionOr construct(FunctionObject& new_target) override; + +private: + virtual bool has_constructor() const override { return true; } +}; + +} diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp new file mode 100644 index 00000000000..e294dff19fb --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace JS::Intl { + +// 16.4 Properties of the Intl.PluralRules Prototype Object, https://tc39.es/ecma402/#sec-properties-of-intl-pluralrules-prototype-object +PluralRulesPrototype::PluralRulesPrototype(GlobalObject& global_object) + : PrototypeObject(*global_object.object_prototype()) +{ +} + +void PluralRulesPrototype::initialize(GlobalObject& global_object) +{ + Object::initialize(global_object); + + auto& vm = this->vm(); + + // 16.4.2 Intl.PluralRules.prototype [ @@toStringTag ], https://tc39.es/ecma402/#sec-intl.pluralrules.prototype-tostringtag + define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Intl.PluralRules"sv), Attribute::Configurable); +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.h new file mode 100644 index 00000000000..e4c10caa552 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace JS::Intl { + +class PluralRulesPrototype final : public PrototypeObject { + JS_PROTOTYPE_OBJECT(PluralRulesPrototype, PluralRules, Intl.PluralRules); + +public: + explicit PluralRulesPrototype(GlobalObject&); + virtual void initialize(GlobalObject&) override; + virtual ~PluralRulesPrototype() override = default; +}; + +} diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.@@toStringTag.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.@@toStringTag.js new file mode 100644 index 00000000000..1ffa0e20262 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.@@toStringTag.js @@ -0,0 +1,3 @@ +test("basic functionality", () => { + expect(Intl.PluralRules.prototype[Symbol.toStringTag]).toBe("Intl.PluralRules"); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.js new file mode 100644 index 00000000000..2e9d95511d4 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.js @@ -0,0 +1,13 @@ +describe("errors", () => { + test("called without new", () => { + expect(() => { + Intl.PluralRules(); + }).toThrowWithMessage(TypeError, "Intl.PluralRules constructor must be called with 'new'"); + }); +}); + +describe("normal behavior", () => { + test("length is 0", () => { + expect(Intl.PluralRules).toHaveLength(0); + }); +});