diff options
author | Luke Wilde <lukew@serenityos.org> | 2022-11-02 19:24:47 +0000 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-11-03 19:15:50 +0000 |
commit | 4a167cfbec0268b1f9f9732d2679460dd5a21d58 (patch) | |
tree | aef87df5bda2b5737a0a2d5e86a8ee08f3eeb3b4 | |
parent | 192aa75279448dec13258d89e3c9827bfa7833f0 (diff) | |
download | serenity-4a167cfbec0268b1f9f9732d2679460dd5a21d58.zip |
LibJS: Add calendarName: "critical" option to toString() methods
This is a normative change in the Temporal spec.
See: https://github.com/tc39/proposal-temporal/commit/e715a50
9 files changed, 73 insertions, 15 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index c7877eb253..f7102fcd63 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -246,8 +246,8 @@ ThrowCompletionOr<String> to_temporal_offset(VM& vm, Object const* options, Stri // 13.9 ToShowCalendarOption ( normalizedOptions ), https://tc39.es/proposal-temporal/#sec-temporal-toshowcalendaroption ThrowCompletionOr<String> to_show_calendar_option(VM& vm, Object const& normalized_options) { - // 1. Return ? GetOption(normalizedOptions, "calendarName", "string", « "auto", "always", "never" », "auto"). - auto option = TRY(get_option(vm, normalized_options, vm.names.calendarName, OptionType::String, { "auto"sv, "always"sv, "never"sv }, "auto"sv)); + // 1. Return ? GetOption(normalizedOptions, "calendarName", "string", « "auto", "always", "never", "critical" », "auto"). + auto option = TRY(get_option(vm, normalized_options, vm.names.calendarName, OptionType::String, { "auto"sv, "always"sv, "never"sv, "critical"sv }, "auto"sv)); VERIFY(option.is_string()); return option.as_string().string(); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index 3ffedb7eb8..4f577770ab 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -579,19 +579,21 @@ ThrowCompletionOr<String> maybe_format_calendar_annotation(VM& vm, Object const* // 12.2.27 FormatCalendarAnnotation ( id, showCalendar ), https://tc39.es/proposal-temporal/#sec-temporal-formatcalendarannotation String format_calendar_annotation(StringView id, StringView show_calendar) { - // 1. Assert: showCalendar is "auto", "always", or "never". - VERIFY(show_calendar == "auto"sv || show_calendar == "always"sv || show_calendar == "never"sv); + VERIFY(show_calendar == "auto"sv || show_calendar == "always"sv || show_calendar == "never"sv || show_calendar == "critical"sv); - // 2. If showCalendar is "never", return the empty String. + // 1. If showCalendar is "never", return the empty String. if (show_calendar == "never"sv) return String::empty(); - // 3. If showCalendar is "auto" and id is "iso8601", return the empty String. + // 2. If showCalendar is "auto" and id is "iso8601", return the empty String. if (show_calendar == "auto"sv && id == "iso8601"sv) return String::empty(); - // 4. Return the string-concatenation of "[u-ca=", id, and "]". - return String::formatted("[u-ca={}]", id); + // 3. If showCalendar is "critical", let flag be "!"; else, let flag be the empty String. + auto flag = show_calendar == "critical"sv ? "!"sv : ""sv; + + // 4. Return the string-concatenation of "[", flag, "u-ca=", id, and "]". + return String::formatted("[{}u-ca={}]", flag, id); } // 12.2.28 CalendarEquals ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal-calendarequals diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp index 16979bc13e..0bd7ad8741 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainMonthDay.cpp @@ -186,8 +186,8 @@ ThrowCompletionOr<String> temporal_month_day_to_string(VM& vm, PlainMonthDay& mo // 6. Let calendarID be ? ToString(monthDay.[[Calendar]]). auto calendar_id = TRY(Value(&month_day.calendar()).to_string(vm)); - // 7. If showCalendar is "always" or if calendarID is not "iso8601", then - if (show_calendar == "always"sv || calendar_id != "iso8601"sv) { + // 7. If showCalendar is one of "always" or "critical", or if calendarID is not "iso8601", then + if (show_calendar.is_one_of("always"sv, "critical"sv) || calendar_id != "iso8601"sv) { // a. Let year be ! PadISOYear(monthDay.[[ISOYear]]). // b. Set result to the string-concatenation of year, the code unit 0x002D (HYPHEN-MINUS), and result. result = String::formatted("{}-{}", pad_iso_year(month_day.iso_year()), result); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp index fd885815cc..b056789fc6 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainYearMonth.cpp @@ -213,8 +213,8 @@ ThrowCompletionOr<String> temporal_year_month_to_string(VM& vm, PlainYearMonth& // 6. Let calendarID be ? ToString(yearMonth.[[Calendar]]). auto calendar_id = TRY(Value(&year_month.calendar()).to_string(vm)); - // 7. If showCalendar is "always" or if calendarID is not "iso8601", then - if (show_calendar == "always"sv || calendar_id != "iso8601") { + // 7. If showCalendar is one of "always" or "critical", or if calendarID is not "iso8601", then + if (show_calendar.is_one_of("always"sv, "critical"sv) || calendar_id != "iso8601") { // a. Let day be ToZeroPaddedDecimalString(yearMonth.[[ISODay]], 2). // b. Set result to the string-concatenation of result, the code unit 0x002D (HYPHEN-MINUS), and day. result = String::formatted("{}-{:02}", result, year_month.iso_day()); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toString.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toString.js index eabe334c48..87b2f1e5fa 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toString.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDate/PlainDate.prototype.toString.js @@ -11,12 +11,14 @@ describe("correct behavior", () => { expect(plainDate.toString({ calendarName: "auto" })).toBe("2021-07-06"); expect(plainDate.toString({ calendarName: "always" })).toBe("2021-07-06[u-ca=iso8601]"); expect(plainDate.toString({ calendarName: "never" })).toBe("2021-07-06"); + expect(plainDate.toString({ calendarName: "critical" })).toBe("2021-07-06[!u-ca=iso8601]"); plainDate = new Temporal.PlainDate(2021, 7, 6, { toString: () => "foo" }); expect(plainDate.toString()).toBe("2021-07-06[u-ca=foo]"); expect(plainDate.toString({ calendarName: "auto" })).toBe("2021-07-06[u-ca=foo]"); expect(plainDate.toString({ calendarName: "always" })).toBe("2021-07-06[u-ca=foo]"); expect(plainDate.toString({ calendarName: "never" })).toBe("2021-07-06"); + expect(plainDate.toString({ calendarName: "critical" })).toBe("2021-07-06[!u-ca=foo]"); plainDate = new Temporal.PlainDate(0, 1, 1); expect(plainDate.toString()).toBe("0000-01-01"); @@ -62,7 +64,7 @@ describe("errors", () => { }).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDate"); }); - test("calendarName option must be one of 'auto', 'always', 'never'", () => { + test("calendarName option must be one of 'auto', 'always', 'never', 'critical'", () => { const plainDate = new Temporal.PlainDate(2021, 7, 6); expect(() => { plainDate.toString({ calendarName: "foo" }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.prototype.toString.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.prototype.toString.js index 2ee72db75b..c26aa854b9 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.prototype.toString.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainDateTime/PlainDateTime.prototype.toString.js @@ -80,6 +80,21 @@ describe("correct behavior", () => { expect(plainDateTime.toString(options)).toBe("2022-08-08T14:38:40.1002003"); expect(calledToString).toBeFalse(); }); + + test("calendarName option", () => { + const plainDateTime = new Temporal.PlainDateTime(2022, 11, 2, 19, 4, 35, 100, 200, 300); + const values = [ + ["auto", "2022-11-02T19:04:35.1002003"], + ["always", "2022-11-02T19:04:35.1002003[u-ca=iso8601]"], + ["never", "2022-11-02T19:04:35.1002003"], + ["critical", "2022-11-02T19:04:35.1002003[!u-ca=iso8601]"], + ]; + + for (const [calendarName, expected] of values) { + const options = { calendarName }; + expect(plainDateTime.toString(options)).toBe(expected); + } + }); }); describe("errors", () => { @@ -88,4 +103,11 @@ describe("errors", () => { Temporal.PlainDateTime.prototype.toString.call("foo"); }).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainDateTime"); }); + + test("calendarName option must be one of 'auto', 'always', 'never', 'critical'", () => { + const plainDateTime = new Temporal.PlainDateTime(2022, 11, 2, 19, 5, 40, 100, 200, 300); + expect(() => { + plainDateTime.toString({ calendarName: "foo" }); + }).toThrowWithMessage(RangeError, "foo is not a valid value for option calendarName"); + }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.prototype.toString.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.prototype.toString.js index fa70d2e4fa..3b7be044cf 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.prototype.toString.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainMonthDay/PlainMonthDay.prototype.toString.js @@ -11,12 +11,16 @@ describe("correct behavior", () => { expect(plainMonthDay.toString({ calendarName: "auto" })).toBe("07-06"); expect(plainMonthDay.toString({ calendarName: "always" })).toBe("1972-07-06[u-ca=iso8601]"); expect(plainMonthDay.toString({ calendarName: "never" })).toBe("07-06"); + expect(plainMonthDay.toString({ calendarName: "critical" })).toBe( + "1972-07-06[!u-ca=iso8601]" + ); plainMonthDay = new Temporal.PlainMonthDay(7, 6, { toString: () => "foo" }, 2021); expect(plainMonthDay.toString()).toBe("2021-07-06[u-ca=foo]"); expect(plainMonthDay.toString({ calendarName: "auto" })).toBe("2021-07-06[u-ca=foo]"); expect(plainMonthDay.toString({ calendarName: "always" })).toBe("2021-07-06[u-ca=foo]"); expect(plainMonthDay.toString({ calendarName: "never" })).toBe("2021-07-06"); + expect(plainMonthDay.toString({ calendarName: "critical" })).toBe("2021-07-06[!u-ca=foo]"); }); }); @@ -27,7 +31,7 @@ describe("errors", () => { }).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainMonthDay"); }); - test("calendarName option must be one of 'auto', 'always', 'never'", () => { + test("calendarName option must be one of 'auto', 'always', 'never', 'critical'", () => { const plainMonthDay = new Temporal.PlainMonthDay(7, 6); expect(() => { plainMonthDay.toString({ calendarName: "foo" }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.prototype.toString.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.prototype.toString.js index 487cedda4d..5ad78a4f80 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.prototype.toString.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainYearMonth/PlainYearMonth.prototype.toString.js @@ -13,12 +13,16 @@ describe("correct behavior", () => { "2021-07-01[u-ca=iso8601]" ); expect(plainYearMonth.toString({ calendarName: "never" })).toBe("2021-07"); + expect(plainYearMonth.toString({ calendarName: "critical" })).toBe( + "2021-07-01[!u-ca=iso8601]" + ); plainYearMonth = new Temporal.PlainYearMonth(2021, 7, { toString: () => "foo" }, 6); expect(plainYearMonth.toString()).toBe("2021-07-06[u-ca=foo]"); expect(plainYearMonth.toString({ calendarName: "auto" })).toBe("2021-07-06[u-ca=foo]"); expect(plainYearMonth.toString({ calendarName: "always" })).toBe("2021-07-06[u-ca=foo]"); expect(plainYearMonth.toString({ calendarName: "never" })).toBe("2021-07-06"); + expect(plainYearMonth.toString({ calendarName: "critical" })).toBe("2021-07-06[!u-ca=foo]"); plainYearMonth = new Temporal.PlainYearMonth(0, 1); expect(plainYearMonth.toString()).toBe("0000-01"); @@ -47,7 +51,7 @@ describe("errors", () => { }).toThrowWithMessage(TypeError, "Not an object of type Temporal.PlainYearMonth"); }); - test("calendarName option must be one of 'auto', 'always', 'never'", () => { + test("calendarName option must be one of 'auto', 'always', 'never', 'critical'", () => { const plainYearMonth = new Temporal.PlainYearMonth(2021, 7); expect(() => { plainYearMonth.toString({ calendarName: "foo" }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.toString.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.toString.js index d16b05defa..39fe61082b 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.toString.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.toString.js @@ -125,6 +125,23 @@ describe("correct behavior", () => { expect(zonedDateTime.toString(options)).toBe("2022-08-08T14:38:40.1002003+00:00[UTC]"); expect(calledToString).toBeFalse(); }); + + test("calendarName option", () => { + const plainDateTime = new Temporal.PlainDateTime(2022, 11, 2, 19, 4, 35, 100, 200, 300); + const timeZone = new Temporal.TimeZone("UTC"); + const zonedDateTime = plainDateTime.toZonedDateTime(timeZone); + const values = [ + ["auto", "2022-11-02T19:04:35.1002003+00:00[UTC]"], + ["always", "2022-11-02T19:04:35.1002003+00:00[UTC][u-ca=iso8601]"], + ["never", "2022-11-02T19:04:35.1002003+00:00[UTC]"], + ["critical", "2022-11-02T19:04:35.1002003+00:00[UTC][!u-ca=iso8601]"], + ]; + + for (const [calendarName, expected] of values) { + const options = { calendarName }; + expect(zonedDateTime.toString(options)).toBe(expected); + } + }); }); describe("errors", () => { @@ -140,4 +157,11 @@ describe("errors", () => { zonedDateTime.toString(); }).toThrowWithMessage(TypeError, "null is not a function"); }); + + test("calendarName option must be one of 'auto', 'always', 'never', 'critical'", () => { + const zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC"); + expect(() => { + zonedDateTime.toString({ calendarName: "foo" }); + }).toThrowWithMessage(RangeError, "foo is not a valid value for option calendarName"); + }); }); |