2021-07-11 21:04:11 +03:00
|
|
|
|
/*
|
|
|
|
|
|
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
2023-01-26 12:07:38 +00:00
|
|
|
|
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
|
2025-02-28 12:15:49 -05:00
|
|
|
|
* Copyright (c) 2024-2025, Tim Flynn <trflynn89@ladybird.org>
|
2021-07-11 21:04:11 +03:00
|
|
|
|
*
|
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
2021-08-31 00:15:36 +01:00
|
|
|
|
#include <AK/Variant.h>
|
2024-11-18 14:27:54 -05:00
|
|
|
|
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
|
|
|
|
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
2024-11-18 10:36:03 -05:00
|
|
|
|
#include <LibGC/Ptr.h>
|
2021-07-18 21:44:05 +01:00
|
|
|
|
#include <LibJS/Forward.h>
|
2025-02-28 12:15:49 -05:00
|
|
|
|
#include <LibJS/Runtime/AbstractOperations.h>
|
2021-09-15 23:03:38 +01:00
|
|
|
|
#include <LibJS/Runtime/Completion.h>
|
2024-11-20 12:59:15 -05:00
|
|
|
|
#include <LibJS/Runtime/Temporal/ISO8601.h>
|
2024-11-22 16:39:21 -05:00
|
|
|
|
#include <LibJS/Runtime/Temporal/ISORecords.h>
|
2024-11-16 12:51:53 -05:00
|
|
|
|
#include <LibJS/Runtime/VM.h>
|
2023-10-06 17:54:21 +02:00
|
|
|
|
#include <LibJS/Runtime/ValueInlines.h>
|
2024-11-18 11:58:51 -05:00
|
|
|
|
#include <math.h>
|
2021-07-11 21:04:11 +03:00
|
|
|
|
|
|
|
|
|
|
namespace JS::Temporal {
|
|
|
|
|
|
|
2024-11-18 12:48:10 -05:00
|
|
|
|
enum class ArithmeticOperation {
|
|
|
|
|
|
Add,
|
|
|
|
|
|
Subtract,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-20 12:59:15 -05:00
|
|
|
|
enum class DateType {
|
|
|
|
|
|
Date,
|
|
|
|
|
|
MonthDay,
|
|
|
|
|
|
YearMonth,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-25 13:51:48 -05:00
|
|
|
|
enum class Direction {
|
|
|
|
|
|
Next,
|
|
|
|
|
|
Previous,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-24 20:42:47 -05:00
|
|
|
|
enum class Disambiguation {
|
|
|
|
|
|
Compatible,
|
|
|
|
|
|
Earlier,
|
|
|
|
|
|
Later,
|
|
|
|
|
|
Reject,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-21 13:21:29 -05:00
|
|
|
|
enum class DurationOperation {
|
|
|
|
|
|
Since,
|
|
|
|
|
|
Until,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-24 20:42:47 -05:00
|
|
|
|
enum class OffsetOption {
|
|
|
|
|
|
Prefer,
|
|
|
|
|
|
Use,
|
|
|
|
|
|
Ignore,
|
|
|
|
|
|
Reject,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-20 12:59:15 -05:00
|
|
|
|
enum class Overflow {
|
|
|
|
|
|
Constrain,
|
|
|
|
|
|
Reject,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-20 14:57:18 -05:00
|
|
|
|
enum class ShowCalendar {
|
|
|
|
|
|
Auto,
|
|
|
|
|
|
Always,
|
|
|
|
|
|
Never,
|
|
|
|
|
|
Critical,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-25 10:17:28 -05:00
|
|
|
|
enum class ShowOffset {
|
|
|
|
|
|
Auto,
|
|
|
|
|
|
Never,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum class ShowTimeZoneName {
|
|
|
|
|
|
Auto,
|
|
|
|
|
|
Never,
|
|
|
|
|
|
Critical,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-20 12:59:15 -05:00
|
|
|
|
enum class TimeStyle {
|
|
|
|
|
|
Separated,
|
|
|
|
|
|
Unseparated,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-18 11:58:51 -05:00
|
|
|
|
// https://tc39.es/proposal-temporal/#sec-temporal-units
|
|
|
|
|
|
enum class Unit {
|
|
|
|
|
|
Year,
|
|
|
|
|
|
Month,
|
|
|
|
|
|
Week,
|
|
|
|
|
|
Day,
|
|
|
|
|
|
Hour,
|
|
|
|
|
|
Minute,
|
|
|
|
|
|
Second,
|
|
|
|
|
|
Millisecond,
|
|
|
|
|
|
Microsecond,
|
|
|
|
|
|
Nanosecond,
|
|
|
|
|
|
};
|
2025-06-28 21:39:13 -07:00
|
|
|
|
JS_API StringView temporal_unit_to_string(Unit);
|
2024-11-18 11:58:51 -05:00
|
|
|
|
|
|
|
|
|
|
// https://tc39.es/proposal-temporal/#sec-temporal-units
|
|
|
|
|
|
enum class UnitCategory {
|
|
|
|
|
|
Date,
|
|
|
|
|
|
Time,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// https://tc39.es/proposal-temporal/#sec-temporal-units
|
|
|
|
|
|
enum class UnitGroup {
|
|
|
|
|
|
Date,
|
|
|
|
|
|
Time,
|
|
|
|
|
|
DateTime,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-18 14:27:54 -05:00
|
|
|
|
// https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
|
|
|
|
|
|
enum class UnsignedRoundingMode {
|
|
|
|
|
|
HalfEven,
|
|
|
|
|
|
HalfInfinity,
|
|
|
|
|
|
HalfZero,
|
|
|
|
|
|
Infinity,
|
|
|
|
|
|
Zero,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
|
|
|
|
|
|
enum class Sign {
|
|
|
|
|
|
Negative,
|
|
|
|
|
|
Positive,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Auto { };
|
2024-11-18 11:58:51 -05:00
|
|
|
|
struct Unset { };
|
2024-11-18 14:27:54 -05:00
|
|
|
|
using Precision = Variant<Auto, u8>;
|
2024-11-18 11:58:51 -05:00
|
|
|
|
using RoundingIncrement = Variant<Unset, u64>;
|
2024-11-18 14:27:54 -05:00
|
|
|
|
using UnitDefault = Variant<Required, Unset, Auto, Unit>;
|
|
|
|
|
|
using UnitValue = Variant<Unset, Auto, Unit>;
|
|
|
|
|
|
|
|
|
|
|
|
struct SecondsStringPrecision {
|
|
|
|
|
|
struct Minute { };
|
2024-11-20 12:59:15 -05:00
|
|
|
|
using Precision = Variant<Minute, Auto, u8>;
|
2024-11-18 14:27:54 -05:00
|
|
|
|
|
2024-11-20 12:59:15 -05:00
|
|
|
|
Precision precision;
|
2024-11-18 14:27:54 -05:00
|
|
|
|
Unit unit;
|
|
|
|
|
|
u8 increment { 0 };
|
|
|
|
|
|
};
|
2024-11-18 11:58:51 -05:00
|
|
|
|
|
|
|
|
|
|
struct RelativeTo {
|
2024-11-25 08:40:25 -05:00
|
|
|
|
GC::Ptr<PlainDate> plain_relative_to; // [[PlainRelativeTo]]
|
|
|
|
|
|
GC::Ptr<ZonedDateTime> zoned_relative_to; // [[ZonedRelativeTo]]
|
2024-11-18 11:58:51 -05:00
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-21 13:21:29 -05:00
|
|
|
|
struct DifferenceSettings {
|
|
|
|
|
|
Unit smallest_unit;
|
|
|
|
|
|
Unit largest_unit;
|
|
|
|
|
|
RoundingMode rounding_mode;
|
|
|
|
|
|
u64 rounding_increment { 0 };
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-06-28 21:39:13 -07:00
|
|
|
|
JS_API double iso_date_to_epoch_days(double year, double month, double date);
|
|
|
|
|
|
JS_API double epoch_days_to_epoch_ms(double day, double time);
|
|
|
|
|
|
JS_API ThrowCompletionOr<void> check_iso_days_range(VM&, ISODate);
|
|
|
|
|
|
JS_API ThrowCompletionOr<Overflow> get_temporal_overflow_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API ThrowCompletionOr<Disambiguation> get_temporal_disambiguation_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API RoundingMode negate_rounding_mode(RoundingMode);
|
|
|
|
|
|
JS_API ThrowCompletionOr<OffsetOption> get_temporal_offset_option(VM&, Object const& options, OffsetOption fallback);
|
|
|
|
|
|
JS_API ThrowCompletionOr<ShowTimeZoneName> get_temporal_show_time_zone_name_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API ThrowCompletionOr<ShowOffset> get_temporal_show_offset_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API ThrowCompletionOr<ShowCalendar> get_temporal_show_calendar_name_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API ThrowCompletionOr<Direction> get_direction_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API ThrowCompletionOr<void> validate_temporal_rounding_increment(VM&, u64 increment, u64 dividend, bool inclusive);
|
|
|
|
|
|
JS_API ThrowCompletionOr<Precision> get_temporal_fractional_second_digits_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API SecondsStringPrecision to_seconds_string_precision_record(UnitValue, Precision);
|
|
|
|
|
|
JS_API ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM&, Object const& options, PropertyKey const&, UnitGroup, UnitDefault const&, ReadonlySpan<UnitValue> extra_values = {});
|
|
|
|
|
|
JS_API ThrowCompletionOr<RelativeTo> get_temporal_relative_to_option(VM&, Object const& options);
|
|
|
|
|
|
JS_API Unit larger_of_two_temporal_units(Unit, Unit);
|
|
|
|
|
|
JS_API bool is_calendar_unit(Unit);
|
|
|
|
|
|
JS_API UnitCategory temporal_unit_category(Unit);
|
|
|
|
|
|
JS_API RoundingIncrement maximum_temporal_duration_rounding_increment(Unit);
|
|
|
|
|
|
JS_API Crypto::UnsignedBigInteger const& temporal_unit_length_in_nanoseconds(Unit);
|
|
|
|
|
|
JS_API ThrowCompletionOr<bool> is_partial_temporal_object(VM&, Value);
|
|
|
|
|
|
JS_API String format_fractional_seconds(u64, Precision);
|
|
|
|
|
|
JS_API String format_time_string(u8 hour, u8 minute, u8 second, u64 sub_second_nanoseconds, SecondsStringPrecision::Precision, Optional<TimeStyle> = {});
|
|
|
|
|
|
JS_API UnsignedRoundingMode get_unsigned_rounding_mode(RoundingMode, Sign);
|
|
|
|
|
|
JS_API double apply_unsigned_rounding_mode(double, double r1, double r2, UnsignedRoundingMode);
|
|
|
|
|
|
JS_API Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResult const&, Crypto::SignedBigInteger r1, Crypto::SignedBigInteger r2, UnsignedRoundingMode, Crypto::UnsignedBigInteger const& increment);
|
|
|
|
|
|
JS_API double round_number_to_increment(double, u64 increment, RoundingMode);
|
|
|
|
|
|
JS_API Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
|
|
|
|
|
|
JS_API Crypto::SignedBigInteger round_number_to_increment_as_if_positive(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
|
|
|
|
|
|
JS_API ThrowCompletionOr<ParsedISODateTime> parse_iso_date_time(VM&, StringView iso_string, ReadonlySpan<Production> allowed_formats);
|
|
|
|
|
|
JS_API ThrowCompletionOr<String> parse_temporal_calendar_string(VM&, String const&);
|
|
|
|
|
|
JS_API ThrowCompletionOr<GC::Ref<Duration>> parse_temporal_duration_string(VM&, StringView iso_string);
|
|
|
|
|
|
JS_API ThrowCompletionOr<TimeZone> parse_temporal_time_zone_string(VM&, StringView time_zone_string);
|
|
|
|
|
|
JS_API ThrowCompletionOr<String> to_month_code(VM&, Value argument);
|
|
|
|
|
|
JS_API ThrowCompletionOr<String> to_offset_string(VM&, Value argument);
|
|
|
|
|
|
JS_API CalendarFields iso_date_to_fields(StringView calendar, ISODate, DateType);
|
|
|
|
|
|
JS_API ThrowCompletionOr<DifferenceSettings> get_difference_settings(VM&, DurationOperation, Object const& options, UnitGroup, ReadonlySpan<Unit> disallowed_units, Unit fallback_smallest_unit, Unit smallest_largest_default_unit);
|
2024-11-18 11:58:51 -05:00
|
|
|
|
|
|
|
|
|
|
// 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
|
|
|
|
|
|
template<typename... Args>
|
|
|
|
|
|
ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. Let number be ? ToNumber(argument).
|
|
|
|
|
|
auto number = TRY(argument.to_number(vm));
|
|
|
|
|
|
|
|
|
|
|
|
// 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
|
|
|
|
|
|
if (number.is_nan() || number.is_infinity())
|
|
|
|
|
|
return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. Return truncate(ℝ(number)).
|
|
|
|
|
|
return trunc(number.as_double());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
|
|
|
|
|
|
// AD-HOC: We often need to use this AO when we have a parsed StringView. This overload allows callers to avoid creating
|
|
|
|
|
|
// a PrimitiveString for the primary definition.
|
|
|
|
|
|
template<typename... Args>
|
|
|
|
|
|
ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, StringView argument, ErrorType error_type, Args&&... args)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. Let number be ? ToNumber(argument).
|
|
|
|
|
|
auto number = string_to_number(argument);
|
|
|
|
|
|
|
|
|
|
|
|
// 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
|
|
|
|
|
|
if (isnan(number) || isinf(number))
|
|
|
|
|
|
return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. Return truncate(ℝ(number)).
|
|
|
|
|
|
return trunc(number);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-20 12:59:15 -05:00
|
|
|
|
// 13.37 ToPositiveIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-topositiveintegerwithtruncation
|
|
|
|
|
|
template<typename... Args>
|
|
|
|
|
|
ThrowCompletionOr<double> to_positive_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. Let integer be ? ToIntegerWithTruncation(argument).
|
|
|
|
|
|
auto integer = TRY(to_integer_with_truncation(vm, argument, error_type, args...));
|
|
|
|
|
|
|
|
|
|
|
|
// 2. If integer ≤ 0, throw a RangeError exception.
|
|
|
|
|
|
if (integer <= 0)
|
|
|
|
|
|
return vm.throw_completion<RangeError>(error_type, args...);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. Return integer.
|
|
|
|
|
|
return integer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-11 21:04:11 +03:00
|
|
|
|
}
|