mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 09:34:57 +09:00
LibJS: Implement the Temporal.PlainDateTime constructor
And the simple Temporal.PlainDateTime.prototype getters, so that the constructed Temporal.PlainDateTime may actually be validated.
This commit is contained in:
parent
a61cdeba24
commit
029b6ad1a8
Notes:
github-actions[bot]
2024-11-24 10:45:50 +00:00
Author: https://github.com/trflynn89
Commit: 029b6ad1a8
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2544
41 changed files with 1210 additions and 13 deletions
|
@ -216,6 +216,8 @@ set(SOURCES
|
|||
Runtime/Temporal/PlainDateConstructor.cpp
|
||||
Runtime/Temporal/PlainDatePrototype.cpp
|
||||
Runtime/Temporal/PlainDateTime.cpp
|
||||
Runtime/Temporal/PlainDateTimeConstructor.cpp
|
||||
Runtime/Temporal/PlainDateTimePrototype.cpp
|
||||
Runtime/Temporal/PlainMonthDay.cpp
|
||||
Runtime/Temporal/PlainMonthDayConstructor.cpp
|
||||
Runtime/Temporal/PlainMonthDayPrototype.cpp
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
#define JS_ENUMERATE_TEMPORAL_OBJECTS \
|
||||
__JS_ENUMERATE(Duration, duration, DurationPrototype, DurationConstructor) \
|
||||
__JS_ENUMERATE(PlainDate, plain_date, PlainDatePrototype, PlainDateConstructor) \
|
||||
__JS_ENUMERATE(PlainDateTime, plain_date_time, PlainDateTimePrototype, PlainDateTimeConstructor) \
|
||||
__JS_ENUMERATE(PlainMonthDay, plain_month_day, PlainMonthDayPrototype, PlainMonthDayConstructor) \
|
||||
__JS_ENUMERATE(PlainTime, plain_time, PlainTimePrototype, PlainTimeConstructor) \
|
||||
__JS_ENUMERATE(PlainYearMonth, plain_year_month, PlainYearMonthPrototype, PlainYearMonthConstructor)
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include <LibJS/Runtime/StringPrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainMonthDay.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainYearMonth.h>
|
||||
|
@ -848,6 +849,15 @@ ErrorOr<void> print_temporal_plain_date(JS::PrintContext& print_context, JS::Tem
|
|||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> print_temporal_plain_date_time(JS::PrintContext& print_context, JS::Temporal::PlainDateTime const& plain_date_time, HashTable<JS::Object*>& seen_objects)
|
||||
{
|
||||
TRY(print_type(print_context, "Temporal.PlainDateTime"sv));
|
||||
TRY(js_out(print_context, " \033[34;1m{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}{:03}{:03}\033[0m", plain_date_time.iso_date_time().iso_date.year, plain_date_time.iso_date_time().iso_date.month, plain_date_time.iso_date_time().iso_date.day, plain_date_time.iso_date_time().time.hour, plain_date_time.iso_date_time().time.minute, plain_date_time.iso_date_time().time.second, plain_date_time.iso_date_time().time.millisecond, plain_date_time.iso_date_time().time.microsecond, plain_date_time.iso_date_time().time.nanosecond));
|
||||
TRY(js_out(print_context, "\n calendar: "));
|
||||
TRY(print_value(print_context, JS::PrimitiveString::create(plain_date_time.vm(), plain_date_time.calendar()), seen_objects));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> print_temporal_plain_month_day(JS::PrintContext& print_context, JS::Temporal::PlainMonthDay const& plain_month_day, HashTable<JS::Object*>& seen_objects)
|
||||
{
|
||||
TRY(print_type(print_context, "Temporal.PlainMonthDay"sv));
|
||||
|
@ -992,6 +1002,8 @@ ErrorOr<void> print_value(JS::PrintContext& print_context, JS::Value value, Hash
|
|||
return print_temporal_duration(print_context, static_cast<JS::Temporal::Duration&>(object), seen_objects);
|
||||
if (is<JS::Temporal::PlainDate>(object))
|
||||
return print_temporal_plain_date(print_context, static_cast<JS::Temporal::PlainDate&>(object), seen_objects);
|
||||
if (is<JS::Temporal::PlainDateTime>(object))
|
||||
return print_temporal_plain_date_time(print_context, static_cast<JS::Temporal::PlainDateTime&>(object), seen_objects);
|
||||
if (is<JS::Temporal::PlainMonthDay>(object))
|
||||
return print_temporal_plain_month_day(print_context, static_cast<JS::Temporal::PlainMonthDay&>(object), seen_objects);
|
||||
if (is<JS::Temporal::PlainTime>(object))
|
||||
|
|
|
@ -103,6 +103,8 @@
|
|||
#include <LibJS/Runtime/Temporal/DurationPrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDatePrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTimeConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTimePrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainMonthDayConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainMonthDayPrototype.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||
|
|
|
@ -431,11 +431,18 @@ ThrowCompletionOr<RelativeTo> get_temporal_relative_to_option(VM& vm, Object con
|
|||
return RelativeTo { .plain_relative_to = static_cast<PlainDate&>(object), .zoned_relative_to = {} };
|
||||
}
|
||||
|
||||
// FIXME: c. If value has an [[InitializedTemporalDateTime]] internal slot, then
|
||||
// FIXME: i. Let plainDate be ! CreateTemporalDate(value.[[ISODateTime]].[[ISODate]], value.[[Calendar]]).
|
||||
// FIXME: ii. Return the Record { [[PlainRelativeTo]]: plainDate, [[ZonedRelativeTo]]: undefined }.
|
||||
// c. If value has an [[InitializedTemporalDateTime]] internal slot, then
|
||||
if (is<PlainDateTime>(object)) {
|
||||
auto const& plain_date_time = static_cast<PlainDateTime const&>(object);
|
||||
|
||||
// FIXME: d. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(value).
|
||||
// i. Let plainDate be ! CreateTemporalDate(value.[[ISODateTime]].[[ISODate]], value.[[Calendar]]).
|
||||
auto plain_date = MUST(create_temporal_date(vm, plain_date_time.iso_date_time().iso_date, plain_date_time.calendar()));
|
||||
|
||||
// ii. Return the Record { [[PlainRelativeTo]]: plainDate, [[ZonedRelativeTo]]: undefined }.
|
||||
return RelativeTo { .plain_relative_to = plain_date, .zoned_relative_to = {} };
|
||||
}
|
||||
|
||||
// d. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(value).
|
||||
calendar = TRY(get_temporal_calendar_identifier_with_iso_default(vm, object));
|
||||
|
||||
// e. Let fields be ? PrepareCalendarFields(calendar, value, « YEAR, MONTH, MONTH-CODE, DAY », « HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND, OFFSET, TIME-ZONE », «»).
|
||||
|
@ -626,6 +633,8 @@ ThrowCompletionOr<bool> is_partial_temporal_object(VM& vm, Value value)
|
|||
// FIXME: Add the other types as we define them.
|
||||
if (is<PlainDate>(object))
|
||||
return false;
|
||||
if (is<PlainDateTime>(object))
|
||||
return false;
|
||||
if (is<PlainMonthDay>(object))
|
||||
return false;
|
||||
if (is<PlainTime>(object))
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/Temporal/ISO8601.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainMonthDay.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainYearMonth.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
|
@ -454,6 +455,8 @@ ThrowCompletionOr<String> to_temporal_calendar_identifier(VM& vm, Value temporal
|
|||
// FIXME: Add the other calendar-holding types as we define them.
|
||||
if (is<PlainDate>(temporal_calendar_object))
|
||||
return static_cast<PlainDate const&>(temporal_calendar_object).calendar();
|
||||
if (is<PlainDateTime>(temporal_calendar_object))
|
||||
return static_cast<PlainDateTime const&>(temporal_calendar_object).calendar();
|
||||
if (is<PlainMonthDay>(temporal_calendar_object))
|
||||
return static_cast<PlainMonthDay const&>(temporal_calendar_object).calendar();
|
||||
if (is<PlainYearMonth>(temporal_calendar_object))
|
||||
|
@ -480,6 +483,8 @@ ThrowCompletionOr<String> get_temporal_calendar_identifier_with_iso_default(VM&
|
|||
// FIXME: Add the other calendar-holding types as we define them.
|
||||
if (is<PlainDate>(item))
|
||||
return static_cast<PlainDate const&>(item).calendar();
|
||||
if (is<PlainDateTime>(item))
|
||||
return static_cast<PlainDateTime const&>(item).calendar();
|
||||
if (is<PlainMonthDay>(item))
|
||||
return static_cast<PlainMonthDay const&>(item).calendar();
|
||||
if (is<PlainYearMonth>(item))
|
||||
|
|
|
@ -83,15 +83,26 @@ ThrowCompletionOr<GC::Ref<PlainDate>> to_temporal_date(VM& vm, Value item, Value
|
|||
// iii. Return ! CreateTemporalDate(item.[[ISODate]], item.[[Calendar]]).
|
||||
return MUST(create_temporal_date(vm, plain_date.iso_date(), plain_date.calendar()));
|
||||
}
|
||||
|
||||
// FIXME: b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
// FIXME: i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
|
||||
// FIXME: ii. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
// FIXME: iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
// FIXME: iv. Return ! CreateTemporalDate(isoDateTime.[[ISODate]], item.[[Calendar]]).
|
||||
// FIXME: c. If item has an [[InitializedTemporalDateTime]] internal slot, then
|
||||
// FIXME: i. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
// FIXME: ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
// FIXME: iii. Return ! CreateTemporalDate(item.[[ISODateTime]].[[ISODate]], item.[[Calendar]]).
|
||||
|
||||
// c. If item has an [[InitializedTemporalDateTime]] internal slot, then
|
||||
if (is<PlainDateTime>(object)) {
|
||||
auto const& plain_date_time = static_cast<PlainDateTime const&>(object);
|
||||
|
||||
// i. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, options));
|
||||
|
||||
// ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||
|
||||
// iii. Return ! CreateTemporalDate(item.[[ISODateTime]].[[ISODate]], item.[[Calendar]]).
|
||||
return MUST(create_temporal_date(vm, plain_date_time.iso_date_time().iso_date, plain_date_time.calendar()));
|
||||
}
|
||||
|
||||
// d. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
|
||||
auto calendar = TRY(get_temporal_calendar_identifier_with_iso_default(vm, object));
|
||||
|
|
|
@ -6,15 +6,26 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTimeConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(PlainDateTime);
|
||||
|
||||
PlainDateTime::PlainDateTime(ISODateTime const& iso_date_time, String calendar, Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
, m_iso_date_time(iso_date_time)
|
||||
, m_calendar(move(calendar))
|
||||
{
|
||||
}
|
||||
|
||||
// 5.5.3 CombineISODateAndTimeRecord ( isoDate, time ), https://tc39.es/proposal-temporal/#sec-temporal-combineisodateandtimerecord
|
||||
ISODateTime combine_iso_date_and_time_record(ISODate iso_date, Time time)
|
||||
{
|
||||
|
@ -68,6 +79,106 @@ ThrowCompletionOr<ISODateTime> interpret_temporal_date_time_fields(VM& vm, Strin
|
|||
return combine_iso_date_and_time_record(iso_date, time);
|
||||
}
|
||||
|
||||
// 5.5.6 ToTemporalDateTime ( item [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaldatetime
|
||||
ThrowCompletionOr<GC::Ref<PlainDateTime>> to_temporal_date_time(VM& vm, Value item, Value options)
|
||||
{
|
||||
// 1. If options is not present, set options to undefined.
|
||||
|
||||
// 2. If item is an Object, then
|
||||
if (item.is_object()) {
|
||||
auto const& object = item.as_object();
|
||||
|
||||
// a. If item has an [[InitializedTemporalDateTime]] internal slot, then
|
||||
if (is<PlainDateTime>(object)) {
|
||||
auto const& plain_date_time = static_cast<PlainDateTime const&>(object);
|
||||
|
||||
// i. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, options));
|
||||
|
||||
// ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||
|
||||
// iii. Return ! CreateTemporalDateTime(item.[[ISODateTime]], item.[[Calendar]]).
|
||||
return MUST(create_temporal_date_time(vm, plain_date_time.iso_date_time(), plain_date_time.calendar()));
|
||||
}
|
||||
|
||||
// FIXME: b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
// FIXME: i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
|
||||
// FIXME: ii. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
// FIXME: iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
// FIXME: iv. Return ! CreateTemporalDateTime(isoDateTime, item.[[Calendar]]).
|
||||
|
||||
// c. If item has an [[InitializedTemporalDate]] internal slot, then
|
||||
if (is<PlainDate>(object)) {
|
||||
auto const& plain_date = static_cast<PlainDate const&>(object);
|
||||
|
||||
// i. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, options));
|
||||
|
||||
// ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||
|
||||
// iii. Let isoDateTime be CombineISODateAndTimeRecord(item.[[ISODate]], MidnightTimeRecord()).
|
||||
auto iso_date_time = combine_iso_date_and_time_record(plain_date.iso_date(), midnight_time_record());
|
||||
|
||||
// iv. Return ? CreateTemporalDateTime(isoDateTime, item.[[Calendar]]).
|
||||
return TRY(create_temporal_date_time(vm, iso_date_time, plain_date.calendar()));
|
||||
}
|
||||
|
||||
// d. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
|
||||
auto calendar = TRY(get_temporal_calendar_identifier_with_iso_default(vm, object));
|
||||
|
||||
// e. Let fields be ? PrepareCalendarFields(calendar, item, « YEAR, MONTH, MONTH-CODE, DAY », « HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND », «»).
|
||||
static constexpr auto calendar_field_names = to_array({ CalendarField::Year, CalendarField::Month, CalendarField::MonthCode, CalendarField::Day });
|
||||
static constexpr auto non_calendar_field_names = to_array({ CalendarField::Hour, CalendarField::Minute, CalendarField::Second, CalendarField::Millisecond, CalendarField::Microsecond, CalendarField::Nanosecond });
|
||||
auto fields = TRY(prepare_calendar_fields(vm, calendar, object, calendar_field_names, non_calendar_field_names, CalendarFieldList {}));
|
||||
|
||||
// f. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, options));
|
||||
|
||||
// g. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
|
||||
auto overflow = TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||
|
||||
// h. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
|
||||
auto result = TRY(interpret_temporal_date_time_fields(vm, calendar, fields, overflow));
|
||||
|
||||
// i. Return ? CreateTemporalDateTime(result, calendar).
|
||||
return TRY(create_temporal_date_time(vm, result, move(calendar)));
|
||||
}
|
||||
|
||||
// 3. If item is not a String, throw a TypeError exception.
|
||||
if (!item.is_string())
|
||||
return vm.throw_completion<TypeError>(ErrorType::TemporalInvalidPlainDateTime);
|
||||
|
||||
// 4. Let result be ? ParseISODateTime(item, « TemporalDateTimeString[~Zoned] »).
|
||||
auto result = TRY(parse_iso_date_time(vm, item.as_string().utf8_string_view(), { { Production::TemporalDateTimeString } }));
|
||||
|
||||
// 5. If result.[[Time]] is START-OF-DAY, let time be MidnightTimeRecord(); else let time be result.[[Time]].
|
||||
auto time = result.time.has<ParsedISODateTime::StartOfDay>() ? midnight_time_record() : result.time.get<Time>();
|
||||
|
||||
// 6. Let calendar be result.[[Calendar]].
|
||||
// 7. If calendar is empty, set calendar to "iso8601".
|
||||
auto calendar = result.calendar.value_or("iso8601"_string);
|
||||
|
||||
// 8. Set calendar to ? CanonicalizeCalendar(calendar).
|
||||
calendar = TRY(canonicalize_calendar(vm, calendar));
|
||||
|
||||
// 9. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, options));
|
||||
|
||||
// 10. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||
|
||||
// 11. Let isoDate be CreateISODateRecord(result.[[Year]], result.[[Month]], result.[[Day]]).
|
||||
auto iso_date = create_iso_date_record(*result.year, result.month, result.day);
|
||||
|
||||
// 12. Let isoDateTime be CombineISODateAndTimeRecord(isoDate, time).
|
||||
auto iso_date_time = combine_iso_date_and_time_record(iso_date, time);
|
||||
|
||||
// 13. Return ? CreateTemporalDateTime(isoDateTime, calendar).
|
||||
return TRY(create_temporal_date_time(vm, iso_date_time, move(calendar)));
|
||||
}
|
||||
|
||||
// 5.5.7 BalanceISODateTime ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-balanceisodatetime
|
||||
ISODateTime balance_iso_date_time(double year, double month, double day, double hour, double minute, double second, double millisecond, double microsecond, double nanosecond)
|
||||
{
|
||||
|
@ -81,6 +192,30 @@ ISODateTime balance_iso_date_time(double year, double month, double day, double
|
|||
return combine_iso_date_and_time_record(balanced_date, balanced_time);
|
||||
}
|
||||
|
||||
// 5.5.8 CreateTemporalDateTime ( isoDateTime, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaldatetime
|
||||
ThrowCompletionOr<GC::Ref<PlainDateTime>> create_temporal_date_time(VM& vm, ISODateTime const& iso_date_time, String calendar, GC::Ptr<FunctionObject> new_target)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. If ISODateTimeWithinLimits(isoDateTime) is false, then
|
||||
if (!iso_date_time_within_limits(iso_date_time)) {
|
||||
// a. Throw a RangeError exception.
|
||||
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidPlainDateTime);
|
||||
}
|
||||
|
||||
// 2. If newTarget is not present, set newTarget to %Temporal.PlainDateTime%.
|
||||
if (!new_target)
|
||||
new_target = realm.intrinsics().temporal_plain_date_time_constructor();
|
||||
|
||||
// 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainDateTime.prototype%", « [[InitializedTemporalDateTime]], [[ISODateTime]], [[Calendar]] »).
|
||||
// 4. Set object.[[ISODateTime]] to isoDateTime.
|
||||
// 5. Set object.[[Calendar]] to calendar.
|
||||
auto object = TRY(ordinary_create_from_constructor<PlainDateTime>(vm, *new_target, &Intrinsics::temporal_plain_date_time_prototype, iso_date_time, move(calendar)));
|
||||
|
||||
// 6. Return object.
|
||||
return object;
|
||||
}
|
||||
|
||||
// 5.5.10 CompareISODateTime ( isoDateTime1, isoDateTime2 ), https://tc39.es/proposal-temporal/#sec-temporal-compareisodatetime
|
||||
i8 compare_iso_date_time(ISODateTime const& iso_date_time1, ISODateTime const& iso_date_time2)
|
||||
{
|
||||
|
|
|
@ -9,15 +9,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibCrypto/BigFraction/BigFraction.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/ISORecords.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class PlainDateTime final : public Object {
|
||||
JS_OBJECT(PlainDateTime, Object);
|
||||
GC_DECLARE_ALLOCATOR(PlainDateTime);
|
||||
|
||||
public:
|
||||
virtual ~PlainDateTime() override = default;
|
||||
|
||||
[[nodiscard]] ISODateTime iso_date_time() const { return m_iso_date_time; }
|
||||
[[nodiscard]] String const& calendar() const { return m_calendar; }
|
||||
|
||||
private:
|
||||
PlainDateTime(ISODateTime const&, String calendar, Object& prototype);
|
||||
|
||||
ISODateTime m_iso_date_time; // [[ISODateTime]]
|
||||
String m_calendar; // [[Calendar]]
|
||||
};
|
||||
|
||||
ISODateTime combine_iso_date_and_time_record(ISODate, Time);
|
||||
bool iso_date_time_within_limits(ISODateTime);
|
||||
ThrowCompletionOr<ISODateTime> interpret_temporal_date_time_fields(VM&, StringView calendar, CalendarFields&, Overflow);
|
||||
ThrowCompletionOr<GC::Ref<PlainDateTime>> to_temporal_date_time(VM&, Value item, Value options = js_undefined());
|
||||
ISODateTime balance_iso_date_time(double year, double month, double day, double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
|
||||
ThrowCompletionOr<GC::Ref<PlainDateTime>> create_temporal_date_time(VM&, ISODateTime const&, String calendar, GC::Ptr<FunctionObject> new_target = {});
|
||||
i8 compare_iso_date_time(ISODateTime const&, ISODateTime const&);
|
||||
ThrowCompletionOr<InternalDuration> difference_iso_date_time(VM&, ISODateTime const&, ISODateTime const&, StringView calendar, Unit largest_unit);
|
||||
ThrowCompletionOr<InternalDuration> difference_plain_date_time_with_rounding(VM&, ISODateTime const&, ISODateTime const&, StringView calendar, Unit largest_unit, u64 rounding_increment, Unit smallest_unit, RoundingMode);
|
||||
|
|
148
Libraries/LibJS/Runtime/Temporal/PlainDateTimeConstructor.cpp
Normal file
148
Libraries/LibJS/Runtime/Temporal/PlainDateTimeConstructor.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Checked.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTimeConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(PlainDateTimeConstructor);
|
||||
|
||||
// 5.1 The Temporal.PlainDateTime Constructor, https://tc39.es/proposal-temporal/#sec-temporal-plaindatetime-constructor
|
||||
PlainDateTimeConstructor::PlainDateTimeConstructor(Realm& realm)
|
||||
: NativeFunction(realm.vm().names.PlainDateTime.as_string(), realm.intrinsics().function_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void PlainDateTimeConstructor::initialize(Realm& realm)
|
||||
{
|
||||
Base::initialize(realm);
|
||||
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 5.2.1 Temporal.PlainDateTime.prototype, https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype
|
||||
define_direct_property(vm.names.prototype, realm.intrinsics().temporal_plain_date_time_prototype(), 0);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.from, from, 1, attr);
|
||||
define_native_function(realm, vm.names.compare, compare, 2, attr);
|
||||
|
||||
define_direct_property(vm.names.length, Value(3), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 5.1.1 Temporal.PlainDateTime ( isoYear, isoMonth, isoDay [ , hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond [ , calendar ] ] ] ] ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime
|
||||
ThrowCompletionOr<Value> PlainDateTimeConstructor::call()
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 1. If NewTarget is undefined, then
|
||||
// a. Throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, "Temporal.PlainDateTime");
|
||||
}
|
||||
|
||||
// 5.1.1 Temporal.PlainDateTime ( isoYear, isoMonth, isoDay [ , hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond [ , calendar ] ] ] ] ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime
|
||||
ThrowCompletionOr<GC::Ref<Object>> PlainDateTimeConstructor::construct(FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
auto calendar_value = vm.argument(9);
|
||||
|
||||
auto next_integer_argument = [&, index = 0](Optional<double> fallback) mutable -> ThrowCompletionOr<double> {
|
||||
auto value = vm.argument(index++);
|
||||
if (value.is_undefined() && fallback.has_value())
|
||||
return *fallback;
|
||||
|
||||
return to_integer_with_truncation(vm, value, ErrorType::TemporalInvalidPlainDateTime);
|
||||
};
|
||||
|
||||
// 2. Set isoYear to ? ToIntegerWithTruncation(isoYear).
|
||||
auto iso_year = TRY(next_integer_argument({}));
|
||||
|
||||
// 3. Set isoMonth to ? ToIntegerWithTruncation(isoMonth).
|
||||
auto iso_month = TRY(next_integer_argument({}));
|
||||
|
||||
// 4. Set isoDay to ? ToIntegerWithTruncation(isoDay).
|
||||
auto iso_day = TRY(next_integer_argument({}));
|
||||
|
||||
// 5. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour).
|
||||
auto hour = TRY(next_integer_argument(0));
|
||||
|
||||
// 6. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute).
|
||||
auto minute = TRY(next_integer_argument(0));
|
||||
|
||||
// 7. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second).
|
||||
auto second = TRY(next_integer_argument(0));
|
||||
|
||||
// 8. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond).
|
||||
auto millisecond = TRY(next_integer_argument(0));
|
||||
|
||||
// 9. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond).
|
||||
auto microsecond = TRY(next_integer_argument(0));
|
||||
|
||||
// 10. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond).
|
||||
auto nanosecond = TRY(next_integer_argument(0));
|
||||
|
||||
// 11. If calendar is undefined, set calendar to "iso8601".
|
||||
if (calendar_value.is_undefined())
|
||||
calendar_value = PrimitiveString::create(vm, "iso8601"_string);
|
||||
|
||||
// 12. If calendar is not a String, throw a TypeError exception.
|
||||
if (!calendar_value.is_string())
|
||||
return vm.throw_completion<TypeError>(ErrorType::NotAString, "calendar"sv);
|
||||
|
||||
// 13. Set calendar to ? CanonicalizeCalendar(calendar).
|
||||
auto calendar = TRY(canonicalize_calendar(vm, calendar_value.as_string().utf8_string_view()));
|
||||
|
||||
// 14. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
|
||||
if (!is_valid_iso_date(iso_year, iso_month, iso_day))
|
||||
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidPlainDateTime);
|
||||
|
||||
// 15. Let isoDate be CreateISODateRecord(isoYear, isoMonth, isoDay).
|
||||
auto iso_date = create_iso_date_record(iso_year, iso_month, iso_day);
|
||||
|
||||
// 16. If IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
|
||||
if (!is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond))
|
||||
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidPlainDateTime);
|
||||
|
||||
// 17. Let time be CreateTimeRecord(hour, minute, second, millisecond, microsecond, nanosecond).
|
||||
auto time = create_time_record(hour, minute, second, millisecond, microsecond, nanosecond);
|
||||
|
||||
// 18. Let isoDateTime be CombineISODateAndTimeRecord(isoDate, time).
|
||||
auto iso_date_time = combine_iso_date_and_time_record(iso_date, time);
|
||||
|
||||
// 19. Return ? CreateTemporalDateTime(isoDateTime, calendar, NewTarget).
|
||||
return TRY(create_temporal_date_time(vm, iso_date_time, move(calendar), new_target));
|
||||
}
|
||||
|
||||
// 5.2.2 Temporal.PlainDateTime.from ( item [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.from
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimeConstructor::from)
|
||||
{
|
||||
// 1. Return ? ToTemporalDateTime(item, options).
|
||||
return TRY(to_temporal_date_time(vm, vm.argument(0), vm.argument(1)));
|
||||
}
|
||||
|
||||
// 5.2.3 Temporal.PlainDateTime.compare ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.compare
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimeConstructor::compare)
|
||||
{
|
||||
// 1. Set one to ? ToTemporalDateTime(one).
|
||||
auto one = TRY(to_temporal_date_time(vm, vm.argument(0)));
|
||||
|
||||
// 2. Set two to ? ToTemporalDateTime(two).
|
||||
auto two = TRY(to_temporal_date_time(vm, vm.argument(1)));
|
||||
|
||||
// 3. Return 𝔽(CompareISODateTime(one.[[ISODateTime]], two.[[ISODateTime]])).
|
||||
return compare_iso_date_time(one->iso_date_time(), two->iso_date_time());
|
||||
}
|
||||
|
||||
}
|
34
Libraries/LibJS/Runtime/Temporal/PlainDateTimeConstructor.h
Normal file
34
Libraries/LibJS/Runtime/Temporal/PlainDateTimeConstructor.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class PlainDateTimeConstructor final : public NativeFunction {
|
||||
JS_OBJECT(PlainDateTimeConstructor, NativeFunction);
|
||||
GC_DECLARE_ALLOCATOR(PlainDateTimeConstructor);
|
||||
|
||||
public:
|
||||
virtual void initialize(Realm&) override;
|
||||
virtual ~PlainDateTimeConstructor() override = default;
|
||||
|
||||
virtual ThrowCompletionOr<Value> call() override;
|
||||
virtual ThrowCompletionOr<GC::Ref<Object>> construct(FunctionObject& new_target) override;
|
||||
|
||||
private:
|
||||
explicit PlainDateTimeConstructor(Realm&);
|
||||
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(from);
|
||||
JS_DECLARE_NATIVE_FUNCTION(compare);
|
||||
};
|
||||
|
||||
}
|
210
Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.cpp
Normal file
210
Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTimePrototype.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(PlainDateTimePrototype);
|
||||
|
||||
// 5.3 Properties of the Temporal.PlainDateTime Prototype Object, https://tc39.es/proposal-temporal/#sec-properties-of-the-temporal-plaindatetime-prototype-object
|
||||
PlainDateTimePrototype::PlainDateTimePrototype(Realm& realm)
|
||||
: PrototypeObject(realm.intrinsics().object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void PlainDateTimePrototype::initialize(Realm& realm)
|
||||
{
|
||||
Base::initialize(realm);
|
||||
|
||||
auto& vm = this->vm();
|
||||
|
||||
// 5.3.2 Temporal.PlainDateTime.prototype[ %Symbol.toStringTag% ], https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Temporal.PlainDateTime"_string), Attribute::Configurable);
|
||||
|
||||
define_native_accessor(realm, vm.names.calendarId, calendar_id_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.era, era_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.eraYear, era_year_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.year, year_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.month, month_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.monthCode, month_code_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.day, day_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.hour, hour_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.minute, minute_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.second, second_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.millisecond, millisecond_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.microsecond, microsecond_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.nanosecond, nanosecond_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.dayOfWeek, day_of_week_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.dayOfYear, day_of_year_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.weekOfYear, week_of_year_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.yearOfWeek, year_of_week_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.daysInWeek, days_in_week_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.daysInMonth, days_in_month_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.daysInYear, days_in_year_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.monthsInYear, months_in_year_getter, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.inLeapYear, in_leap_year_getter, {}, Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 5.3.3 get Temporal.PlainDateTime.prototype.calendarId, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.calendarid
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::calendar_id_getter)
|
||||
{
|
||||
// 1. Let dateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
|
||||
auto date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Return dateTime.[[Calendar]].
|
||||
return PrimitiveString::create(vm, date_time->calendar());
|
||||
}
|
||||
|
||||
// 5.3.4 get Temporal.PlainDateTime.prototype.era, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.era
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::era_getter)
|
||||
{
|
||||
// 1. Let plainDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(plainDateTime, [[InitializedTemporalDateTime]]).
|
||||
auto date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Return CalendarISOToDate(plainDateTime.[[Calendar]], plainDateTime.[[ISODateTime]].[[ISODate]]).[[Era]].
|
||||
auto result = calendar_iso_to_date(date_time->calendar(), date_time->iso_date_time().iso_date).era;
|
||||
|
||||
if (!result.has_value())
|
||||
return js_undefined();
|
||||
|
||||
return PrimitiveString::create(vm, result.release_value());
|
||||
}
|
||||
|
||||
// 5.3.5 get Temporal.PlainDateTime.prototype.eraYear, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.erayear
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::era_year_getter)
|
||||
{
|
||||
// 1. Let plainDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(plainDateTime, [[InitializedTemporalDateTime]]).
|
||||
auto date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let result be CalendarISOToDate(plainDateTime.[[Calendar]], plainDateTime.[[ISODateTime]].[[ISODate]]).[[EraYear]].
|
||||
auto result = calendar_iso_to_date(date_time->calendar(), date_time->iso_date_time().iso_date).era_year;
|
||||
|
||||
// 4. If result is undefined, return undefined.
|
||||
if (!result.has_value())
|
||||
return js_undefined();
|
||||
|
||||
// 5. Return 𝔽(result).
|
||||
return *result;
|
||||
}
|
||||
|
||||
// 5.3.6 get Temporal.PlainDateTime.prototype.year, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.year
|
||||
// 5.3.7 get Temporal.PlainDateTime.prototype.month, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.month
|
||||
// 5.3.9 get Temporal.PlainDateTime.prototype.day, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.monthcode
|
||||
// 5.3.16 get Temporal.PlainDateTime.prototype.dayOfWeek, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.dayofweek
|
||||
// 5.3.17 get Temporal.PlainDateTime.prototype.dayOfYear, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.dayofyear
|
||||
// 5.3.20 get Temporal.PlainDateTime.prototype.daysInWeek, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.daysinweek
|
||||
// 5.3.21 get Temporal.PlainDateTime.prototype.daysInMonth, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.daysinmonth
|
||||
// 5.3.22 get Temporal.PlainDateTime.prototype.daysInYear, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.daysinyear
|
||||
// 5.3.23 get Temporal.PlainDateTime.prototype.monthsInYear, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.monthsinyear
|
||||
// 5.3.24 get Temporal.PlainDateTime.prototype.inLeapYear, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.inleapyear
|
||||
#define JS_ENUMERATE_PLAIN_DATE_TIME_SIMPLE_DATE_FIELDS \
|
||||
__JS_ENUMERATE(year) \
|
||||
__JS_ENUMERATE(month) \
|
||||
__JS_ENUMERATE(day) \
|
||||
__JS_ENUMERATE(day_of_week) \
|
||||
__JS_ENUMERATE(day_of_year) \
|
||||
__JS_ENUMERATE(days_in_week) \
|
||||
__JS_ENUMERATE(days_in_month) \
|
||||
__JS_ENUMERATE(days_in_year) \
|
||||
__JS_ENUMERATE(months_in_year) \
|
||||
__JS_ENUMERATE(in_leap_year)
|
||||
|
||||
#define __JS_ENUMERATE(field) \
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::field##_getter) \
|
||||
{ \
|
||||
/* 1. Let dateTime be the this value. */ \
|
||||
/* 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]). */ \
|
||||
auto date_time = TRY(typed_this_object(vm)); \
|
||||
\
|
||||
/* 3. Return 𝔽(CalendarISOToDate(dateTime.[[Calendar]], dateTime.[[ISODateTime]].[[ISODate]]).[[<field>]]). */ \
|
||||
return calendar_iso_to_date(date_time->calendar(), date_time->iso_date_time().iso_date).field; \
|
||||
}
|
||||
JS_ENUMERATE_PLAIN_DATE_TIME_SIMPLE_DATE_FIELDS
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
// 5.3.8 get Temporal.PlainDateTime.prototype.monthCode, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.monthcode
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::month_code_getter)
|
||||
{
|
||||
// 1. Let dateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
|
||||
auto date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Return CalendarISOToDate(dateTime.[[Calendar]], dateTime.[[ISODateTime]].[[ISODate]]).[[MonthCode]].
|
||||
auto month_code = calendar_iso_to_date(date_time->calendar(), date_time->iso_date_time().iso_date).month_code;
|
||||
return PrimitiveString::create(vm, move(month_code));
|
||||
}
|
||||
|
||||
// 5.3.10 get Temporal.PlainDateTime.prototype.hour, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.hour
|
||||
// 5.3.11 get Temporal.PlainDateTime.prototype.minute, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.minute
|
||||
// 5.3.12 get Temporal.PlainDateTime.prototype.second, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.second
|
||||
// 5.3.13 get Temporal.PlainDateTime.prototype.millisecond, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.millisecond
|
||||
// 5.3.14 get Temporal.PlainDateTime.prototype.microsecond, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.microsecond
|
||||
// 5.3.15 get Temporal.PlainDateTime.prototype.nanosecond, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.nanosecond
|
||||
#define JS_ENUMERATE_PLAIN_DATE_TIME_TIME_FIELDS \
|
||||
__JS_ENUMERATE(hour) \
|
||||
__JS_ENUMERATE(minute) \
|
||||
__JS_ENUMERATE(second) \
|
||||
__JS_ENUMERATE(millisecond) \
|
||||
__JS_ENUMERATE(microsecond) \
|
||||
__JS_ENUMERATE(nanosecond)
|
||||
|
||||
#define __JS_ENUMERATE(field) \
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::field##_getter) \
|
||||
{ \
|
||||
/* 1. Let dateTime be the this value. */ \
|
||||
/* 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]). */ \
|
||||
auto date_time = TRY(typed_this_object(vm)); \
|
||||
\
|
||||
/* 3. Return 𝔽(dateTime.[[ISODateTime]].[[Time]].[[<field>]]). */ \
|
||||
return date_time->iso_date_time().time.field; \
|
||||
}
|
||||
JS_ENUMERATE_PLAIN_DATE_TIME_TIME_FIELDS
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
// 5.3.18 get Temporal.PlainDateTime.prototype.weekOfYear, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.weekofyear
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::week_of_year_getter)
|
||||
{
|
||||
// 1. Let dateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
|
||||
auto date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let result be CalendarISOToDate(dateTime.[[Calendar]], dateTime.[[ISODateTime]].[[ISODate]]).[[WeekOfYear]].[[Week]].
|
||||
auto result = calendar_iso_to_date(date_time->calendar(), date_time->iso_date_time().iso_date).week_of_year.week;
|
||||
|
||||
// 4. If result is undefined, return undefined.
|
||||
if (!result.has_value())
|
||||
return js_undefined();
|
||||
|
||||
// 5. Return 𝔽(result).
|
||||
return *result;
|
||||
}
|
||||
|
||||
// 5.3.19 get Temporal.PlainDateTime.prototype.yearOfWeek, https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.yearofweek
|
||||
JS_DEFINE_NATIVE_FUNCTION(PlainDateTimePrototype::year_of_week_getter)
|
||||
{
|
||||
// 1. Let dateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
|
||||
auto date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let result be CalendarISOToDate(dateTime.[[Calendar]], dateTime.[[ISODateTime]].[[ISODate]]).[[WeekOfYear]].[[Year]].
|
||||
auto result = calendar_iso_to_date(date_time->calendar(), date_time->iso_date_time().iso_date).week_of_year.year;
|
||||
|
||||
// 4. If result is undefined, return undefined.
|
||||
if (!result.has_value())
|
||||
return js_undefined();
|
||||
|
||||
// 5. Return 𝔽(result).
|
||||
return *result;
|
||||
}
|
||||
|
||||
}
|
50
Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.h
Normal file
50
Libraries/LibJS/Runtime/Temporal/PlainDateTimePrototype.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/PrototypeObject.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
|
||||
namespace JS::Temporal {
|
||||
|
||||
class PlainDateTimePrototype final : public PrototypeObject<PlainDateTimePrototype, PlainDateTime> {
|
||||
JS_PROTOTYPE_OBJECT(PlainDateTimePrototype, PlainDateTime, Temporal.PlainDateTime);
|
||||
GC_DECLARE_ALLOCATOR(PlainDateTimePrototype);
|
||||
|
||||
public:
|
||||
virtual void initialize(Realm&) override;
|
||||
virtual ~PlainDateTimePrototype() override = default;
|
||||
|
||||
private:
|
||||
explicit PlainDateTimePrototype(Realm&);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(calendar_id_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(era_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(era_year_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(year_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(month_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(month_code_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(day_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(hour_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(minute_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(second_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(millisecond_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(microsecond_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(nanosecond_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(day_of_week_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(day_of_year_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(week_of_year_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(year_of_week_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(days_in_week_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(days_in_month_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(days_in_year_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(months_in_year_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(in_leap_year_getter);
|
||||
};
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||
#include <math.h>
|
||||
|
@ -128,10 +129,19 @@ ThrowCompletionOr<GC::Ref<PlainTime>> to_temporal_time(VM& vm, Value item, Value
|
|||
return MUST(create_temporal_time(vm, plain_time.time()));
|
||||
}
|
||||
|
||||
// FIXME: b. If item has an [[InitializedTemporalDateTime]] internal slot, then
|
||||
// FIXME: i. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
// FIXME: ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
// FIXME: iii. Return ! CreateTemporalTime(item.[[ISODateTime]].[[Time]]).
|
||||
// b. If item has an [[InitializedTemporalDateTime]] internal slot, then
|
||||
if (is<PlainDateTime>(object)) {
|
||||
auto const& plain_date_time = static_cast<PlainDateTime const&>(object);
|
||||
|
||||
// i. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, options));
|
||||
|
||||
// ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||
|
||||
// iii. Return ! CreateTemporalTime(item.[[ISODateTime]].[[Time]]).
|
||||
return MUST(create_temporal_time(vm, plain_date_time.iso_date_time().time));
|
||||
}
|
||||
|
||||
// FIXME: c. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
// FIXME: i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/DurationConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTimeConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainMonthDayConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainYearMonthConstructor.h>
|
||||
|
@ -35,6 +36,7 @@ void Temporal::initialize(Realm& realm)
|
|||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_intrinsic_accessor(vm.names.Duration, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_duration_constructor(); });
|
||||
define_intrinsic_accessor(vm.names.PlainDate, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_plain_date_constructor(); });
|
||||
define_intrinsic_accessor(vm.names.PlainDateTime, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_plain_date_time_constructor(); });
|
||||
define_intrinsic_accessor(vm.names.PlainMonthDay, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_plain_month_day_constructor(); });
|
||||
define_intrinsic_accessor(vm.names.PlainTime, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_plain_time_constructor(); });
|
||||
define_intrinsic_accessor(vm.names.PlainYearMonth, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_plain_year_month_constructor(); });
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 2", () => {
|
||||
expect(Temporal.PlainDateTime.compare).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime1 = new Temporal.PlainDateTime(2021, 8, 27, 16, 38, 40, 1, 2, 3);
|
||||
expect(Temporal.PlainDateTime.compare(plainDateTime1, plainDateTime1)).toBe(0);
|
||||
const plainDateTime2 = new Temporal.PlainDateTime(2021, 8, 27, 16, 39, 5, 0, 1, 2);
|
||||
expect(Temporal.PlainDateTime.compare(plainDateTime1, plainDateTime2)).toBe(-1);
|
||||
expect(Temporal.PlainDateTime.compare(plainDateTime2, plainDateTime1)).toBe(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,171 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(Temporal.PlainDateTime.from).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("PlainDate instance argument", () => {
|
||||
const plainDate = new Temporal.PlainDate(2021, 7, 6);
|
||||
const plainDateTime = Temporal.PlainDateTime.from(plainDate);
|
||||
expect(plainDateTime.year).toBe(2021);
|
||||
expect(plainDateTime.month).toBe(7);
|
||||
expect(plainDateTime.day).toBe(6);
|
||||
expect(plainDateTime.hour).toBe(0);
|
||||
expect(plainDateTime.minute).toBe(0);
|
||||
expect(plainDateTime.second).toBe(0);
|
||||
expect(plainDateTime.millisecond).toBe(0);
|
||||
expect(plainDateTime.microsecond).toBe(0);
|
||||
expect(plainDateTime.nanosecond).toBe(0);
|
||||
});
|
||||
|
||||
test("PlainDateTime instance argument", () => {
|
||||
const plainDateTime_ = new Temporal.PlainDateTime(2021, 7, 6, 18, 14, 47);
|
||||
const plainDateTime = Temporal.PlainDateTime.from(plainDateTime_);
|
||||
expect(plainDateTime).not.toBe(plainDateTime_);
|
||||
expect(plainDateTime.year).toBe(2021);
|
||||
expect(plainDateTime.month).toBe(7);
|
||||
expect(plainDateTime.day).toBe(6);
|
||||
expect(plainDateTime.hour).toBe(18);
|
||||
expect(plainDateTime.minute).toBe(14);
|
||||
expect(plainDateTime.second).toBe(47);
|
||||
expect(plainDateTime.millisecond).toBe(0);
|
||||
expect(plainDateTime.microsecond).toBe(0);
|
||||
expect(plainDateTime.nanosecond).toBe(0);
|
||||
});
|
||||
|
||||
test("fields object argument", () => {
|
||||
const object = {
|
||||
year: 2021,
|
||||
month: 7,
|
||||
day: 6,
|
||||
hour: 23,
|
||||
minute: 42,
|
||||
second: 1,
|
||||
millisecond: 0,
|
||||
microsecond: 0,
|
||||
nanosecond: 0,
|
||||
};
|
||||
const plainDateTime = Temporal.PlainDateTime.from(object);
|
||||
expect(plainDateTime.year).toBe(2021);
|
||||
expect(plainDateTime.month).toBe(7);
|
||||
expect(plainDateTime.day).toBe(6);
|
||||
expect(plainDateTime.hour).toBe(23);
|
||||
expect(plainDateTime.minute).toBe(42);
|
||||
expect(plainDateTime.second).toBe(1);
|
||||
expect(plainDateTime.millisecond).toBe(0);
|
||||
expect(plainDateTime.microsecond).toBe(0);
|
||||
expect(plainDateTime.nanosecond).toBe(0);
|
||||
});
|
||||
|
||||
test("with 'constrain' overflow option", () => {
|
||||
const object = {
|
||||
year: 0,
|
||||
month: 1,
|
||||
day: 1,
|
||||
hour: 24,
|
||||
minute: 60,
|
||||
second: 60,
|
||||
millisecond: 1000,
|
||||
microsecond: 1000,
|
||||
nanosecond: 1000,
|
||||
};
|
||||
const plainDateTime = Temporal.PlainDateTime.from(object, { overflow: "constrain" });
|
||||
expect(plainDateTime.year).toBe(0);
|
||||
expect(plainDateTime.month).toBe(1);
|
||||
expect(plainDateTime.day).toBe(1);
|
||||
expect(plainDateTime.hour).toBe(23);
|
||||
expect(plainDateTime.minute).toBe(59);
|
||||
expect(plainDateTime.second).toBe(59);
|
||||
expect(plainDateTime.millisecond).toBe(999);
|
||||
expect(plainDateTime.microsecond).toBe(999);
|
||||
expect(plainDateTime.nanosecond).toBe(999);
|
||||
});
|
||||
|
||||
test("PlainDateTime string argument", () => {
|
||||
const plainDateTime = Temporal.PlainDateTime.from("2021-07-06T23:42:01");
|
||||
expect(plainDateTime.year).toBe(2021);
|
||||
expect(plainDateTime.month).toBe(7);
|
||||
expect(plainDateTime.day).toBe(6);
|
||||
expect(plainDateTime.hour).toBe(23);
|
||||
expect(plainDateTime.minute).toBe(42);
|
||||
expect(plainDateTime.second).toBe(1);
|
||||
expect(plainDateTime.millisecond).toBe(0);
|
||||
expect(plainDateTime.microsecond).toBe(0);
|
||||
expect(plainDateTime.nanosecond).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("missing fields", () => {
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime.from({ year: 0, month: 1 });
|
||||
}).toThrowWithMessage(TypeError, "Required property day is missing or undefined");
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime.from({ year: 0, day: 1 });
|
||||
}).toThrowWithMessage(TypeError, "Required property month is missing or undefined");
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime.from({ month: 1, day: 1 });
|
||||
}).toThrowWithMessage(TypeError, "Required property year is missing or undefined");
|
||||
});
|
||||
|
||||
test("with 'reject' overflow option", () => {
|
||||
const values = [
|
||||
[{ year: 1234567, month: 1, day: 1 }, "Invalid ISO date"],
|
||||
[{ year: 0, month: 13, day: 1 }, "Invalid ISO date"],
|
||||
[{ year: 0, month: 1, day: 32 }, "Invalid ISO date"],
|
||||
[{ year: 0, month: 1, day: 1, hour: 24 }, "Invalid plain time"],
|
||||
[{ year: 0, month: 1, day: 1, hour: 0, minute: 60 }, "Invalid plain time"],
|
||||
[{ year: 0, month: 1, day: 1, hour: 0, minute: 0, second: 60 }, "Invalid plain time"],
|
||||
[
|
||||
{ year: 0, month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 1000 },
|
||||
"Invalid plain time",
|
||||
],
|
||||
[
|
||||
{
|
||||
year: 0,
|
||||
month: 1,
|
||||
day: 1,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
microsecond: 1000,
|
||||
},
|
||||
"Invalid plain time",
|
||||
],
|
||||
[
|
||||
{
|
||||
year: 0,
|
||||
month: 1,
|
||||
day: 1,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
microsecond: 0,
|
||||
nanosecond: 1000,
|
||||
},
|
||||
"Invalid plain time",
|
||||
],
|
||||
];
|
||||
for (const [object, error] of values) {
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime.from(object, { overflow: "reject" });
|
||||
}).toThrowWithMessage(RangeError, error);
|
||||
}
|
||||
});
|
||||
|
||||
test("string must not contain a UTC designator", () => {
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime.from("2021-07-06T23:42:01Z");
|
||||
}).toThrowWithMessage(RangeError, "Invalid ISO date time");
|
||||
});
|
||||
|
||||
test("extended year must not be negative zero", () => {
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime.from("-000000-01-01");
|
||||
}).toThrowWithMessage(RangeError, "Invalid ISO date time");
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime.from("−000000-01-01"); // U+2212
|
||||
}).toThrowWithMessage(RangeError, "Invalid ISO date time");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,53 @@
|
|||
describe("errors", () => {
|
||||
test("called without new", () => {
|
||||
expect(() => {
|
||||
Temporal.PlainDateTime();
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Temporal.PlainDateTime constructor must be called with 'new'"
|
||||
);
|
||||
});
|
||||
|
||||
test("cannot pass Infinity", () => {
|
||||
for (let i = 0; i < 9; ++i) {
|
||||
const args = Array(9).fill(0);
|
||||
|
||||
args[i] = Infinity;
|
||||
expect(() => {
|
||||
new Temporal.PlainDateTime(...args);
|
||||
}).toThrowWithMessage(RangeError, "Invalid plain date time");
|
||||
|
||||
args[i] = -Infinity;
|
||||
expect(() => {
|
||||
new Temporal.PlainDateTime(...args);
|
||||
}).toThrowWithMessage(RangeError, "Invalid plain date time");
|
||||
}
|
||||
});
|
||||
|
||||
test("cannot pass invalid ISO date or time", () => {
|
||||
// NOTE: The year max value is 3 more than in the polyfill, but they incorrectly seem to
|
||||
// use ISOYearMonthWithinLimits, which AFAICT isn't used for PlainDate{,Time} in the spec.
|
||||
// ¯\_(ツ)_/¯
|
||||
const badValues = [275764, 0, 0, 24, 60, 60, 1000, 1000, 1000];
|
||||
for (let i = 0; i < 9; ++i) {
|
||||
const args = [0, 1, 1, 0, 0, 0, 0, 0, 0];
|
||||
args[i] = badValues[i];
|
||||
expect(() => {
|
||||
new Temporal.PlainDateTime(...args);
|
||||
}).toThrowWithMessage(RangeError, "Invalid plain date time");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("normal behavior", () => {
|
||||
test("length is 3", () => {
|
||||
expect(Temporal.PlainDateTime).toHaveLength(3);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 22, 19, 46, 32, 123, 456, 789);
|
||||
expect(typeof plainDateTime).toBe("object");
|
||||
expect(plainDateTime).toBeInstanceOf(Temporal.PlainDateTime);
|
||||
expect(Object.getPrototypeOf(plainDateTime)).toBe(Temporal.PlainDateTime.prototype);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
describe("correct behavior", () => {
|
||||
test("calendarId basic functionality", () => {
|
||||
const calendar = "gregory";
|
||||
const plainDateTime = new Temporal.PlainDateTime(2000, 5, 1, 12, 30, 0, 0, 0, 0, calendar);
|
||||
expect(plainDateTime.calendarId).toBe(calendar);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "calendarId", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 29);
|
||||
expect(plainDateTime.day).toBe(29);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "day", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.dayOfWeek).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "dayOfWeek", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.dayOfYear).toBe(211);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "dayOfYear", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.daysInMonth).toBe(31);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "daysInMonth", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.daysInWeek).toBe(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "daysInWeek", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.daysInYear).toBe(365);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "daysInYear", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 6, 18, 14, 47);
|
||||
expect(plainDateTime.era).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "era", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 6, 18, 14, 47);
|
||||
expect(plainDateTime.eraYear).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "eraYear", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30, 1);
|
||||
expect(plainDateTime.hour).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "hour", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.inLeapYear).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "inLeapYear", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30, 1, 4, 32, 111, 420);
|
||||
expect(plainDateTime.microsecond).toBe(420);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "microsecond", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30, 1, 4, 32, 111);
|
||||
expect(plainDateTime.millisecond).toBe(111);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "millisecond", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30, 1, 4);
|
||||
expect(plainDateTime.minute).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "minute", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 29);
|
||||
expect(plainDateTime.month).toBe(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "month", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 29);
|
||||
expect(plainDateTime.monthCode).toBe("M07");
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "monthCode", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.monthsInYear).toBe(12);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "monthsInYear", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30, 1, 4, 32, 111, 420, 963);
|
||||
expect(plainDateTime.nanosecond).toBe(963);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "nanosecond", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30, 1, 4, 32);
|
||||
expect(plainDateTime.second).toBe(32);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "second", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 30);
|
||||
expect(plainDateTime.weekOfYear).toBe(30);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "weekOfYear", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 7, 29);
|
||||
expect(plainDateTime.year).toBe(2021);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "year", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
describe("correct behavior", () => {
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2023, 1, 1);
|
||||
expect(plainDateTime.yearOfWeek).toBe(2022);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.PlainDateTime object", () => {
|
||||
expect(() => {
|
||||
Reflect.get(Temporal.PlainDateTime.prototype, "yearOfWeek", "foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime");
|
||||
});
|
||||
});
|
|
@ -9,7 +9,7 @@ const PLAIN_TIME_PROPERTIES = [
|
|||
|
||||
const REJECTED_CALENDAR_TYPES_THREE_ARGUMENTS = [
|
||||
Temporal.PlainDate,
|
||||
// Temporal.PlainDateTime,
|
||||
Temporal.PlainDateTime,
|
||||
Temporal.PlainTime,
|
||||
];
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue