2022-06-30 00:58:40 +03:00
/*
* Copyright ( c ) 2022 , Idan Horowitz < idan . horowitz @ serenityos . org >
2024-06-13 16:05:57 -04:00
* Copyright ( c ) 2022 - 2024 , Tim Flynn < trflynn89 @ serenityos . org >
2022-06-30 00:58:40 +03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <LibJS/Runtime/AbstractOperations.h>
2022-06-30 01:25:47 +03:00
# include <LibJS/Runtime/Array.h>
2022-06-30 00:58:40 +03:00
# include <LibJS/Runtime/GlobalObject.h>
# include <LibJS/Runtime/Intl/AbstractOperations.h>
# include <LibJS/Runtime/Intl/DurationFormat.h>
# include <LibJS/Runtime/Intl/DurationFormatConstructor.h>
2024-06-13 16:05:57 -04:00
# include <LibLocale/DurationFormat.h>
2022-06-30 00:58:40 +03:00
namespace JS : : Intl {
2023-11-19 09:45:05 +01:00
JS_DEFINE_ALLOCATOR ( DurationFormatConstructor ) ;
2022-06-30 00:58:40 +03:00
// 1.2 The Intl.DurationFormat Constructor, https://tc39.es/proposal-intl-duration-format/#sec-intl-durationformat-constructor
2022-08-16 00:20:49 +01:00
DurationFormatConstructor : : DurationFormatConstructor ( Realm & realm )
2023-04-13 00:47:15 +02:00
: NativeFunction ( realm . vm ( ) . names . DurationFormat . as_string ( ) , realm . intrinsics ( ) . function_prototype ( ) )
2022-06-30 00:58:40 +03:00
{
}
2023-08-07 08:41:28 +02:00
void DurationFormatConstructor : : initialize ( Realm & realm )
2022-06-30 00:58:40 +03:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2022-06-30 00:58:40 +03:00
auto & vm = this - > vm ( ) ;
// 1.3.1 Intl.DurationFormat.prototype, https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat.prototype
2022-08-27 00:54:55 +01:00
define_direct_property ( vm . names . prototype , realm . intrinsics ( ) . intl_duration_format_prototype ( ) , 0 ) ;
2022-06-30 00:58:40 +03:00
define_direct_property ( vm . names . length , Value ( 0 ) , Attribute : : Configurable ) ;
2022-06-30 01:25:47 +03: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-06-30 00:58:40 +03:00
}
// 1.2.1 Intl.DurationFormat ( [ locales [ , options ] ] ), https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat
ThrowCompletionOr < Value > DurationFormatConstructor : : 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.DurationFormat " ) ;
2022-06-30 00:58:40 +03:00
}
// 1.2.1 Intl.DurationFormat ( [ locales [ , options ] ] ), https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat
2022-12-14 19:18:10 +00:00
ThrowCompletionOr < NonnullGCPtr < Object > > DurationFormatConstructor : : construct ( FunctionObject & new_target )
2022-06-30 00:58:40 +03:00
{
auto & vm = this - > vm ( ) ;
auto locales = vm . argument ( 0 ) ;
auto options_value = vm . argument ( 1 ) ;
2024-06-13 16:05:57 -04:00
// 2. Let durationFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%DurationFormatPrototype%", « [[InitializedDurationFormat]], [[Locale]], [[DataLocale]], [[NumberingSystem]], [[Style]], [[YearsStyle]], [[YearsDisplay]], [[MonthsStyle]], [[MonthsDisplay]], [[WeeksStyle]], [[WeeksDisplay]], [[DaysStyle]], [[DaysDisplay]], [[HoursStyle]], [[HoursDisplay]], [[MinutesStyle]], [[MinutesDisplay]], [[SecondsStyle]], [[SecondsDisplay]], [[MillisecondsStyle]], [[MillisecondsDisplay]], [[MicrosecondsStyle]], [[MicrosecondsDisplay]], [[NanosecondsStyle]], [[NanosecondsDisplay]], [[HoursMinutesSeparator]], [[MinutesSecondsSeparator]], [[FractionalDigits]], [[TwoDigitHours]] »).
2022-12-14 18:34:32 +00:00
auto duration_format = TRY ( ordinary_create_from_constructor < DurationFormat > ( vm , new_target , & Intrinsics : : intl_duration_format_prototype ) ) ;
2022-06-30 00:58:40 +03:00
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
2022-08-20 08:25:24 +01:00
auto requested_locales = TRY ( canonicalize_locale_list ( vm , locales ) ) ;
2022-06-30 00:58:40 +03:00
// 4. Let options be ? GetOptionsObject(options).
2022-08-20 08:52:42 +01:00
auto * options = TRY ( Temporal : : get_options_object ( vm , options_value ) ) ;
2022-06-30 00:58:40 +03:00
2023-01-12 10:22:37 -05:00
// 5. 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 , { " lookup " sv , " best fit " sv } , " best fit " sv ) ) ;
2022-06-30 00:58:40 +03:00
2024-06-13 16:05:57 -04:00
// 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-06-30 00:58:40 +03:00
2022-08-30 10:12:24 -04:00
// 7. If numberingSystem is not undefined, then
2022-06-30 00:58:40 +03:00
if ( ! numbering_system . is_undefined ( ) ) {
2022-08-30 10:12:24 -04:00
// a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
2023-08-08 19:17:55 +02:00
if ( ! : : Locale : : is_type_identifier ( numbering_system . as_string ( ) . utf8_string_view ( ) ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , numbering_system , " numberingSystem " sv ) ;
2022-06-30 00:58:40 +03:00
}
// 8. Let opt be the Record { [[localeMatcher]]: matcher, [[nu]]: numberingSystem }.
LocaleOptions opt { } ;
opt . locale_matcher = matcher ;
2024-06-16 15:36:34 -04:00
opt . nu = locale_key_from_value ( numbering_system ) ;
2022-06-30 00:58:40 +03:00
// 9. Let r be ResolveLocale(%DurationFormat%.[[AvailableLocales]], requestedLocales, opt, %DurationFormat%.[[RelevantExtensionKeys]], %DurationFormat%.[[LocaleData]]).
2023-08-30 11:08:15 -04:00
auto result = resolve_locale ( requested_locales , opt , DurationFormat : : relevant_extension_keys ( ) ) ;
2022-06-30 00:58:40 +03:00
// 10. Let locale be r.[[locale]].
auto locale = move ( result . locale ) ;
// 11. Set durationFormat.[[Locale]] to locale.
duration_format - > set_locale ( move ( locale ) ) ;
2024-06-13 16:05:57 -04:00
// 12. Set durationFormat.[[DataLocale]] to r.[[dataLocale]].
2024-06-18 10:13:30 -04:00
// NOTE: The [[dataLocale]] internal slot no longer exists.
2024-06-13 16:05:57 -04:00
// 13. Let dataLocale be durationFormat.[[DataLocale]].
// 14. Let dataLocaleData be durationFormat.[[LocaleData]].[[<dataLocale>]].
// 15. Let digitalFormat be dataLocaleData.[[DigitalFormat]].
2024-06-18 10:13:30 -04:00
auto digital_format = : : Locale : : digital_format ( duration_format - > locale ( ) ) ;
2024-06-13 16:05:57 -04:00
// 16. Let twoDigitHours be digitalFormat.[[TwoDigitHours]].
// 17. Set durationFormat.[[TwoDigitHours]] to twoDigitHours.
duration_format - > set_two_digit_hours ( digital_format . uses_two_digit_hours ) ;
// 18. Let hoursMinutesSeparator be digitalFormat.[[HoursMinutesSeparator]].
// 19. Set durationFormat.[[HoursMinutesSeparator]] to hoursMinutesSeparator.
duration_format - > set_hours_minutes_separator ( move ( digital_format . hours_minutes_separator ) ) ;
// 20. Let minutesSecondsSeparator be digitalFormat.[[MinutesSecondsSeparator]].
// 21. Set durationFormat.[[MinutesSecondsSeparator]] to minutesSecondsSeparator.
duration_format - > set_minutes_seconds_separator ( move ( digital_format . minutes_seconds_separator ) ) ;
// 22. Set durationFormat.[[NumberingSystem]] to r.[[nu]].
2024-06-16 15:36:34 -04:00
if ( auto * resolved_numbering_system = result . nu . get_pointer < String > ( ) )
duration_format - > set_numbering_system ( move ( * resolved_numbering_system ) ) ;
2022-06-30 00:58:40 +03:00
2024-06-13 16:05:57 -04:00
// 23. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow", "digital" », "short").
2022-08-30 10:23:38 -04:00
auto style = TRY ( get_option ( vm , * options , vm . names . style , OptionType : : String , { " long " sv , " short " sv , " narrow " sv , " digital " sv } , " short " sv ) ) ;
2022-06-30 00:58:40 +03:00
2024-06-13 16:05:57 -04:00
// 24. Set durationFormat.[[Style]] to style.
2023-08-08 19:17:55 +02:00
duration_format - > set_style ( style . as_string ( ) . utf8_string_view ( ) ) ;
2022-06-30 00:58:40 +03:00
2024-06-13 16:05:57 -04:00
// 25. Let prevStyle be the empty String.
2023-01-27 15:57:43 -05:00
String previous_style { } ;
2022-06-30 00:58:40 +03:00
2024-06-13 16:05:57 -04:00
// 26. For each row of Table 3, except the header row, in table order, do
2022-06-30 00:58:40 +03:00
for ( auto const & duration_instances_component : duration_instances_components ) {
2022-08-30 11:24:17 -04:00
// a. Let styleSlot be the Style Slot value of the current row.
2022-06-30 00:58:40 +03:00
auto style_slot = duration_instances_component . set_style_slot ;
2022-08-30 11:24:17 -04:00
// b. Let displaySlot be the Display Slot value of the current row.
2022-06-30 00:58:40 +03:00
auto display_slot = duration_instances_component . set_display_slot ;
2024-06-13 16:05:57 -04:00
// c. Let unit be the Unit value of the current row.
2023-08-30 11:35:04 -04:00
auto unit = MUST ( String : : from_utf8 ( duration_instances_component . unit ) ) ;
2022-06-30 00:58:40 +03:00
2024-06-13 16:05:57 -04:00
// d. Let valueList be the Values value of the current row.
2022-06-30 00:58:40 +03:00
auto value_list = duration_instances_component . values ;
2024-06-13 16:05:57 -04:00
// e. Let digitalBase be the Digital Default value of the current row.
2022-06-30 00:58:40 +03:00
auto digital_base = duration_instances_component . digital_default ;
2024-06-13 16:05:57 -04:00
// f. Let unitOptions be ? GetDurationUnitOptions(unit, options, style, valueList, digitalBase, prevStyle, twoDigitHours).
auto unit_options = TRY ( get_duration_unit_options ( vm , unit , * options , duration_format - > style_string ( ) , value_list , digital_base , previous_style , duration_format - > two_digit_hours ( ) ) ) ;
2022-06-30 00:58:40 +03:00
// g. Set the value of the styleSlot slot of durationFormat to unitOptions.[[Style]].
( duration_format - > * style_slot ) ( unit_options . style ) ;
// h. Set the value of the displaySlot slot of durationFormat to unitOptions.[[Display]].
( duration_format - > * display_slot ) ( unit_options . display ) ;
// i. If unit is one of "hours", "minutes", "seconds", "milliseconds", or "microseconds", then
if ( unit . is_one_of ( " hours " sv , " minutes " sv , " seconds " sv , " milliseconds " sv , " microseconds " sv ) ) {
// i. Set prevStyle to unitOptions.[[Style]].
2024-06-13 16:05:57 -04:00
previous_style = move ( unit_options . style ) ;
2022-06-30 00:58:40 +03:00
}
}
2024-06-13 16:05:57 -04:00
// 27. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options, "fractionalDigits", 0, 9, undefined).
duration_format - > set_fractional_digits ( Optional < u8 > ( TRY ( get_number_option ( vm , * options , vm . names . fractionalDigits , 0 , 9 , { } ) ) ) ) ;
2022-06-30 00:58:40 +03:00
2024-06-13 16:05:57 -04:00
// 28. Return durationFormat.
2022-12-14 19:18:10 +00:00
return duration_format ;
2022-06-30 00:58:40 +03:00
}
2022-06-30 01:25:47 +03:00
// 1.3.2 Intl.DurationFormat.supportedLocalesOf ( locales [ , options ] ), https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat.supportedLocalesOf
JS_DEFINE_NATIVE_FUNCTION ( DurationFormatConstructor : : supported_locales_of )
{
auto locales = vm . argument ( 0 ) ;
auto options = vm . argument ( 1 ) ;
// 1. Let availableLocales be %DurationFormat%.[[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-06-30 01:25:47 +03:00
2024-06-18 10:13:30 -04:00
// 3. Return ? FilterLocales(availableLocales, requestedLocales, options).
return TRY ( filter_locales ( vm , requested_locales , options ) ) ;
2022-06-30 01:25:47 +03:00
}
2022-06-30 00:58:40 +03:00
}