1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:47:44 +00:00

LibJS: Require 'T' prefix for ambiguous time-only strings

This is a normative change in the Temporal spec.

See: 514ede3
This commit is contained in:
Linus Groh 2021-12-22 22:44:46 +01:00
parent a73c71e877
commit 3ab1c52e2b
4 changed files with 443 additions and 29 deletions

View file

@ -1079,60 +1079,83 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object,
// 1. Assert: Type(isoString) is String.
// 2. Let year, month, day, hour, minute, second, fraction, and calendar be the parts of isoString produced respectively by the DateYear, DateMonth, DateDay, TimeHour, TimeMinute, TimeSecond, TimeFraction, and CalendarName productions, or undefined if not present.
// 2. Let year, month, day, fraction, and calendar be the parts of isoString produced respectively by the DateYear, DateMonth, DateDay, TimeFraction, and CalendarName productions, or undefined if not present.
auto year_part = parse_result.date_year;
auto month_part = parse_result.date_month;
auto day_part = parse_result.date_day;
auto hour_part = parse_result.time_hour;
auto minute_part = parse_result.time_minute;
auto second_part = parse_result.time_second;
auto fraction_part = parse_result.time_fraction;
auto calendar_part = parse_result.calendar_name;
// 3. If the first code unit of year is 0x2212 (MINUS SIGN), replace it with the code unit 0x002D (HYPHEN-MINUS).
// 3. Let year be the part of isoString produced by the DateYear production.
// NOTE: Duplicate assignment, already covered above (see https://github.com/tc39/proposal-temporal/pull/1987)
// 4. Let hour be the part of isoString produced by the TimeHour, TimeHourNotValidMonth, TimeHourNotThirtyOneDayMonth, or TimeHourTwoOnly productions, or undefined if none of those are present.
auto hour_part = parse_result.time_hour;
if (!hour_part.has_value())
hour_part = parse_result.time_hour_not_valid_month;
if (!hour_part.has_value())
hour_part = parse_result.time_hour_not_thirty_one_day_month;
if (!hour_part.has_value())
hour_part = parse_result.time_hour_two_only;
// 5. Let minute be the part of isoString produced by the TimeMinute, TimeMinuteNotValidDay, TimeMinuteThirtyOnly, or TimeMinuteThirtyOneOnly productions, or undefined if none of those are present.
auto minute_part = parse_result.time_minute;
if (!minute_part.has_value())
minute_part = parse_result.time_minute_not_valid_day;
if (!minute_part.has_value())
minute_part = parse_result.time_minute_thirty_only;
if (!minute_part.has_value())
minute_part = parse_result.time_minute_thirty_one_only;
// 6. Let second be the part of isoString produced by the TimeSecond or TimeSecondNotValidMonth productions, or undefined if neither of those are present.
auto second_part = parse_result.time_second;
if (!second_part.has_value())
second_part = parse_result.time_second_not_valid_month;
// 7. If the first code unit of year is 0x2212 (MINUS SIGN), replace it with the code unit 0x002D (HYPHEN-MINUS).
String normalized_year;
if (year_part.has_value() && year_part->starts_with("\xE2\x88\x92"sv))
normalized_year = String::formatted("-{}", year_part->substring_view(3));
else
normalized_year = year_part.value_or("0");
// 4. Set year to ! ToIntegerOrInfinity(year).
// 8. Set year to ! ToIntegerOrInfinity(year).
auto year = *normalized_year.to_int<i32>();
u8 month;
// 5. If month is undefined, then
// 9. If month is undefined, then
if (!month_part.has_value()) {
// a. Set month to 1.
month = 1;
}
// 6. Else,
// 10. Else,
else {
// a. Set month to ! ToIntegerOrInfinity(month).
month = *month_part->to_uint<u8>();
}
u8 day;
// 7. If day is undefined, then
// 11. If day is undefined, then
if (!day_part.has_value()) {
// a. Set day to 1.
day = 1;
}
// 8. Else,
// 12. Else,
else {
// a. Set day to ! ToIntegerOrInfinity(day).
day = *day_part->to_uint<u8>();
}
// 9. Set hour to ! ToIntegerOrInfinity(hour).
// 13. Set hour to ! ToIntegerOrInfinity(hour).
u8 hour = *hour_part.value_or("0"sv).to_uint<u8>();
// 10. Set minute to ! ToIntegerOrInfinity(minute).
// 14. Set minute to ! ToIntegerOrInfinity(minute).
u8 minute = *minute_part.value_or("0"sv).to_uint<u8>();
// 11. Set second to ! ToIntegerOrInfinity(second).
// 15. Set second to ! ToIntegerOrInfinity(second).
u8 second = *second_part.value_or("0"sv).to_uint<u8>();
// 12. If second is 60, then
// 16. If second is 60, then
if (second == 60) {
// a. Set second to 59.
second = 59;
@ -1141,7 +1164,7 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object,
u16 millisecond;
u16 microsecond;
u16 nanosecond;
// 13. If fraction is not undefined, then
// 17. If fraction is not undefined, then
if (fraction_part.has_value()) {
// a. Set fraction to the string-concatenation of the previous value of fraction and the string "000000000".
auto fraction = String::formatted("{}000000000", *fraction_part);
@ -1155,7 +1178,7 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object,
// g. Set nanosecond to ! ToIntegerOrInfinity(nanosecond).
nanosecond = *fraction.substring(7, 3).to_uint<u16>();
}
// 14. Else,
// 18. Else,
else {
// a. Let millisecond be 0.
millisecond = 0;
@ -1165,15 +1188,15 @@ ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject& global_object,
nanosecond = 0;
}
// 15. If ! IsValidISODate(year, month, day) is false, throw a RangeError exception.
// 19. If ! IsValidISODate(year, month, day) is false, throw a RangeError exception.
if (!is_valid_iso_date(year, month, day))
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidISODate);
// 16. If ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
// 20. If ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
if (!is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond))
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidTime);
// 17. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond, [[Calendar]]: calendar }.
// 21. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond, [[Calendar]]: calendar }.
return ISODateTime { .year = year, .month = month, .day = day, .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = microsecond, .nanosecond = nanosecond, .calendar = calendar_part.has_value() ? *calendar_part : Optional<String>() };
}
@ -1567,7 +1590,11 @@ ThrowCompletionOr<TemporalTime> parse_temporal_time_string(GlobalObject& global_
// 4. Let result be ? ParseISODateTime(isoString).
auto result = TRY(parse_iso_date_time(global_object, *parse_result));
// 5. Return the Record { [[Hour]]: result.[[Hour]], [[Minute]]: result.[[Minute]], [[Second]]: result.[[Second]], [[Millisecond]]: result.[[Millisecond]], [[Microsecond]]: result.[[Microsecond]], [[Nanosecond]]: result.[[Nanosecond]], [[Calendar]]: result.[[Calendar]] }.
// 5. Assert: ParseText(! StringToCodePoints(isoString), CalendarDate) is a List of errors.
// 6. Assert: ParseText(! StringToCodePoints(isoString), DateSpecYearMonth) is a List of errors.
// 7. Assert: ParseText(! StringToCodePoints(isoString), DateSpecMonthDay) is a List of errors.
// 8. Return the Record { [[Hour]]: result.[[Hour]], [[Minute]]: result.[[Minute]], [[Second]]: result.[[Second]], [[Millisecond]]: result.[[Millisecond]], [[Microsecond]]: result.[[Microsecond]], [[Nanosecond]]: result.[[Nanosecond]], [[Calendar]]: result.[[Calendar]] }.
return TemporalTime { .hour = result.hour, .minute = result.minute, .second = result.second, .millisecond = result.millisecond, .microsecond = result.microsecond, .nanosecond = result.nanosecond, .calendar = move(result.calendar) };
}