UNPKG

@js-temporal/polyfill

Version:

Polyfill for Tc39 Stage 3 proposal Temporal (https://github.com/tc39/proposal-temporal)

292 lines (265 loc) 8.79 kB
import type JSBI from 'jsbi'; import type { Temporal } from '..'; import type { BuiltinCalendarId, AnyTemporalType } from './internaltypes'; // Instant export const EPOCHNANOSECONDS = 'slot-epochNanoSeconds'; // TimeZone export const TIMEZONE_ID = 'slot-timezone-identifier'; // DateTime, Date, Time, YearMonth, MonthDay export const ISO_YEAR = 'slot-year'; export const ISO_MONTH = 'slot-month'; export const ISO_DAY = 'slot-day'; export const ISO_HOUR = 'slot-hour'; export const ISO_MINUTE = 'slot-minute'; export const ISO_SECOND = 'slot-second'; export const ISO_MILLISECOND = 'slot-millisecond'; export const ISO_MICROSECOND = 'slot-microsecond'; export const ISO_NANOSECOND = 'slot-nanosecond'; export const CALENDAR = 'slot-calendar'; // Date, YearMonth, and MonthDay all have the same slots, disambiguation needed: export const DATE_BRAND = 'slot-date-brand'; export const YEAR_MONTH_BRAND = 'slot-year-month-brand'; export const MONTH_DAY_BRAND = 'slot-month-day-brand'; // ZonedDateTime export const INSTANT = 'slot-cached-instant'; export const TIME_ZONE = 'slot-time-zone'; // Duration export const YEARS = 'slot-years'; export const MONTHS = 'slot-months'; export const WEEKS = 'slot-weeks'; export const DAYS = 'slot-days'; export const HOURS = 'slot-hours'; export const MINUTES = 'slot-minutes'; export const SECONDS = 'slot-seconds'; export const MILLISECONDS = 'slot-milliseconds'; export const MICROSECONDS = 'slot-microseconds'; export const NANOSECONDS = 'slot-nanoseconds'; // Calendar export const CALENDAR_ID = 'slot-calendar-identifier'; interface SlotInfo<ValueType, UsedByType extends AnyTemporalType> { value: ValueType; usedBy: UsedByType; } interface SlotInfoRecord { [k: string]: SlotInfo<unknown, AnyTemporalType>; } interface Slots extends SlotInfoRecord { // Instant [EPOCHNANOSECONDS]: SlotInfo<JSBI, Temporal.Instant | Temporal.ZonedDateTime>; // number? JSBI? // TimeZone [TIMEZONE_ID]: SlotInfo<string, Temporal.TimeZone>; // DateTime, Date, Time, YearMonth, MonthDay [ISO_YEAR]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_MONTH]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_DAY]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_HOUR]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_MINUTE]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_SECOND]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_MILLISECOND]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_MICROSECOND]: SlotInfo<number, TypesWithCalendarUnits>; [ISO_NANOSECOND]: SlotInfo<number, TypesWithCalendarUnits>; [CALENDAR]: SlotInfo<Temporal.CalendarProtocol, TypesWithCalendarUnits | Temporal.ZonedDateTime>; // Date, YearMonth, MonthDay common slots [DATE_BRAND]: SlotInfo<true, Temporal.PlainDate>; [YEAR_MONTH_BRAND]: SlotInfo<true, Temporal.PlainYearMonth>; [MONTH_DAY_BRAND]: SlotInfo<true, Temporal.PlainMonthDay>; // ZonedDateTime [INSTANT]: SlotInfo<Temporal.Instant, Temporal.ZonedDateTime>; [TIME_ZONE]: SlotInfo<Temporal.TimeZoneProtocol, Temporal.ZonedDateTime>; // Duration [YEARS]: SlotInfo<number, Temporal.Duration>; [MONTHS]: SlotInfo<number, Temporal.Duration>; [WEEKS]: SlotInfo<number, Temporal.Duration>; [DAYS]: SlotInfo<number, Temporal.Duration>; [HOURS]: SlotInfo<number, Temporal.Duration>; [MINUTES]: SlotInfo<number, Temporal.Duration>; [SECONDS]: SlotInfo<number, Temporal.Duration>; [MILLISECONDS]: SlotInfo<number, Temporal.Duration>; [MICROSECONDS]: SlotInfo<number, Temporal.Duration>; [NANOSECONDS]: SlotInfo<number, Temporal.Duration>; // Calendar [CALENDAR_ID]: SlotInfo<BuiltinCalendarId, Temporal.Calendar>; } type TypesWithCalendarUnits = | Temporal.PlainDateTime | Temporal.PlainDate | Temporal.PlainTime | Temporal.PlainYearMonth | Temporal.PlainMonthDay | Temporal.ZonedDateTime; interface SlotsToTypes { // Instant [EPOCHNANOSECONDS]: Temporal.Instant; // TimeZone [TIMEZONE_ID]: Temporal.TimeZone; // DateTime, Date, Time, YearMonth, MonthDay [ISO_YEAR]: TypesWithCalendarUnits; [ISO_MONTH]: TypesWithCalendarUnits; [ISO_DAY]: TypesWithCalendarUnits; [ISO_HOUR]: TypesWithCalendarUnits; [ISO_MINUTE]: TypesWithCalendarUnits; [ISO_SECOND]: TypesWithCalendarUnits; [ISO_MILLISECOND]: TypesWithCalendarUnits; [ISO_MICROSECOND]: TypesWithCalendarUnits; [ISO_NANOSECOND]: TypesWithCalendarUnits; [CALENDAR]: TypesWithCalendarUnits; // Date, YearMonth, MonthDay common slots [DATE_BRAND]: Temporal.PlainDate; [YEAR_MONTH_BRAND]: Temporal.PlainYearMonth; [MONTH_DAY_BRAND]: Temporal.PlainMonthDay; // ZonedDateTime [INSTANT]: Temporal.ZonedDateTime; [TIME_ZONE]: Temporal.ZonedDateTime; // Duration [YEARS]: Temporal.Duration; [MONTHS]: Temporal.Duration; [WEEKS]: Temporal.Duration; [DAYS]: Temporal.Duration; [HOURS]: Temporal.Duration; [MINUTES]: Temporal.Duration; [SECONDS]: Temporal.Duration; [MILLISECONDS]: Temporal.Duration; [MICROSECONDS]: Temporal.Duration; [NANOSECONDS]: Temporal.Duration; // Calendar [CALENDAR_ID]: Temporal.Calendar; } type SlotKey = keyof SlotsToTypes; const slots = new WeakMap(); export function CreateSlots(container: AnyTemporalType): void { slots.set(container, Object.create(null)); } function GetSlots<T extends AnyTemporalType>(container: T) { return slots.get(container); } // TODO: is there a better way than 9 overloads to make HasSlot into a type // guard that takes a variable number of parameters? export function HasSlot<ID1 extends SlotKey>(container: unknown, id1: ID1): container is Slots[ID1]['usedBy']; export function HasSlot<ID1 extends SlotKey, ID2 extends SlotKey>( container: unknown, id1: ID1, id2: ID2 ): container is Slots[ID1]['usedBy'] | Slots[ID2]['usedBy']; export function HasSlot<ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey>( container: unknown, id1: ID1, id2: ID2, id3: ID3 ): container is Slots[ID1]['usedBy'] | Slots[ID2]['usedBy'] | Slots[ID3]['usedBy']; export function HasSlot<ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey, ID4 extends SlotKey>( container: unknown, id1: ID1, id2: ID2, id3: ID3, id4: ID4 ): container is Slots[ID1 | ID2 | ID3 | ID4]['usedBy']; export function HasSlot< ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey, ID4 extends SlotKey, ID5 extends SlotKey >( container: unknown, id1: ID1, id2: ID2, id3: ID3, id4: ID4, id5: ID5 ): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5]['usedBy']; export function HasSlot< ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey, ID4 extends SlotKey, ID5 extends SlotKey, ID6 extends SlotKey >( container: unknown, id1: ID1, id2: ID2, id3: ID3, id4: ID4, id5: ID5, id6: ID6 ): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6]['usedBy']; export function HasSlot< ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey, ID4 extends SlotKey, ID5 extends SlotKey, ID6 extends SlotKey, ID7 extends SlotKey >( container: unknown, id1: ID1, id2: ID2, id3: ID3, id4: ID4, id5: ID5, id6: ID6, id7: ID7 ): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6 | ID7]['usedBy']; export function HasSlot< ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey, ID4 extends SlotKey, ID5 extends SlotKey, ID6 extends SlotKey, ID7 extends SlotKey, ID8 extends SlotKey >( container: unknown, id1: ID1, id2: ID2, id3: ID3, id4: ID4, id5: ID5, id6: ID6, id7: ID7, id8: ID8 ): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6 | ID7 | ID8]['usedBy']; export function HasSlot< ID1 extends SlotKey, ID2 extends SlotKey, ID3 extends SlotKey, ID4 extends SlotKey, ID5 extends SlotKey, ID6 extends SlotKey, ID7 extends SlotKey, ID8 extends SlotKey, ID9 extends SlotKey >( container: unknown, id1: ID1, id2: ID2, id3: ID3, id4: ID4, id5: ID5, id6: ID6, id7: ID7, id8: ID8, id9: ID9 ): container is Slots[ID1 | ID2 | ID3 | ID4 | ID5 | ID6 | ID7 | ID8 | ID9]['usedBy']; export function HasSlot(container: unknown, ...ids: (keyof Slots)[]): boolean { if (!container || 'object' !== typeof container) return false; const myslots = GetSlots(container as AnyTemporalType); return !!myslots && ids.reduce((all: boolean, id) => all && id in myslots, true); } export function GetSlot<KeyT extends keyof Slots>( container: Slots[typeof id]['usedBy'], id: KeyT ): Slots[KeyT]['value'] { const value = GetSlots(container)[id]; if (value === undefined) throw new TypeError(`Missing internal slot ${id}`); return value; } export function SetSlot<KeyT extends SlotKey>( container: Slots[KeyT]['usedBy'], id: KeyT, value: Slots[KeyT]['value'] ): void { GetSlots(container)[id] = value; }