From 2d5b15295a9c02f3743dba6ca457cf968be40b75 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Fri, 10 Sep 2021 03:44:34 +0100 Subject: [PATCH] LibJS: Implement Temporal.PlainMonthDay.from --- .../Temporal/PlainMonthDayConstructor.cpp | 31 ++++++++++ .../Temporal/PlainMonthDayConstructor.h | 2 + .../PlainMonthDay/PlainMonthDay.from.js | 58 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.cpp index 8401b53409..639d713783 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -28,6 +29,9 @@ void PlainMonthDayConstructor::initialize(GlobalObject& global_object) define_direct_property(vm.names.prototype, global_object.temporal_plain_month_day_prototype(), 0); define_direct_property(vm.names.length, Value(2), Attribute::Configurable); + + u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(vm.names.from, from, 1, attr); } // 10.1.1 Temporal.PlainMonthDay ( isoMonth, isoDay [ , calendarLike [ , referenceISOYear ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.plainmonthday @@ -89,4 +93,31 @@ Value PlainMonthDayConstructor::construct(FunctionObject& new_target) return create_temporal_month_day(global_object, m, d, *calendar, ref, &new_target); } +// 10.2.2 Temporal.PlainMonthDay.from ( item [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal.plainmonthday.from +JS_DEFINE_NATIVE_FUNCTION(PlainMonthDayConstructor::from) +{ + // 1. Set options to ? GetOptionsObject(options). + auto* options = get_options_object(global_object, vm.argument(1)); + if (vm.exception()) + return {}; + + auto item = vm.argument(0); + + // 2. If Type(item) is Object and item has an [[InitializedTemporalMonthDay]] internal slot, then + if (item.is_object() && is(item.as_object())) { + // a. Perform ? ToTemporalOverflow(options). + (void)to_temporal_overflow(global_object, *options); + if (vm.exception()) + return {}; + + auto& plain_month_day_object = static_cast(item.as_object()); + + // b. Return ? CreateTemporalMonthDay(item.[[ISOMonth]], item.[[ISODay]], item.[[Calendar]], item.[[ISOYear]]). + return create_temporal_month_day(global_object, plain_month_day_object.iso_month(), plain_month_day_object.iso_day(), plain_month_day_object.calendar(), plain_month_day_object.iso_year()); + } + + // 3. Return ? ToTemporalMonthDay(item, options). + return to_temporal_month_day(global_object, item, options); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.h b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.h index 540df5f210..01ab59c0e7 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDayConstructor.h @@ -23,6 +23,8 @@ public: private: virtual bool has_constructor() const override { return true; } + + JS_DECLARE_NATIVE_FUNCTION(from); }; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js new file mode 100644 index 0000000000..b9b01c4d32 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.from.js @@ -0,0 +1,58 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.PlainMonthDay.from).toHaveLength(1); + }); + + test("PlainDate instance argument", () => { + const plainDate = new Temporal.PlainDate(2021, 7, 6); + const plainMonthDay = Temporal.PlainMonthDay.from(plainDate); + expect(plainMonthDay.monthCode).toBe("M07"); + expect(plainMonthDay.day).toBe(6); + }); + + test("PlainMonthDay instance argument", () => { + const plainMonthDay_ = new Temporal.PlainMonthDay(7, 6); + const plainMonthDay = Temporal.PlainMonthDay.from(plainMonthDay_); + expect(plainMonthDay.monthCode).toBe("M07"); + expect(plainMonthDay.day).toBe(6); + }); + + test("ZonedDateTime instance argument", () => { + const timeZone = new Temporal.TimeZone("UTC"); + const zonedDateTime = new Temporal.ZonedDateTime(1625614921000000000n, timeZone); + const plainMonthDay = Temporal.PlainMonthDay.from(zonedDateTime); + expect(plainMonthDay.monthCode).toBe("M07"); + expect(plainMonthDay.day).toBe(6); + }); + + test("fields object argument", () => { + const object = { + month: 7, + day: 6, + }; + const plainMonthDay = Temporal.PlainMonthDay.from(object); + expect(plainMonthDay.monthCode).toBe("M07"); + expect(plainMonthDay.day).toBe(6); + }); + + // Un-skip once ParseISODateTime, ToTemporalMonthDay & ParseTemporalMonthDayString are fully implemented + test.skip("PlainMonthDay string argument", () => { + const plainMonthDay = Temporal.PlainMonthDay.from("2021-07-06T23:42:01Z"); + expect(plainMonthDay.monthCode).toBe("M07"); + expect(plainMonthDay.day).toBe(6); + }); +}); + +describe("errors", () => { + test("missing fields", () => { + expect(() => { + Temporal.PlainMonthDay.from({}); + }).toThrowWithMessage(TypeError, "Required property month is missing or undefined"); + expect(() => { + Temporal.PlainMonthDay.from({ month: 1 }); + }).toThrowWithMessage(TypeError, "Required property day is missing or undefined"); + expect(() => { + Temporal.PlainMonthDay.from({ day: 1 }); + }).toThrowWithMessage(TypeError, "Required property month is missing or undefined"); + }); +});