2022-01-25 10:41:57 -05:00
/*
2022-01-31 13:07:22 -05:00
* Copyright ( c ) 2022 , Tim Flynn < trflynn89 @ serenityos . org >
2022-01-25 10:41:57 -05:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <LibJS/Runtime/AbstractOperations.h>
2022-01-25 12:11:56 -05:00
# include <LibJS/Runtime/Array.h>
2022-01-25 10:41:57 -05:00
# include <LibJS/Runtime/GlobalObject.h>
2022-01-25 12:11:56 -05:00
# include <LibJS/Runtime/Intl/AbstractOperations.h>
2022-03-15 11:09:11 -04:00
# include <LibJS/Runtime/Intl/NumberFormat.h>
# include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
2022-07-07 13:59:46 -04:00
# include <LibJS/Runtime/Intl/PluralRules.h>
# include <LibJS/Runtime/Intl/PluralRulesConstructor.h>
2022-01-25 10:41:57 -05:00
# include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
# include <LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h>
2022-09-02 12:11:30 -04:00
# include <LibLocale/Locale.h>
2022-01-25 10:41:57 -05:00
namespace JS : : Intl {
2022-03-15 11:09:11 -04:00
// 17.1 The Intl.RelativeTimeFormat Constructor, https://tc39.es/ecma402/#sec-intl-relativetimeformat-constructor
2022-08-16 00:20:49 +01:00
RelativeTimeFormatConstructor : : RelativeTimeFormatConstructor ( Realm & realm )
2022-09-14 19:10:27 -04:00
: NativeFunction ( realm . vm ( ) . names . RelativeTimeFormat . as_string ( ) , * realm . intrinsics ( ) . function_prototype ( ) )
2022-01-25 10:41:57 -05:00
{
}
2022-08-16 00:20:49 +01:00
void RelativeTimeFormatConstructor : : initialize ( Realm & realm )
2022-01-25 10:41:57 -05:00
{
2022-08-16 00:20:49 +01:00
NativeFunction : : initialize ( realm ) ;
2022-01-25 10:41:57 -05:00
auto & vm = this - > vm ( ) ;
2022-03-15 11:09:11 -04:00
// 17.2.1 Intl.RelativeTimeFormat.prototype, https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype
2022-08-27 00:54:55 +01:00
define_direct_property ( vm . names . prototype , realm . intrinsics ( ) . intl_relative_time_format_prototype ( ) , 0 ) ;
2022-01-25 10:41:57 -05:00
define_direct_property ( vm . names . length , Value ( 0 ) , Attribute : : Configurable ) ;
2022-01-25 12:11:56 -05:00
u8 attr = Attribute : : Writable | Attribute : : Configurable ;
2022-08-22 21:47:35 +01:00
define_native_function ( realm , vm . names . supportedLocalesOf , supported_locales_of , 1 , attr ) ;
2022-01-25 10:41:57 -05:00
}
2022-03-15 11:09:11 -04:00
// 17.1.1 Intl.RelativeTimeFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
2022-01-25 10:41:57 -05:00
ThrowCompletionOr < Value > RelativeTimeFormatConstructor : : call ( )
{
// 1. If NewTarget is undefined, throw a TypeError exception.
2022-08-16 20:33:17 +01:00
return vm ( ) . throw_completion < TypeError > ( ErrorType : : ConstructorWithoutNew , " Intl.RelativeTimeFormat " ) ;
2022-01-25 10:41:57 -05:00
}
2022-03-15 11:09:11 -04:00
// 17.1.1 Intl.RelativeTimeFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
2022-01-25 10:41:57 -05:00
ThrowCompletionOr < Object * > RelativeTimeFormatConstructor : : construct ( FunctionObject & new_target )
{
2022-01-25 11:50:14 -05:00
auto & vm = this - > vm ( ) ;
2022-01-25 10:41:57 -05:00
2022-01-25 11:50:14 -05:00
auto locales = vm . argument ( 0 ) ;
auto options = vm . argument ( 1 ) ;
2022-01-25 10:41:57 -05:00
// 2. Let relativeTimeFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%RelativeTimeFormat.prototype%", « [[InitializedRelativeTimeFormat]], [[Locale]], [[DataLocale]], [[Style]], [[Numeric]], [[NumberFormat]], [[NumberingSystem]], [[PluralRules]] »).
2022-08-27 00:54:55 +01:00
auto * relative_time_format = TRY ( ordinary_create_from_constructor < RelativeTimeFormat > ( vm , new_target , & Intrinsics : : intl_relative_time_format_prototype ) ) ;
2022-01-25 10:41:57 -05:00
// 3. Return ? InitializeRelativeTimeFormat(relativeTimeFormat, locales, options).
2022-08-20 08:25:24 +01:00
return TRY ( initialize_relative_time_format ( vm , * relative_time_format , locales , options ) ) ;
2022-01-25 10:41:57 -05:00
}
2022-03-15 11:09:11 -04:00
// 17.2.2 Intl.RelativeTimeFormat.supportedLocalesOf ( locales [ , options ] ), https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.supportedLocalesOf
2022-01-25 12:11:56 -05:00
JS_DEFINE_NATIVE_FUNCTION ( RelativeTimeFormatConstructor : : supported_locales_of )
{
auto locales = vm . argument ( 0 ) ;
auto options = vm . argument ( 1 ) ;
// 1. Let availableLocales be %RelativeTimeFormat%.[[AvailableLocales]].
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
2022-08-20 08:25:24 +01:00
auto requested_locales = TRY ( canonicalize_locale_list ( vm , locales ) ) ;
2022-01-25 12:11:56 -05:00
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).
2022-08-20 08:25:24 +01:00
return TRY ( supported_locales ( vm , requested_locales , options ) ) ;
2022-01-25 12:11:56 -05:00
}
2022-03-15 11:09:11 -04:00
// 17.1.2 InitializeRelativeTimeFormat ( relativeTimeFormat, locales, options ), https://tc39.es/ecma402/#sec-InitializeRelativeTimeFormat
2022-08-20 08:25:24 +01:00
ThrowCompletionOr < RelativeTimeFormat * > initialize_relative_time_format ( VM & vm , RelativeTimeFormat & relative_time_format , Value locales_value , Value options_value )
2022-03-15 11:09:11 -04:00
{
2022-08-20 08:25:24 +01:00
auto & realm = * vm . current_realm ( ) ;
2022-03-15 11:09:11 -04:00
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
2022-08-20 08:25:24 +01:00
auto requested_locales = TRY ( canonicalize_locale_list ( vm , locales_value ) ) ;
2022-03-15 11:09:11 -04:00
// 2. Set options to ? CoerceOptionsToObject(options).
2022-08-20 08:25:24 +01:00
auto * options = TRY ( coerce_options_to_object ( vm , options_value ) ) ;
2022-03-15 11:09:11 -04:00
// 3. Let opt be a new Record.
LocaleOptions opt { } ;
// 4. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
2022-08-20 08:52:42 +01:00
auto matcher = TRY ( get_option ( vm , * options , vm . names . localeMatcher , OptionType : : String , AK : : Array { " lookup " sv , " best fit " sv } , " best fit " sv ) ) ;
2022-03-15 11:09:11 -04:00
// 5. Set opt.[[LocaleMatcher]] to matcher.
opt . locale_matcher = matcher ;
// 6. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined).
2022-08-20 08:52:42 +01:00
auto numbering_system = TRY ( get_option ( vm , * options , vm . names . numberingSystem , OptionType : : String , { } , Empty { } ) ) ;
2022-03-15 11:09:11 -04:00
// 7. If numberingSystem is not undefined, then
if ( ! numbering_system . is_undefined ( ) ) {
// a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
2022-12-06 01:12:49 +00:00
if ( ! : : Locale : : is_type_identifier ( numbering_system . as_string ( ) . deprecated_string ( ) ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , numbering_system , " numberingSystem " sv ) ;
2022-03-15 11:09:11 -04:00
// 8. Set opt.[[nu]] to numberingSystem.
2022-12-06 01:12:49 +00:00
opt . nu = numbering_system . as_string ( ) . deprecated_string ( ) ;
2022-03-15 11:09:11 -04:00
}
// 9. Let localeData be %RelativeTimeFormat%.[[LocaleData]].
// 10. Let r be ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData).
auto result = resolve_locale ( requested_locales , opt , RelativeTimeFormat : : relevant_extension_keys ( ) ) ;
// 11. Let locale be r.[[locale]].
auto locale = move ( result . locale ) ;
// 12. Set relativeTimeFormat.[[Locale]] to locale.
relative_time_format . set_locale ( locale ) ;
// 13. Set relativeTimeFormat.[[DataLocale]] to r.[[dataLocale]].
relative_time_format . set_data_locale ( move ( result . data_locale ) ) ;
// 14. Set relativeTimeFormat.[[NumberingSystem]] to r.[[nu]].
if ( result . nu . has_value ( ) )
relative_time_format . set_numbering_system ( result . nu . release_value ( ) ) ;
// 15. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
2022-08-20 08:52:42 +01:00
auto style = TRY ( get_option ( vm , * options , vm . names . style , OptionType : : String , { " long " sv , " short " sv , " narrow " sv } , " long " sv ) ) ;
2022-03-15 11:09:11 -04:00
// 16. Set relativeTimeFormat.[[Style]] to style.
2022-12-06 01:12:49 +00:00
relative_time_format . set_style ( style . as_string ( ) . deprecated_string ( ) ) ;
2022-03-15 11:09:11 -04:00
// 17. Let numeric be ? GetOption(options, "numeric", "string", « "always", "auto" », "always").
2022-08-20 08:52:42 +01:00
auto numeric = TRY ( get_option ( vm , * options , vm . names . numeric , OptionType : : String , { " always " sv , " auto " sv } , " always " sv ) ) ;
2022-03-15 11:09:11 -04:00
// 18. Set relativeTimeFormat.[[Numeric]] to numeric.
2022-12-06 01:12:49 +00:00
relative_time_format . set_numeric ( numeric . as_string ( ) . deprecated_string ( ) ) ;
2022-03-15 11:09:11 -04:00
// 19. Let relativeTimeFormat.[[NumberFormat]] be ! Construct(%NumberFormat%, « locale »).
2022-12-06 22:17:27 +00:00
auto * number_format = MUST ( construct ( vm , * realm . intrinsics ( ) . intl_number_format_constructor ( ) , PrimitiveString : : create ( vm , locale ) ) ) ;
2022-03-15 11:09:11 -04:00
relative_time_format . set_number_format ( static_cast < NumberFormat * > ( number_format ) ) ;
// 20. Let relativeTimeFormat.[[PluralRules]] be ! Construct(%PluralRules%, « locale »).
2022-12-06 22:17:27 +00:00
auto * plural_rules = MUST ( construct ( vm , * realm . intrinsics ( ) . intl_plural_rules_constructor ( ) , PrimitiveString : : create ( vm , locale ) ) ) ;
2022-07-07 13:59:46 -04:00
relative_time_format . set_plural_rules ( static_cast < PluralRules * > ( plural_rules ) ) ;
2022-03-15 11:09:11 -04:00
// 21. Return relativeTimeFormat.
return & relative_time_format ;
}
2022-01-25 10:41:57 -05:00
}