diff --git a/polyfill/lib/intl.mjs b/polyfill/lib/intl.mjs index 6539f6658..f4760c3d2 100644 --- a/polyfill/lib/intl.mjs +++ b/polyfill/lib/intl.mjs @@ -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'; @@ -316,8 +317,8 @@ 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, @@ -326,7 +327,10 @@ function timeAmend(options) { dateStyle: false }); 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' @@ -335,7 +339,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 = { @@ -344,7 +348,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, @@ -360,12 +364,15 @@ function yearMonthAmend(options) { ObjectAssign(options, dateStyleHacks[style]); } if (!('year' in options || 'month' in options || 'era' in options)) { - options = ObjectAssign(options, { year: 'numeric', month: 'numeric' }); + 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' }, @@ -373,7 +380,7 @@ function monthDayAmend(options) { long: { month: 'long', day: 'numeric' }, full: { month: 'long', day: 'numeric' } }; - options = amend(options, { + const options = amend(originalOptions, { year: false, hour: false, minute: false, @@ -389,13 +396,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, @@ -404,7 +414,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' @@ -413,10 +426,13 @@ function dateAmend(options) { return options; } -function datetimeAmend(options) { - options = amend(options, { timeZoneName: false }); +function datetimeAmend(originalOptions) { + const options = amend(originalOptions, { timeZoneName: false }); 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', @@ -464,6 +480,16 @@ function hasTimeOptions(options) { ); } +function hasAnyDateTimeOptions(originalOptions) { + return ( + hasDateOptions(originalOptions) || + hasTimeOptions(originalOptions) || + 'dateStyle' in originalOptions || + 'timeStyle' in originalOptions || + 'timeZoneName' in originalOptions + ); +} + function isTemporalObject(obj) { return ( ES.IsTemporalDate(obj) || diff --git a/polyfill/lib/primordials.mjs b/polyfill/lib/primordials.mjs index 093072dec..2e89099e5 100644 --- a/polyfill/lib/primordials.mjs +++ b/polyfill/lib/primordials.mjs @@ -34,7 +34,8 @@ export const { getOwnPropertyNames: ObjectGetOwnPropertyNames, defineProperty: ObjectDefineProperty, defineProperties: ObjectDefineProperties, - entries: ObjectEntries + entries: ObjectEntries, + keys: ObjectKeys } = Object; export const { diff --git a/spec/intl.html b/spec/intl.html index b83cf81a6..ef93e2bcc 100644 --- a/spec/intl.html +++ b/spec/intl.html @@ -854,12 +854,16 @@

1. Set _formatOptions_.[[era]] to _options_.[[era]]. 1. If _required_ is ~time~ or ~any~, then 1. Set _formatOptions_.[[hourCycle]] to _options_.[[hourCycle]]. + 1. Let _anyPresent_ be *false*. + 1. For each property name _prop_ of « *"weekday"*, *"year"*, *"month"*, *"day"*, *"era"*, *"dayPeriod"*, *"hour"*, *"minute"*, *"second"*, *"fractionalSecondDigits"* », do + 1. If _options_.[[<_prop_>]] is not *undefined*, set _anyPresent_ to *true*. 1. Let _needDefaults_ be *true*. 1. For each property name _prop_ of _requiredOptions_, do 1. Let _value_ be _options_.[[<_prop_>]]. 1. If _value_ is not *undefined*, then 1. Set _formatOptions_.[[<_prop_>]] to _value_. 1. Set _needDefaults_ to *false*. + 1. If _anyPresent_ is *true* and _needDefaults_ is *true*, return *null*. 1. If _needDefaults_ is *true*, then 1. For each property name _prop_ of _defaultOptions_, do 1. Set _formatOptions_.[[<_prop_>]] to *"numeric"*.