From d5d1146cc31e1a9b7cdf2a10daa63013fa129d05 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Fri, 14 Oct 2022 16:10:04 +0100 Subject: [PATCH] LibJS/Temporal: Fix inconsistency in order of observable operations This is a normative change in the Temporal spec. See: https://github.com/tc39/proposal-temporal/commit/a3a8237 --- .../LibJS/Runtime/Temporal/Calendar.cpp | 24 +++++------ .../Calendar.prototype.dateFromFields.js | 43 +++++++++++++++++++ .../Calendar.prototype.monthDayFromFields.js | 43 +++++++++++++++++++ .../Calendar.prototype.yearMonthFromFields.js | 37 ++++++++++++++++ 4 files changed, 135 insertions(+), 12 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index 3b09e1f1dc..03a22a2e1a 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -758,12 +758,12 @@ ThrowCompletionOr iso_date_from_fields(VM& vm, Object const& fiel { // 1. Assert: Type(fields) is Object. - // 2. Let overflow be ? ToTemporalOverflow(options). - auto overflow = TRY(to_temporal_overflow(vm, &options)); - - // 3. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "year", "day" »). + // 2. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "year", "day" »). auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "day", "month", "monthCode", "year" }, Vector { "year"sv, "day"sv })); + // 3. Let overflow be ? ToTemporalOverflow(options). + auto overflow = TRY(to_temporal_overflow(vm, &options)); + // 4. Let year be ! Get(fields, "year"). auto year = MUST(prepared_fields->get(vm.names.year)); @@ -788,12 +788,12 @@ ThrowCompletionOr iso_year_month_from_fields(VM& vm, Object const& { // 1. Assert: Type(fields) is Object. - // 2. Let overflow be ? ToTemporalOverflow(options). - auto overflow = TRY(to_temporal_overflow(vm, &options)); - - // 3. Set fields to ? PrepareTemporalFields(fields, « "month", "monthCode", "year" », « "year" »). + // 2. Set fields to ? PrepareTemporalFields(fields, « "month", "monthCode", "year" », « "year" »). auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "month"sv, "monthCode"sv, "year"sv }, Vector { "year"sv })); + // 3. Let overflow be ? ToTemporalOverflow(options). + auto overflow = TRY(to_temporal_overflow(vm, &options)); + // 4. Let year be ! Get(fields, "year"). auto year = MUST(prepared_fields->get(vm.names.year)); @@ -815,12 +815,12 @@ ThrowCompletionOr iso_month_day_from_fields(VM& vm, Object const& f { // 1. Assert: Type(fields) is Object. - // 2. Let overflow be ? ToTemporalOverflow(options). - auto overflow = TRY(to_temporal_overflow(vm, &options)); - - // 3. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "day" »). + // 2. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "day" »). auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "day"sv, "month"sv, "monthCode"sv, "year"sv }, Vector { "day"sv })); + // 3. Let overflow be ? ToTemporalOverflow(options). + auto overflow = TRY(to_temporal_overflow(vm, &options)); + // 4. Let month be ! Get(fields, "month"). auto month_value = MUST(prepared_fields->get(vm.names.month)); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.dateFromFields.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.dateFromFields.js index 5485af1c74..ad0121fa2a 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.dateFromFields.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.dateFromFields.js @@ -8,4 +8,47 @@ describe("correct behavior", () => { const date = calendar.dateFromFields({ year: 2000, month: 5, day: 2 }); expect(date.calendar).toBe(calendar); }); + + test("gets overflow after temporal fields", () => { + const operations = []; + const calendar = new Temporal.Calendar("iso8601"); + + const fields = { + get day() { + operations.push("get day"); + return 3; + }, + + get month() { + operations.push("get month"); + return 10; + }, + + get monthCode() { + operations.push("get monthCode"); + return "M10"; + }, + + get year() { + operations.push("get year"); + return 2022; + }, + }; + + const options = { + get overflow() { + operations.push("get overflow"); + return "constrain"; + }, + }; + + expect(operations).toHaveLength(0); + calendar.dateFromFields(fields, options); + expect(operations).toHaveLength(5); + expect(operations[0]).toBe("get day"); + expect(operations[1]).toBe("get month"); + expect(operations[2]).toBe("get monthCode"); + expect(operations[3]).toBe("get year"); + expect(operations[4]).toBe("get overflow"); + }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.monthDayFromFields.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.monthDayFromFields.js index 2d80d1b259..ff5e9cccf3 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.monthDayFromFields.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.monthDayFromFields.js @@ -24,6 +24,49 @@ describe("correct behavior", () => { const fields = plainMonthDay.getISOFields(); expect(fields.isoYear).toBe(1972); }); + + test("gets overflow after temporal fields", () => { + const operations = []; + const calendar = new Temporal.Calendar("iso8601"); + + const fields = { + get day() { + operations.push("get day"); + return 3; + }, + + get month() { + operations.push("get month"); + return 10; + }, + + get monthCode() { + operations.push("get monthCode"); + return "M10"; + }, + + get year() { + operations.push("get year"); + return 2022; + }, + }; + + const options = { + get overflow() { + operations.push("get overflow"); + return "constrain"; + }, + }; + + expect(operations).toHaveLength(0); + calendar.monthDayFromFields(fields, options); + expect(operations).toHaveLength(5); + expect(operations[0]).toBe("get day"); + expect(operations[1]).toBe("get month"); + expect(operations[2]).toBe("get monthCode"); + expect(operations[3]).toBe("get year"); + expect(operations[4]).toBe("get overflow"); + }); }); describe("errors", () => { diff --git a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.yearMonthFromFields.js b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.yearMonthFromFields.js index 83630a7bac..1a7c36184e 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.yearMonthFromFields.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.yearMonthFromFields.js @@ -18,6 +18,43 @@ describe("correct behavior", () => { expect(plainYearMonth.year).toBe(2021); expect(plainYearMonth.month).toBe(7); }); + + test("gets overflow after temporal fields", () => { + const operations = []; + const calendar = new Temporal.Calendar("iso8601"); + + const fields = { + get month() { + operations.push("get month"); + return 10; + }, + + get monthCode() { + operations.push("get monthCode"); + return "M10"; + }, + + get year() { + operations.push("get year"); + return 2022; + }, + }; + + const options = { + get overflow() { + operations.push("get overflow"); + return "constrain"; + }, + }; + + expect(operations).toHaveLength(0); + calendar.yearMonthFromFields(fields, options); + expect(operations).toHaveLength(4); + expect(operations[0]).toBe("get month"); + expect(operations[1]).toBe("get monthCode"); + expect(operations[2]).toBe("get year"); + expect(operations[3]).toBe("get overflow"); + }); }); describe("errors", () => {