From a77cdc5f92241db4a1845aa9dcaf9c5908ed268e Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Fri, 27 Aug 2021 18:49:37 +0300 Subject: [PATCH] LibJS: Implement Temporal.PlainTime.from() --- .../Runtime/Temporal/PlainTimeConstructor.cpp | 30 +++++++++++ .../Runtime/Temporal/PlainTimeConstructor.h | 2 + .../Temporal/PlainTime/PlainTime.from.js | 50 +++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.from.js diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.cpp index 1447c22ea2..04d7d3d8b7 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -26,6 +27,9 @@ void PlainTimeConstructor::initialize(GlobalObject& global_object) // 4.2.1 Temporal.PlainTime.prototype, https://tc39.es/proposal-temporal/#sec-temporal-plaintime-prototype define_direct_property(vm.names.prototype, global_object.temporal_plain_time_prototype(), 0); + u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(vm.names.from, from, 1, attr); + define_direct_property(vm.names.length, Value(0), Attribute::Configurable); } @@ -88,4 +92,30 @@ Value PlainTimeConstructor::construct(FunctionObject& new_target) return create_temporal_time(global_object, hour, minute, second, millisecond, microsecond, nanosecond, &new_target); } +// 4.2.2 Temporal.PlainTime.from ( item [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaintime.from +JS_DEFINE_NATIVE_FUNCTION(PlainTimeConstructor::from) +{ + // 1. Set options to ? GetOptionsObject(options). + auto* options = get_options_object(global_object, vm.argument(1)); + if (vm.exception()) + return {}; + + // 2. Let overflow be ? ToTemporalOverflow(options). + auto overflow = to_temporal_overflow(global_object, *options); + if (vm.exception()) + return {}; + + auto item = vm.argument(0); + + // 3. If Type(item) is Object and item has an [[InitializedTemporalTime]] internal slot, then + if (item.is_object() && is(item.as_object())) { + auto& plain_time = static_cast(item.as_object()); + // a. Return ? CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]]). + return create_temporal_time(global_object, plain_time.iso_hour(), plain_time.iso_minute(), plain_time.iso_second(), plain_time.iso_millisecond(), plain_time.iso_microsecond(), plain_time.iso_nanosecond()); + } + + // 4. Return ? ToTemporalTime(item, overflow). + return to_temporal_time(global_object, item, *overflow); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.h b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.h index 2ecd73e123..483b218e71 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.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/PlainTime/PlainTime.from.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.from.js new file mode 100644 index 0000000000..c0c1a2967c --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.from.js @@ -0,0 +1,50 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Temporal.PlainTime.from).toHaveLength(1); + }); + + test("PlainTime instance argument", () => { + const plainTime = new Temporal.PlainTime(18, 45, 37, 1, 2, 3); + const createdPlainTime = Temporal.PlainTime.from(plainTime); + expect(createdPlainTime.hour).toBe(18); + expect(createdPlainTime.minute).toBe(45); + expect(createdPlainTime.second).toBe(37); + expect(createdPlainTime.millisecond).toBe(1); + expect(createdPlainTime.microsecond).toBe(2); + expect(createdPlainTime.nanosecond).toBe(3); + }); + + test("PlainDateTime instance argument", () => { + const plainDateTime = new Temporal.PlainDateTime(2021, 8, 27, 18, 45, 37, 1, 2, 3); + const createdPlainTime = Temporal.PlainTime.from(plainDateTime); + expect(createdPlainTime.hour).toBe(18); + expect(createdPlainTime.minute).toBe(45); + expect(createdPlainTime.second).toBe(37); + expect(createdPlainTime.millisecond).toBe(1); + expect(createdPlainTime.microsecond).toBe(2); + expect(createdPlainTime.nanosecond).toBe(3); + }); + + test("ZonedDateTime instance argument", () => { + const timeZone = new Temporal.TimeZone("UTC"); + const zonedDateTime = new Temporal.ZonedDateTime(1627318123456789000n, timeZone); + const createdPlainTime = Temporal.PlainTime.from(zonedDateTime); + expect(createdPlainTime.hour).toBe(16); + expect(createdPlainTime.minute).toBe(48); + expect(createdPlainTime.second).toBe(43); + expect(createdPlainTime.millisecond).toBe(456); + expect(createdPlainTime.microsecond).toBe(789); + expect(createdPlainTime.nanosecond).toBe(0); + }); + + // Un-skip once ParseISODateTime & ParseTemporalTimeString are implemented + test.skip("PlainTime string argument", () => { + const createdPlainTime = Temporal.PlainTime.from("2021-08-27T18:44:11Z"); + expect(createdPlainTime.hour).toBe(18); + expect(createdPlainTime.minute).toBe(44); + expect(createdPlainTime.second).toBe(11); + expect(createdPlainTime.millisecond).toBe(0); + expect(createdPlainTime.microsecond).toBe(0); + expect(createdPlainTime.nanosecond).toBe(0); + }); +});