@js-temporal/polyfill
Version:
Polyfill for Tc39 Stage 3 proposal Temporal (https://github.com/tc39/proposal-temporal)
292 lines (265 loc) • 8.79 kB
text/typescript
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 {
[]: SlotInfo<unknown, AnyTemporalType>;
}
interface Slots extends SlotInfoRecord {
// Instant
[]: SlotInfo<JSBI, Temporal.Instant | Temporal.ZonedDateTime>; // number? JSBI?
// TimeZone
[]: SlotInfo<string, Temporal.TimeZone>;
// DateTime, Date, Time, YearMonth, MonthDay
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<number, TypesWithCalendarUnits>;
[]: SlotInfo<Temporal.CalendarProtocol, TypesWithCalendarUnits | Temporal.ZonedDateTime>;
// Date, YearMonth, MonthDay common slots
[]: SlotInfo<true, Temporal.PlainDate>;
[]: SlotInfo<true, Temporal.PlainYearMonth>;
[]: SlotInfo<true, Temporal.PlainMonthDay>;
// ZonedDateTime
[]: SlotInfo<Temporal.Instant, Temporal.ZonedDateTime>;
[]: SlotInfo<Temporal.TimeZoneProtocol, Temporal.ZonedDateTime>;
// Duration
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
[]: SlotInfo<number, Temporal.Duration>;
// Calendar
[]: SlotInfo<BuiltinCalendarId, Temporal.Calendar>;
}
type TypesWithCalendarUnits =
| Temporal.PlainDateTime
| Temporal.PlainDate
| Temporal.PlainTime
| Temporal.PlainYearMonth
| Temporal.PlainMonthDay
| Temporal.ZonedDateTime;
interface SlotsToTypes {
// Instant
[]: Temporal.Instant;
// TimeZone
[]: Temporal.TimeZone;
// DateTime, Date, Time, YearMonth, MonthDay
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
[]: TypesWithCalendarUnits;
// Date, YearMonth, MonthDay common slots
[]: Temporal.PlainDate;
[]: Temporal.PlainYearMonth;
[]: Temporal.PlainMonthDay;
// ZonedDateTime
[]: Temporal.ZonedDateTime;
[]: Temporal.ZonedDateTime;
// Duration
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
[]: Temporal.Duration;
// Calendar
[]: 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;
}