diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp index d7fbb067d60..2c1463623a1 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Linus Groh + * Copyright (c) 2021, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -8,8 +9,11 @@ #include #include #include +#include #include #include +#include +#include namespace JS::Temporal { @@ -29,6 +33,111 @@ void PlainMonthDay::visit_edges(Visitor& visitor) visitor.visit(&m_calendar); } +// 10.5.1 ToTemporalMonthDay ( item [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalmonthday +PlainMonthDay* to_temporal_month_day(GlobalObject& global_object, Value item, Object const* options) +{ + auto& vm = global_object.vm(); + + // 1. If options is not present, set options to ! OrdinaryObjectCreate(null). + if (!options) + options = Object::create(global_object, nullptr); + + // 2. Let referenceISOYear be 1972 (the first leap year after the Unix epoch). + i32 reference_iso_year = 1972; + + // 3. If Type(item) is Object, then + if (item.is_object()) { + auto& item_object = item.as_object(); + + // a. If item has an [[InitializedTemporalMonthDay]] internal slot, then + if (is(item_object)) { + // i. Return item. + return static_cast(&item_object); + } + + Object* calendar = nullptr; + bool calendar_absent; + + // b. If item has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then + // i. Let calendar be item.[[Calendar]]. + // ii. Let calendarAbsent be false. + if (is(item_object)) { + calendar = &static_cast(item_object).calendar(); + calendar_absent = false; + } else if (is(item_object)) { + calendar = &static_cast(item_object).calendar(); + calendar_absent = false; + } else if (is(item_object)) { + calendar = &static_cast(item_object).calendar(); + calendar_absent = false; + } else if (is(item_object)) { + calendar = &static_cast(item_object).calendar(); + calendar_absent = false; + } else if (is(item_object)) { + calendar = &static_cast(item_object).calendar(); + calendar_absent = false; + } else if (is(item_object)) { + calendar = &static_cast(item_object).calendar(); + calendar_absent = false; + } else { + // i. Let calendar be ? Get(item, "calendar"). + auto calendar_value = item_object.get(vm.names.calendar); + if (vm.exception()) + return {}; + + // ii. If calendar is undefined, then + // 1. Let calendarAbsent be true. + // iii. Else, + // 1. Let calendarAbsent be false. + calendar_absent = calendar_value.is_undefined(); + + // iv. Set calendar to ? ToTemporalCalendarWithISODefault(calendar). + calendar = to_temporal_calendar_with_iso_default(global_object, calendar_value); + if (vm.exception()) + return {}; + } + + // d. Let fieldNames be ? CalendarFields(calendar, « "day", "month", "monthCode", "year" »). + auto field_names = calendar_fields(global_object, *calendar, { "day"sv, "month"sv, "monthCode"sv, "year"sv }); + if (vm.exception()) + return {}; + + // e. Let fields be ? PrepareTemporalFields(item, fieldNames, «»). + auto* fields = prepare_temporal_fields(global_object, item_object, field_names, {}); + if (vm.exception()) + return {}; + + // f. Let month be ? Get(fields, "month"). + auto month = fields->get(vm.names.month); + if (vm.exception()) + return {}; + + // g. Let monthCode be ? Get(fields, "monthCode"). + auto month_code = fields->get(vm.names.monthCode); + if (vm.exception()) + return {}; + + // h. Let year be ? Get(fields, "year"). + auto year = fields->get(vm.names.year); + if (vm.exception()) + return {}; + + // i. If calendarAbsent is true, and month is not undefined, and monthCode is undefined and year is undefined, then + if (calendar_absent && !month.is_undefined() && month_code.is_undefined() && year.is_undefined()) { + // i. Perform ! CreateDataPropertyOrThrow(fields, "year", 𝔽(referenceISOYear)). + fields->create_data_property_or_throw(vm.names.year, Value(reference_iso_year)); + } + + // j. Return ? MonthDayFromFields(calendar, fields, options). + return month_day_from_fields(global_object, *calendar, *fields, options); + } + + // FIXME: The spec has an issue in this part which makes it unimplementable, namely: + // - ParseTemporalMonthDayString doesn't return a [[Calendar]] field, which is required in step 7. + // This is a known issue, see https://github.com/tc39/proposal-temporal/issues/1502 + TODO(); +} + // 10.5.2 CreateTemporalMonthDay ( isoMonth, isoDay, calendar, referenceISOYear [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalmonthday PlainMonthDay* create_temporal_month_day(GlobalObject& global_object, u8 iso_month, u8 iso_day, Object& calendar, i32 reference_iso_year, FunctionObject const* new_target) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.h b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.h index a2d7a0dd02a..0137fa0faa3 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.h @@ -39,6 +39,7 @@ struct ISOMonthDay { i32 reference_iso_year; }; +PlainMonthDay* to_temporal_month_day(GlobalObject&, Value item, Object const* options = nullptr); PlainMonthDay* create_temporal_month_day(GlobalObject&, u8 iso_month, u8 iso_day, Object& calendar, i32 reference_iso_year, FunctionObject const* new_target = nullptr); Optional temporal_month_day_to_string(GlobalObject&, PlainMonthDay&, StringView show_calendar);