Procházet zdrojové kódy

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
Luke Wilde před 2 roky
rodič
revize
d5d1146cc3

+ 12 - 12
Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp

@@ -758,12 +758,12 @@ ThrowCompletionOr<ISODateRecord> iso_date_from_fields(VM& vm, Object const& fiel
 {
 {
     // 1. Assert: Type(fields) is Object.
     // 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<StringView> { "year"sv, "day"sv }));
     auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "day", "month", "monthCode", "year" }, Vector<StringView> { "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").
     // 4. Let year be ! Get(fields, "year").
     auto year = MUST(prepared_fields->get(vm.names.year));
     auto year = MUST(prepared_fields->get(vm.names.year));
 
 
@@ -788,12 +788,12 @@ ThrowCompletionOr<ISOYearMonth> iso_year_month_from_fields(VM& vm, Object const&
 {
 {
     // 1. Assert: Type(fields) is Object.
     // 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<StringView> { "year"sv }));
     auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "month"sv, "monthCode"sv, "year"sv }, Vector<StringView> { "year"sv }));
 
 
+    // 3. Let overflow be ? ToTemporalOverflow(options).
+    auto overflow = TRY(to_temporal_overflow(vm, &options));
+
     // 4. Let year be ! Get(fields, "year").
     // 4. Let year be ! Get(fields, "year").
     auto year = MUST(prepared_fields->get(vm.names.year));
     auto year = MUST(prepared_fields->get(vm.names.year));
 
 
@@ -815,12 +815,12 @@ ThrowCompletionOr<ISOMonthDay> iso_month_day_from_fields(VM& vm, Object const& f
 {
 {
     // 1. Assert: Type(fields) is Object.
     // 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<StringView> { "day"sv }));
     auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "day"sv, "month"sv, "monthCode"sv, "year"sv }, Vector<StringView> { "day"sv }));
 
 
+    // 3. Let overflow be ? ToTemporalOverflow(options).
+    auto overflow = TRY(to_temporal_overflow(vm, &options));
+
     // 4. Let month be ! Get(fields, "month").
     // 4. Let month be ! Get(fields, "month").
     auto month_value = MUST(prepared_fields->get(vm.names.month));
     auto month_value = MUST(prepared_fields->get(vm.names.month));
 
 

+ 43 - 0
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 });
         const date = calendar.dateFromFields({ year: 2000, month: 5, day: 2 });
         expect(date.calendar).toBe(calendar);
         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");
+    });
 });
 });

+ 43 - 0
Userland/Libraries/LibJS/Tests/builtins/Temporal/Calendar/Calendar.prototype.monthDayFromFields.js

@@ -24,6 +24,49 @@ describe("correct behavior", () => {
         const fields = plainMonthDay.getISOFields();
         const fields = plainMonthDay.getISOFields();
         expect(fields.isoYear).toBe(1972);
         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", () => {
 describe("errors", () => {

+ 37 - 0
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.year).toBe(2021);
         expect(plainYearMonth.month).toBe(7);
         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", () => {
 describe("errors", () => {