1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 23:28:11 +00:00

LibJS: Include hour-cycle in DateTimeFormat options

This is a normative change to the Intl spec:
20e5c26

Note that this doesn't actually affect us. Its purpose is to provide the
hour-cycle to BestFitFormatMatcher. This AO is implementation defined,
and ours just invokes BasicFormatMatcher, which doesn't use this field.
We could now have LibUnicode generate this field and use it to find a
better format pattern, though.
This commit is contained in:
Timothy Flynn 2022-01-10 08:02:01 -05:00 committed by Linus Groh
parent 15947aa1f0
commit 05de9b82b8

View file

@ -179,7 +179,7 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
// 27. Set dateTimeFormat.[[TimeZone]] to timeZone.
date_time_format.set_time_zone(move(time_zone));
// 28. Let opt be a new Record.
// 28. Let formatOptions be a new Record.
Unicode::CalendarPattern format_options {};
// 29. For each row of Table 4, except the header row, in table order, do
@ -193,7 +193,7 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
// i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
auto value = TRY(get_number_option(global_object, *options, property, 1, 3, {}));
// d. Set opt.[[<prop>]] to value.
// d. Set formatOptions.[[<prop>]] to value.
if (value.has_value())
option = static_cast<ValueType>(value.value());
}
@ -202,7 +202,7 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
// i. Let value be ? GetOption(options, prop, "string", « the strings given in the Values column of the row », undefined).
auto value = TRY(get_option(global_object, *options, property, Value::Type::String, defaults, Empty {}));
// d. Set opt.[[<prop>]] to value.
// d. Set formatOptions.[[<prop>]] to value.
if (!value.is_undefined())
option = Unicode::calendar_pattern_style_from_string(value.as_string().string());
}
@ -212,31 +212,81 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
// 30. Let dataLocaleData be localeData.[[<dataLocale>]].
// 31. Let matcher be ? GetOption(options, "formatMatcher", "string", « "basic", "best fit" », "best fit").
// 31. Let hcDefault be dataLocaleData.[[hourCycle]].
auto default_hour_cycle = Unicode::get_default_regional_hour_cycle(data_locale);
// Non-standard, default_hour_cycle will be empty if Unicode data generation is disabled.
if (!default_hour_cycle.has_value())
return &date_time_format;
// 32. Let hc be dateTimeFormat.[[HourCycle]].
// 33. If hc is null, then
// a. Set hc to hcDefault.
auto hour_cycle_value = date_time_format.has_hour_cycle() ? date_time_format.hour_cycle() : *default_hour_cycle;
// 34. If hour12 is true, then
if (hour12.is_boolean() && hour12.as_bool()) {
// a. If hcDefault is "h11" or "h23", then
if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
// i. Set hc to "h11".
hour_cycle_value = Unicode::HourCycle::H11;
}
// b. Else,
else {
// i. Set hc to "h12".
hour_cycle_value = Unicode::HourCycle::H12;
}
}
// 35. Else if hour12 is false, then
else if (hour12.is_boolean() && !hour12.as_bool()) {
// a. If hcDefault is "h11" or "h23", then
if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
// i. Set hc to "h23".
hour_cycle_value = Unicode::HourCycle::H23;
}
// b. Else,
else {
// i. Set hc to "h24".
hour_cycle_value = Unicode::HourCycle::H24;
}
}
// 36. Else,
else {
// a. Assert: hour12 is undefined.
VERIFY(hour12.is_undefined());
}
// 37. Set dateTimeFormat.[[HourCycle]] to hc.
date_time_format.set_hour_cycle(hour_cycle_value);
// 38. Set formatOptions.[[hourCycle]] to hc.
format_options.hour_cycle = hour_cycle_value;
// 39. Let matcher be ? GetOption(options, "formatMatcher", "string", « "basic", "best fit" », "best fit").
matcher = TRY(get_option(global_object, *options, vm.names.formatMatcher, Value::Type::String, AK::Array { "basic"sv, "best fit"sv }, "best fit"sv));
// 32. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined).
// 40. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined).
auto date_style = TRY(get_option(global_object, *options, vm.names.dateStyle, Value::Type::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {}));
// 33. Set dateTimeFormat.[[DateStyle]] to dateStyle.
// 41. Set dateTimeFormat.[[DateStyle]] to dateStyle.
if (!date_style.is_undefined())
date_time_format.set_date_style(date_style.as_string().string());
// 34. Let timeStyle be ? GetOption(options, "timeStyle", "string", « "full", "long", "medium", "short" », undefined).
// 42. Let timeStyle be ? GetOption(options, "timeStyle", "string", « "full", "long", "medium", "short" », undefined).
auto time_style = TRY(get_option(global_object, *options, vm.names.timeStyle, Value::Type::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {}));
// 35. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
// 43. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
if (!time_style.is_undefined())
date_time_format.set_time_style(time_style.as_string().string());
Optional<Unicode::CalendarPattern> best_format {};
// 36. If dateStyle is not undefined or timeStyle is not undefined, then
// 44. If dateStyle is not undefined or timeStyle is not undefined, then
if (date_time_format.has_date_style() || date_time_format.has_time_style()) {
// a. For each row in Table 4, except the header row, do
TRY(for_each_calendar_field(global_object, format_options, [&](auto const& option, auto const& property, auto const&) -> ThrowCompletionOr<void> {
// i. Let prop be the name given in the Property column of the row.
// ii. Let p be opt.[[<prop>]].
// ii. Let p be formatOptions.[[<prop>]].
// iii. If p is not undefined, then
if (option.has_value()) {
// 1. Throw a TypeError exception.
@ -250,28 +300,24 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
// c. Let bestFormat be DateTimeStyleFormat(dateStyle, timeStyle, styles).
best_format = date_time_style_format(data_locale, date_time_format);
}
// 37. Else,
// 45. Else,
else {
// a. Let formats be dataLocaleData.[[formats]].[[<calendar>]].
auto formats = Unicode::get_calendar_available_formats(data_locale, date_time_format.calendar());
// b. If matcher is "basic", then
if (matcher.as_string().string() == "basic"sv) {
// i. Let bestFormat be BasicFormatMatcher(opt, formats).
// i. Let bestFormat be BasicFormatMatcher(formatOptions, formats).
best_format = basic_format_matcher(format_options, move(formats));
}
// c. Else,
else {
// i. Let bestFormat be BestFitFormatMatcher(opt, formats).
// i. Let bestFormat be BestFitFormatMatcher(formatOptions, formats).
best_format = best_fit_format_matcher(format_options, move(formats));
}
}
// Non-standard, best_format will be empty if Unicode data generation is disabled.
if (!best_format.has_value())
return &date_time_format;
// 38. For each row in Table 4, except the header row, in table order, do
// 46. For each row in Table 4, except the header row, in table order, do
date_time_format.for_each_calendar_field_zipped_with(*best_format, [&](auto& date_time_format_field, auto const& best_format_field, auto) {
// a. Let prop be the name given in the Property column of the row.
// b. If bestFormat has a field [[<prop>]], then
@ -285,93 +331,42 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
String pattern;
Vector<Unicode::CalendarRangePattern> range_patterns;
// 39. If dateTimeFormat.[[Hour]] is undefined, then
// 47. If dateTimeFormat.[[Hour]] is undefined, then
if (!date_time_format.has_hour()) {
// a. Set dateTimeFormat.[[HourCycle]] to undefined.
date_time_format.clear_hour_cycle();
}
// b. Let pattern be bestFormat.[[pattern]].
// 48. If dateTimeformat.[[HourCycle]] is "h11" or "h12", then
if ((hour_cycle_value == Unicode::HourCycle::H11) || (hour_cycle_value == Unicode::HourCycle::H12)) {
// a. Let pattern be bestFormat.[[pattern12]].
if (best_format->pattern12.has_value()) {
pattern = best_format->pattern12.release_value();
} else {
// Non-standard, LibUnicode only provides [[pattern12]] when [[pattern]] has a day
// period. Other implementations provide [[pattern12]] as a copy of [[pattern]].
pattern = move(best_format->pattern);
}
// b. Let rangePatterns be bestFormat.[[rangePatterns12]].
range_patterns = Unicode::get_calendar_range12_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
}
// 49. Else,
else {
// a. Let pattern be bestFormat.[[pattern]].
pattern = move(best_format->pattern);
// c. Let rangePatterns be bestFormat.[[rangePatterns]].
// b. Let rangePatterns be bestFormat.[[rangePatterns]].
range_patterns = Unicode::get_calendar_range_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
}
// 40. Else,
else {
// a. Let hcDefault be dataLocaleData.[[hourCycle]].
auto default_hour_cycle = Unicode::get_default_regional_hour_cycle(data_locale);
VERIFY(default_hour_cycle.has_value());
// b. Let hc be dateTimeFormat.[[HourCycle]].
// c. If hc is null, then
// i. Set hc to hcDefault.
auto hour_cycle = date_time_format.has_hour_cycle() ? date_time_format.hour_cycle() : *default_hour_cycle;
// d. If hour12 is not undefined, then
if (!hour12.is_undefined()) {
// i. If hour12 is true, then
if (hour12.as_bool()) {
// 1. If hcDefault is "h11" or "h23", then
if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
// a. Set hc to "h11".
hour_cycle = Unicode::HourCycle::H11;
}
// 2. Else,
else {
// a. Set hc to "h12".
hour_cycle = Unicode::HourCycle::H12;
}
}
// ii. Else,
else {
// 1. Assert: hour12 is false.
// 2. If hcDefault is "h11" or "h23", then
if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
// a. Set hc to "h23".
hour_cycle = Unicode::HourCycle::H23;
}
// 3. Else,
else {
// a. Set hc to "h24".
hour_cycle = Unicode::HourCycle::H24;
}
}
}
// e. Set dateTimeFormat.[[HourCycle]] to hc.
date_time_format.set_hour_cycle(hour_cycle);
// f. If dateTimeformat.[[HourCycle]] is "h11" or "h12", then
if ((hour_cycle == Unicode::HourCycle::H11) || (hour_cycle == Unicode::HourCycle::H12)) {
// i. Let pattern be bestFormat.[[pattern12]].
if (best_format->pattern12.has_value()) {
pattern = best_format->pattern12.release_value();
} else {
// Non-standard, LibUnicode only provides [[pattern12]] when [[pattern]] has a day
// period. Other implementations provide [[pattern12]] as a copy of [[pattern]].
pattern = move(best_format->pattern);
}
// ii. Let rangePatterns be bestFormat.[[rangePatterns12]].
range_patterns = Unicode::get_calendar_range12_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
}
// g. Else,
else {
// i. Let pattern be bestFormat.[[pattern]].
pattern = move(best_format->pattern);
// ii. Let rangePatterns be bestFormat.[[rangePatterns]].
range_patterns = Unicode::get_calendar_range_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
}
}
// 41. Set dateTimeFormat.[[Pattern]] to pattern.
// 50. Set dateTimeFormat.[[Pattern]] to pattern.
date_time_format.set_pattern(move(pattern));
// 42. Set dateTimeFormat.[[RangePatterns]] to rangePatterns.
// 51. Set dateTimeFormat.[[RangePatterns]] to rangePatterns.
date_time_format.set_range_patterns(move(range_patterns));
// 43. Return dateTimeFormat.
// 52. Return dateTimeFormat.
return &date_time_format;
}