Ver código fonte

LibJS: Reject relativeTo string such as "2022-08-18T17:01Z"

This is a normative change in the Temporal spec.

See: https://github.com/tc39/proposal-temporal/commit/2dc20bf
Linus Groh 2 anos atrás
pai
commit
4567ded8e4

+ 2 - 0
Userland/Libraries/LibJS/Runtime/ErrorTypes.h

@@ -254,6 +254,8 @@
     M(TemporalInvalidPlainMonthDay, "Invalid plain month day")                                                                          \
     M(TemporalInvalidPlainMonthDay, "Invalid plain month day")                                                                          \
     M(TemporalInvalidPlainTime, "Invalid plain time")                                                                                   \
     M(TemporalInvalidPlainTime, "Invalid plain time")                                                                                   \
     M(TemporalInvalidPlainYearMonth, "Invalid plain year month")                                                                        \
     M(TemporalInvalidPlainYearMonth, "Invalid plain year month")                                                                        \
+    M(TemporalInvalidRelativeToStringUTCDesignatorWithoutBracketedTimeZone, "Invalid relativeTo string '{}': must not contain a UTC "   \
+                                                                            "designator without bracketed time zone")                   \
     M(TemporalInvalidTime, "Invalid time")                                                                                              \
     M(TemporalInvalidTime, "Invalid time")                                                                                              \
     M(TemporalInvalidTimeString, "Invalid time string '{}'")                                                                            \
     M(TemporalInvalidTimeString, "Invalid time string '{}'")                                                                            \
     M(TemporalInvalidTimeStringUTCDesignator, "Invalid time string '{}': must not contain a UTC designator")                            \
     M(TemporalInvalidTimeStringUTCDesignator, "Invalid time string '{}': must not contain a UTC designator")                            \

+ 8 - 2
Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp

@@ -1609,12 +1609,18 @@ ThrowCompletionOr<TemporalMonthDay> parse_temporal_month_day_string(VM& vm, Stri
 // 13.36 ParseTemporalRelativeToString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalrelativetostring
 // 13.36 ParseTemporalRelativeToString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalrelativetostring
 ThrowCompletionOr<ISODateTime> parse_temporal_relative_to_string(VM& vm, String const& iso_string)
 ThrowCompletionOr<ISODateTime> parse_temporal_relative_to_string(VM& vm, String const& iso_string)
 {
 {
-    // 1. If ParseText(StringToCodePoints(isoString), TemporalDateTimeString) is a List of errors, throw a RangeError exception.
+    // 1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalDateTimeString).
     auto parse_result = parse_iso8601(Production::TemporalDateTimeString, iso_string);
     auto parse_result = parse_iso8601(Production::TemporalDateTimeString, iso_string);
+
+    // 2. If parseResult is a List of errors, throw a RangeError exception.
     if (!parse_result.has_value())
     if (!parse_result.has_value())
         return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidDateTimeString, iso_string);
         return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidDateTimeString, iso_string);
 
 
-    // 2. Return ? ParseISODateTime(isoString).
+    // 3. If parseResult contains a UTCDesignator ParseNode but no TimeZoneBracketedAnnotation Parse Node, throw a RangeError exception.
+    if (parse_result->utc_designator.has_value() && !parse_result->time_zone_bracketed_annotation.has_value())
+        return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidRelativeToStringUTCDesignatorWithoutBracketedTimeZone, iso_string);
+
+    // 4. Return ? ParseISODateTime(isoString).
     return parse_iso_date_time(vm, *parse_result);
     return parse_iso_date_time(vm, *parse_result);
 }
 }
 
 

+ 1 - 0
Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp

@@ -830,6 +830,7 @@ bool ISO8601Parser::parse_time_zone_bracketed_annotation()
         return false;
         return false;
     if (!m_state.lexer.consume_specific(']'))
     if (!m_state.lexer.consume_specific(']'))
         return false;
         return false;
+    m_state.parse_result.time_zone_bracketed_annotation = transaction.parsed_string_view();
     transaction.commit();
     transaction.commit();
     return true;
     return true;
 }
 }

+ 1 - 0
Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h

@@ -24,6 +24,7 @@ struct ParseResult {
     Optional<StringView> time_fraction;
     Optional<StringView> time_fraction;
     Optional<StringView> calendar_name;
     Optional<StringView> calendar_name;
     Optional<StringView> utc_designator;
     Optional<StringView> utc_designator;
+    Optional<StringView> time_zone_bracketed_annotation;
     Optional<StringView> time_zone_numeric_utc_offset;
     Optional<StringView> time_zone_numeric_utc_offset;
     Optional<StringView> time_zone_utc_offset_sign;
     Optional<StringView> time_zone_utc_offset_sign;
     Optional<StringView> time_zone_utc_offset_hour;
     Optional<StringView> time_zone_utc_offset_hour;

+ 10 - 0
Userland/Libraries/LibJS/Tests/builtins/Temporal/Duration/Duration.compare.js

@@ -100,4 +100,14 @@ describe("errors", () => {
             Temporal.Duration.compare(duration, duration, { relativeTo: zonedDateTime });
             Temporal.Duration.compare(duration, duration, { relativeTo: zonedDateTime });
         }).toThrowWithMessage(TypeError, "null is not a function");
         }).toThrowWithMessage(TypeError, "null is not a function");
     });
     });
+
+    test("UTC designator only allowed with bracketed time zone", () => {
+        const duration = new Temporal.Duration();
+        expect(() => {
+            Temporal.Duration.compare(duration, duration, { relativeTo: "2022-08-18T17:01Z" });
+        }).toThrowWithMessage(
+            RangeError,
+            "Invalid relativeTo string '2022-08-18T17:01Z': must not contain a UTC designator without bracketed time zone"
+        );
+    });
 });
 });