Skip to content

Commit

Permalink
Normative: tighten language in mergeFields()
Browse files Browse the repository at this point in the history
This pulls as much logic as possible out of the calendar-dependent
operation into algorithm steps that are common to all calendars, in order
to address the implementor questions about the previous definition of the
operation.

Note, there is the potential for a rebase conflict with #2310, which
removes one use of DefaultCalendarMergeFields and renames it to
ISOCalendarMergeFields.
  • Loading branch information
ptomato committed Jan 20, 2023
1 parent dcdc47f commit 49f510e
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 19 deletions.
15 changes: 9 additions & 6 deletions spec/calendar.html
Original file line number Diff line number Diff line change
Expand Up @@ -800,15 +800,18 @@ <h1>
<dd>It implements the default logic for the `Temporal.Calendar.prototype.mergeFields` method, which is used for the ISO 8601 calendar and as a fallback if the method is not present on a calendar.</dd>
</dl>
<emu-alg>
1. Let _merged_ be OrdinaryObjectCreate(%Object.prototype%).
1. Perform ? CopyDataProperties(_merged_, _fields_, « », « *undefined* »).
1. Let _additionalFieldsCopy_ be OrdinaryObjectCreate(*null*).
1. Perform ? CopyDataProperties(_additionalFieldsCopy_, _additionalFields_, « », « *undefined* »).
1. NOTE: Every property of _additionalFieldsCopy_ is a data property with non-*undefined* value, but some property keys may be Symbols.
1. If ! _additionalFieldsCopy_.[[OwnPropertyKeys]]() contains *"month"* or *"monthCode"*, then
1. Perform ! DeletePropertyOrThrow(_merged_, *"month"*).
1. Perform ! DeletePropertyOrThrow(_merged_, *"monthCode"*).
1. Perform ? CopyDataProperties(_merged_, _additionalFieldsCopy_, « »).
1. Let _excludedKeys_ be « ».
1. Let _additionalKeys_ be ! _additionalFieldsCopy_.[[OwnPropertyKeys]]().
1. For each element _key_ of _additionalKeys_, do
1. Append _key_ to _excludedKeys_.
1. If _key_ is *"month"*, append *"monthCode"* to _excludedKeys_.
1. Else if _key_ is *"monthCode"*, append *"month"* to _excludedKeys_.
1. Let _merged_ be OrdinaryObjectCreate(%Object.prototype%).
1. Perform ? CopyDataProperties(_merged_, _fields_, _excludedKeys_, « *undefined* »).
1. Perform ! CopyDataProperties(_merged_, _additionalFieldsCopy_, « »).
1. Return _merged_.
</emu-alg>
</emu-clause>
Expand Down
78 changes: 65 additions & 13 deletions spec/intl.html
Original file line number Diff line number Diff line change
Expand Up @@ -1676,20 +1676,63 @@ <h1>
</dl>
</emu-clause>

<emu-clause id="sec-temporal-calendardatemergefields" type="abstract operation">
<emu-clause id="sec-temporal-calendarmutuallyexclusivekeys" type="abstract operation">
<h1>
CalendarDateMergeFields (
CalendarMutuallyExclusiveKeys (
_calendar_: a String,
_fields_: an Object,
_additionalFields_: an Object,
): an Object
_key_: a property key,
): a List of property keys
</h1>
<dl class="header">
<dt>description</dt>
<dd>It takes two Objects of calendar-specific fields for the calendar represented by _calendar_ in _fields_ and _additionalFields_ and returns a new Object that includes both sets of fields. The values in _additionalFields_ should supersede the values in _fields_. Also, the returned Object must be free of ambiguity or conflicts. This is relevant for calendars which accept fields other than the standard set of built-in calendar fields.</dd>
<dd>
It performs the calendar-specific operation of determining which fields are mutually exclusive for the field given by _key_.
The returned List may be empty.
</dd>
</dl>
<p>
Mutually exclusive means that the fields are alternate, potentially conflicting, ways of expressing the same data.
This operation is relevant for calendars which accept fields other than the standard set of ISO calendar fields, in order to implement the Temporal objects' `with()` methods, and `Temporal.Calendar.prototype.mergeFields()` in such a way that the result is free of ambiguity or conflicts.
</p>
<p>
For example, given a _calendar_ that uses eras, such as *"gregory"*, a _key_ of *"year"* would mutually exclude *"era"* and *"eraYear"*, and vice versa, because specifying *"era"* and *"eraYear"* is an alternate way of specifying *"year"* and the two could potentially conflict.
In addition to the ISO 8601 mutual exclusion of *"month"* and *"monthCode"*, a possible implementation might produce the following results when _calendar_ is *"gregory"*:
</p>
<emu-table id="table-calendarmutuallyexclusivekeys-example">
<emu-caption>Example results of CalendarMutuallyExclusiveKeys</emu-caption>
<table>
<thead>
<tr>
<th>_key_</th>
<th>Returned List</th>
</tr>
</thead>
<tbody>
<tr>
<td>*"era"*</td>
<td*"year*" »</td>
</tr>
<tr>
<td>*"eraYear"*</td>
<td*"year"* »</td>
</tr>
<tr>
<td>*"year"*</td>
<td*"era"*, *"eraYear"* »</td>
</tr>
<tr>
<td>*"month"*</td>
<td*"monthCode*" »</td>
</tr>
<tr>
<td>*"monthCode"*</td>
<td*"month"* »</td>
</tr>
</tbody>
</table>
</emu-table>
<emu-note>
For example, if _fields_ contains *"year"* but _additionalFields_ contains *"era"* and *"eraYear"*, then the returned list must not include *"year"* in order to avoid ambiguity or conflict between different ways of specifying the year.
In calendars where eras do not start and end at year and month boundaries, note that the returned List should contain *"era"* and *"eraYear"* if _key_ is *"day"*, *"month"*, or *"monthCode"*, in addition to *"year"*, because it's possible for changing the day or month to cause a conflict with the era.
</emu-note>
</emu-clause>
</emu-clause>
Expand Down Expand Up @@ -2139,13 +2182,22 @@ <h1>Temporal.Calendar.prototype.mergeFields ( _fields_, _additionalFields_ )</h1
1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]).
1. Set _fields_ to ? ToObject(_fields_).
1. Set _additionalFields_ to ? ToObject(_additionalFields_).
1. If _calendar_.[[Identifier]] is *"iso8601"*, then
1. Return ? DefaultMergeCalendarFields(_fields_, _additionalFields_).
1. Let _fieldsCopy_ be OrdinaryObjectCreate(%Object.prototype%).
1. Perform ? CopyDataProperties(_fieldsCopy_, _fields_, « », « *undefined* »).
1. Let _additionalFieldsCopy_ be OrdinaryObjectCreate(%Object.prototype%).
1. Let _additionalFieldsCopy_ be OrdinaryObjectCreate(*null*).
1. Perform ? CopyDataProperties(_additionalFieldsCopy_, _additionalFields_, « », « *undefined* »).
1. Return CalendarDateMergeFields(_calendar_.[[Identifier]], _fieldsCopy_, _additionalFieldsCopy_).
1. NOTE: Every property of _additionalFieldsCopy_ is a data property with non-*undefined* value, but some property keys may be Symbols.
1. Let _excludedKeys_ be « ».
1. Let _additionalKeys_ be ! _additionalFieldsCopy_.[[OwnPropertyKeys]]().
1. For each element _key_ of _additionalKeys_, do
1. Append _key_ to _excludedKeys_.
1. If _calendar_.[[Identifier]] is *"iso8601"*, then
1. If _key_ is *"month"*, append *"monthCode"* to _excludedKeys_.
1. Else if _key_ is *"monthCode"*, append *"month"* to _excludedKeys_.
1. Else,
1. Set _excludedKeys_ to the list-concatenation of _excludedKeys_ and CalendarMutuallyExclusiveKeys(_calendar_, _key_).
1. Let _merged_ be OrdinaryObjectCreate(%Object.prototype%).
1. Perform ? CopyDataProperties(_merged_, _fields_, _excludedKeys_, « *undefined* »).
1. Perform ! CopyDataProperties(_merged_, _additionalFieldsCopy_, « »).
1. Return _merged_.
</emu-alg>
</emu-clause>
</emu-clause>
Expand Down

0 comments on commit 49f510e

Please sign in to comment.