diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.cpp index 1e8aa8942b7953..c2f6a196b48522 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace JS::Temporal { @@ -41,6 +42,7 @@ void DurationPrototype::initialize(GlobalObject& global_object) u8 attr = Attribute::Writable | Attribute::Configurable; define_native_function(vm.names.with, with, 1, attr); define_native_function(vm.names.negated, negated, 0, attr); + define_native_function(vm.names.abs, abs, 0, attr); define_native_function(vm.names.valueOf, value_of, 0, attr); } @@ -311,6 +313,19 @@ JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::negated) return create_temporal_duration(global_object, -duration->years(), -duration->months(), -duration->weeks(), -duration->days(), -duration->hours(), -duration->minutes(), -duration->seconds(), -duration->milliseconds(), -duration->microseconds(), -duration->nanoseconds()); } +// 7.3.17 Temporal.Duration.prototype.abs ( ), https://tc39.es/proposal-temporal/#sec-temporal.duration.prototype.abs +JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::abs) +{ + // 1. Let duration be the this value. + // 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). + auto* duration = typed_this(global_object); + if (vm.exception()) + return {}; + + // 3. Return ? CreateTemporalDuration(abs(duration.[[Years]]), abs(duration.[[Months]]), abs(duration.[[Weeks]]), abs(duration.[[Days]]), abs(duration.[[Hours]]), abs(duration.[[Minutes]]), abs(duration.[[Seconds]]), abs(duration.[[Milliseconds]]), abs(duration.[[Microseconds]]), abs(duration.[[Nanoseconds]])). + return create_temporal_duration(global_object, fabs(duration->years()), fabs(duration->months()), fabs(duration->weeks()), fabs(duration->days()), fabs(duration->hours()), fabs(duration->minutes()), fabs(duration->seconds()), fabs(duration->milliseconds()), fabs(duration->microseconds()), fabs(duration->nanoseconds())); +} + // 7.3.25 Temporal.Duration.prototype.valueOf ( ), https://tc39.es/proposal-temporal/#sec-temporal.duration.prototype.valueof JS_DEFINE_NATIVE_FUNCTION(DurationPrototype::value_of) { diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.h b/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.h index 7d57107905b226..5d06103a5e1d7d 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/DurationPrototype.h @@ -33,6 +33,7 @@ class DurationPrototype final : public Object { JS_DECLARE_NATIVE_FUNCTION(blank_getter); JS_DECLARE_NATIVE_FUNCTION(with); JS_DECLARE_NATIVE_FUNCTION(negated); + JS_DECLARE_NATIVE_FUNCTION(abs); JS_DECLARE_NATIVE_FUNCTION(value_of); }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Duration/Duration.prototype.abs.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Duration/Duration.prototype.abs.js new file mode 100644 index 00000000000000..d5e6b6b840f91c --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Duration/Duration.prototype.abs.js @@ -0,0 +1,53 @@ +const DURATION_PROPERTIES = [ + "years", + "months", + "weeks", + "days", + "hours", + "minutes", + "seconds", + "milliseconds", + "microseconds", + "nanoseconds", +]; + +describe("correct behavior", () => { + test("length is 0", () => { + expect(Temporal.Duration.prototype.abs).toHaveLength(0); + }); + + test("basic functionality", () => { + let absoluteDuration; + + absoluteDuration = new Temporal.Duration(123).abs(); + expect(absoluteDuration.years).toBe(123); + + absoluteDuration = new Temporal.Duration(-123).abs(); + expect(absoluteDuration.years).toBe(123); + }); + + test("each property is made absolute", () => { + let values; + let duration; + + values = Array(DURATION_PROPERTIES.length).fill(-1); + duration = new Temporal.Duration(...values).abs(); + for (const property of DURATION_PROPERTIES) { + expect(duration[property]).toBe(1); + } + + values = Array(DURATION_PROPERTIES.length).fill(1); + duration = new Temporal.Duration(...values).abs(); + for (const property of DURATION_PROPERTIES) { + expect(duration[property]).toBe(1); + } + }); +}); + +test("errors", () => { + test("this value must be a Temporal.Duration object", () => { + expect(() => { + Temporal.Duration.prototype.abs.call("foo"); + }).toThrowWithMessage(TypeError, "Not a Temporal.Duration"); + }); +});