Skip to content

Commit

Permalink
Fix overflow affecting invalid ISO string
Browse files Browse the repository at this point in the history
It was decided in #260 that overflow: 'constrain' should not affect
invalid values coming from ISO strings, but it seems that it crept back in
during a refactor. Fix this and add a test so that it doesn't regress
again.
  • Loading branch information
ptomato committed Nov 16, 2020
1 parent e09e5ec commit e3e40b6
Show file tree
Hide file tree
Showing 12 changed files with 44 additions and 14 deletions.
28 changes: 15 additions & 13 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ export const ES = ObjectAssign({}, ES2020, {
return ES.DateFromFields(calendar, fields, constructor, overflow);
}
let { year, month, day, calendar } = ES.ParseTemporalDateString(ES.ToString(item));
({ year, month, day } = ES.RegulateDate(year, month, day, overflow));
ES.RejectDate(year, month, day);
if (calendar === undefined) calendar = ES.GetISO8601Calendar();
calendar = ES.ToTemporalCalendar(calendar);
let result = new constructor(year, month, day, calendar);
Expand Down Expand Up @@ -1021,6 +1021,7 @@ export const ES = ObjectAssign({}, ES2020, {
nanosecond,
calendar
} = ES.ParseTemporalDateTimeString(ES.ToString(item)));
ES.RejectDateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond);
if (calendar === undefined) calendar = ES.GetISO8601Calendar();
calendar = ES.ToTemporalCalendar(calendar);
}
Expand Down Expand Up @@ -1102,8 +1103,8 @@ export const ES = ObjectAssign({}, ES2020, {
return ES.MonthDayFromFields(calendar, fields, constructor, overflow);
}

let { month, day, referenceISOYear, calendar } = ES.ParseTemporalMonthDayString(ES.ToString(item));
({ month, day } = ES.RegulateMonthDay(month, day, overflow));
let { month, day, referenceISOYear = 1972, calendar } = ES.ParseTemporalMonthDayString(ES.ToString(item));
ES.RejectDate(referenceISOYear, month, day);
if (calendar === undefined) calendar = ES.GetISO8601Calendar();
calendar = ES.ToTemporalCalendar(calendar);
if (referenceISOYear === undefined) referenceISOYear = 1972;
Expand All @@ -1123,23 +1124,24 @@ export const ES = ObjectAssign({}, ES2020, {
}
}
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.ToTemporalTimeRecord(item));
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime(
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
overflow
));
} else {
({ hour, minute, second, millisecond, microsecond, nanosecond, calendar } = ES.ParseTemporalTimeString(
ES.ToString(item)
));
ES.RejectTime(hour, minute, second, millisecond, microsecond, nanosecond);
if (calendar !== undefined && calendar !== 'iso8601') {
throw new RangeError('PlainTime can only have iso8601 calendar');
}
}
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime(
hour,
minute,
second,
millisecond,
microsecond,
nanosecond,
overflow
));
let result = new constructor(hour, minute, second, millisecond, microsecond, nanosecond);
if (!ES.IsTemporalTime(result)) throw new TypeError('invalid result');
return result;
Expand All @@ -1156,7 +1158,7 @@ export const ES = ObjectAssign({}, ES2020, {
}

let { year, month, referenceISODay = 1, calendar } = ES.ParseTemporalYearMonthString(ES.ToString(item));
({ year, month } = ES.RegulateYearMonth(year, month, overflow));
ES.RejectDate(year, month, referenceISODay);
if (calendar === undefined) calendar = ES.GetISO8601Calendar();
calendar = ES.ToTemporalCalendar(calendar);
let result = new constructor(year, month, calendar, referenceISODay);
Expand Down
3 changes: 3 additions & 0 deletions polyfill/test/plaindate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,9 @@ describe('Date', () => {
);
});
});
it('constrain has no effect on invalid ISO string', () => {
throws(() => PlainDate.from('2020-13-34', { overflow: 'constrain' }), RangeError);
});
});
});
describe('Date.compare works', () => {
Expand Down
3 changes: 3 additions & 0 deletions polyfill/test/plaindatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,9 @@ describe('DateTime', () => {
const leap = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
it('reject leap second', () => throws(() => PlainDateTime.from(leap, { overflow: 'reject' }), RangeError));
it('constrain leap second', () => equal(`${PlainDateTime.from(leap)}`, '2016-12-31T23:59:59'));
it('constrain has no effect on invalid ISO string', () => {
throws(() => PlainDateTime.from('2020-13-34T24:60', { overflow: 'constrain' }), RangeError);
});
});
it('variant time separators', () => {
equal(`${PlainDateTime.from('1976-11-18t15:23Z')}`, '1976-11-18T15:23:00');
Expand Down
3 changes: 3 additions & 0 deletions polyfill/test/plainmonthday.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ describe('MonthDay', () => {
);
});
});
it('constrain has no effect on invalid ISO string', () => {
throws(() => PlainMonthDay.from('13-34', { overflow: 'constrain' }), RangeError);
});
});
describe('Leap day', () => {
['reject', 'constrain'].forEach((overflow) =>
Expand Down
3 changes: 3 additions & 0 deletions polyfill/test/plaintime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,9 @@ describe('Time', () => {
const leap = { hour: 23, minute: 59, second: 60 };
it('reject leap second', () => throws(() => PlainTime.from(leap, { overflow: 'reject' }), RangeError));
it('constrain leap second', () => equal(`${PlainTime.from(leap)}`, '23:59:59'));
it('constrain has no effect on invalid ISO string', () => {
throws(() => PlainTime.from('24:60', { overflow: 'constrain' }), RangeError);
});
});
it('object must contain at least one correctly-spelled property', () => {
throws(() => PlainTime.from({}), TypeError);
Expand Down
3 changes: 3 additions & 0 deletions polyfill/test/plainyearmonth.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ describe('YearMonth', () => {
);
});
});
it('constrain has no effect on invalid ISO string', () => {
throws(() => PlainYearMonth.from('2020-13', { overflow: 'constrain' }), RangeError);
});
});
it('object must contain at least the required correctly-spelled properties', () => {
throws(() => PlainYearMonth.from({}), TypeError);
Expand Down
3 changes: 3 additions & 0 deletions polyfill/test/zoneddatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,9 @@ describe('ZonedDateTime', () => {
});
it('no junk at end of string', () =>
throws(() => ZonedDateTime.from('1976-11-18T15:23:30.123456789-08:00[America/Los_Angeles]junk'), RangeError));
it('constrain has no effect on invalid ISO string', () => {
throws(() => ZonedDateTime.from('2020-13-34T24:60[America/Los_Angeles]', { overflow: 'constrain' }), RangeError);
});
describe('Offset option', () => {
it("{ offset: 'reject' } throws if offset does not match offset time zone", () => {
throws(() => ZonedDateTime.from('2020-03-08T01:00-04:00[-08:00]'), RangeError);
Expand Down
2 changes: 2 additions & 0 deletions spec/plaindate.html
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,8 @@ <h1>ToTemporalDate ( _item_ [ , _constructor_ [ , _overflow_ ] ] )</h1>
1. Return ? DateFromFields(_calendar_, _fields_, _constructor_, _overflow_).
1. Let _string_ be ? ToString(_item_).
1. Let _result_ be ? ParseTemporalDateString(_string_).
1. If ! ValidateDate(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]) is *false*, then
1. Throw a *RangeError* exception.
1. Let _calendar_ be _result_.[[Calendar]].
1. If _calendar_ is *undefined*, set _calendar_ to ? GetISO8601Calendar().
1. Set _calendar_ to ? ToTemporalCalendar(_calendar_).
Expand Down
2 changes: 2 additions & 0 deletions spec/plaindatetime.html
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,8 @@ <h1>ToTemporalDateTime ( _item_ [ , _constructor_ [ , _overflow_ ] ] )</h1>
1. Else,
1. Let _string_ be ? ToString(_item_).
1. Let _result_ be ? ParseTemporalDateTimeString(_string_).
1. If ! ValidateDateTime(__.[[Year]], __.[[Month]], __.[[Day]], __.[[Hour]], __.[[Minute]], __.[[Second]], __.[[Millisecond]], __.[[Microsecond]], __.[[Nanosecond]]) is *false*, then
1. Throw a *RangeError* exception.
1. Let _calendar_ be _result_.[[Calendar]].
1. If _calendar_ is *undefined*, set _calendar_ to ? GetISO8601Calendar().
1. Set _calendar_ to ? ToTemporalCalendar(_calendar_).
Expand Down
2 changes: 2 additions & 0 deletions spec/plainmonthday.html
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,8 @@ <h1>ToTemporalMonthDay ( _item_ [ , _constructor_ [ , _overflow_ ] ] )</h1>
1. Let _result_ be ? ParseTemporalMonthDayString(_string_).
1. Let _referenceISOYear_ be the first leap year after the Unix epoch (1972).
1. <mark>TODO: get referenceISOYear from string</mark>.
1. If ! ValidateDate(_referenceISOYear_, _result_.[[Month]], _result_.[[Day]]) is *false*, then
1. Throw a *RangeError* exception.
1. Let _calendar_ be _result_.[[Calendar]].
1. If _calendar_ is *undefined*, set _calendar_ to ? GetISO8601Calendar().
1. Set _calendar_ to ? ToTemporalCalendar(_calendar_).
Expand Down
4 changes: 3 additions & 1 deletion spec/plaintime.html
Original file line number Diff line number Diff line change
Expand Up @@ -657,12 +657,14 @@ <h1>ToTemporalTime ( _item_ [ , _constructor_ [ , _overflow_ ] ] )</h1>
1. If ? CalendarToString(_calendar_) is not *"iso8601"*, then
1. Throw a *RangeError* exception.
1. Let _result_ be ? ToTemporalTimeRecord(_item_).
1. Set _result_ to ? RegulateTime(_result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _overflow_).
1. Else,
1. Let _string_ be ? ToString(_item_).
1. Let _result_ be ? ParseTemporalTimeString(_string_).
1. If ! ValidateTime(_result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]]) is *false*, then
1. Throw a *RangeError* exception.
1. If _result_.[[Calendar]] is not one of *undefined* or *"iso8601"*, then
1. Throw a *RangeError* exception.
1. Set _result_ to ? RegulateTime(_result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _overflow_).
1. Return ? CreateTemporalTimeFromStatic(_constructor_, _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]]).
</emu-alg>
</emu-clause>
Expand Down
2 changes: 2 additions & 0 deletions spec/plainyearmonth.html
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,8 @@ <h1>ToTemporalYearMonth ( _item_ [ , _constructor_ [ , _overflow_ ] ] )</h1>
1. Let _result_ be ? ParseTemporalYearMonthString(_string_).
1. Let _referenceISODay_ be 1.
1. <mark>TODO: get referenceISODay from string</mark>.
1. If ! ValidateDate(_result_.[[Year]], _result_.[[Month]], _referenceISODay_) is *false*, then
1. Throw a *RangeError* exception.
1. Let _calendar_ be _result_.[[Calendar]].
1. If _calendar_ is *undefined*, set _calendar_ to ? GetISO8601Calendar().
1. Set _calendar_ to ? ToTemporalCalendar(_calendar_).
Expand Down

0 comments on commit e3e40b6

Please sign in to comment.