Skip to content

Commit a1fd8ac

Browse files
committed
Polyfill: Implement CanonicalizeEraInCalendar as in spec
This makes the reference implementation slightly more like the spec text, which should help make sure the spec text is correct.
1 parent 97d20d6 commit a1fd8ac

File tree

2 files changed

+81
-41
lines changed

2 files changed

+81
-41
lines changed

polyfill/lib/calendar.mjs

Lines changed: 80 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
MathSign,
3434
ObjectAssign,
3535
ObjectEntries,
36+
ObjectHasOwn,
3637
RegExpPrototypeExec,
3738
SetPrototypeAdd,
3839
SetPrototypeValues,
@@ -334,24 +335,74 @@ function weekNumber(firstDayOfWeek, minimalDaysInFirstWeek, desiredDay, dayOfWee
334335
// about non-ISO calendars. However, non-ISO calendar implementation is subject
335336
// to change because these calendars are implementation-defined.
336337

337-
const eraInfo = [
338-
'buddhist',
339-
'coptic',
340-
'ethioaa',
341-
'ethiopic',
342-
'gregory',
343-
'hebrew',
344-
'indian',
345-
'islamic-civil',
346-
'islamic-tbla',
347-
'islamic-umalqura',
348-
'japanese',
349-
'persian',
350-
'roc'
351-
];
338+
const eraInfo = {
339+
buddhist: {
340+
be: {}
341+
},
342+
coptic: {
343+
am: {}
344+
},
345+
ethioaa: {
346+
aa: { aliases: ['mundi'] }
347+
},
348+
ethiopic: {
349+
am: { aliases: ['incar'] },
350+
aa: { aliases: ['mundi'] }
351+
},
352+
gregory: {
353+
ce: { aliases: ['ad'] },
354+
bce: { aliases: ['bc'] }
355+
},
356+
hebrew: {
357+
am: {}
358+
},
359+
indian: {
360+
shaka: {}
361+
},
362+
'islamic-civil': {
363+
ah: {},
364+
bh: {}
365+
},
366+
'islamic-tbla': {
367+
ah: {},
368+
bh: {}
369+
},
370+
'islamic-umalqura': {
371+
ah: {},
372+
bh: {}
373+
},
374+
japanese: {
375+
reiwa: {},
376+
heisei: {},
377+
showa: {},
378+
taisho: {},
379+
meiji: {},
380+
ce: { aliases: ['ad'] },
381+
bce: { aliases: ['bc'] }
382+
},
383+
persian: {
384+
ap: {}
385+
},
386+
roc: {
387+
roc: { aliases: ['minguo'] },
388+
broc: { aliases: ['before-roc', 'minguo-qian'] }
389+
}
390+
};
352391

353392
function CalendarSupportsEra(calendar) {
354-
return Call(ArrayPrototypeIncludes, eraInfo, [calendar]);
393+
return ObjectHasOwn(eraInfo, calendar);
394+
}
395+
396+
function CanonicalizeEraInCalendar(calendar, era) {
397+
const eras = eraInfo[calendar];
398+
const entries = ObjectEntries(eras);
399+
for (let ix = 0; ix < entries.length; ix++) {
400+
const canonicalName = entries[ix][0];
401+
const info = entries[ix][1];
402+
if (era === canonicalName) return era;
403+
if (info.aliases && Call(ArrayPrototypeIncludes, info.aliases, [era])) return canonicalName;
404+
}
405+
return undefined;
355406
}
356407

357408
/**
@@ -653,27 +704,22 @@ const nonIsoHelperBase = {
653704
if (ix === -1) throw new RangeErrorCtor(`Year ${year} was not matched by any era`);
654705
let matchingEra = this.eras[ix];
655706
if (matchingEra.skip) matchingEra = this.eras[ix - 1];
656-
return { eraYear, era: matchingEra.code, eraNames: matchingEra.names };
707+
return { eraYear, era: matchingEra.code };
657708
};
658709

659710
let { year, eraYear, era } = calendarDate;
660711
if (year !== undefined) {
661712
const matchData = eraFromYear(year);
662713
({ eraYear, era } = matchData);
663-
if (
664-
calendarDate.era !== undefined &&
665-
calendarDate.era !== era &&
666-
!Call(ArrayPrototypeIncludes, matchData?.eraNames ?? [], [calendarDate.era])
667-
) {
714+
if (calendarDate.era !== undefined && CanonicalizeEraInCalendar(this.id, calendarDate.era) !== era) {
668715
throw new RangeErrorCtor(`Input era ${calendarDate.era} doesn't match calculated value ${era}`);
669716
}
670717
if (calendarDate.eraYear !== undefined && calendarDate.eraYear !== eraYear) {
671718
throw new RangeErrorCtor(`Input eraYear ${calendarDate.eraYear} doesn't match calculated value ${eraYear}`);
672719
}
673720
} else if (eraYear !== undefined) {
674-
const matchingEra = Call(ArrayPrototypeFind, this.eras, [
675-
({ code, names = [] }) => code === era || Call(ArrayPrototypeIncludes, names, [era])
676-
]);
721+
const canonicalName = CanonicalizeEraInCalendar(this.id, era);
722+
const matchingEra = Call(ArrayPrototypeFind, this.eras, [({ code }) => code === canonicalName]);
677723
if (!matchingEra) throw new RangeErrorCtor(`Era ${era} (ISO year ${eraYear}) was not matched by any era`);
678724
if (matchingEra.reverseOf) {
679725
year = matchingEra.anchorEpoch.year - eraYear;
@@ -1394,13 +1440,6 @@ const helperIndian = makeNonISOHelper([{ code: 'shaka', isoEpoch: { year: 79, mo
13941440
* // See https://tc39.es/proposal-intl-era-monthcode/#table-eras
13951441
* code: string;
13961442
*
1397-
* // Names are additionally accepted as alternate era codes on input, and the
1398-
* // first name is also output in error messages (and may be the era code if
1399-
* // desired.)
1400-
* // See https://tc39.es/proposal-intl-era-monthcode/#table-eras
1401-
* // If absent, this field defaults to a single element matching the code.
1402-
* names: string[];
1403-
*
14041443
* // alternate name of the era used in old versions of ICU data
14051444
* // format is `era{n}` where n is the zero-based index of the era
14061445
* // with the oldest era being 0.
@@ -1624,7 +1663,7 @@ const makeHelperOrthodox = (id, originalEras) => {
16241663
// - Ethiopic has an additional second era that starts at the same date as the
16251664
// zero era of ethioaa.
16261665
const helperEthioaa = ObjectAssign(
1627-
makeHelperOrthodox('ethioaa', [{ code: 'aa', names: ['mundi'], isoEpoch: { year: -5492, month: 7, day: 17 } }])
1666+
makeHelperOrthodox('ethioaa', [{ code: 'aa', isoEpoch: { year: -5492, month: 7, day: 17 } }])
16281667
);
16291668
const copticLegacyEra0 = Symbol('era0');
16301669
const helperCoptic = ObjectAssign(
@@ -1644,13 +1683,13 @@ const helperCoptic = ObjectAssign(
16441683
// Anchor is currently the older era to match ethioaa, but should it be the newer era?
16451684
// See https://github.com/tc39/ecma402/issues/534 for discussion.
16461685
const helperEthiopic = makeHelperOrthodox('ethiopic', [
1647-
{ code: 'aa', names: ['mundi'], isoEpoch: { year: -5492, month: 7, day: 17 } },
1648-
{ code: 'am', names: ['incar'], isoEpoch: { year: 8, month: 8, day: 27 }, anchorEpoch: { year: 5501 } }
1686+
{ code: 'aa', isoEpoch: { year: -5492, month: 7, day: 17 } },
1687+
{ code: 'am', isoEpoch: { year: 8, month: 8, day: 27 }, anchorEpoch: { year: 5501 } }
16491688
]);
16501689

16511690
const helperRoc = makeHelperSameMonthDayAsGregorian('roc', [
1652-
{ code: 'roc', names: ['minguo'], isoEpoch: { year: 1912, month: 1, day: 1 } },
1653-
{ code: 'broc', names: ['before-roc', 'minguo-qian'], reverseOf: 'roc' }
1691+
{ code: 'roc', isoEpoch: { year: 1912, month: 1, day: 1 } },
1692+
{ code: 'broc', reverseOf: 'roc' }
16541693
]);
16551694

16561695
const helperBuddhist = ObjectAssign(
@@ -1659,8 +1698,8 @@ const helperBuddhist = ObjectAssign(
16591698

16601699
const helperGregory = ObjectAssign(
16611700
makeHelperSameMonthDayAsGregorian('gregory', [
1662-
{ code: 'ce', names: ['ad'], isoEpoch: { year: 1, month: 1, day: 1 } },
1663-
{ code: 'bce', names: ['bc'], reverseOf: 'ce' }
1701+
{ code: 'ce', isoEpoch: { year: 1, month: 1, day: 1 } },
1702+
{ code: 'bce', reverseOf: 'ce' }
16641703
]),
16651704
{
16661705
reviseIntlEra(calendarDate /*, isoDate*/) {
@@ -1714,8 +1753,8 @@ const helperJapanese = ObjectAssign(
17141753
{ code: 'showa', isoEpoch: { year: 1926, month: 12, day: 25 }, anchorEpoch: { year: 1926, month: 12, day: 25 } },
17151754
{ code: 'taisho', isoEpoch: { year: 1912, month: 7, day: 30 }, anchorEpoch: { year: 1912, month: 7, day: 30 } },
17161755
{ code: 'meiji', isoEpoch: { year: 1868, month: 9, day: 8 }, anchorEpoch: { year: 1868, month: 9, day: 8 } },
1717-
{ code: 'ce', names: ['ad'], isoEpoch: { year: 1, month: 1, day: 1 } },
1718-
{ code: 'bce', names: ['bc'], reverseOf: 'ce' }
1756+
{ code: 'ce', isoEpoch: { year: 1, month: 1, day: 1 } },
1757+
{ code: 'bce', reverseOf: 'ce' }
17191758
]),
17201759
{
17211760
erasBeginMidYear: true,

polyfill/lib/primordials.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const {
3535
defineProperty: ObjectDefineProperty,
3636
defineProperties: ObjectDefineProperties,
3737
entries: ObjectEntries,
38+
hasOwn: ObjectHasOwn,
3839
keys: ObjectKeys
3940
} = Object;
4041

0 commit comments

Comments
 (0)