From 2729c881544d68ef6c608f4f3d064bc2323d9006 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 7 Apr 2025 17:39:23 -0400 Subject: [PATCH] LibJS: Migrate remaining Intl objects to use ResolveOptions This is an editorial change in the ECMA-402 spec. See: https://github.com/tc39/ecma402/commit/75e67db --- .../LibJS/Runtime/Intl/AbstractOperations.cpp | 11 --- .../LibJS/Runtime/Intl/AbstractOperations.h | 1 - .../Intl/DurationFormatConstructor.cpp | 56 ++++--------- .../Runtime/Intl/ListFormatConstructor.cpp | 41 ++++------ .../Runtime/Intl/NumberFormatConstructor.cpp | 78 +++++++------------ .../Runtime/Intl/PluralRulesConstructor.cpp | 31 +++----- .../Intl/RelativeTimeFormatConstructor.cpp | 58 ++++---------- .../Runtime/Intl/SegmenterConstructor.cpp | 31 +++----- 8 files changed, 92 insertions(+), 215 deletions(-) diff --git a/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp b/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp index 73eb3fbde13..4d85f3bf6c0 100644 --- a/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp @@ -23,17 +23,6 @@ namespace JS::Intl { -Optional locale_key_from_value(Value value) -{ - if (value.is_undefined()) - return OptionalNone {}; - if (value.is_null()) - return Empty {}; - if (value.is_string()) - return value.as_string().utf8_string(); - VERIFY_NOT_REACHED(); -} - // 6.2.1 IsStructurallyValidLanguageTag ( locale ), https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag bool is_structurally_valid_language_tag(StringView locale) { diff --git a/Libraries/LibJS/Runtime/Intl/AbstractOperations.h b/Libraries/LibJS/Runtime/Intl/AbstractOperations.h index e35fe92e535..f6360c5ba15 100644 --- a/Libraries/LibJS/Runtime/Intl/AbstractOperations.h +++ b/Libraries/LibJS/Runtime/Intl/AbstractOperations.h @@ -20,7 +20,6 @@ namespace JS::Intl { using LocaleKey = Variant; -Optional locale_key_from_value(Value); struct LocaleOptions { Value locale_matcher; diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp index f0227ea07d1..b1174b607e8 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp @@ -50,67 +50,45 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Function { auto& vm = this->vm(); - auto locales = vm.argument(0); + auto locales_value = vm.argument(0); auto options_value = vm.argument(1); // 2. Let durationFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.DurationFormatPrototype%", « [[InitializedDurationFormat]], [[Locale]], [[NumberingSystem]], [[Style]], [[YearsOptions]], [[MonthsOptions]], [[WeeksOptions]], [[DaysOptions]], [[HoursOptions]], [[MinutesOptions]], [[SecondsOptions]], [[MillisecondsOptions]], [[MicrosecondsOptions]], [[NanosecondsOptions]], [[HourMinuteSeparator]], [[MinuteSecondSeparator]], [[FractionalDigits]] »). auto duration_format = TRY(ordinary_create_from_constructor(vm, new_target, &Intrinsics::intl_duration_format_prototype)); - // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). - auto requested_locales = TRY(canonicalize_locale_list(vm, locales)); + // 3. Let optionsResolution be ? ResolveOptions(%Intl.DurationFormat%, %Intl.DurationFormat%.[[LocaleData]], locales, options). + // 4. Set options to optionsResolution.[[Options]]. + // 5. Let r be optionsResolution.[[ResolvedLocale]]. + auto [options, result, _] = TRY(resolve_options(vm, duration_format, locales_value, options_value)); - // 4. Let options be ? GetOptionsObject(options). - auto options = TRY(get_options_object(vm, options_value)); - - // 5. Let matcher be ? GetOption(options, "localeMatcher", STRING, « "lookup", "best fit" », "best fit"). - auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv)); - - // 6. Let numberingSystem be ? GetOption(options, "numberingSystem", STRING, EMPTY, undefined). - auto numbering_system = TRY(get_option(vm, *options, vm.names.numberingSystem, OptionType::String, {}, Empty {})); - - // 7. If numberingSystem is not undefined, then - if (!numbering_system.is_undefined()) { - // a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception. - if (!Unicode::is_type_identifier(numbering_system.as_string().utf8_string_view())) - return vm.throw_completion(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv); - } - - // 8. Let opt be the Record { [[localeMatcher]]: matcher, [[nu]]: numberingSystem }. - LocaleOptions opt {}; - opt.locale_matcher = matcher; - opt.nu = locale_key_from_value(numbering_system); - - // 9. Let r be ResolveLocale(%Intl.DurationFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.DurationFormat%.[[RelevantExtensionKeys]], %Intl.DurationFormat%.[[LocaleData]]). - auto result = resolve_locale(requested_locales, opt, duration_format->relevant_extension_keys()); - - // 10. Set durationFormat.[[Locale]] to r.[[Locale]]. + // 6. Set durationFormat.[[Locale]] to r.[[Locale]]. duration_format->set_locale(move(result.locale)); - // 11. Let resolvedLocaleData be r.[[LocaleData]]. + // 7. Let resolvedLocaleData be r.[[LocaleData]]. - // 12. Let digitalFormat be resolvedLocaleData.[[DigitalFormat]]. + // 8. Let digitalFormat be resolvedLocaleData.[[DigitalFormat]]. auto digital_format = Unicode::digital_format(result.icu_locale); - // 13. Set durationFormat.[[HourMinuteSeparator]] to digitalFormat.[[HourMinuteSeparator]]. + // 9. Set durationFormat.[[HourMinuteSeparator]] to digitalFormat.[[HourMinuteSeparator]]. duration_format->set_hour_minute_separator(move(digital_format.hours_minutes_separator)); - // 14. Set durationFormat.[[MinuteSecondSeparator]] to digitalFormat.[[MinuteSecondSeparator]]. + // 10. Set durationFormat.[[MinuteSecondSeparator]] to digitalFormat.[[MinuteSecondSeparator]]. duration_format->set_minute_second_separator(move(digital_format.minutes_seconds_separator)); - // 15. Set durationFormat.[[NumberingSystem]] to r.[[nu]]. + // 11. Set durationFormat.[[NumberingSystem]] to r.[[nu]]. if (auto* resolved_numbering_system = result.nu.get_pointer()) duration_format->set_numbering_system(move(*resolved_numbering_system)); - // 16. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow", "digital" », "short"). + // 12. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow", "digital" », "short"). auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv, "digital"sv }, "short"sv)); - // 17. Set durationFormat.[[Style]] to style. + // 13. Set durationFormat.[[Style]] to style. duration_format->set_style(style.as_string().utf8_string_view()); - // 18. Let prevStyle be the empty String. + // 14. Let prevStyle be the empty String. Optional previous_style; - // 19. For each row of Table 20, except the header row, in table order, do + // 15. For each row of Table 20, except the header row, in table order, do for (auto const& duration_instances_component : duration_instances_components) { // a. Let slot be the Internal Slot value of the current row. auto slot = duration_instances_component.set_internal_slot; @@ -137,10 +115,10 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Function } } - // 20. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options, "fractionalDigits", 0, 9, undefined). + // 16. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options, "fractionalDigits", 0, 9, undefined). duration_format->set_fractional_digits(Optional(TRY(get_number_option(vm, *options, vm.names.fractionalDigits, 0, 9, {})))); - // 21. Return durationFormat. + // 17. Return durationFormat. return duration_format; } diff --git a/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp index 049c8c1dd9b..5206d34c9b6 100644 --- a/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp @@ -48,55 +48,42 @@ ThrowCompletionOr> ListFormatConstructor::construct(FunctionObje { auto& vm = this->vm(); - auto locale_value = vm.argument(0); + auto locales_value = vm.argument(0); auto options_value = vm.argument(1); // 2. Let listFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.ListFormat.prototype%", « [[InitializedListFormat]], [[Locale]], [[Type]], [[Style]], [[Templates]] »). auto list_format = TRY(ordinary_create_from_constructor(vm, new_target, &Intrinsics::intl_list_format_prototype)); - // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). - auto requested_locales = TRY(canonicalize_locale_list(vm, locale_value)); + // 3. Let optionsResolution be ? ResolveOptions(%Intl.ListFormat%, %Intl.ListFormat%.[[LocaleData]], locales, options). + // 4. Set options to optionsResolution.[[Options]]. + // 5. Let r be optionsResolution.[[ResolvedLocale]]. + auto [options, result, _] = TRY(resolve_options(vm, list_format, locales_value, options_value)); - // 4. Set options to ? GetOptionsObject(options). - auto options = TRY(get_options_object(vm, options_value)); - - // 5. Let opt be a new Record. - LocaleOptions opt {}; - - // 6. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). - auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv)); - - // 7. Set opt.[[localeMatcher]] to matcher. - opt.locale_matcher = matcher; - - // 8. Let r be ResolveLocale(%Intl.ListFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.ListFormat%.[[RelevantExtensionKeys]], %Intl.ListFormat%.[[LocaleData]]). - auto result = resolve_locale(requested_locales, opt, list_format->relevant_extension_keys()); - - // 9. Set listFormat.[[Locale]] to r.[[Locale]]. + // 6. Set listFormat.[[Locale]] to r.[[Locale]]. list_format->set_locale(move(result.locale)); - // 10. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction"). + // 7. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction"). auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "conjunction"sv, "disjunction"sv, "unit"sv }, "conjunction"sv)); - // 11. Set listFormat.[[Type]] to type. + // 8. Set listFormat.[[Type]] to type. list_format->set_type(type.as_string().utf8_string_view()); - // 12. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long"). + // 9. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long"). auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv)); - // 14. Set listFormat.[[Style]] to style. + // 10. Set listFormat.[[Style]] to style. list_format->set_style(style.as_string().utf8_string_view()); - // 14. Let resolvedLocaleData be r.[[LocaleData]]. - // 15. Let dataLocaleTypes be resolvedLocaleData.[[]]. - // 16. Set listFormat.[[Templates]] to dataLocaleTypes.[[