diff --git a/.gitignore b/.gitignore index d7c7c711..197c5b0e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ tsc-out/ .vscode/* !.vscode/launch.json *.tgz +.DS_Store diff --git a/lib/calendar.ts b/lib/calendar.ts index 2958e7e5..4844a35c 100644 --- a/lib/calendar.ts +++ b/lib/calendar.ts @@ -1,6 +1,5 @@ import { DEBUG } from './debug'; import * as ES from './ecmascript'; -import { GetIntrinsic, MakeIntrinsicClass, DefineIntrinsic } from './intrinsicclass'; import { CALENDAR_ID, ISO_YEAR, @@ -28,6 +27,7 @@ import type { CalendarReturn as Return, FieldRecord } from './internaltypes'; +import { Duration } from './duration'; const ArrayIncludes = Array.prototype.includes; const ArrayPrototypePush = Array.prototype.push; @@ -244,7 +244,6 @@ export class Calendar implements Temporal.Calendar { 'day' ); const { years, months, weeks, days } = impl[GetSlot(this, CALENDAR_ID)].dateUntil(one, two, largestUnit); - const Duration = GetIntrinsic('%Temporal.Duration%'); return new Duration(years, months, weeks, days, 0, 0, 0, 0, 0, 0); } year(dateParam: Params['year'][0]): Return['year'] { @@ -344,9 +343,6 @@ export class Calendar implements Temporal.Calendar { [Symbol.toStringTag]!: 'Temporal.Calendar'; } -MakeIntrinsicClass(Calendar, 'Temporal.Calendar'); -DefineIntrinsic('Temporal.Calendar.from', Calendar.from); - /** * Implementation for the ISO 8601 calendar. This is the only calendar that's * guaranteed to be supported by all ECMAScript implementations, including those diff --git a/lib/duration.ts b/lib/duration.ts index dc4c3ffd..de7c799a 100644 --- a/lib/duration.ts +++ b/lib/duration.ts @@ -1,6 +1,5 @@ import { DEBUG } from './debug'; import * as ES from './ecmascript'; -import { MakeIntrinsicClass } from './intrinsicclass'; import { YEARS, MONTHS, @@ -452,5 +451,3 @@ export class Duration implements Temporal.Duration { } [Symbol.toStringTag]!: 'Temporal.Duration'; } - -MakeIntrinsicClass(Duration, 'Temporal.Duration'); diff --git a/lib/ecmascript.ts b/lib/ecmascript.ts index 0ed29b18..8ef8b1fe 100644 --- a/lib/ecmascript.ts +++ b/lib/ecmascript.ts @@ -40,7 +40,6 @@ import type { FieldRecord, BuiltinCalendarId } from './internaltypes'; -import { GetIntrinsic } from './intrinsicclass'; import { CreateSlots, GetSlot, @@ -250,6 +249,16 @@ const SINGULAR_PLURAL_UNITS: readonly PluralAndSingularUnitTuple(); @@ -1349,8 +1358,7 @@ export function ToTemporalDate( ToTemporalOverflow(options); // validate and ignore const { year, month, day, calendar, z } = ParseTemporalDateString(ToString(item)); if (z) throw new RangeError('Z designator not supported for PlainDate'); - const TemporalPlainDate = GetIntrinsic('%Temporal.PlainDate%'); - return new TemporalPlainDate(year, month, day, calendar); // include validation + return new PlainDate(year, month, day, calendar); // include validation } export function InterpretTemporalDateTimeFields( @@ -1447,30 +1455,16 @@ export function ToTemporalDuration(item: DurationParams['from'][0]) { if (IsTemporalDuration(item)) return item; let { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ToTemporalDurationRecord(item); - const TemporalDuration = GetIntrinsic('%Temporal.Duration%'); - return new TemporalDuration( - years, - months, - weeks, - days, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds - ); + return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } export function ToTemporalInstant(item: InstantParams['from'][0]) { if (IsTemporalInstant(item)) return item; if (IsTemporalZonedDateTime(item)) { - const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); - return new TemporalInstant(GetSlot(item, EPOCHNANOSECONDS)); + return new Instant(GetSlot(item, EPOCHNANOSECONDS)); } const ns = ParseTemporalInstant(ToString(item)); - const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); - return new TemporalInstant(ns); + return new Instant(ns); } export function ToTemporalMonthDay(item: PlainMonthDayParams['from'][0], options?: PlainMonthDayParams['from'][1]) { @@ -1527,8 +1521,7 @@ export function ToTemporalTime( ); } if (IsTemporalDateTime(item)) { - const TemporalPlainTime = GetIntrinsic('%Temporal.PlainTime%'); - return new TemporalPlainTime( + return new PlainTime( GetSlot(item, ISO_HOUR), GetSlot(item, ISO_MINUTE), GetSlot(item, ISO_SECOND), @@ -1560,8 +1553,7 @@ export function ToTemporalTime( throw new RangeError('PlainTime can only have iso8601 calendar'); } } - const TemporalPlainTime = GetIntrinsic('%Temporal.PlainTime%'); - return new TemporalPlainTime(hour, minute, second, millisecond, microsecond, nanosecond); + return new PlainTime(hour, minute, second, millisecond, microsecond, nanosecond); } export function ToTemporalYearMonth(item: PlainYearMonthParams['from'][0], options?: PlainYearMonthParams['from'][1]) { @@ -1575,10 +1567,8 @@ export function ToTemporalYearMonth(item: PlainYearMonthParams['from'][0], optio ToTemporalOverflow(options); // validate and ignore let { year, month, referenceISODay, calendar: maybeStringCalendar } = ParseTemporalYearMonthString(ToString(item)); - // TODO: replace with ternary? - let calendar: Temporal.CalendarProtocol | string = maybeStringCalendar; - if (calendar === undefined) calendar = GetISO8601Calendar(); - calendar = ToTemporalCalendar(calendar); + + const calendar = maybeStringCalendar ? ToTemporalCalendar(maybeStringCalendar) : GetISO8601Calendar(); if (referenceISODay === undefined) { RejectISODate(year, month, 1); @@ -1607,8 +1597,7 @@ export function InterpretISODateTimeOffset( offsetOpt: Temporal.OffsetDisambiguationOptions['offset'], matchMinute: boolean ) { - const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); - const dt = new DateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); + const dt = new PlainDateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); if (offsetBehaviour === 'wall' || offsetOpt === 'ignore') { // Simple case: ISO string without a TZ offset (or caller wants to ignore @@ -1712,8 +1701,7 @@ export function ToTemporalZonedDateTime( } else if (!offset) { offsetBehaviour = 'wall'; } - const TemporalTimeZone = GetIntrinsic('%Temporal.TimeZone%'); - timeZone = new TemporalTimeZone(ianaName); + timeZone = new TimeZone(ianaName); if (!calendar) calendar = GetISO8601Calendar(); calendar = ToTemporalCalendar(calendar); matchMinute = true; // ISO strings may specify offset with less precision @@ -1741,7 +1729,8 @@ export function ToTemporalZonedDateTime( offsetOpt, matchMinute ); - return CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar); + // make sure that calendar is CalendarPrototocol + return CreateTemporalZonedDateTime(epochNanoseconds, timeZone, ToTemporalCalendar(calendar)); } export function CreateTemporalDateSlots( @@ -1777,8 +1766,7 @@ export function CreateTemporalDate( isoDay: number, calendar: Temporal.CalendarProtocol = GetISO8601Calendar() ) { - const TemporalPlainDate = GetIntrinsic('%Temporal.PlainDate%'); - const result = ObjectCreate(TemporalPlainDate.prototype); + const result = ObjectCreate(PlainDate.prototype); CreateTemporalDateSlots(result, isoYear, isoMonth, isoDay, calendar); return result; } @@ -1833,8 +1821,7 @@ export function CreateTemporalDateTime( ns: number, calendar: Temporal.CalendarProtocol = GetISO8601Calendar() ) { - const TemporalPlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); - const result = ObjectCreate(TemporalPlainDateTime.prototype); + const result = ObjectCreate(PlainDateTime.prototype); CreateTemporalDateTimeSlots(result, isoYear, isoMonth, isoDay, h, min, s, ms, µs, ns, calendar); return result as Temporal.PlainDateTime; } @@ -1872,8 +1859,7 @@ export function CreateTemporalMonthDay( calendar: Temporal.CalendarProtocol = GetISO8601Calendar(), referenceISOYear = 1972 ) { - const TemporalPlainMonthDay = GetIntrinsic('%Temporal.PlainMonthDay%'); - const result = ObjectCreate(TemporalPlainMonthDay.prototype); + const result = ObjectCreate(PlainMonthDay.prototype); CreateTemporalMonthDaySlots(result, isoMonth, isoDay, calendar, referenceISOYear); return result; } @@ -1911,8 +1897,7 @@ export function CreateTemporalYearMonth( calendar: Temporal.CalendarProtocol = GetISO8601Calendar(), referenceISODay = 1 ) { - const TemporalPlainYearMonth = GetIntrinsic('%Temporal.PlainYearMonth%'); - const result = ObjectCreate(TemporalPlainYearMonth.prototype); + const result = ObjectCreate(PlainYearMonth.prototype); CreateTemporalYearMonthSlots(result, isoYear, isoMonth, calendar, referenceISODay); return result; } @@ -1930,8 +1915,7 @@ export function CreateTemporalZonedDateTimeSlots( SetSlot(result, TIME_ZONE, timeZone); SetSlot(result, CALENDAR, calendar); - const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); - const instant = new TemporalInstant(GetSlot(result, EPOCHNANOSECONDS)); + const instant = new Instant(GetSlot(result, EPOCHNANOSECONDS)); SetSlot(result, INSTANT, instant); if (DEBUG) { @@ -1949,15 +1933,13 @@ export function CreateTemporalZonedDateTime( timeZone: Temporal.TimeZoneProtocol, calendar: Temporal.CalendarProtocol = GetISO8601Calendar() ) { - const TemporalZonedDateTime = GetIntrinsic('%Temporal.ZonedDateTime%'); - const result = ObjectCreate(TemporalZonedDateTime.prototype); + const result = ObjectCreate(ZonedDateTime.prototype); CreateTemporalZonedDateTimeSlots(result, epochNanoseconds, timeZone, calendar); return result; } export function GetISO8601Calendar() { - const TemporalCalendar = GetIntrinsic('%Temporal.Calendar%'); - return new TemporalCalendar('iso8601'); + return new Calendar('iso8601'); } // TODO: should (can?) we make this generic so the field names are checked @@ -2137,8 +2119,7 @@ export function ToTemporalCalendar(calendarLikeParam: CalendarParams['from'][0]) if (IsObject(calendarLike) && !('calendar' in calendarLike)) return calendarLike; } const identifier = ToString(calendarLike); - const TemporalCalendar = GetIntrinsic('%Temporal.Calendar%'); - if (IsBuiltinCalendar(identifier)) return new TemporalCalendar(identifier); + if (IsBuiltinCalendar(identifier)) return new Calendar(identifier); let calendar; try { ({ calendar } = ParseISODateTime(identifier)); @@ -2146,7 +2127,7 @@ export function ToTemporalCalendar(calendarLikeParam: CalendarParams['from'][0]) throw new RangeError(`Invalid calendar: ${identifier}`); } if (!calendar) calendar = 'iso8601'; - return new TemporalCalendar(calendar); + return new Calendar(calendar); } function GetTemporalCalendarWithISODefault( @@ -2220,8 +2201,7 @@ export function ToTemporalTimeZone(temporalTimeZoneLikeParam: TimeZoneParams['fr } const identifier = ToString(temporalTimeZoneLike); const timeZone = ParseTemporalTimeZone(identifier); - const TemporalTimeZone = GetIntrinsic('%Temporal.TimeZone%'); - return new TemporalTimeZone(timeZone); + return new TimeZone(timeZone); } export function TimeZoneEquals(one: Temporal.TimeZoneProtocol, two: Temporal.TimeZoneProtocol) { @@ -2241,8 +2221,7 @@ export function TemporalDateTimeToDate(dateTime: Temporal.PlainDateTime) { } export function TemporalDateTimeToTime(dateTime: Temporal.PlainDateTime) { - const Time = GetIntrinsic('%Temporal.PlainTime%'); - return new Time( + return new PlainTime( GetSlot(dateTime, ISO_HOUR), GetSlot(dateTime, ISO_MINUTE), GetSlot(dateTime, ISO_SECOND), @@ -2312,7 +2291,6 @@ function DisambiguatePossibleInstants( dateTime: Temporal.PlainDateTime, disambiguation: NonNullable ) { - const Instant = GetIntrinsic('%Temporal.Instant%'); const numInstants = possibleInstants.length; if (numInstants === 1) return possibleInstants[0]; @@ -2349,7 +2327,6 @@ function DisambiguatePossibleInstants( switch (disambiguation) { case 'earlier': { const calendar = GetSlot(dateTime, CALENDAR); - const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const earlier = AddDateTime( year, month, @@ -2391,7 +2368,6 @@ function DisambiguatePossibleInstants( // fall through because 'compatible' means 'later' for "spring forward" transitions case 'later': { const calendar = GetSlot(dateTime, CALENDAR); - const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const later = AddDateTime( year, month, @@ -2497,8 +2473,7 @@ export function TemporalInstantToString( ) { let outputTimeZone = timeZone; if (outputTimeZone === undefined) { - const TemporalTimeZone = GetIntrinsic('%Temporal.TimeZone%'); - outputTimeZone = new TemporalTimeZone('UTC'); + outputTimeZone = new TimeZone('UTC'); } const iso = GetISO8601Calendar(); const dateTime = BuiltinTimeZoneGetPlainDateTimeFor(outputTimeZone, instant, iso); @@ -2705,8 +2680,7 @@ export function TemporalZonedDateTimeToString( if (options) { const { unit, increment, roundingMode } = options; const ns = RoundInstant(GetSlot(zdt, EPOCHNANOSECONDS), increment, unit, roundingMode); - const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); - instant = new TemporalInstant(ns); + instant = new Instant(ns); } const tz = GetSlot(zdt, TIME_ZONE); @@ -3279,7 +3253,6 @@ export function TotalDurationNanoseconds( } function NanosecondsToDays(nanosecondsParam: JSBI, relativeTo: ReturnType) { - const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); const sign = MathSign(JSBI.toNumber(nanosecondsParam)); let nanoseconds = JSBI.BigInt(nanosecondsParam); let dayLengthNs = 86400e9; @@ -3293,7 +3266,7 @@ function NanosecondsToDays(nanosecondsParam: JSBI, relativeTo: ReturnTypePlainDate @@ -5579,10 +5518,10 @@ export function RoundDuration( // convert months and weeks to days by calculating difference( // relativeTo + years, relativeTo + { years, months, weeks }) - const yearsDuration = new TemporalDuration(years); + const yearsDuration = new Duration(years); const dateAdd = calendar.dateAdd; const yearsLater = CalendarDateAdd(calendar, relativeTo as Temporal.PlainDate, yearsDuration, undefined, dateAdd); - const yearsMonthsWeeks = new TemporalDuration(years, months, weeks); + const yearsMonthsWeeks = new Duration(years, months, weeks); const yearsMonthsWeeksLater = CalendarDateAdd( calendar, relativeTo as Temporal.PlainDate, @@ -5603,7 +5542,7 @@ export function RoundDuration( relativeTo = CalendarDateAdd(calendar, relativeTo, { years: yearsPassed }, undefined, dateAdd); const daysPassed = DaysUntil(oldRelativeTo, relativeTo); days -= daysPassed; - const oneYear = new TemporalDuration(days < 0 ? -1 : 1); + const oneYear = new Duration(days < 0 ? -1 : 1); let { days: oneYearDays } = MoveRelativeDate(calendar, relativeTo, oneYear); // Note that `nanoseconds` below (here and in similar code for months, @@ -5637,7 +5576,7 @@ export function RoundDuration( // convert weeks to days by calculating difference(relativeTo + // { years, months }, relativeTo + { years, months, weeks }) - const yearsMonths = new TemporalDuration(years, months); + const yearsMonths = new Duration(years, months); const dateAdd = calendar.dateAdd; const yearsMonthsLater = CalendarDateAdd( calendar, @@ -5646,7 +5585,7 @@ export function RoundDuration( undefined, dateAdd ); - const yearsMonthsWeeks = new TemporalDuration(years, months, weeks); + const yearsMonthsWeeks = new Duration(years, months, weeks); const yearsMonthsWeeksLater = CalendarDateAdd( calendar, relativeTo as Temporal.PlainDate, @@ -5661,7 +5600,7 @@ export function RoundDuration( // Months may be different lengths of days depending on the calendar, // convert days to months in a loop as described above under 'years'. const sign = MathSign(days); - const oneMonth = new TemporalDuration(0, days < 0 ? -1 : 1); + const oneMonth = new Duration(0, days < 0 ? -1 : 1); let oneMonthDays: number; ({ relativeTo, days: oneMonthDays } = MoveRelativeDate(calendar, relativeTo, oneMonth)); while (MathAbs(days) >= MathAbs(oneMonthDays)) { @@ -5694,7 +5633,7 @@ export function RoundDuration( // Weeks may be different lengths of days depending on the calendar, // convert days to weeks in a loop as described above under 'years'. const sign = MathSign(days); - const oneWeek = new TemporalDuration(0, 0, days < 0 ? -1 : 1); + const oneWeek = new Duration(0, 0, days < 0 ? -1 : 1); let oneWeekDays; ({ relativeTo, days: oneWeekDays } = MoveRelativeDate(calendar, relativeTo as Temporal.PlainDate, oneWeek)); while (MathAbs(days) >= MathAbs(oneWeekDays)) { @@ -5911,8 +5850,7 @@ export const SystemUTCEpochNanoSeconds: () => JSBI = (() => { export function SystemTimeZone() { const fmt = new IntlDateTimeFormat('en-us'); - const TemporalTimeZone = GetIntrinsic('%Temporal.TimeZone%'); - return new TemporalTimeZone(ParseTemporalTimeZone(fmt.resolvedOptions().timeZone)); + return new TimeZone(ParseTemporalTimeZone(fmt.resolvedOptions().timeZone)); } export function ComparisonResult(value: number) { diff --git a/lib/instant.ts b/lib/instant.ts index 7fd3050b..fc9e0beb 100644 --- a/lib/instant.ts +++ b/lib/instant.ts @@ -1,6 +1,5 @@ import { DEBUG } from './debug'; import * as ES from './ecmascript'; -import { MakeIntrinsicClass } from './intrinsicclass'; import { EPOCHNANOSECONDS, CreateSlots, GetSlot, SetSlot } from './slots'; import type { Temporal } from '..'; import { DateTimeFormat } from './intl'; @@ -204,5 +203,3 @@ export class Instant implements Temporal.Instant { } [Symbol.toStringTag]!: 'Temporal.Instant'; } - -MakeIntrinsicClass(Instant, 'Temporal.Instant'); diff --git a/lib/intl.ts b/lib/intl.ts index 634f8b53..f22bea6c 100644 --- a/lib/intl.ts +++ b/lib/intl.ts @@ -1,5 +1,4 @@ import * as ES from './ecmascript'; -import { GetIntrinsic } from './intrinsicclass'; import { GetSlot, INSTANT, @@ -17,6 +16,7 @@ import { } from './slots'; import type { Temporal, Intl } from '..'; import type { DateTimeFormatParams as Params, DateTimeFormatReturn as Return } from './internaltypes'; +import { PlainDateTime } from './plaindatetime'; const DATE = Symbol('date'); const YM = Symbol('ym'); @@ -526,8 +526,6 @@ type TypesWithToLocaleString = | Temporal.Instant; function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormatImpl) { - const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); - if (ES.IsTemporalTime(temporalObj)) { const hour = GetSlot(temporalObj, ISO_HOUR); const minute = GetSlot(temporalObj, ISO_MINUTE); @@ -535,7 +533,18 @@ function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormat const millisecond = GetSlot(temporalObj, ISO_MILLISECOND); const microsecond = GetSlot(temporalObj, ISO_MICROSECOND); const nanosecond = GetSlot(temporalObj, ISO_NANOSECOND); - const datetime = new DateTime(1970, 1, 1, hour, minute, second, millisecond, microsecond, nanosecond, main[CAL_ID]); + const datetime = new PlainDateTime( + 1970, + 1, + 1, + hour, + minute, + second, + millisecond, + microsecond, + nanosecond, + main[CAL_ID] + ); return { instant: ES.BuiltinTimeZoneGetInstantFor(getResolvedTimeZoneLazy(main), datetime, 'compatible'), formatter: getPropLazy(main, TIME) @@ -552,7 +561,7 @@ function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormat `cannot format PlainYearMonth with calendar ${calendar} in locale with calendar ${main[CAL_ID]}` ); } - const datetime = new DateTime(isoYear, isoMonth, referenceISODay, 12, 0, 0, 0, 0, 0, calendar); + const datetime = new PlainDateTime(isoYear, isoMonth, referenceISODay, 12, 0, 0, 0, 0, 0, calendar); return { instant: ES.BuiltinTimeZoneGetInstantFor(getResolvedTimeZoneLazy(main), datetime, 'compatible'), formatter: getPropLazy(main, YM) @@ -569,7 +578,7 @@ function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormat `cannot format PlainMonthDay with calendar ${calendar} in locale with calendar ${main[CAL_ID]}` ); } - const datetime = new DateTime(referenceISOYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, calendar); + const datetime = new PlainDateTime(referenceISOYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, calendar); return { instant: ES.BuiltinTimeZoneGetInstantFor(getResolvedTimeZoneLazy(main), datetime, 'compatible'), formatter: getPropLazy(main, MD) @@ -584,7 +593,7 @@ function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormat if (calendar !== 'iso8601' && calendar !== main[CAL_ID]) { throw new RangeError(`cannot format PlainDate with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`); } - const datetime = new DateTime(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, main[CAL_ID]); + const datetime = new PlainDateTime(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, main[CAL_ID]); return { instant: ES.BuiltinTimeZoneGetInstantFor(getResolvedTimeZoneLazy(main), datetime, 'compatible'), formatter: getPropLazy(main, DATE) @@ -609,7 +618,7 @@ function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormat } let datetime = temporalObj; if (calendar === 'iso8601') { - datetime = new DateTime( + datetime = new PlainDateTime( isoYear, isoMonth, isoDay, diff --git a/lib/intrinsicclass.ts b/lib/intrinsicclass.ts deleted file mode 100644 index c8b329b7..00000000 --- a/lib/intrinsicclass.ts +++ /dev/null @@ -1,143 +0,0 @@ -import type JSBI from 'jsbi'; -import type { Temporal } from '..'; - -import { DEBUG } from './debug'; - -type OmitConstructor = { [P in keyof T as T[P] extends new (...args: any[]) => any ? P : never]: T[P] }; - -type TemporalIntrinsics = Omit & { - Instant: OmitConstructor & - (new (epochNanoseconds: JSBI) => Temporal.Instant) & { prototype: typeof Temporal.Instant.prototype }; - ZonedDateTime: OmitConstructor & - (new ( - epochNanoseconds: JSBI, - timeZone: Temporal.TimeZoneProtocol | string, - calendar?: Temporal.CalendarProtocol | string - ) => Temporal.ZonedDateTime) & { - prototype: typeof Temporal.ZonedDateTime.prototype; - from: typeof Temporal.ZonedDateTime.from; - compare: typeof Temporal.ZonedDateTime.compare; - }; -}; -type TemporalIntrinsicRegistrations = { - [key in keyof TemporalIntrinsics as `Temporal.${key}`]: TemporalIntrinsics[key]; -}; -type TemporalIntrinsicPrototypeRegistrations = { - [key in keyof TemporalIntrinsics as `Temporal.${key}.prototype`]: TemporalIntrinsics[key]['prototype']; -}; -type TemporalIntrinsicRegisteredKeys = { - [key in keyof TemporalIntrinsicRegistrations as `%${key}%`]: TemporalIntrinsicRegistrations[key]; -}; -type TemporalIntrinsicPrototypeRegisteredKeys = { - [key in keyof TemporalIntrinsicPrototypeRegistrations as `%${key}%`]: TemporalIntrinsicPrototypeRegistrations[key]; -}; - -interface StandaloneIntrinsics { - 'Temporal.Calendar.from': typeof Temporal.Calendar.from; -} -type RegisteredStandaloneIntrinsics = { [key in keyof StandaloneIntrinsics as `%${key}%`]: StandaloneIntrinsics[key] }; -const INTRINSICS = {} as TemporalIntrinsicRegisteredKeys & - TemporalIntrinsicPrototypeRegisteredKeys & - RegisteredStandaloneIntrinsics; - -type customFormatFunction = ( - this: T, - depth: number, - options: { stylize: (value: unknown, type: 'number' | 'special') => string } -) => string; -const customUtilInspectFormatters: Partial<{ - [key in keyof TemporalIntrinsicRegistrations]: customFormatFunction< - InstanceType - >; -}> = { - ['Temporal.Duration'](depth, options) { - const descr = options.stylize(`${this[Symbol.toStringTag]} <${this}>`, 'special'); - if (depth < 1) return descr; - const entries = []; - for (const prop of [ - 'years', - 'months', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ] as const) { - if (this[prop] !== 0) entries.push(` ${prop}: ${options.stylize(this[prop], 'number')}`); - } - return descr + ' {\n' + entries.join(',\n') + '\n}'; - } -}; - -type InspectFormatterOptions = { stylize: (str: string, styleType: string) => string }; -function defaultUtilInspectFormatter(this: any, depth: number, options: InspectFormatterOptions) { - return options.stylize(`${this[Symbol.toStringTag]} <${this}>`, 'special'); -} - -export function MakeIntrinsicClass( - Class: TemporalIntrinsicRegistrations[typeof name], - name: keyof TemporalIntrinsicRegistrations -) { - Object.defineProperty(Class.prototype, Symbol.toStringTag, { - value: name, - writable: false, - enumerable: false, - configurable: true - }); - if (DEBUG) { - Object.defineProperty(Class.prototype, Symbol.for('nodejs.util.inspect.custom'), { - value: customUtilInspectFormatters[name] || defaultUtilInspectFormatter, - writable: false, - enumerable: false, - configurable: true - }); - } - for (const prop of Object.getOwnPropertyNames(Class)) { - // we know that `prop` is present, so the descriptor is never undefined - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const desc = Object.getOwnPropertyDescriptor(Class, prop)!; - if (!desc.configurable || !desc.enumerable) continue; - desc.enumerable = false; - Object.defineProperty(Class, prop, desc); - } - for (const prop of Object.getOwnPropertyNames(Class.prototype)) { - // we know that `prop` is present, so the descriptor is never undefined - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const desc = Object.getOwnPropertyDescriptor(Class.prototype, prop)!; - if (!desc.configurable || !desc.enumerable) continue; - desc.enumerable = false; - Object.defineProperty(Class.prototype, prop, desc); - } - - DefineIntrinsic(name, Class); - DefineIntrinsic(`${name}.prototype`, Class.prototype); -} - -type IntrinsicDefinitionKeys = - | keyof TemporalIntrinsicRegistrations - | keyof TemporalIntrinsicPrototypeRegistrations - | keyof StandaloneIntrinsics; -export function DefineIntrinsic( - name: KeyT, - value: TemporalIntrinsicRegistrations[KeyT] -): void; -export function DefineIntrinsic( - name: KeyT, - value: TemporalIntrinsicPrototypeRegistrations[KeyT] -): void; -export function DefineIntrinsic( - name: KeyT, - value: StandaloneIntrinsics[KeyT] -): void; -export function DefineIntrinsic(name: KeyT, value: never): void; -export function DefineIntrinsic(name: KeyT, value: unknown): void { - const key: `%${IntrinsicDefinitionKeys}%` = `%${name}%`; - if (INTRINSICS[key] !== undefined) throw new Error(`intrinsic ${name} already exists`); - INTRINSICS[key] = value; -} -export function GetIntrinsic(intrinsic: KeyT): typeof INTRINSICS[KeyT] { - return INTRINSICS[intrinsic]; -} diff --git a/lib/now.ts b/lib/now.ts index 8f43cce2..977aa77c 100644 --- a/lib/now.ts +++ b/lib/now.ts @@ -1,9 +1,8 @@ import * as ES from './ecmascript'; -import { GetIntrinsic } from './intrinsicclass'; import type { Temporal } from '..'; +import { Instant } from './instant'; const instant: typeof Temporal.Now['instant'] = () => { - const Instant = GetIntrinsic('%Temporal.Instant%'); return new Instant(ES.SystemUTCEpochNanoSeconds()); }; const plainDateTime: typeof Temporal.Now['plainDateTime'] = (calendarLike, temporalTimeZoneLike = timeZone()) => { diff --git a/lib/plaindate.ts b/lib/plaindate.ts index c4f06991..7e4a806e 100644 --- a/lib/plaindate.ts +++ b/lib/plaindate.ts @@ -1,5 +1,4 @@ import * as ES from './ecmascript'; -import { MakeIntrinsicClass } from './intrinsicclass'; import { ISO_YEAR, ISO_MONTH, @@ -321,5 +320,3 @@ export class PlainDate implements Temporal.PlainDate { } [Symbol.toStringTag]!: 'Temporal.PlainDate'; } - -MakeIntrinsicClass(PlainDate, 'Temporal.PlainDate'); diff --git a/lib/plaindatetime.ts b/lib/plaindatetime.ts index bfe27d10..15e07eb1 100644 --- a/lib/plaindatetime.ts +++ b/lib/plaindatetime.ts @@ -1,5 +1,4 @@ import * as ES from './ecmascript'; -import { MakeIntrinsicClass } from './intrinsicclass'; import { ISO_YEAR, @@ -479,5 +478,3 @@ export class PlainDateTime implements Temporal.PlainDateTime { } [Symbol.toStringTag]!: 'Temporal.PlainDateTime'; } - -MakeIntrinsicClass(PlainDateTime, 'Temporal.PlainDateTime'); diff --git a/lib/plainmonthday.ts b/lib/plainmonthday.ts index 76c0c033..cce8d25a 100644 --- a/lib/plainmonthday.ts +++ b/lib/plainmonthday.ts @@ -1,5 +1,4 @@ import * as ES from './ecmascript'; -import { MakeIntrinsicClass } from './intrinsicclass'; import { ISO_MONTH, ISO_DAY, ISO_YEAR, CALENDAR, GetSlot } from './slots'; import type { Temporal } from '..'; import { DateTimeFormat } from './intl'; @@ -148,5 +147,3 @@ export class PlainMonthDay implements Temporal.PlainMonthDay { } [Symbol.toStringTag]!: 'Temporal.PlainMonthDay'; } - -MakeIntrinsicClass(PlainMonthDay, 'Temporal.PlainMonthDay'); diff --git a/lib/plaintime.ts b/lib/plaintime.ts index 446db75e..0163010b 100644 --- a/lib/plaintime.ts +++ b/lib/plaintime.ts @@ -1,6 +1,5 @@ import { DEBUG } from './debug'; import * as ES from './ecmascript'; -import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass'; import { ISO_YEAR, @@ -21,6 +20,7 @@ import { import type { Temporal } from '..'; import { DateTimeFormat } from './intl'; import type { PlainTimeParams as Params, PlainTimeReturn as Return } from './internaltypes'; +import { PlainDateTime } from './plaindatetime'; const ObjectAssign = Object.assign; @@ -312,7 +312,6 @@ export class PlainTime implements Temporal.PlainTime { const microsecond = GetSlot(this, ISO_MICROSECOND); const nanosecond = GetSlot(this, ISO_NANOSECOND); - const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const dt = new PlainDateTime( year, month, @@ -368,5 +367,3 @@ export class PlainTime implements Temporal.PlainTime { } [Symbol.toStringTag]!: 'Temporal.PlainTime'; } - -MakeIntrinsicClass(PlainTime, 'Temporal.PlainTime'); diff --git a/lib/plainyearmonth.ts b/lib/plainyearmonth.ts index 1b2fed89..c455bded 100644 --- a/lib/plainyearmonth.ts +++ b/lib/plainyearmonth.ts @@ -1,5 +1,4 @@ import * as ES from './ecmascript'; -import { MakeIntrinsicClass } from './intrinsicclass'; import { ISO_YEAR, ISO_MONTH, ISO_DAY, CALENDAR, GetSlot } from './slots'; import type { Temporal } from '..'; import { DateTimeFormat } from './intl'; @@ -209,5 +208,3 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { } [Symbol.toStringTag]!: 'Temporal.PlainYearMonth'; } - -MakeIntrinsicClass(PlainYearMonth, 'Temporal.PlainYearMonth'); diff --git a/lib/timezone.ts b/lib/timezone.ts index f8f21129..7bc90675 100644 --- a/lib/timezone.ts +++ b/lib/timezone.ts @@ -1,6 +1,5 @@ import { DEBUG } from './debug'; import * as ES from './ecmascript'; -import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass'; import { TIMEZONE_ID, EPOCHNANOSECONDS, @@ -20,6 +19,7 @@ import { import JSBI from 'jsbi'; import type { Temporal } from '..'; import type { TimeZoneParams as Params, TimeZoneReturn as Return } from './internaltypes'; +import { Instant } from './instant'; export class TimeZone implements Temporal.TimeZone { constructor(timeZoneIdentifierParam: string) { @@ -82,7 +82,6 @@ export class TimeZone implements Temporal.TimeZone { getPossibleInstantsFor(dateTimeParam: Params['getPossibleInstantsFor'][0]): Return['getPossibleInstantsFor'] { if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver'); const dateTime = ES.ToTemporalDateTime(dateTimeParam); - const Instant = GetIntrinsic('%Temporal.Instant%'); const id = GetSlot(this, TIMEZONE_ID); if (ES.TestTimeZoneOffsetString(id)) { @@ -127,7 +126,6 @@ export class TimeZone implements Temporal.TimeZone { } let epochNanoseconds: JSBI | null = GetSlot(startingPoint, EPOCHNANOSECONDS); - const Instant = GetIntrinsic('%Temporal.Instant%'); epochNanoseconds = ES.GetIANATimeZoneNextTransition(epochNanoseconds, id); return epochNanoseconds === null ? null : new Instant(epochNanoseconds); } @@ -142,7 +140,6 @@ export class TimeZone implements Temporal.TimeZone { } let epochNanoseconds: JSBI | null = GetSlot(startingPoint, EPOCHNANOSECONDS); - const Instant = GetIntrinsic('%Temporal.Instant%'); epochNanoseconds = ES.GetIANATimeZonePreviousTransition(epochNanoseconds, id); return epochNanoseconds === null ? null : new Instant(epochNanoseconds); } @@ -159,5 +156,3 @@ export class TimeZone implements Temporal.TimeZone { } [Symbol.toStringTag]!: 'Temporal.TimeZone'; } - -MakeIntrinsicClass(TimeZone, 'Temporal.TimeZone'); diff --git a/lib/zoneddatetime.ts b/lib/zoneddatetime.ts index 0b109fbf..a0c7ec56 100644 --- a/lib/zoneddatetime.ts +++ b/lib/zoneddatetime.ts @@ -1,5 +1,4 @@ import * as ES from './ecmascript'; -import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass'; import { CALENDAR, EPOCHNANOSECONDS, @@ -22,6 +21,9 @@ import type { ZonedDateTimeParams as Params, ZonedDateTimeReturn as Return } fro import JSBI from 'jsbi'; import { BILLION, MILLION, THOUSAND, ZERO } from './ecmascript'; +import { PlainDateTime } from './plaindatetime'; +import { PlainTime } from './plaintime'; +import { Instant } from './instant'; const ArrayPrototypePush = Array.prototype.push; @@ -134,13 +136,12 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { get hoursInDay(): Return['hoursInDay'] { if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver'); const dt = dateTime(this); - const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const year = GetSlot(dt, ISO_YEAR); const month = GetSlot(dt, ISO_MONTH); const day = GetSlot(dt, ISO_DAY); - const today = new DateTime(year, month, day, 0, 0, 0, 0, 0, 0); + const today = new PlainDateTime(year, month, day, 0, 0, 0, 0, 0, 0); const tomorrowFields = ES.AddISODate(year, month, day, 0, 0, 0, 1, 'reject'); - const tomorrow = new DateTime(tomorrowFields.year, tomorrowFields.month, tomorrowFields.day, 0, 0, 0, 0, 0, 0); + const tomorrow = new PlainDateTime(tomorrowFields.year, tomorrowFields.month, tomorrowFields.day, 0, 0, 0, 0, 0, 0); const timeZone = GetSlot(this, TIME_ZONE); const todayNs = GetSlot(ES.BuiltinTimeZoneGetInstantFor(timeZone, today, 'compatible'), EPOCHNANOSECONDS); const tomorrowNs = GetSlot(ES.BuiltinTimeZoneGetInstantFor(timeZone, tomorrow, 'compatible'), EPOCHNANOSECONDS); @@ -270,7 +271,6 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { calendar = ES.ConsolidateCalendars(GetSlot(this, CALENDAR), calendar); const timeZone = GetSlot(this, TIME_ZONE); - const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const dt = new PlainDateTime( year, month, @@ -289,7 +289,6 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { withPlainTime(temporalTimeParam: Params['withPlainTime'][0] = undefined): Return['withPlainTime'] { if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver'); - const PlainTime = GetIntrinsic('%Temporal.PlainTime%'); const temporalTime = temporalTimeParam === undefined ? new PlainTime() : ES.ToTemporalTime(temporalTimeParam); const thisDt = dateTime(this); @@ -305,7 +304,6 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { const nanosecond = GetSlot(temporalTime, ISO_NANOSECOND); const timeZone = GetSlot(this, TIME_ZONE); - const PlainDateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const dt = new PlainDateTime( year, month, @@ -383,10 +381,19 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { let microsecond = GetSlot(dt, ISO_MICROSECOND); let nanosecond = GetSlot(dt, ISO_NANOSECOND); - const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const timeZone = GetSlot(this, TIME_ZONE); const calendar = GetSlot(this, CALENDAR); - const dtStart = new DateTime(GetSlot(dt, ISO_YEAR), GetSlot(dt, ISO_MONTH), GetSlot(dt, ISO_DAY), 0, 0, 0, 0, 0, 0); + const dtStart = new PlainDateTime( + GetSlot(dt, ISO_YEAR), + GetSlot(dt, ISO_MONTH), + GetSlot(dt, ISO_DAY), + 0, + 0, + 0, + 0, + 0, + 0 + ); const instantStart = ES.BuiltinTimeZoneGetInstantFor(timeZone, dtStart, 'compatible'); const endNs = ES.AddZonedDateTime(instantStart, timeZone, calendar, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); const dayLengthNs = JSBI.subtract(endNs, JSBI.BigInt(GetSlot(instantStart, EPOCHNANOSECONDS))); @@ -477,9 +484,8 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { startOfDay(): Return['startOfDay'] { if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver'); const dt = dateTime(this); - const DateTime = GetIntrinsic('%Temporal.PlainDateTime%'); const calendar = GetSlot(this, CALENDAR); - const dtStart = new DateTime( + const dtStart = new PlainDateTime( GetSlot(dt, ISO_YEAR), GetSlot(dt, ISO_MONTH), GetSlot(dt, ISO_DAY), @@ -497,8 +503,7 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { } toInstant(): Return['toInstant'] { if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver'); - const TemporalInstant = GetIntrinsic('%Temporal.Instant%'); - return new TemporalInstant(GetSlot(this, EPOCHNANOSECONDS)); + return new Instant(GetSlot(this, EPOCHNANOSECONDS)); } toPlainDate(): Return['toPlainDate'] { if (!ES.IsTemporalZonedDateTime(this)) throw new TypeError('invalid receiver'); @@ -571,8 +576,6 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { [Symbol.toStringTag]!: 'Temporal.ZonedDateTime'; } -MakeIntrinsicClass(ZonedDateTime, 'Temporal.ZonedDateTime'); - function dateTime(zdt: Temporal.ZonedDateTime) { return ES.BuiltinTimeZoneGetPlainDateTimeFor(GetSlot(zdt, TIME_ZONE), GetSlot(zdt, INSTANT), GetSlot(zdt, CALENDAR)); } diff --git a/package.json b/package.json index 2bcc9949..46b2dfd4 100644 --- a/package.json +++ b/package.json @@ -109,11 +109,7 @@ "prettier": { "printWidth": 120, "trailingComma": "none", - "tabWidth": 2, - "semi": true, - "singleQuote": true, - "bracketSpacing": true, - "arrowParens": "always" + "singleQuote": true }, "directories": { "lib": "lib", diff --git a/test/all.mjs b/test/all.mjs index 883ff607..01facd90 100644 --- a/test/all.mjs +++ b/test/all.mjs @@ -29,6 +29,9 @@ import './calendar.mjs'; import './usertimezone.mjs'; import './usercalendar.mjs'; +// monkeypatching +import './monkeypatch.mjs'; + Promise.resolve() .then(() => { return Demitasse.report(Pretty.reporter); diff --git a/test/monkeypatch.mjs b/test/monkeypatch.mjs new file mode 100644 index 00000000..11ac5632 --- /dev/null +++ b/test/monkeypatch.mjs @@ -0,0 +1,29 @@ +#! /usr/bin/env -S node --experimental-modules +/* eslint-disable no-import-assign */ + +import Demitasse from '@pipobscure/demitasse'; +const { describe, it, report } = Demitasse; + +import Pretty from '@pipobscure/demitasse-pretty'; +const { reporter } = Pretty; + +import { strict as assert } from 'assert'; +const { equal } = assert; + +import * as Temporal from '@js-temporal/polyfill'; +const { PlainDate } = Temporal; + +describe('Monkeypatch', () => { + describe('PlainDate', () => { + it("Monkeypatching Duration constructor doesn't affect PlainDate", () => { + Temporal.Duration.prototype.constructor = null; + const date = PlainDate.from('2021-12-09'); + equal(`${date.until('2021-12-10')}`, 'P1D'); + }); + }); +}); + +import { normalize } from 'path'; +if (normalize(import.meta.url.slice(8)) === normalize(process.argv[1])) { + report(reporter).then((failed) => process.exit(failed ? 1 : 0)); +} diff --git a/tsconfig.json b/tsconfig.json index d5397b7b..57256740 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,19 +5,16 @@ "downlevelIteration": true, "importHelpers": true, "importsNotUsedAsValues": "error", - "inlineSources": false, "lib": ["dom", "ES2020"], "module": "es6", "moduleResolution": "node", "noEmitOnError": true, "noErrorTruncation": true, - // "noFallthroughCasesInSwitch": true, "noImplicitAny": true, "noImplicitOverride": true, "noImplicitReturns": true, "noImplicitThis": true, "outDir": "tsc-out/", - "preserveConstEnums": false, "skipDefaultLibCheck": true, "sourceMap": true, "strictBindCallApply": true,