Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editorial: Fixes for remaining issues from Anba #2995

Merged
merged 6 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
SetPrototypeHas,
StringFromCharCode,
StringPrototypeCharCodeAt,
StringPrototypeIndexOf,
StringPrototypeMatch,
StringPrototypeReplace,
StringPrototypeSlice,
Expand Down Expand Up @@ -234,11 +235,28 @@ export function RequireString(value) {
return value;
}

// This function is an enum in the spec, but it's helpful to make it a
// function in the polyfill.
function ToPrimitiveAndRequireString(value) {
function ToSyntacticallyValidMonthCode(value) {
value = ToPrimitive(value, StringCtor);
return RequireString(value);
RequireString(value);
if (
value.length < 3 ||
value.length > 4 ||
value[0] !== 'M' ||
Call(StringPrototypeIndexOf, '0123456789', [value[1]]) === -1 ||
Call(StringPrototypeIndexOf, '0123456789', [value[2]]) === -1 ||
(value[1] + value[2] === '00' && value[3] !== 'L') ||
(value[3] !== 'L' && value[3] !== undefined)
) {
throw new RangeError(`bad month code ${value}; must match M01-M99 or M00L-M99L`);
}
return value;
}

function ToOffsetString(value) {
value = ToPrimitive(value, StringCtor);
RequireString(value);
ParseDateTimeUTCOffset(value);
return value;
}

const CALENDAR_FIELD_KEYS = [
Expand All @@ -263,15 +281,15 @@ const BUILTIN_CASTS = new MapCtor([
['eraYear', ToIntegerWithTruncation],
['year', ToIntegerWithTruncation],
['month', ToPositiveIntegerWithTruncation],
['monthCode', ToPrimitiveAndRequireString],
['monthCode', ToSyntacticallyValidMonthCode],
['day', ToPositiveIntegerWithTruncation],
['hour', ToIntegerWithTruncation],
['minute', ToIntegerWithTruncation],
['second', ToIntegerWithTruncation],
['millisecond', ToIntegerWithTruncation],
['microsecond', ToIntegerWithTruncation],
['nanosecond', ToIntegerWithTruncation],
['offset', ToPrimitiveAndRequireString],
['offset', ToOffsetString],
['timeZone', ToTemporalTimeZoneIdentifier]
]);

Expand Down Expand Up @@ -2143,13 +2161,13 @@ export function TemporalZonedDateTimeToString(
}

export function IsOffsetTimeZoneIdentifier(string) {
return Call(RegExpPrototypeTest, OFFSET, [string]);
return Call(RegExpPrototypeTest, OFFSET_IDENTIFIER, [string]);
}

export function ParseDateTimeUTCOffset(string) {
const match = Call(RegExpPrototypeExec, OFFSET_WITH_PARTS, [string]);
if (!match) {
throw new RangeErrorCtor(`invalid time zone offset: ${string}`);
throw new RangeErrorCtor(`invalid time zone offset: ${string}; must match ±HH:MM[:SS.SSSSSSSSS]`);
}
const sign = match[1] === '-' ? -1 : +1;
const hours = +match[2];
Expand Down
86 changes: 67 additions & 19 deletions polyfill/lib/intl.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
ObjectAssign,
ObjectCreate,
ObjectDefineProperties,
ObjectDefineProperty
ObjectDefineProperty,
ObjectKeys
} from './primordials.mjs';
import { assert } from './assert.mjs';
import * as ES from './ecmascript.mjs';
Expand Down Expand Up @@ -316,17 +317,25 @@ function amend(options = {}, amended = {}) {
return options;
}

function timeAmend(options) {
options = amend(options, {
function timeAmend(originalOptions) {
const options = amend(originalOptions, {
year: false,
month: false,
day: false,
weekday: false,
timeZoneName: false,
dateStyle: false
});
if (options.timeStyle === 'long' || options.timeStyle === 'full') {
// Try to fake what timeStyle should do if not printing the time zone name
delete options.timeStyle;
ObjectAssign(options, { hour: 'numeric', minute: '2-digit', second: '2-digit' });
}
if (!hasTimeOptions(options)) {
options = ObjectAssign({}, options, {
if (hasAnyDateTimeOptions(originalOptions)) {
throw new TypeError(`cannot format Temporal.PlainTime with options [${ObjectKeys(originalOptions)}]`);
}
ObjectAssign(options, {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
Expand All @@ -335,7 +344,7 @@ function timeAmend(options) {
return options;
}

function yearMonthAmend(options) {
function yearMonthAmend(originalOptions) {
// Try to fake what dateStyle should do for dates without a day. This is not
// accurate for locales that always print the era
const dateStyleHacks = {
Expand All @@ -344,7 +353,7 @@ function yearMonthAmend(options) {
long: { year: 'numeric', month: 'long' },
full: { year: 'numeric', month: 'long' }
};
options = amend(options, {
const options = amend(originalOptions, {
day: false,
hour: false,
minute: false,
Expand All @@ -359,21 +368,24 @@ function yearMonthAmend(options) {
delete options.dateStyle;
ObjectAssign(options, dateStyleHacks[style]);
}
if (!('year' in options || 'month' in options)) {
options = ObjectAssign(options, { year: 'numeric', month: 'numeric' });
if (!('year' in options || 'month' in options || 'era' in options)) {
if (hasAnyDateTimeOptions(originalOptions)) {
throw new TypeError(`cannot format PlainYearMonth with options [${ObjectKeys(originalOptions)}]`);
}
ObjectAssign(options, { year: 'numeric', month: 'numeric' });
}
return options;
}

function monthDayAmend(options) {
function monthDayAmend(originalOptions) {
// Try to fake what dateStyle should do for dates without a day
const dateStyleHacks = {
short: { month: 'numeric', day: 'numeric' },
medium: { month: 'short', day: 'numeric' },
long: { month: 'long', day: 'numeric' },
full: { month: 'long', day: 'numeric' }
};
options = amend(options, {
const options = amend(originalOptions, {
year: false,
hour: false,
minute: false,
Expand All @@ -389,13 +401,16 @@ function monthDayAmend(options) {
ObjectAssign(options, dateStyleHacks[style]);
}
if (!('month' in options || 'day' in options)) {
options = ObjectAssign({}, options, { month: 'numeric', day: 'numeric' });
if (hasAnyDateTimeOptions(originalOptions)) {
throw new TypeError(`cannot format PlainMonthDay with options [${ObjectKeys(originalOptions)}]`);
}
ObjectAssign(options, { month: 'numeric', day: 'numeric' });
}
return options;
}

function dateAmend(options) {
options = amend(options, {
function dateAmend(originalOptions) {
const options = amend(originalOptions, {
hour: false,
minute: false,
second: false,
Expand All @@ -404,7 +419,10 @@ function dateAmend(options) {
timeStyle: false
});
if (!hasDateOptions(options)) {
options = ObjectAssign({}, options, {
if (hasAnyDateTimeOptions(originalOptions)) {
throw new TypeError(`cannot format PlainDate with options [${ObjectKeys(originalOptions)}]`);
}
ObjectAssign(options, {
year: 'numeric',
month: 'numeric',
day: 'numeric'
Expand All @@ -413,10 +431,18 @@ function dateAmend(options) {
return options;
}

function datetimeAmend(options) {
options = amend(options, { timeZoneName: false });
function datetimeAmend(originalOptions) {
const options = amend(originalOptions, { timeZoneName: false });
if (options.timeStyle === 'long' || options.timeStyle === 'full') {
// Try to fake what timeStyle should do if not printing the time zone name
delete options.timeStyle;
ObjectAssign(options, { hour: 'numeric', minute: '2-digit', second: '2-digit' });
}
if (!hasTimeOptions(options) && !hasDateOptions(options)) {
options = ObjectAssign({}, options, {
if (hasAnyDateTimeOptions(originalOptions)) {
throw new TypeError(`cannot format PlainDateTime with options [${ObjectKeys(originalOptions)}]`);
}
ObjectAssign(options, {
year: 'numeric',
month: 'numeric',
day: 'numeric',
Expand All @@ -443,12 +469,34 @@ function instantAmend(options) {
}

function hasDateOptions(options) {
return 'year' in options || 'month' in options || 'day' in options || 'weekday' in options || 'dateStyle' in options;
return (
'year' in options ||
'month' in options ||
'day' in options ||
'weekday' in options ||
'dateStyle' in options ||
'era' in options
);
}

function hasTimeOptions(options) {
return (
'hour' in options || 'minute' in options || 'second' in options || 'timeStyle' in options || 'dayPeriod' in options
'hour' in options ||
'minute' in options ||
'second' in options ||
'timeStyle' in options ||
'dayPeriod' in options ||
'fractionalSecondDigits' in options
);
}

function hasAnyDateTimeOptions(originalOptions) {
return (
hasDateOptions(originalOptions) ||
hasTimeOptions(originalOptions) ||
'dateStyle' in originalOptions ||
'timeStyle' in originalOptions ||
'timeZoneName' in originalOptions
);
}

Expand Down
3 changes: 2 additions & 1 deletion polyfill/lib/primordials.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export const {
getOwnPropertyNames: ObjectGetOwnPropertyNames,
defineProperty: ObjectDefineProperty,
defineProperties: ObjectDefineProperties,
entries: ObjectEntries
entries: ObjectEntries,
keys: ObjectKeys
} = Object;

export const {
Expand Down
2 changes: 2 additions & 0 deletions polyfill/lib/zoneddatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,13 @@ export class ZonedDateTime {
optionsCopy.year === undefined &&
optionsCopy.month === undefined &&
optionsCopy.day === undefined &&
optionsCopy.era === undefined &&
optionsCopy.weekday === undefined &&
optionsCopy.dateStyle === undefined &&
optionsCopy.hour === undefined &&
optionsCopy.minute === undefined &&
optionsCopy.second === undefined &&
optionsCopy.fractionalSecondDigits === undefined &&
optionsCopy.timeStyle === undefined &&
optionsCopy.dayPeriod === undefined &&
optionsCopy.timeZoneName === undefined
Expand Down
2 changes: 1 addition & 1 deletion polyfill/test262
Submodule test262 updated 207 files
60 changes: 55 additions & 5 deletions spec/abstractops.html
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ <h1>
1. Let _plainDate_ be ? CreateTemporalDate(_isoDate_, _calendar_).
1. Return the Record { [[PlainRelativeTo]]: _plainDate_, [[ZonedRelativeTo]]: *undefined* }.
1. If _offsetBehaviour_ is ~option~, then
1. Let _offsetNs_ be ? ParseDateTimeUTCOffset(_offsetString_).
1. Let _offsetNs_ be ! ParseDateTimeUTCOffset(_offsetString_).
1. Else,
1. Let _offsetNs_ be 0.
1. Let _epochNanoseconds_ be ? InterpretISODateTimeOffset(_isoDate_, _time_, _offsetBehaviour_, _offsetNs_, _timeZone_, ~compatible~, ~reject~, _matchBehaviour_).
Expand Down Expand Up @@ -1764,6 +1764,56 @@ <h1>
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal-tomonthcode" type="abstract operation">
<h1>
ToMonthCode (
_argument_: an ECMAScript language value,
): either a normal completion containing a String or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>
It converts _argument_ to a String, or throws a *TypeError* if that is not possible.
It also requires that the String is a syntactically valid month code, or throws a *RangeError* if it is not.
The month code is not guaranteed to be correct in the context of any particular calendar; for example, some calendars do not have leap months.
</dd>
</dl>
<emu-alg>
1. Let _monthCode_ be ? ToPrimitive(_argument_, ~string~).
1. If _monthCode_ is not a String, throw a *TypeError* exception.
1. If the length of _monthCode_ is not 3 or 4, throw a *RangeError* exception.
1. If the first code unit of _monthCode_ is not 0x004D (LATIN CAPITAL LETTER M), throw a *RangeError* exception.
1. If the second code unit of _monthCode_ is not in the inclusive interval from 0x0030 (DIGIT ZERO) to 0x0039 (DIGIT NINE), throw a *RangeError* exception.
1. If the third code unit of _monthCode_ is not in the inclusive interval from 0x0030 (DIGIT ZERO) to 0x0039 (DIGIT NINE), throw a *RangeError* exception.
1. If the length of _monthCode_ is 4 and the fourth code unit of _monthCode_ is not 0x004C (LATIN CAPITAL LETTER L), throw a *RangeError* exception.
1. Let _monthCodeDigits_ be the substring of monthCode from 1 to 3.
1. Let _monthCodeInteger_ be ℝ(StringToNumber(_monthCodeDigits_)).
1. If _monthCodeInteger_ is 0 and the length of _monthCode_ is not 4, throw a *RangeError* exception.
1. Return _monthCode_.
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal-tooffsetstring" type="abstract operation">
<h1>
ToOffsetString (
_argument_: an ECMAScript language value,
): either a normal completion containing a String or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>
It converts _argument_ to a String, or throws a *TypeError* if that is not possible.
It also requires that the String is parseable as a UTC offset string, or throws a *RangeError* if it is not.
</dd>
</dl>
<emu-alg>
1. Let _offset_ be ? ToPrimitive(_argument_, ~string~).
1. If _offset_ is not a String, throw a *TypeError* exception.
1. Perform ? ParseDateTimeUTCOffset(_offset_).
1. Return _offset_.
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal-isodatetofields" type="abstract operation">
<h1>
ISODateToFields (
Expand Down Expand Up @@ -1832,11 +1882,11 @@ <h1>
1. Set _value_ to ? ToString(_value_).
1. Else if _Conversion_ is ~to-temporal-time-zone-identifier~, then
1. Set _value_ to ? ToTemporalTimeZoneIdentifier(_value_).
1. Else if _Conversion_ is ~to-month-code~, then
1. Set _value_ to ? ToMonthCode(_value_).
1. Else,
1. Assert: _Conversion_ is ~to-primitive-and-require-string~.
1. NOTE: Non-primitive values are supported here for consistency with other fields, but such values must coerce to Strings.
1. Set _value_ to ? ToPrimitive(_value_, ~string~).
1. If _value_ is not a String, throw a *TypeError* exception.
1. Assert: _Conversion_ is ~to-offset-string~.
1. Set _value_ to ? ToOffsetString(_value_).
1. Set _result_'s field whose name is given in the Field Name column of the same row to _value_.
1. Else if _requiredFieldNames_ is a List, then
1. If _requiredFieldNames_ contains _key_, then
Expand Down
6 changes: 3 additions & 3 deletions spec/calendar.html
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ <h1>Calendar Fields Records</h1>
<td>~unset~</td>
<td>*"monthCode"*</td>
<td>~month-code~</td>
<td>~to-primitive-and-require-string~</td>
<td>~to-month-code~</td>
<td>
The month code of the month.
</td>
Expand Down Expand Up @@ -346,9 +346,9 @@ <h1>Calendar Fields Records</h1>
<td>~unset~</td>
<td>*"offset"*</td>
<td>~offset~</td>
<td>~to-primitive-and-require-string~</td>
<td>~to-offset-string~</td>
<td>
A string of the form `±HH:MM` that can be parsed by ParseDateTimeUTCOffset.
A string of the form `±HH:MM[:SS.SSSSSSSSS]` that can be parsed by ParseDateTimeUTCOffset.
</td>
</tr>
<tr>
Expand Down
Loading
Loading