From 706ff5ac8385029d870c7465d7aeeae152ad376e Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Thu, 30 Jun 2022 16:43:53 +0300 Subject: [PATCH] LibJS: Implement Intl.DurationFormat.prototype.format --- .../Runtime/Intl/DurationFormatPrototype.cpp | 27 ++++++++ .../Runtime/Intl/DurationFormatPrototype.h | 1 + .../DurationFormat.prototype.format.js | 65 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 Userland/Libraries/LibJS/Tests/builtins/Intl/DurationFormat/DurationFormat.prototype.format.js diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp index b269d68e24..abd2f22540 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp @@ -25,9 +25,36 @@ void DurationFormatPrototype::initialize(GlobalObject& global_object) define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Intl.DurationFormat"), Attribute::Configurable); u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(vm.names.format, format, 1, attr); define_native_function(vm.names.resolvedOptions, resolved_options, 0, attr); } +// 1.4.3 Intl.DurationFormat.prototype.format ( duration ), https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat.prototype.format +JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::format) +{ + // 1. Let df be this value. + // 2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]). + auto* duration_format = TRY(typed_this_object(global_object)); + + // 3. Let record be ? ToDurationRecord(duration). + auto record = TRY(to_duration_record(global_object, vm.argument(0))); + + // 4. Let formatted be ? PartitionDurationFormatPattern(df, record). + auto formatted = TRY(partition_duration_format_pattern(global_object, *duration_format, record)); + + // 5. Let result be a new empty String. + StringBuilder result; + + // 6. For each element part in formatted, in List order, do + for (auto const& part : formatted) { + // a. Set result to the string-concatenation of result and part.[[Value]]. + result.append(part.value); + } + + // 7. Return result. + return js_string(vm, result.build()); +} + // 1.4.5 Intl.DurationFormat.prototype.resolvedOptions ( ), https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat.prototype.resolvedOptions JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::resolved_options) { diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h index de460b4937..4689fcb5aa 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h @@ -20,6 +20,7 @@ public: virtual ~DurationFormatPrototype() override = default; private: + JS_DECLARE_NATIVE_FUNCTION(format); JS_DECLARE_NATIVE_FUNCTION(resolved_options); }; diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/DurationFormat/DurationFormat.prototype.format.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/DurationFormat/DurationFormat.prototype.format.js new file mode 100644 index 0000000000..a9ead8bec3 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/DurationFormat/DurationFormat.prototype.format.js @@ -0,0 +1,65 @@ +describe("correct behavior", () => { + test("length is 1", () => { + expect(Intl.DurationFormat.prototype.format).toHaveLength(1); + }); + + test("formats duration correctly", () => { + const duration = { + years: 1, + months: 2, + weeks: 3, + days: 3, + hours: 4, + minutes: 5, + seconds: 6, + milliseconds: 7, + microseconds: 8, + nanoseconds: 9, + }; + expect(new Intl.DurationFormat().format(duration)).toBe( + "1 year, 2 months, 3 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds, 8 microseconds, and 9 nanoseconds" + ); + expect(new Intl.DurationFormat("en").format(duration)).toBe( + "1 year, 2 months, 3 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds, 8 microseconds, and 9 nanoseconds" + ); + expect(new Intl.DurationFormat("en", { style: "long" }).format(duration)).toBe( + "1 year, 2 months, 3 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds, 8 microseconds, and 9 nanoseconds" + ); + expect(new Intl.DurationFormat("en", { style: "short" }).format(duration)).toBe( + "1 yr, 2 mths, 3 wks, 3 days, 4 hr, 5 min, 6 sec, 7 ms, 8 μs, and 9 ns" + ); + expect(new Intl.DurationFormat("en", { style: "narrow" }).format(duration)).toBe( + "1y, 2m, 3w, 3d, 4h, 5m, 6s, 7ms, 8μs, and 9ns" + ); + expect(new Intl.DurationFormat("en", { style: "digital" }).format(duration)).toBe( + "1y, 2m, 3w, 3d, and 4:05:06.007" + ); + expect( + new Intl.DurationFormat("en", { + style: "narrow", + nanoseconds: "numeric", + fractionalDigits: 7, + }).format(duration) + ).toBe("1y, 2m, 3w, 3d, 4h, 5m, 6s, 7ms, and 8.009μs"); + + expect(new Intl.DurationFormat("de", { style: "long" }).format(duration)).toBe( + "1 Jahr, 2 Monate, 3 Wochen, 3 Tage, 4 Stunden, 5 Minuten, 6 Sekunden, 7 Millisekunden, 8 Mikrosekunden und 9 Nanosekunden" + ); + expect(new Intl.DurationFormat("de", { style: "short" }).format(duration)).toBe( + "1 J, 2 Mon., 3 Wo., 3 Tg., 4 Std., 5 Min., 6 Sek., 7 ms, 8 μs und 9 ns" + ); + expect(new Intl.DurationFormat("de", { style: "narrow" }).format(duration)).toBe( + "1 J, 2 M, 3 W, 3 T, 4 Std., 5 Min., 6 Sek., 7 ms, 8 μs und 9 ns" + ); + expect(new Intl.DurationFormat("de", { style: "digital" }).format(duration)).toBe( + "1 J, 2 M, 3 W, 3 T und 4:05:06,007" + ); + expect( + new Intl.DurationFormat("de", { + style: "narrow", + nanoseconds: "numeric", + fractionalDigits: 7, + }).format(duration) + ).toBe("1 J, 2 M, 3 W, 3 T, 4 Std., 5 Min., 6 Sek., 7 ms und 8,009 μs"); + }); +});