Temporal: Limit allowed values for Calendar.fields to date units

This commit is contained in:
Philip Chimento 2023-03-02 12:55:38 -08:00 committed by Philip Chimento
parent c372de0bbe
commit 4b4de778d4
25 changed files with 29 additions and 146 deletions

View File

@ -14,7 +14,7 @@ features: [Temporal]
const calendar = new Temporal.Calendar("iso8601");
assert.throws(RangeError, () => calendar.fields(["day", "month", "day"]));
assert.throws(RangeError, () => calendar.fields(["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "year"]));
assert.throws(RangeError, () => calendar.fields(["year", "month", "monthCode", "day", "year"]));
const manyFields = {
count: 0

View File

@ -3,7 +3,9 @@
/*---
esid: sec-temporal.calendar.prototype.fields
description: Calendar.prototype.fields rejects input field names that are not singular names of temporal units
description: >
Calendar.prototype.fields rejects input field names that are not singular
names of Temporal date units
info: |
sec-temporal.calendar.prototype.fields step 7.b.ii:
7. Repeat, while next is not false,
@ -14,7 +16,7 @@ info: |
1. Let completion be ThrowCompletion(a newly created TypeError object).
2. Return ? IteratorClose(iteratorRecord, completion).
sec-temporal.calendar.prototype.fields step 7.b.iv:
iv. If _nextValue_ is not one of *"year"*, *"month"*, *"monthCode"*, *"day"*, *"hour"*, *"minute"*, *"second"*, *"millisecond"*, *"microsecond"*, *"nanosecond"*, then
iv. If _nextValue_ is not one of *"year"*, *"month"*, *"monthCode"*, or *"day"*, then
1. Let _completion_ be ThrowCompletion(a newly created *RangeError* object).
2. Return ? IteratorClose(_iteratorRecord_, _completion_).
@ -30,6 +32,12 @@ assert.throws(TypeError, () => calendar.fields([null]));
assert.throws(TypeError, () => calendar.fields([{}]));
assert.throws(TypeError, () => calendar.fields([undefined]));
assert.throws(TypeError, () => calendar.fields(["day", 1]));
assert.throws(RangeError, () => calendar.fields(["hour"]));
assert.throws(RangeError, () => calendar.fields(["minute"]));
assert.throws(RangeError, () => calendar.fields(["second"]));
assert.throws(RangeError, () => calendar.fields(["millisecond"]));
assert.throws(RangeError, () => calendar.fields(["microsecond"]));
assert.throws(RangeError, () => calendar.fields(["nanosecond"]));
assert.throws(RangeError, () => calendar.fields(["month", "days"]));
assert.throws(RangeError, () => calendar.fields(["days"]));
assert.throws(RangeError, () => calendar.fields(["people"]));

View File

@ -17,7 +17,7 @@ info: |
a. Set next to ? IteratorStep(iteratorRecord).
b. If next is not false, then
i. Let nextValue be ? IteratorValue(next).
iv. If nextValue is not one of "year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", then
iv. If nextValue is not one of "year", "month", "monthCode", or "day", then
1. Let completion be ThrowCompletion(a newly created RangeError object).
2. Return ? IteratorClose(iteratorRecord, completion).
features: [Symbol, Symbol.iterator, Temporal, computed-property-names, generators]
@ -38,7 +38,7 @@ const fields = {
// The following three lines should not be reached if the implemention
// correctly check the previous line.
i++;
yield "hour";
yield "day";
i++;
}
}

View File

@ -4,7 +4,7 @@
/*---
esid: sec-temporal.calendar.prototype.fields
description: >
Temporal.Calendar.prototype.fields will throw if its input iterable yields
Temporal.Calendar.prototype.fields will throw if its input iterable yields
the same value twice.
info: |
## 12.4.21 Temporal.Calendar.prototype.fields ( fields )
@ -38,9 +38,8 @@ assert.throws(
RangeError, () => cal.fields(fields), "repeated valid value should throw");
assert.sameValue(i, 2, "Should stop at 2");
// Test all valid value will throw while repeate
[ "nanosecond", "microsecond", "millisecond", "second",
"minute", "hour", "day", "monthCode", "month", "year" ].forEach((f) => {
// Test all valid values will throw when repeated
[ "day", "monthCode", "month", "year" ].forEach((f) => {
i = 0;
const fields2 = {
*[Symbol.iterator]() {

View File

@ -17,7 +17,7 @@ info: |
a. Set next to ? IteratorStep(iteratorRecord).
b. If next is not false, then
i. Let nextValue be ? IteratorValue(next).
iv. If nextValue is not one of "year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", then
iv. If nextValue is not one of "year", "month", "monthCode", or "day", then
1. Let completion be ThrowCompletion(a newly created RangeError object).
2. Return ? IteratorClose(iteratorRecord, completion).
features: [Symbol, Symbol.iterator, Temporal, computed-property-names, generators]
@ -26,12 +26,6 @@ includes: [compareArray.js]
let cal = new Temporal.Calendar("iso8601")
const fields = {
*[Symbol.iterator]() {
yield "nanosecond";
yield "microsecond";
yield "millisecond";
yield "second";
yield "minute";
yield "hour";
yield "day";
yield "monthCode";
yield "month";

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -18,14 +18,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -6,7 +6,7 @@ esid: sec-temporal.plaindatetime.prototype.with
description: Verify the result of calendar.fields() is treated correctly.
info: |
sec-temporal.plaindatetime.prototype.with step 9:
9. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"year"* »).
9. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
sec-temporal-calendarfields step 4:
4. Let _result_ be ? IterableToList(_fieldsArray_).
includes: [compareArray.js, temporalHelpers.js]
@ -15,14 +15,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -18,14 +18,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -17,14 +17,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -6,7 +6,7 @@ esid: sec-temporal.zoneddatetime.prototype.with
description: Verify the result of calendar.fields() is treated correctly.
info: |
sec-temporal.zoneddatetime.prototype.with step 9:
9. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"year"* »).
9. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
sec-temporal-calendarfields step 4:
4. Let _result_ be ? IterableToList(_fieldsArray_).
includes: [compareArray.js, temporalHelpers.js]
@ -15,14 +15,8 @@ features: [Temporal]
const expected = [
"day",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
"monthCode",
"nanosecond",
"second",
"year",
];

View File

@ -5,16 +5,12 @@
esid: sec-temporal.zoneddatetime.protoype.with
description: TypeError thrown when the offset field of the receiver is broken
info: |
10. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"year"* »).
11. Append *"offset"* to _fieldNames_.
12. Let _partialZonedDateTime_ be ? PreparePartialTemporalFields(_temporalZonedDateTimeLike_, _fieldNames_).
...
17. Append *"timeZone"* to _fieldNames_.
18. Let _fields_ be ? PrepareTemporalFields(_zonedDateTime_, _fieldNames_, « *"timeZone"*, *"offset"* »).
19. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialZonedDateTime_).
20. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, « *"timeZone"*, *"offset"* »).
21. Let _offsetString_ be ! Get(_fields_, *"offset"*).
22. Assert: Type(_offsetString_) is String.
7. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
8. Append *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"nanosecond"*, *"offset"*, and *"second"* to _fieldNames_.
9. Let _fields_ be ? PrepareTemporalFields(_zonedDateTime_, _fieldNames_, « *"offset"* »).
10. Let _partialZonedDateTime_ be ? PrepareTemporalFields(_temporalZonedDateTimeLike_, _fieldNames_, ~partial~).
11. Set _fields_ to ? CalendarMergeFields(_calendar_, _fields_, _partialZonedDateTime_).
12. Set _fields_ to ? PrepareTemporalFields(_fields_, _fieldNames_, « *"offset"* »).
features: [Temporal]
---*/
@ -43,21 +39,21 @@ class ObservedCalendar extends Temporal.Calendar {
const calendar = new ObservedCalendar();
const dateTime = new Temporal.ZonedDateTime(1_000_000_000_000_000_000n, "UTC", calendar);
// Test throw in step 12
// Test throw in step 10
assert.throws(TypeError, () => dateTime.with({ offset: Symbol("can't convert to string") }), "conversion failure on ZonedDateTime-like");
assert.sameValue(calendar.mergeFieldsCalled, 0, "calendar.mergeFields should not be called");
calendar.resetCalls();
// Test throw in step 20 (before sabotaging the ZonedDateTime instance)
// Test throw in step 12 (before sabotaging the ZonedDateTime instance)
assert.throws(TypeError, () => dateTime.with({ year: 2002 }), "conversion failure on sabotaged return value from mergeFields");
assert.sameValue(calendar.mergeFieldsCalled, 1, "calendar.mergeFields was called once");
calendar.resetCalls();
// Test throw in step 18
// Test throw in step 9
Object.defineProperty(dateTime, "offset", { value: Symbol("can't convert to string"), configurable: true });
@ -66,7 +62,7 @@ assert.sameValue(calendar.mergeFieldsCalled, 0, "calendar.mergeFields should not
calendar.resetCalls();
// Test offset being required in step 18
// Test offset being required in step 9
Object.defineProperty(dateTime, "offset", { value: undefined });