mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-12 02:59:45 +00:00
LibJS: Implement the Temporal.PlainTime constructor
And the simple Temporal.PlainTime.prototype getters, so that the constructed Temporal.PlainTime may actually be validated.
This commit is contained in:
parent
971f794127
commit
66365fef57
Notes:
github-actions[bot]
2024-11-24 00:38:03 +00:00
Author: https://github.com/trflynn89
Commit: 66365fef57
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2535
22 changed files with 693 additions and 1 deletions
|
@ -219,10 +219,12 @@ set(SOURCES
|
||||||
Runtime/Temporal/PlainMonthDay.cpp
|
Runtime/Temporal/PlainMonthDay.cpp
|
||||||
Runtime/Temporal/PlainMonthDayConstructor.cpp
|
Runtime/Temporal/PlainMonthDayConstructor.cpp
|
||||||
Runtime/Temporal/PlainMonthDayPrototype.cpp
|
Runtime/Temporal/PlainMonthDayPrototype.cpp
|
||||||
|
Runtime/Temporal/PlainTime.cpp
|
||||||
|
Runtime/Temporal/PlainTimeConstructor.cpp
|
||||||
|
Runtime/Temporal/PlainTimePrototype.cpp
|
||||||
Runtime/Temporal/PlainYearMonth.cpp
|
Runtime/Temporal/PlainYearMonth.cpp
|
||||||
Runtime/Temporal/PlainYearMonthConstructor.cpp
|
Runtime/Temporal/PlainYearMonthConstructor.cpp
|
||||||
Runtime/Temporal/PlainYearMonthPrototype.cpp
|
Runtime/Temporal/PlainYearMonthPrototype.cpp
|
||||||
Runtime/Temporal/PlainTime.cpp
|
|
||||||
Runtime/Temporal/Temporal.cpp
|
Runtime/Temporal/Temporal.cpp
|
||||||
Runtime/Temporal/TimeZone.cpp
|
Runtime/Temporal/TimeZone.cpp
|
||||||
Runtime/TypedArray.cpp
|
Runtime/TypedArray.cpp
|
||||||
|
|
|
@ -91,6 +91,7 @@
|
||||||
__JS_ENUMERATE(Duration, duration, DurationPrototype, DurationConstructor) \
|
__JS_ENUMERATE(Duration, duration, DurationPrototype, DurationConstructor) \
|
||||||
__JS_ENUMERATE(PlainDate, plain_date, PlainDatePrototype, PlainDateConstructor) \
|
__JS_ENUMERATE(PlainDate, plain_date, PlainDatePrototype, PlainDateConstructor) \
|
||||||
__JS_ENUMERATE(PlainMonthDay, plain_month_day, PlainMonthDayPrototype, PlainMonthDayConstructor) \
|
__JS_ENUMERATE(PlainMonthDay, plain_month_day, PlainMonthDayPrototype, PlainMonthDayConstructor) \
|
||||||
|
__JS_ENUMERATE(PlainTime, plain_time, PlainTimePrototype, PlainTimeConstructor) \
|
||||||
__JS_ENUMERATE(PlainYearMonth, plain_year_month, PlainYearMonthPrototype, PlainYearMonthConstructor)
|
__JS_ENUMERATE(PlainYearMonth, plain_year_month, PlainYearMonthPrototype, PlainYearMonthConstructor)
|
||||||
|
|
||||||
#define JS_ENUMERATE_BUILTIN_NAMESPACE_OBJECTS \
|
#define JS_ENUMERATE_BUILTIN_NAMESPACE_OBJECTS \
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainMonthDay.h>
|
#include <LibJS/Runtime/Temporal/PlainMonthDay.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainYearMonth.h>
|
#include <LibJS/Runtime/Temporal/PlainYearMonth.h>
|
||||||
#include <LibJS/Runtime/TypedArray.h>
|
#include <LibJS/Runtime/TypedArray.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
@ -856,6 +857,13 @@ ErrorOr<void> print_temporal_plain_month_day(JS::PrintContext& print_context, JS
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> print_temporal_plain_time(JS::PrintContext& print_context, JS::Temporal::PlainTime const& plain_time, HashTable<JS::Object*>&)
|
||||||
|
{
|
||||||
|
TRY(print_type(print_context, "Temporal.PlainTime"sv));
|
||||||
|
TRY(js_out(print_context, " \033[34;1m{:02}:{:02}:{:02}.{:03}{:03}{:03}\033[0m", plain_time.time().hour, plain_time.time().minute, plain_time.time().second, plain_time.time().millisecond, plain_time.time().microsecond, plain_time.time().nanosecond));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> print_temporal_plain_year_month(JS::PrintContext& print_context, JS::Temporal::PlainYearMonth const& plain_year_month, HashTable<JS::Object*>& seen_objects)
|
ErrorOr<void> print_temporal_plain_year_month(JS::PrintContext& print_context, JS::Temporal::PlainYearMonth const& plain_year_month, HashTable<JS::Object*>& seen_objects)
|
||||||
{
|
{
|
||||||
TRY(print_type(print_context, "Temporal.PlainYearMonth"sv));
|
TRY(print_type(print_context, "Temporal.PlainYearMonth"sv));
|
||||||
|
@ -986,6 +994,8 @@ ErrorOr<void> print_value(JS::PrintContext& print_context, JS::Value value, Hash
|
||||||
return print_temporal_plain_date(print_context, static_cast<JS::Temporal::PlainDate&>(object), seen_objects);
|
return print_temporal_plain_date(print_context, static_cast<JS::Temporal::PlainDate&>(object), seen_objects);
|
||||||
if (is<JS::Temporal::PlainMonthDay>(object))
|
if (is<JS::Temporal::PlainMonthDay>(object))
|
||||||
return print_temporal_plain_month_day(print_context, static_cast<JS::Temporal::PlainMonthDay&>(object), seen_objects);
|
return print_temporal_plain_month_day(print_context, static_cast<JS::Temporal::PlainMonthDay&>(object), seen_objects);
|
||||||
|
if (is<JS::Temporal::PlainTime>(object))
|
||||||
|
return print_temporal_plain_time(print_context, static_cast<JS::Temporal::PlainTime&>(object), seen_objects);
|
||||||
if (is<JS::Temporal::PlainYearMonth>(object))
|
if (is<JS::Temporal::PlainYearMonth>(object))
|
||||||
return print_temporal_plain_year_month(print_context, static_cast<JS::Temporal::PlainYearMonth&>(object), seen_objects);
|
return print_temporal_plain_year_month(print_context, static_cast<JS::Temporal::PlainYearMonth&>(object), seen_objects);
|
||||||
return print_object(print_context, object, seen_objects);
|
return print_object(print_context, object, seen_objects);
|
||||||
|
|
|
@ -278,6 +278,7 @@
|
||||||
M(TemporalInvalidRelativeToStringUTCDesignatorWithoutBracketedTimeZone, "Invalid relativeTo string '{}': must not contain a UTC " \
|
M(TemporalInvalidRelativeToStringUTCDesignatorWithoutBracketedTimeZone, "Invalid relativeTo string '{}': must not contain a UTC " \
|
||||||
"designator without bracketed time zone") \
|
"designator without bracketed time zone") \
|
||||||
M(TemporalInvalidTime, "Invalid time") \
|
M(TemporalInvalidTime, "Invalid time") \
|
||||||
|
M(TemporalInvalidTimeLikeField, "Invalid value {} for time field '{}'") \
|
||||||
M(TemporalInvalidTimeString, "Invalid time string '{}'") \
|
M(TemporalInvalidTimeString, "Invalid time string '{}'") \
|
||||||
M(TemporalInvalidTimeStringUTCDesignator, "Invalid time string '{}': must not contain a UTC designator") \
|
M(TemporalInvalidTimeStringUTCDesignator, "Invalid time string '{}': must not contain a UTC designator") \
|
||||||
M(TemporalInvalidTimeZoneName, "Invalid time zone name '{}'") \
|
M(TemporalInvalidTimeZoneName, "Invalid time zone name '{}'") \
|
||||||
|
|
|
@ -105,6 +105,8 @@
|
||||||
#include <LibJS/Runtime/Temporal/PlainDatePrototype.h>
|
#include <LibJS/Runtime/Temporal/PlainDatePrototype.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainMonthDayConstructor.h>
|
#include <LibJS/Runtime/Temporal/PlainMonthDayConstructor.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainMonthDayPrototype.h>
|
#include <LibJS/Runtime/Temporal/PlainMonthDayPrototype.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/PlainTimePrototype.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainYearMonthConstructor.h>
|
#include <LibJS/Runtime/Temporal/PlainYearMonthConstructor.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainYearMonthPrototype.h>
|
#include <LibJS/Runtime/Temporal/PlainYearMonthPrototype.h>
|
||||||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||||
|
|
|
@ -628,6 +628,8 @@ ThrowCompletionOr<bool> is_partial_temporal_object(VM& vm, Value value)
|
||||||
return false;
|
return false;
|
||||||
if (is<PlainMonthDay>(object))
|
if (is<PlainMonthDay>(object))
|
||||||
return false;
|
return false;
|
||||||
|
if (is<PlainTime>(object))
|
||||||
|
return false;
|
||||||
if (is<PlainYearMonth>(object))
|
if (is<PlainYearMonth>(object))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,20 @@
|
||||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
namespace JS::Temporal {
|
namespace JS::Temporal {
|
||||||
|
|
||||||
|
GC_DEFINE_ALLOCATOR(PlainTime);
|
||||||
|
|
||||||
|
// 4 Temporal.PlainTime Objects, https://tc39.es/proposal-temporal/#sec-temporal-plaintime-objects
|
||||||
|
PlainTime::PlainTime(Time const& time, Object& prototype)
|
||||||
|
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||||
|
, m_time(time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: We should add a generic floor() method to our BigInt classes. But for now, since we know we are only dividing
|
// FIXME: We should add a generic floor() method to our BigInt classes. But for now, since we know we are only dividing
|
||||||
// by powers of 10, we can implement a very situationally specific method to compute the floor of a division.
|
// by powers of 10, we can implement a very situationally specific method to compute the floor of a division.
|
||||||
static TimeDuration big_floor(TimeDuration const& numerator, Crypto::UnsignedBigInteger const& denominator)
|
static TimeDuration big_floor(TimeDuration const& numerator, Crypto::UnsignedBigInteger const& denominator)
|
||||||
|
@ -93,6 +103,83 @@ TimeDuration difference_time(Time const& time1, Time const& time2)
|
||||||
return time_duration;
|
return time_duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4.5.6 ToTemporalTime ( item [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltime
|
||||||
|
ThrowCompletionOr<GC::Ref<PlainTime>> to_temporal_time(VM& vm, Value item, Value options)
|
||||||
|
{
|
||||||
|
// 1. If options is not present, set options to undefined.
|
||||||
|
|
||||||
|
Time time;
|
||||||
|
|
||||||
|
// 2. If item is an Object, then
|
||||||
|
if (item.is_object()) {
|
||||||
|
auto const& object = item.as_object();
|
||||||
|
|
||||||
|
// a. If item has an [[InitializedTemporalTime]] internal slot, then
|
||||||
|
if (is<PlainTime>(object)) {
|
||||||
|
auto const& plain_time = static_cast<PlainTime 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.[[Time]]).
|
||||||
|
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]]).
|
||||||
|
|
||||||
|
// FIXME: c. 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 ! CreateTemporalTime(isoDateTime.[[Time]]).
|
||||||
|
|
||||||
|
// d. Let result be ? ToTemporalTimeRecord(item).
|
||||||
|
auto result = TRY(to_temporal_time_record(vm, object));
|
||||||
|
|
||||||
|
// e. Let resolvedOptions be ? GetOptionsObject(options).
|
||||||
|
auto resolved_options = TRY(get_options_object(vm, options));
|
||||||
|
|
||||||
|
// f. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
|
||||||
|
auto overflow = TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||||
|
|
||||||
|
// g. Set result to ? RegulateTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], overflow).
|
||||||
|
time = TRY(regulate_time(vm, *result.hour, *result.minute, *result.second, *result.millisecond, *result.microsecond, *result.nanosecond, overflow));
|
||||||
|
}
|
||||||
|
// 3. Else,
|
||||||
|
else {
|
||||||
|
// a. If item is not a String, throw a TypeError exception.
|
||||||
|
if (!item.is_string())
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::TemporalInvalidPlainTime);
|
||||||
|
|
||||||
|
// b. Let parseResult be ? ParseISODateTime(item, « TemporalTimeString »).
|
||||||
|
auto parse_result = TRY(parse_iso_date_time(vm, item.as_string().utf8_string_view(), { { Production::TemporalTimeString } }));
|
||||||
|
|
||||||
|
// c. Assert: parseResult.[[Time]] is not START-OF-DAY.
|
||||||
|
VERIFY(!parse_result.time.has<ParsedISODateTime::StartOfDay>());
|
||||||
|
|
||||||
|
// d. Set result to parseResult.[[Time]].
|
||||||
|
time = parse_result.time.get<Time>();
|
||||||
|
|
||||||
|
// e. NOTE: A successful parse using TemporalTimeString guarantees absence of ambiguity with respect to any
|
||||||
|
// ISO 8601 date-only, year-month, or month-day representation.
|
||||||
|
|
||||||
|
// f. Let resolvedOptions be ? GetOptionsObject(options).
|
||||||
|
auto resolved_options = TRY(get_options_object(vm, options));
|
||||||
|
|
||||||
|
// g. Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||||
|
TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Return ! CreateTemporalTime(result).
|
||||||
|
return MUST(create_temporal_time(vm, time));
|
||||||
|
}
|
||||||
|
|
||||||
// 4.5.8 RegulateTime ( hour, minute, second, millisecond, microsecond, nanosecond, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-regulatetime
|
// 4.5.8 RegulateTime ( hour, minute, second, millisecond, microsecond, nanosecond, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-regulatetime
|
||||||
ThrowCompletionOr<Time> regulate_time(VM& vm, double hour, double minute, double second, double millisecond, double microsecond, double nanosecond, Overflow overflow)
|
ThrowCompletionOr<Time> regulate_time(VM& vm, double hour, double minute, double second, double millisecond, double microsecond, double nanosecond, Overflow overflow)
|
||||||
{
|
{
|
||||||
|
@ -262,6 +349,98 @@ Time balance_time(double hour, double minute, double second, double millisecond,
|
||||||
return create_time_record(hour, minute, second, millisecond, microsecond, nanosecond, delta_days);
|
return create_time_record(hour, minute, second, millisecond, microsecond, nanosecond, delta_days);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4.5.11 CreateTemporalTime ( time [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaltime
|
||||||
|
ThrowCompletionOr<GC::Ref<PlainTime>> create_temporal_time(VM& vm, Time const& time, GC::Ptr<FunctionObject> new_target)
|
||||||
|
{
|
||||||
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
|
// 1. If newTarget is not present, set newTarget to %Temporal.PlainTime%.
|
||||||
|
if (!new_target)
|
||||||
|
new_target = realm.intrinsics().temporal_plain_time_constructor();
|
||||||
|
|
||||||
|
// 2. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainTime.prototype%", « [[InitializedTemporalTime]], [[Time]] »).
|
||||||
|
// 3. Set object.[[Time]] to time.
|
||||||
|
auto object = TRY(ordinary_create_from_constructor<PlainTime>(vm, *new_target, &Intrinsics::temporal_plain_time_prototype, time));
|
||||||
|
|
||||||
|
// 4. Return object.
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.5.12 ToTemporalTimeRecord ( temporalTimeLike [ , completeness ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimerecord
|
||||||
|
ThrowCompletionOr<TemporalTimeLike> to_temporal_time_record(VM& vm, Object const& temporal_time_like, Completeness completeness)
|
||||||
|
{
|
||||||
|
// 1. If completeness is not present, set completeness to COMPLETE.
|
||||||
|
|
||||||
|
TemporalTimeLike result;
|
||||||
|
|
||||||
|
// 2. If completeness is COMPLETE, then
|
||||||
|
if (completeness == Completeness::Complete) {
|
||||||
|
// a. Let result be a new TemporalTimeLike Record with each field set to 0.
|
||||||
|
result = TemporalTimeLike::zero();
|
||||||
|
}
|
||||||
|
// 3. Else,
|
||||||
|
else {
|
||||||
|
// a. Let result be a new TemporalTimeLike Record with each field set to UNSET.
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Let any be false.
|
||||||
|
auto any = false;
|
||||||
|
|
||||||
|
auto apply_field = [&](auto const& key, auto& result_field) -> ThrowCompletionOr<void> {
|
||||||
|
auto field = TRY(temporal_time_like.get(key));
|
||||||
|
if (field.is_undefined())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
result_field = TRY(to_integer_with_truncation(vm, field, ErrorType::TemporalInvalidTimeLikeField, field, key));
|
||||||
|
any = true;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 5. Let hour be ? Get(temporalTimeLike, "hour").
|
||||||
|
// 6. If hour is not undefined, then
|
||||||
|
// a. Set result.[[Hour]] to ? ToIntegerWithTruncation(hour).
|
||||||
|
// b. Set any to true.
|
||||||
|
TRY(apply_field(vm.names.hour, result.hour));
|
||||||
|
|
||||||
|
// 7. Let microsecond be ? Get(temporalTimeLike, "microsecond").
|
||||||
|
// 8. If microsecond is not undefined, then
|
||||||
|
// a. Set result.[[Microsecond]] to ? ToIntegerWithTruncation(microsecond).
|
||||||
|
// b. Set any to true.
|
||||||
|
TRY(apply_field(vm.names.microsecond, result.microsecond));
|
||||||
|
|
||||||
|
// 9. Let millisecond be ? Get(temporalTimeLike, "millisecond").
|
||||||
|
// 10. If millisecond is not undefined, then
|
||||||
|
// a. Set result.[[Millisecond]] to ? ToIntegerWithTruncation(millisecond).
|
||||||
|
// b. Set any to true.
|
||||||
|
TRY(apply_field(vm.names.millisecond, result.millisecond));
|
||||||
|
|
||||||
|
// 11. Let minute be ? Get(temporalTimeLike, "minute").
|
||||||
|
// 12. If minute is not undefined, then
|
||||||
|
// a. Set result.[[Minute]] to ? ToIntegerWithTruncation(minute).
|
||||||
|
// b. Set any to true.
|
||||||
|
TRY(apply_field(vm.names.minute, result.minute));
|
||||||
|
|
||||||
|
// 13. Let nanosecond be ? Get(temporalTimeLike, "nanosecond").
|
||||||
|
// 14. If nanosecond is not undefined, then
|
||||||
|
// a. Set result.[[Nanosecond]] to ? ToIntegerWithTruncation(nanosecond).
|
||||||
|
// b. Set any to true.
|
||||||
|
TRY(apply_field(vm.names.nanosecond, result.nanosecond));
|
||||||
|
|
||||||
|
// 15. Let second be ? Get(temporalTimeLike, "second").
|
||||||
|
// 16. If second is not undefined, then
|
||||||
|
// a. Set result.[[Second]] to ? ToIntegerWithTruncation(second).
|
||||||
|
// b. Set any to true.
|
||||||
|
TRY(apply_field(vm.names.second, result.second));
|
||||||
|
|
||||||
|
// 17. If any is false, throw a TypeError exception.
|
||||||
|
if (!any)
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::TemporalInvalidTime);
|
||||||
|
|
||||||
|
// 18. Return result.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// 4.5.14 CompareTimeRecord ( time1, time2 ), https://tc39.es/proposal-temporal/#sec-temporal-comparetimerecord
|
// 4.5.14 CompareTimeRecord ( time1, time2 ), https://tc39.es/proposal-temporal/#sec-temporal-comparetimerecord
|
||||||
i8 compare_time_record(Time const& time1, Time const& time2)
|
i8 compare_time_record(Time const& time1, Time const& time2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,14 +13,52 @@
|
||||||
|
|
||||||
namespace JS::Temporal {
|
namespace JS::Temporal {
|
||||||
|
|
||||||
|
class PlainTime final : public Object {
|
||||||
|
JS_OBJECT(PlainTime, Object);
|
||||||
|
GC_DECLARE_ALLOCATOR(PlainTime);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~PlainTime() override = default;
|
||||||
|
|
||||||
|
[[nodiscard]] Time const& time() const { return m_time; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PlainTime(Time const&, Object& prototype);
|
||||||
|
|
||||||
|
Time m_time; // [[Time]]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Table 5: TemporalTimeLike Record Fields, https://tc39.es/proposal-temporal/#table-temporal-temporaltimelike-record-fields
|
||||||
|
struct TemporalTimeLike {
|
||||||
|
static TemporalTimeLike zero()
|
||||||
|
{
|
||||||
|
return { .hour = 0, .minute = 0, .second = 0, .millisecond = 0, .microsecond = 0, .nanosecond = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<double> hour;
|
||||||
|
Optional<double> minute;
|
||||||
|
Optional<double> second;
|
||||||
|
Optional<double> millisecond;
|
||||||
|
Optional<double> microsecond;
|
||||||
|
Optional<double> nanosecond;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Completeness {
|
||||||
|
Complete,
|
||||||
|
Partial,
|
||||||
|
};
|
||||||
|
|
||||||
Time create_time_record(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond, double delta_days = 0);
|
Time create_time_record(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond, double delta_days = 0);
|
||||||
Time midnight_time_record();
|
Time midnight_time_record();
|
||||||
Time noon_time_record();
|
Time noon_time_record();
|
||||||
TimeDuration difference_time(Time const&, Time const&);
|
TimeDuration difference_time(Time const&, Time const&);
|
||||||
|
ThrowCompletionOr<GC::Ref<PlainTime>> to_temporal_time(VM&, Value item, Value options = js_undefined());
|
||||||
ThrowCompletionOr<Time> regulate_time(VM&, double hour, double minute, double second, double millisecond, double microsecond, double nanosecond, Overflow);
|
ThrowCompletionOr<Time> regulate_time(VM&, double hour, double minute, double second, double millisecond, double microsecond, double nanosecond, Overflow);
|
||||||
bool is_valid_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
|
bool is_valid_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
|
||||||
Time balance_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
|
Time balance_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
|
||||||
Time balance_time(double hour, double minute, double second, double millisecond, double microsecond, TimeDuration const& nanosecond);
|
Time balance_time(double hour, double minute, double second, double millisecond, double microsecond, TimeDuration const& nanosecond);
|
||||||
|
ThrowCompletionOr<GC::Ref<PlainTime>> create_temporal_time(VM&, Time const&, GC::Ptr<FunctionObject> new_target = {});
|
||||||
|
ThrowCompletionOr<TemporalTimeLike> to_temporal_time_record(VM&, Object const& temporal_time_like, Completeness = Completeness::Complete);
|
||||||
i8 compare_time_record(Time const&, Time const&);
|
i8 compare_time_record(Time const&, Time const&);
|
||||||
Time add_time(Time const&, TimeDuration const& time_duration);
|
Time add_time(Time const&, TimeDuration const& time_duration);
|
||||||
|
|
||||||
|
|
108
Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.cpp
Normal file
108
Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
||||||
|
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||||
|
|
||||||
|
namespace JS::Temporal {
|
||||||
|
|
||||||
|
GC_DEFINE_ALLOCATOR(PlainTimeConstructor);
|
||||||
|
|
||||||
|
// 4.1 The Temporal.PlainTime Constructor, https://tc39.es/proposal-temporal/#sec-temporal-plaintime-constructor
|
||||||
|
PlainTimeConstructor::PlainTimeConstructor(Realm& realm)
|
||||||
|
: NativeFunction(realm.vm().names.PlainTime.as_string(), realm.intrinsics().function_prototype())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlainTimeConstructor::initialize(Realm& realm)
|
||||||
|
{
|
||||||
|
Base::initialize(realm);
|
||||||
|
|
||||||
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
// 4.2.1 Temporal.PlainTime.prototype, https://tc39.es/proposal-temporal/#sec-temporal.plaintime.prototype
|
||||||
|
define_direct_property(vm.names.prototype, realm.intrinsics().temporal_plain_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(0), Attribute::Configurable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.1.1 Temporal.PlainTime ( [ hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond ] ] ] ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaintime
|
||||||
|
ThrowCompletionOr<Value> PlainTimeConstructor::call()
|
||||||
|
{
|
||||||
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
// 1. If NewTarget is undefined, then
|
||||||
|
// a. Throw a TypeError exception.
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, "Temporal.PlainTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.1.1 Temporal.PlainTime ( [ hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond ] ] ] ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.plaintime
|
||||||
|
ThrowCompletionOr<GC::Ref<Object>> PlainTimeConstructor::construct(FunctionObject& new_target)
|
||||||
|
{
|
||||||
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
auto next_integer_argument = [&, index = 0]() mutable -> ThrowCompletionOr<double> {
|
||||||
|
if (auto value = vm.argument(index++); !value.is_undefined())
|
||||||
|
return to_integer_with_truncation(vm, value, ErrorType::TemporalInvalidPlainTime);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour).
|
||||||
|
auto hour = TRY(next_integer_argument());
|
||||||
|
|
||||||
|
// 3. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute).
|
||||||
|
auto minute = TRY(next_integer_argument());
|
||||||
|
|
||||||
|
// 4. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second).
|
||||||
|
auto second = TRY(next_integer_argument());
|
||||||
|
|
||||||
|
// 5. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond).
|
||||||
|
auto millisecond = TRY(next_integer_argument());
|
||||||
|
|
||||||
|
// 6. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond).
|
||||||
|
auto microsecond = TRY(next_integer_argument());
|
||||||
|
|
||||||
|
// 7. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond).
|
||||||
|
auto nanosecond = TRY(next_integer_argument());
|
||||||
|
|
||||||
|
// 8. 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::TemporalInvalidPlainTime);
|
||||||
|
|
||||||
|
// 9. Let time be CreateTimeRecord(hour, minute, second, millisecond, microsecond, nanosecond).
|
||||||
|
auto time = create_time_record(hour, minute, second, millisecond, microsecond, nanosecond);
|
||||||
|
|
||||||
|
// 10. Return ? CreateTemporalTime(time, NewTarget).
|
||||||
|
return TRY(create_temporal_time(vm, time, 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)
|
||||||
|
{
|
||||||
|
// 4. Return ? ToTemporalTime(item, overflow).
|
||||||
|
return TRY(to_temporal_time(vm, vm.argument(0), vm.argument(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.2.3 Temporal.PlainTime.compare ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal.plaintime.compare
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(PlainTimeConstructor::compare)
|
||||||
|
{
|
||||||
|
// 1. Set one to ? ToTemporalTime(one).
|
||||||
|
auto one = TRY(to_temporal_time(vm, vm.argument(0)));
|
||||||
|
|
||||||
|
// 2. Set two to ? ToTemporalTime(two).
|
||||||
|
auto two = TRY(to_temporal_time(vm, vm.argument(1)));
|
||||||
|
|
||||||
|
// 3. Return 𝔽(CompareTimeRecord(one.[[Time]], two.[[Time]])).
|
||||||
|
return compare_time_record(one->time(), two->time());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.h
Normal file
34
Libraries/LibJS/Runtime/Temporal/PlainTimeConstructor.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 PlainTimeConstructor final : public NativeFunction {
|
||||||
|
JS_OBJECT(PlainTimeConstructor, NativeFunction);
|
||||||
|
GC_DECLARE_ALLOCATOR(PlainTimeConstructor);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void initialize(Realm&) override;
|
||||||
|
virtual ~PlainTimeConstructor() override = default;
|
||||||
|
|
||||||
|
virtual ThrowCompletionOr<Value> call() override;
|
||||||
|
virtual ThrowCompletionOr<GC::Ref<Object>> construct(FunctionObject& new_target) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit PlainTimeConstructor(Realm&);
|
||||||
|
|
||||||
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(from);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(compare);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
65
Libraries/LibJS/Runtime/Temporal/PlainTimePrototype.cpp
Normal file
65
Libraries/LibJS/Runtime/Temporal/PlainTimePrototype.cpp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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/PlainTimePrototype.h>
|
||||||
|
|
||||||
|
namespace JS::Temporal {
|
||||||
|
|
||||||
|
GC_DEFINE_ALLOCATOR(PlainTimePrototype);
|
||||||
|
|
||||||
|
// 4.3 Properties of the Temporal.PlainTime Prototype Object, https://tc39.es/proposal-temporal/#sec-properties-of-the-temporal-plaintime-prototype-object
|
||||||
|
PlainTimePrototype::PlainTimePrototype(Realm& realm)
|
||||||
|
: PrototypeObject(realm.intrinsics().object_prototype())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlainTimePrototype::initialize(Realm& realm)
|
||||||
|
{
|
||||||
|
Base::initialize(realm);
|
||||||
|
|
||||||
|
auto& vm = this->vm();
|
||||||
|
|
||||||
|
// 4.3.2 Temporal.PlainTime.prototype[ %Symbol.toStringTag% ], https://tc39.es/proposal-temporal/#sec-temporal.plaintime.prototype-%symbol.tostringtag%
|
||||||
|
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Temporal.PlainTime"_string), 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.3.3 get Temporal.PlainTime.prototype.hour, https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.hour
|
||||||
|
// 4.3.4 get Temporal.PlainTime.prototype.minute, https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.minute
|
||||||
|
// 4.3.5 get Temporal.PlainTime.prototype.second, https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.second
|
||||||
|
// 4.3.6 get Temporal.PlainTime.prototype.millisecond, https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.millisecond
|
||||||
|
// 4.3.7 get Temporal.PlainTime.prototype.microsecond, https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.microsecond
|
||||||
|
// 4.3.8 get Temporal.PlainTime.prototype.nanosecond, https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.microsecond
|
||||||
|
#define JS_ENUMERATE_PLAIN_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(PlainTimePrototype::field##_getter) \
|
||||||
|
{ \
|
||||||
|
/* 1. Let temporalTime be the this value. */ \
|
||||||
|
/* 2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]). */ \
|
||||||
|
auto temporal_time = TRY(typed_this_object(vm)); \
|
||||||
|
\
|
||||||
|
/* 3. Return 𝔽(temporalTime.[[Time]].[[<field>]]). */ \
|
||||||
|
return temporal_time->time().field; \
|
||||||
|
}
|
||||||
|
JS_ENUMERATE_PLAIN_TIME_FIELDS
|
||||||
|
#undef __JS_ENUMERATE
|
||||||
|
|
||||||
|
}
|
34
Libraries/LibJS/Runtime/Temporal/PlainTimePrototype.h
Normal file
34
Libraries/LibJS/Runtime/Temporal/PlainTimePrototype.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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/PlainTime.h>
|
||||||
|
|
||||||
|
namespace JS::Temporal {
|
||||||
|
|
||||||
|
class PlainTimePrototype final : public PrototypeObject<PlainTimePrototype, PlainTime> {
|
||||||
|
JS_PROTOTYPE_OBJECT(PlainTimePrototype, PlainTime, Temporal.PlainTime);
|
||||||
|
GC_DECLARE_ALLOCATOR(PlainTimePrototype);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void initialize(Realm&) override;
|
||||||
|
virtual ~PlainTimePrototype() override = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit PlainTimePrototype(Realm&);
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
#include <LibJS/Runtime/Temporal/DurationConstructor.h>
|
#include <LibJS/Runtime/Temporal/DurationConstructor.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainDateConstructor.h>
|
#include <LibJS/Runtime/Temporal/PlainDateConstructor.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainMonthDayConstructor.h>
|
#include <LibJS/Runtime/Temporal/PlainMonthDayConstructor.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/PlainTimeConstructor.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainYearMonthConstructor.h>
|
#include <LibJS/Runtime/Temporal/PlainYearMonthConstructor.h>
|
||||||
#include <LibJS/Runtime/Temporal/Temporal.h>
|
#include <LibJS/Runtime/Temporal/Temporal.h>
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ void Temporal::initialize(Realm& realm)
|
||||||
define_intrinsic_accessor(vm.names.Duration, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_duration_constructor(); });
|
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.PlainDate, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_plain_date_constructor(); });
|
||||||
define_intrinsic_accessor(vm.names.PlainMonthDay, attr, [](auto& realm) -> Value { return realm.intrinsics().temporal_plain_month_day_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(); });
|
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.PlainTime.compare).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime1 = new Temporal.PlainTime(16, 38, 40, 1, 2, 3);
|
||||||
|
expect(Temporal.PlainTime.compare(plainTime1, plainTime1)).toBe(0);
|
||||||
|
const plainTime2 = new Temporal.PlainTime(16, 39, 5, 0, 1, 2);
|
||||||
|
expect(Temporal.PlainTime.compare(plainTime1, plainTime2)).toBe(-1);
|
||||||
|
expect(Temporal.PlainTime.compare(plainTime2, plainTime1)).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,67 @@
|
||||||
|
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("PlainTime string argument", () => {
|
||||||
|
const createdPlainTime = Temporal.PlainTime.from("2021-08-27T18:44:11");
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("string must not contain a UTC designator", () => {
|
||||||
|
expect(() => {
|
||||||
|
Temporal.PlainTime.from("2021-07-06T23:42:01Z");
|
||||||
|
}).toThrowWithMessage(RangeError, "Invalid ISO date time");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("extended year must not be negative zero", () => {
|
||||||
|
expect(() => {
|
||||||
|
Temporal.PlainTime.from("-000000-01-01T00:00:00");
|
||||||
|
}).toThrowWithMessage(RangeError, "Invalid ISO date time");
|
||||||
|
expect(() => {
|
||||||
|
Temporal.PlainTime.from("−000000-01-01T00:00:00"); // U+2212
|
||||||
|
}).toThrowWithMessage(RangeError, "Invalid ISO date time");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("ambiguous string must contain a time designator", () => {
|
||||||
|
const values = [
|
||||||
|
// YYYY-MM or HHMM-UU
|
||||||
|
"2021-12",
|
||||||
|
// MMDD or HHMM
|
||||||
|
"1214",
|
||||||
|
"0229",
|
||||||
|
"1130",
|
||||||
|
// MM-DD or HH-UU
|
||||||
|
"12-14",
|
||||||
|
// YYYYMM or HHMMSS
|
||||||
|
"202112",
|
||||||
|
];
|
||||||
|
for (const value of values) {
|
||||||
|
expect(() => {
|
||||||
|
Temporal.PlainTime.from(value);
|
||||||
|
}).toThrowWithMessage(RangeError, "Invalid ISO date time");
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
Temporal.PlainTime.from(`T${value}`);
|
||||||
|
}).not.toThrow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,50 @@
|
||||||
|
describe("errors", () => {
|
||||||
|
test("called without new", () => {
|
||||||
|
expect(() => {
|
||||||
|
Temporal.PlainTime();
|
||||||
|
}).toThrowWithMessage(
|
||||||
|
TypeError,
|
||||||
|
"Temporal.PlainTime constructor must be called with 'new'"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("cannot pass Infinity", () => {
|
||||||
|
for (let i = 0; i < 6; ++i) {
|
||||||
|
const args = Array(6).fill(0);
|
||||||
|
|
||||||
|
args[i] = Infinity;
|
||||||
|
expect(() => {
|
||||||
|
new Temporal.PlainTime(...args);
|
||||||
|
}).toThrowWithMessage(RangeError, "Invalid plain time");
|
||||||
|
|
||||||
|
args[i] = -Infinity;
|
||||||
|
expect(() => {
|
||||||
|
new Temporal.PlainTime(...args);
|
||||||
|
}).toThrowWithMessage(RangeError, "Invalid plain time");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("cannot pass invalid ISO time", () => {
|
||||||
|
const badValues = [24, 60, 60, 1000, 1000, 1000];
|
||||||
|
for (let i = 0; i < 6; ++i) {
|
||||||
|
const args = [0, 0, 0, 0, 0, 0];
|
||||||
|
args[i] = badValues[i];
|
||||||
|
expect(() => {
|
||||||
|
new Temporal.PlainTime(...args);
|
||||||
|
}).toThrowWithMessage(RangeError, "Invalid plain time");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("normal behavior", () => {
|
||||||
|
test("length is 0", () => {
|
||||||
|
expect(Temporal.PlainTime).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime = new Temporal.PlainTime(19, 46, 32, 123, 456, 789);
|
||||||
|
expect(typeof plainTime).toBe("object");
|
||||||
|
expect(plainTime).toBeInstanceOf(Temporal.PlainTime);
|
||||||
|
expect(Object.getPrototypeOf(plainTime)).toBe(Temporal.PlainTime.prototype);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime = new Temporal.PlainTime(12);
|
||||||
|
expect(plainTime.hour).toBe(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("this value must be a Temporal.PlainTime object", () => {
|
||||||
|
expect(() => {
|
||||||
|
Reflect.get(Temporal.PlainTime.prototype, "hour", "foo");
|
||||||
|
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainTime");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime = new Temporal.PlainTime(0, 0, 0, 0, 12);
|
||||||
|
expect(plainTime.microsecond).toBe(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("this value must be a Temporal.PlainTime object", () => {
|
||||||
|
expect(() => {
|
||||||
|
Reflect.get(Temporal.PlainTime.prototype, "microsecond", "foo");
|
||||||
|
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainTime");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime = new Temporal.PlainTime(0, 0, 0, 12);
|
||||||
|
expect(plainTime.millisecond).toBe(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("this value must be a Temporal.PlainTime object", () => {
|
||||||
|
expect(() => {
|
||||||
|
Reflect.get(Temporal.PlainTime.prototype, "millisecond", "foo");
|
||||||
|
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainTime");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime = new Temporal.PlainTime(0, 12);
|
||||||
|
expect(plainTime.minute).toBe(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("this value must be a Temporal.PlainTime object", () => {
|
||||||
|
expect(() => {
|
||||||
|
Reflect.get(Temporal.PlainTime.prototype, "minute", "foo");
|
||||||
|
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainTime");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime = new Temporal.PlainTime(0, 0, 0, 0, 0, 12);
|
||||||
|
expect(plainTime.nanosecond).toBe(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("this value must be a Temporal.PlainTime object", () => {
|
||||||
|
expect(() => {
|
||||||
|
Reflect.get(Temporal.PlainTime.prototype, "nanosecond", "foo");
|
||||||
|
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainTime");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("basic functionality", () => {
|
||||||
|
const plainTime = new Temporal.PlainTime(0, 0, 12);
|
||||||
|
expect(plainTime.second).toBe(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("this value must be a Temporal.PlainTime object", () => {
|
||||||
|
expect(() => {
|
||||||
|
Reflect.get(Temporal.PlainTime.prototype, "second", "foo");
|
||||||
|
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainTime");
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue