mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 08:07:34 +00:00
LibJS: Leverage PrepareTemporalFields in ToTemporalTimeRecord
This is an editorial change in the Temporal spec.
See: b5ba981
This commit is contained in:
parent
6cc69bbd8e
commit
e96df3b7a7
5 changed files with 52 additions and 45 deletions
|
@ -245,7 +245,6 @@
|
|||
M(TemporalInvalidPlainDateTime, "Invalid plain date time") \
|
||||
M(TemporalInvalidPlainMonthDay, "Invalid plain month day") \
|
||||
M(TemporalInvalidPlainTime, "Invalid plain time") \
|
||||
M(TemporalInvalidPlainTimeLikeObject, "Invalid plain time-like object") \
|
||||
M(TemporalInvalidPlainYearMonth, "Invalid plain year month") \
|
||||
M(TemporalInvalidTime, "Invalid time") \
|
||||
M(TemporalInvalidTimeString, "Invalid time string '{}'") \
|
||||
|
|
|
@ -336,43 +336,39 @@ ThrowCompletionOr<PlainTime*> create_temporal_time(GlobalObject& global_object,
|
|||
}
|
||||
|
||||
// 4.5.8 ToTemporalTimeRecord ( temporalTimeLike [ , completeness ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimerecord
|
||||
ThrowCompletionOr<UnregulatedTemporalTime> to_temporal_time_record(GlobalObject& global_object, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness completeness)
|
||||
ThrowCompletionOr<TemporalTimeLikeRecord> to_temporal_time_record(GlobalObject& global_object, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness completeness)
|
||||
{
|
||||
auto& vm = global_object.vm();
|
||||
|
||||
// 1. If completeness is not present, set completeness to complete.
|
||||
|
||||
// 2. Let result be the Record { [[Hour]]: undefined, [[Minute]]: undefined, [[Second]]: undefined, [[Millisecond]]: undefined, [[Microsecond]]: undefined, [[Nanosecond]]: undefined }.
|
||||
auto result = UnregulatedTemporalTime {};
|
||||
// 2. Let partial be ? PrepareTemporalFields(temporalTimeLike, « "hour", "microsecond", "millisecond", "minute", "nanosecond", "second" », partial).
|
||||
auto* partial = TRY(prepare_temporal_fields(global_object, temporal_time_like, { "hour"sv, "microsecond"sv, "millisecond"sv, "minute"sv, "nanosecond"sv, "second"sv }, PrepareTemporalFieldsPartial {}));
|
||||
|
||||
// 3. Let any be false.
|
||||
auto any = false;
|
||||
// 3. Let result be a new TemporalTimeLike Record with each field set to undefined.
|
||||
auto result = TemporalTimeLikeRecord {};
|
||||
|
||||
// 4. For each row of Table 3, except the header row, in table order, do
|
||||
for (auto& [internal_slot, property] : temporal_time_like_properties<UnregulatedTemporalTime, Optional<double>>(vm)) {
|
||||
// a. Let property be the Property value of the current row.
|
||||
// 4. For each row of Table 4, except the header row, in table order, do
|
||||
for (auto& [field, property_name] : temporal_time_like_record_fields<TemporalTimeLikeRecord, Optional<double>>(vm)) {
|
||||
// a. Let field be the Field Name value of the current row.
|
||||
// b. Let propertyName be the Property Name value of the current row.
|
||||
|
||||
// b. Let value be ? Get(temporalTimeLike, property).
|
||||
auto value = TRY(temporal_time_like.get(property));
|
||||
// c. Let valueDesc be OrdinaryGetOwnProperty(partial, propertyName).
|
||||
auto value_descriptor = MUST(partial->Object::internal_get_own_property(property_name));
|
||||
|
||||
// c. If value is not undefined, set any to true.
|
||||
if (!value.is_undefined())
|
||||
any = true;
|
||||
// d. If valueDesc is not undefined, then
|
||||
if (value_descriptor.has_value()) {
|
||||
// i. Assert: valueDesc is a data Property Descriptor.
|
||||
VERIFY(value_descriptor->is_data_descriptor());
|
||||
|
||||
// d. If value is not undefined or completeness is complete, then
|
||||
if (!value.is_undefined() || completeness == ToTemporalTimeRecordCompleteness::Complete) {
|
||||
// i. Set value to ? ToIntegerThrowOnInfinity(value).
|
||||
auto value_number = TRY(to_integer_throw_on_infinity(global_object, value, ErrorType::TemporalPropertyMustBeFinite));
|
||||
|
||||
// ii. Set result's internal slot whose name is the Internal Slot value of the current row to value.
|
||||
result.*internal_slot = value_number;
|
||||
// ii. Set the field of result whose name is field to valueDesc.[[Value]].
|
||||
result.*field = value_descriptor->value->as_double();
|
||||
}
|
||||
// e. Else if completeness is complete, then
|
||||
else if (completeness == ToTemporalTimeRecordCompleteness::Complete) {
|
||||
// i. Set the field of result whose name is field to 0.
|
||||
result.*field = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. If any is false, then
|
||||
if (!any) {
|
||||
// a. Throw a TypeError exception.
|
||||
return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalInvalidPlainTimeLikeObject);
|
||||
}
|
||||
|
||||
// 6. Return result.
|
||||
|
|
|
@ -54,7 +54,7 @@ struct DaysAndTime {
|
|||
u16 nanosecond;
|
||||
};
|
||||
|
||||
struct UnregulatedTemporalTime {
|
||||
struct TemporalTimeLikeRecord {
|
||||
Optional<double> hour;
|
||||
Optional<double> minute;
|
||||
Optional<double> second;
|
||||
|
@ -63,24 +63,24 @@ struct UnregulatedTemporalTime {
|
|||
Optional<double> nanosecond;
|
||||
};
|
||||
|
||||
// Table 3: Properties of a TemporalTimeLike, https://tc39.es/proposal-temporal/#table-temporal-temporaltimelike-properties
|
||||
// Table 4: TemporalTimeLike Record Fields, https://tc39.es/proposal-temporal/#table-temporal-temporaltimelike-properties
|
||||
|
||||
template<typename StructT, typename ValueT>
|
||||
struct TemporalTimeLikeProperty {
|
||||
ValueT StructT::*internal_slot { nullptr };
|
||||
PropertyKey property;
|
||||
struct TemporalTimeLikeRecordField {
|
||||
ValueT StructT::*field_name { nullptr };
|
||||
PropertyKey property_name;
|
||||
};
|
||||
|
||||
template<typename StructT, typename ValueT>
|
||||
auto temporal_time_like_properties = [](VM& vm) {
|
||||
using PropertyT = TemporalTimeLikeProperty<StructT, ValueT>;
|
||||
auto temporal_time_like_record_fields = [](VM& vm) {
|
||||
using FieldT = TemporalTimeLikeRecordField<StructT, ValueT>;
|
||||
return AK::Array {
|
||||
PropertyT { &StructT::hour, vm.names.hour },
|
||||
PropertyT { &StructT::microsecond, vm.names.microsecond },
|
||||
PropertyT { &StructT::millisecond, vm.names.millisecond },
|
||||
PropertyT { &StructT::minute, vm.names.minute },
|
||||
PropertyT { &StructT::nanosecond, vm.names.nanosecond },
|
||||
PropertyT { &StructT::second, vm.names.second },
|
||||
FieldT { &StructT::hour, vm.names.hour },
|
||||
FieldT { &StructT::microsecond, vm.names.microsecond },
|
||||
FieldT { &StructT::millisecond, vm.names.millisecond },
|
||||
FieldT { &StructT::minute, vm.names.minute },
|
||||
FieldT { &StructT::nanosecond, vm.names.nanosecond },
|
||||
FieldT { &StructT::second, vm.names.second },
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -96,7 +96,7 @@ bool is_valid_time(double hour, double minute, double second, double millisecond
|
|||
DaysAndTime balance_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
|
||||
TemporalTime constrain_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
|
||||
ThrowCompletionOr<PlainTime*> create_temporal_time(GlobalObject&, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, FunctionObject const* new_target = nullptr);
|
||||
ThrowCompletionOr<UnregulatedTemporalTime> to_temporal_time_record(GlobalObject&, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness = ToTemporalTimeRecordCompleteness::Complete);
|
||||
ThrowCompletionOr<TemporalTimeLikeRecord> to_temporal_time_record(GlobalObject&, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness = ToTemporalTimeRecordCompleteness::Complete);
|
||||
String temporal_time_to_string(u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Variant<StringView, u8> const& precision);
|
||||
i8 compare_temporal_time(u8 hour1, u8 minute1, u8 second1, u16 millisecond1, u16 microsecond1, u16 nanosecond1, u8 hour2, u8 minute2, u8 second2, u16 millisecond2, u16 microsecond2, u16 nanosecond2);
|
||||
DaysAndTime add_time(u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);
|
||||
|
|
|
@ -92,10 +92,16 @@ describe("errors", () => {
|
|||
test("argument is an invalid plain time-like object", () => {
|
||||
expect(() => {
|
||||
new Temporal.PlainTime().with({});
|
||||
}).toThrowWithMessage(TypeError, "Invalid plain time-like object");
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
|
||||
);
|
||||
expect(() => {
|
||||
new Temporal.PlainTime().with({ foo: 1, bar: 2 });
|
||||
}).toThrowWithMessage(TypeError, "Invalid plain time-like object");
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
|
||||
);
|
||||
});
|
||||
|
||||
test("error when coercing property to number", () => {
|
||||
|
|
|
@ -118,10 +118,16 @@ describe("errors", () => {
|
|||
test("invalid plain time-like object", () => {
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(1n, {}).withPlainTime({});
|
||||
}).toThrowWithMessage(TypeError, "Invalid plain time-like object");
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
|
||||
);
|
||||
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(1n, {}).withPlainTime({ foo: 1, bar: 2 });
|
||||
}).toThrowWithMessage(TypeError, "Invalid plain time-like object");
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue