diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index bc64cab807..d919410e04 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -207,6 +207,7 @@ M(TemporalInvalidCalendarFieldValue, "Invalid calendar field {}, expected a string") \ M(TemporalInvalidCalendarFunctionResult, "Invalid calendar, {}() function returned {}") \ M(TemporalInvalidCalendarIdentifier, "Invalid calendar identifier '{}'") \ + M(TemporalInvalidDateString, "Invalid date string '{}'") \ M(TemporalInvalidDuration, "Invalid duration") \ M(TemporalInvalidDurationLikeObject, "Invalid duration-like object") \ M(TemporalInvalidDurationPropertyValueNonIntegral, "Invalid value for duration property '{}': must be an integer, got {}") \ diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index 500f09ee80..02af6a4991 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -1240,16 +1240,21 @@ ThrowCompletionOr parse_temporal_calendar_string(GlobalObject& global_ob } // 13.38 ParseTemporalDateString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldatestring -ThrowCompletionOr parse_temporal_date_string(GlobalObject& global_object, [[maybe_unused]] String const& iso_string) +ThrowCompletionOr parse_temporal_date_string(GlobalObject& global_object, String const& iso_string) { + auto& vm = global_object.vm(); + // 1. Assert: Type(isoString) is String. // 2. If isoString does not satisfy the syntax of a TemporalDateString (see 13.33), then - // a. Throw a RangeError exception. - // TODO + auto parse_result = parse_iso8601(Production::TemporalDateString, iso_string); + if (!parse_result.has_value()) { + // a. Throw a RangeError exception. + return vm.throw_completion(global_object, ErrorType::TemporalInvalidDateTimeString, iso_string); + } // 3. Let result be ? ParseISODateTime(isoString). - auto result = TRY(parse_iso_date_time(global_object, {})); + auto result = TRY(parse_iso_date_time(global_object, *parse_result)); // 4. Return the Record { [[Year]]: result.[[Year]], [[Month]]: result.[[Month]], [[Day]]: result.[[Day]], [[Calendar]]: result.[[Calendar]] }. return TemporalDate { .year = result.year, .month = result.month, .day = result.day, .calendar = move(result.calendar) }; diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp index f92446a261..3162e9e232 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.cpp @@ -459,9 +459,18 @@ bool ISO8601Parser::parse_calendar_date_time() return true; } +// https://tc39.es/proposal-temporal/#prod-TemporalDateString +bool ISO8601Parser::parse_temporal_date_string() +{ + // TemporalDateString : + // CalendarDateTime + return parse_calendar_date_time(); } -#define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS +} + +#define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \ + __JS_ENUMERATE(TemporalDateString, parse_temporal_date_string) Optional parse_iso8601(Production production, StringView input) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h index a868c165b5..3625d2421e 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h @@ -26,6 +26,8 @@ struct ParseResult { }; enum class Production { + TemporalDateString, + TemporalDateTimeString, }; Optional parse_iso8601(Production, StringView); @@ -74,6 +76,7 @@ public: [[nodiscard]] bool parse_time_spec_separator(); [[nodiscard]] bool parse_date_time(); [[nodiscard]] bool parse_calendar_date_time(); + [[nodiscard]] bool parse_temporal_date_string(); private: struct State { diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js index 8873f3e388..eed03c7233 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.from.js @@ -28,8 +28,7 @@ describe("correct behavior", () => { expect(createdPlainDate.day).toBe(26); }); - // Un-skip once ParseISODateTime & ParseTemporalDateString are implemented - test.skip("PlainDate string argument", () => { + test("PlainDate string argument", () => { const createdPlainDate = Temporal.PlainDate.from("2021-07-26"); expect(createdPlainDate.year).toBe(2021); expect(createdPlainDate.month).toBe(7); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.since.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.since.js index 5e6dc7f8d7..e0f312f2ed 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.since.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.since.js @@ -102,8 +102,7 @@ describe("correct behavior", () => { } }); - // FIXME: Unskip when plain date string parsing is implemented. - test.skip("PlainDate string argument", () => { + test("PlainDate string argument", () => { const dateTwo = new Temporal.PlainDate(2022, 12, 25); const sinceDuration = dateTwo.since("2021-11-14"); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.until.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.until.js index e73f6a4821..34368074b9 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.until.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.until.js @@ -97,8 +97,7 @@ describe("correct behavior", () => { } }); - // FIXME: Unskip when plain date string parsing is implemented. - test.skip("PlainDate string argument", () => { + test("PlainDate string argument", () => { const dateOne = new Temporal.PlainDate(2021, 11, 14); const untilDuration = dateOne.until("2022-12-25"); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withPlainDate.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withPlainDate.js index 3b33d68203..3221392350 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withPlainDate.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withPlainDate.js @@ -50,8 +50,7 @@ describe("correct behavior", () => { checkExpectedResults(withPlainDateZonedDateTime); }); - // FIXME: Enable when time string parsing is implemented. - test.skip("from plain date string", () => { + test("from plain date string", () => { const plainDateTime = new Temporal.PlainDateTime(2021, 11, 4, 21, 16, 56, 100, 200, 300); const timeZone = new Temporal.TimeZone("UTC"); const zonedDateTime = plainDateTime.toZonedDateTime(timeZone);