diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index ee75aed581b..cdb3492a5a1 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -231,6 +231,31 @@ PlainDate* date_from_fields(GlobalObject& global_object, Object& calendar, Objec return static_cast(date_object); } +// 12.1.28 CalendarEquals ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal-calendarequals +bool calendar_equals(GlobalObject& global_object, Object& one, Object& two) +{ + auto& vm = global_object.vm(); + + // 1. If one and two are the same Object value, return true. + if (&one == &two) + return true; + + // 2. Let calendarOne be ? ToString(one). + auto calendar_one = Value(&one).to_string(global_object); + if (vm.exception()) + return {}; + // 3. Let calendarTwo be ? ToString(two). + auto calendar_two = Value(&two).to_string(global_object); + if (vm.exception()) + return {}; + + // 4. If calendarOne is calendarTwo, return true. + if (calendar_one == calendar_two) + return true; + // 5. Return false. + return false; +} + // 12.1.30 IsISOLeapYear ( year ), https://tc39.es/proposal-temporal/#sec-temporal-isisoleapyear bool is_iso_leap_year(i32 year) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h index fd40bcc5313..5a54d0683be 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h @@ -38,6 +38,7 @@ Object* to_temporal_calendar(GlobalObject&, Value); Object* to_temporal_calendar_with_iso_default(GlobalObject&, Value); Object* get_temporal_calendar_with_iso_default(GlobalObject&, Object&); PlainDate* date_from_fields(GlobalObject&, Object& calendar, Object& fields, Object& options); +bool calendar_equals(GlobalObject&, Object& one, Object& two); bool is_iso_leap_year(i32 year); i32 iso_days_in_month(i32 year, i32 month); String build_iso_month_code(i32 month); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp index 81b55f221c0..a09f442d859 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -28,6 +29,7 @@ void PlainDatePrototype::initialize(GlobalObject& global_object) define_native_accessor(vm.names.calendar, calendar_getter, {}, Attribute::Configurable); u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(vm.names.equals, equals, 1, attr); define_native_function(vm.names.valueOf, value_of, 0, attr); } @@ -57,6 +59,33 @@ JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::calendar_getter) return Value(&temporal_date->calendar()); } +// 3.3.25 Temporal.PlainDate.prototype.equals ( other ), https://tc39.es/proposal-temporal/#sec-temporal.plaindate.prototype.equals +JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::equals) +{ + // 1. Let temporalDate be the this value. + // 2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]). + auto* temporal_date = typed_this(global_object); + if (vm.exception()) + return {}; + + // 3. Set other to ? ToTemporalDate(other). + auto* other = to_temporal_date(global_object, vm.argument(0)); + if (vm.exception()) + return {}; + + // 4. If temporalDate.[[ISOYear]] ≠ other.[[ISOYear]], return false. + if (temporal_date->iso_year() != other->iso_year()) + return Value(false); + // 5. If temporalDate.[[ISOMonth]] ≠ other.[[ISOMonth]], return false. + if (temporal_date->iso_month() != other->iso_month()) + return Value(false); + // 6. If temporalDate.[[ISODay]] ≠ other.[[ISODay]], return false. + if (temporal_date->iso_day() != other->iso_day()) + return Value(false); + // 7. Return ? CalendarEquals(temporalDate.[[Calendar]], other.[[Calendar]]). + return Value(calendar_equals(global_object, temporal_date->calendar(), other->calendar())); +} + // 3.3.31 Temporal.PlainDate.prototype.valueOf ( ), https://tc39.es/proposal-temporal/#sec-temporal.plaindate.prototype.valueof JS_DEFINE_NATIVE_FUNCTION(PlainDatePrototype::value_of) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h index ad37a19f0d0..4182ae0af17 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainDatePrototype.h @@ -21,6 +21,7 @@ public: private: JS_DECLARE_NATIVE_FUNCTION(calendar_getter); + JS_DECLARE_NATIVE_FUNCTION(equals); JS_DECLARE_NATIVE_FUNCTION(value_of); }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.equals.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.equals.js new file mode 100644 index 00000000000..a3aa80a9759 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.equals.js @@ -0,0 +1,13 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.PlainDate.prototype.equals).toHaveLength(1); + }); + + test("basic functionality", () => { + const calendar = { hello: "friends" }; + const first_plain_date = new Temporal.PlainDate(1, 1, 1, calendar); + const second_plain_date = new Temporal.PlainDate(0, 1, 1, calendar); + expect(first_plain_date.equals(first_plain_date)); + expect(!first_plain_date.equals(second_plain_date)); + }); +});