From 5bc9fb52addc45871d533595815d9c379c8559a7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 22 Mar 2023 19:00:21 -0400 Subject: [PATCH 001/805] fixes for new tests --- .../misc/expected-failures.txt | 72 ++++++++++++++++++- .../src/argParse/calendar.ts | 31 ++++++-- .../src/calendarImpl/calendarImplQuery.ts | 8 +++ .../src/dateUtils/fromAndWith.ts | 7 +- .../temporal-polyfill/src/dateUtils/parse.ts | 12 +++- .../src/dateUtils/parseRegExp.ts | 2 +- .../src/dateUtils/translate.ts | 9 +++ .../temporal-polyfill/src/public/calendar.ts | 3 + .../temporal-polyfill/src/public/plainDate.ts | 10 ++- .../src/public/plainDateTime.ts | 1 + .../temporal-polyfill/src/public/temporal.ts | 8 +++ .../src/public/zonedDateTime.ts | 3 + 12 files changed, 152 insertions(+), 14 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index d9e39ed8..0a5e5b99 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -7,6 +7,74 @@ # # fullcalendar/temporal notes # -# Start with `pn test262 'Calendar/**'` -# Figure out `[input.high, input.low]` error + +# +# Calendar +# `pn test262 'Calendar/**'` # + +# really specific calling order of object properties +built-ins/Temporal/Calendar/from/calendar-object-operations.js + +# when creating calendar from datetime-like, .calendar should not be accessed, +# instead, an internal slot should be accessed +built-ins/Temporal/Calendar/from/calendar-temporal-object.js + +# another required optimization to read internal slots +# checkPlainDateTimeConversionFastPath +built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js + +# similar internal-slot-access-only problem +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js +built-ins/Temporal/Calendar/prototype/dateAdd/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js + +# I'm going crazy with RangeError vs TypeError +built-ins/Temporal/Calendar/from/calendar-object-invalid.js +built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js + +# refactor parsing for `[u-ca=iso8601][!u-ca=discord]`, higher-level +built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js + +# refactor parsing so that strings that end with timezone info must have at least one time part +built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js + +# refactor parsing to allow arbitrary notation at end of any string +built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-unknown-annotation.js + +# i don't know how TimeZone::getOffsetNanosecondsFor WOULDN'T be called while instantiating +# a new ZonedDateTime, unless the spec wants the local fields to be lazy? +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js + +# error needs to be thrown for weird constant timezone offset, but it should happen when +# ZonedDateTime is instantiated +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +# for debugging: +# class SpecificOffsetTimeZone extends Temporal.TimeZone { +# constructor() { +# super("UTC"); +# } +# getOffsetNanosecondsFor() { +# return 3600_000_000_000.5; +# } +# getPossibleInstantsFor() { +# return []; +# } +# } +# const timeZone = new SpecificOffsetTimeZone() +# const dateTime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); + +# similar lazy-timezone-offset issue +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js + +# similar +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js + +# lame weird prototype stuff +built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js +built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js + +# NEXT: deal with `throw new TypeError("Must be a calendar");` diff --git a/packages/temporal-polyfill/src/argParse/calendar.ts b/packages/temporal-polyfill/src/argParse/calendar.ts index 713de345..dd360911 100644 --- a/packages/temporal-polyfill/src/argParse/calendar.ts +++ b/packages/temporal-polyfill/src/argParse/calendar.ts @@ -2,18 +2,39 @@ import { Temporal } from 'temporal-spec' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' import { ensureObj } from '../dateUtils/abstract' import { Calendar, createDefaultCalendar } from '../public/calendar' +import { TimeZone } from '../public/timeZone' import { isObjectLike } from './refine' // TODO: move to argParse like timeZoneFromObj? export function calendarFromObj(obj: any): Temporal.CalendarProtocol { - const innerCalendar = obj.calendar - if (innerCalendar === undefined) { + if ('id' in obj) { + if (obj instanceof TimeZone) { + throw RangeError('Cannot be TimeZone') + } return obj } - if (isObjectLike(innerCalendar) && innerCalendar.calendar === undefined) { - return innerCalendar as any + + // a date-like object + if ('calendar' in obj) { + const objCalendar = obj.calendar + + if (typeof objCalendar === 'symbol') { + throw new TypeError('Calendar cannot be symbol') + } else if (isObjectLike(objCalendar)) { + if ('id' in objCalendar) { + if (objCalendar instanceof TimeZone) { + throw RangeError('Cannot be TimeZone') + } + return objCalendar as any + } else { + throw new TypeError('Must be a calendar') + } + } else { // objCalendar converted to string + return new Calendar(objCalendar) + } } - return new Calendar(innerCalendar) + + throw new TypeError('Must be a calendar') // TODO: improve error } export function extractCalendar(input: any): Temporal.CalendarProtocol { diff --git a/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts b/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts index 8558e0cc..5f9cb4b1 100644 --- a/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts +++ b/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts @@ -1,3 +1,4 @@ +import { tryParseDateTime } from '../dateUtils/parse' import { CalendarImpl, getCalendarIDBase } from './calendarImpl' import { GregoryCalendarImpl } from './gregoryCalendarImpl' import { IntlCalendarImpl } from './intlCalendarImpl' @@ -17,6 +18,13 @@ const implCache: { [calendarID: string]: CalendarImpl } = { export function queryCalendarImpl(id: string): CalendarImpl { id = String(id) + + // TODO: more DRY with Calendar::from + const parsedDateTime = tryParseDateTime(id, false, true) // allowZ=true + if (parsedDateTime !== undefined) { + id = parsedDateTime.calendar || 'iso8601' + } + const key = id.toLocaleLowerCase() // lowercase matches isoCalendarID return implCache[key] || diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index d1b61515..006f9e7d 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -265,10 +265,13 @@ function filterFieldsViaCalendar( } function filterFieldsViaWhitelist(objOrFields: any, whitelist: string[]): any { - const filtered = {} as any + /* + needed for "* should be called with null-prototype fields object" + */ + const filtered = Object.create(null) as any for (const propName of whitelist) { - if (objOrFields[propName] !== undefined) { + if (propName in objOrFields) { filtered[propName] = objOrFields[propName] } } diff --git a/packages/temporal-polyfill/src/dateUtils/parse.ts b/packages/temporal-polyfill/src/dateUtils/parse.ts index 94bce594..99a770a2 100644 --- a/packages/temporal-polyfill/src/dateUtils/parse.ts +++ b/packages/temporal-polyfill/src/dateUtils/parse.ts @@ -229,11 +229,19 @@ export function parseNanoAfterDecimal(str: string): number { // general utils function toInt0(input: string | undefined): number { // 0-based - return parseInt(input || '0') + const n = parseInt(input || '0') + if (Object.is(n, -0)) { + throw RangeError('no negative zero') + } + return n } function toInt1(input: string | undefined): number { // 1-based - return parseInt(input || '1') + const n = parseInt(input || '1') + if (Object.is(n, -0)) { + throw RangeError('no negative zero') + } + return n } export function toIntMaybe(input: string | undefined): number | undefined { diff --git a/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts b/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts index 471d8030..7f177ab0 100644 --- a/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts +++ b/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts @@ -37,7 +37,7 @@ const endingRegExpStr = offsetRegExpStr + // 1-8: offset ')?' + '(\\[([^=\\]]+)\\])?' + // 10: timeZone - '(\\[u-ca=([^\\]]+)\\])?' // 12: calendar + '(\\[\\!?u-ca=([^\\]]+)\\])?' // 12: calendar export const yearMonthRegExp = createRegExp(yearMonthRegExpStr + endingRegExpStr) export const monthDayRegExp = createRegExp(monthDayRegExpStr + endingRegExpStr) diff --git a/packages/temporal-polyfill/src/dateUtils/translate.ts b/packages/temporal-polyfill/src/dateUtils/translate.ts index e023b328..4d33aa59 100644 --- a/packages/temporal-polyfill/src/dateUtils/translate.ts +++ b/packages/temporal-polyfill/src/dateUtils/translate.ts @@ -109,6 +109,9 @@ export function addYears( overflowHandling: OverflowHandlingInt, ): LocalDateFields { year += yearsToAdd + if (year < Number.MIN_SAFE_INTEGER || year > Number.MAX_SAFE_INTEGER) { + throw new RangeError('out of range') + } const newMonth = constrainInt(month, 1, calendarImpl.monthsInYear(year), overflowHandling) let newDay = month === newMonth ? day : 1 // month was constrained? reset day newDay = constrainInt(newDay, 1, calendarImpl.daysInMonth(year, newMonth), overflowHandling) @@ -125,10 +128,16 @@ export function addMonths( month += monthsToAdd if (monthsToAdd < 0) { + if (month < Number.MIN_SAFE_INTEGER) { + throw new RangeError('too low') + } while (month < 1) { month += calendarImpl.monthsInYear(--year) } } else { + if (month > Number.MAX_SAFE_INTEGER) { + throw new RangeError('too high') + } let monthsInYear while (month > (monthsInYear = calendarImpl.monthsInYear(year))) { month -= monthsInYear diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index acdedadb..d7a3e624 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -48,6 +48,9 @@ export class Calendar implements Temporal.Calendar { if (isObjectLike(arg)) { return calendarFromObj(arg) } + if (typeof arg === 'symbol') { + throw new TypeError('Calendar cannot be symbol') + } const parsed = tryParseDateTime(String(arg), false, true) // allowZ=true return new Calendar( diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index df48ff67..3bb465c0 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -10,7 +10,7 @@ import { mixinIsoMasterMethods, } from '../dateUtils/abstract' import { compareDateTimes } from '../dateUtils/compare' -import { constrainDateISO } from '../dateUtils/constrain' +import { constrainDateISO, constrainTimeISO } from '../dateUtils/constrain' import { zeroISOTimeFields } from '../dateUtils/dayAndTime' import { diffDates } from '../dateUtils/diff' import { processDateFromFields, processDateWithFields } from '../dateUtils/fromAndWith' @@ -75,7 +75,13 @@ export class PlainDate implements Temporal.PlainDate { return processDateFromFields(arg, options) } - return createDate(refineBaseObj(parseDateTime(String(arg)))) + const parsed = parseDateTime(String(arg)) + + // reject out-of-bound time values if included in the string + // the date values will be checked in constructor + constrainTimeISO(parsed, OVERFLOW_REJECT) + + return createDate(refineBaseObj(parsed)) } static compare(a: PlainDateArg, b: PlainDateArg): Temporal.ComparisonResult { diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/public/plainDateTime.ts index ee5f6fde..80f20b35 100644 --- a/packages/temporal-polyfill/src/public/plainDateTime.ts +++ b/packages/temporal-polyfill/src/public/plainDateTime.ts @@ -81,6 +81,7 @@ export class PlainDateTime implements Temporal.PlainDateTime { isoMicrosecond, isoNanosecond, }, OVERFLOW_REJECT) + const calendar = ensureObj(Calendar, calendarArg) validateDateTime(constrained, calendar.toString()) diff --git a/packages/temporal-polyfill/src/public/temporal.ts b/packages/temporal-polyfill/src/public/temporal.ts index 94f9d6c6..46caea48 100644 --- a/packages/temporal-polyfill/src/public/temporal.ts +++ b/packages/temporal-polyfill/src/public/temporal.ts @@ -25,3 +25,11 @@ export const Temporal = { Now, [Symbol.toStringTag]: 'Temporal', // TODO: make readonly, dry with attachStringTag? } + +for (const key of Object.keys(Temporal)) { + Object.defineProperty(Temporal, key, { + value: (Temporal as any)[key], + enumerable: false, + configurable: true, + }) +} diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/public/zonedDateTime.ts index 7e01b50d..f8b854ae 100644 --- a/packages/temporal-polyfill/src/public/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/public/zonedDateTime.ts @@ -327,6 +327,9 @@ export function buildZonedDateTimeISOFields( ): [ISODateTimeFields, number] { const instant = new Instant(epochNano) // will do validation const offsetNano = timeZone.getOffsetNanosecondsFor(instant) + if (typeof offsetNano !== 'number') { + throw new TypeError('Invalid return value from getOffsetNanosecondsFor') + } const isoFields = epochNanoToISOFields(epochNano.add(offsetNano)) return [isoFields, offsetNano] } From cb896bf20f127aaa5860e5c6501d6d729b62efed Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 22 Mar 2023 22:11:08 -0400 Subject: [PATCH 002/805] inventory of failing Calendar tests --- .../misc/expected-failures.txt | 369 +++++++++++++++--- 1 file changed, 320 insertions(+), 49 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 0a5e5b99..c39a516f 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -7,74 +7,345 @@ # # fullcalendar/temporal notes # - -# -# Calendar -# `pn test262 'Calendar/**'` +# pn test262 'Calendar/**' # -# really specific calling order of object properties -built-ins/Temporal/Calendar/from/calendar-object-operations.js +# opinionated class/prototype/defineProperty +built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js +built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/dateFromFields/builtin.js +built-ins/Temporal/Calendar/prototype/dateFromFields/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/dateUntil/builtin.js +built-ins/Temporal/Calendar/prototype/dateUntil/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/dateUntil/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/day/builtin.js +built-ins/Temporal/Calendar/prototype/day/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/day/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/dayOfYear/builtin.js +built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/builtin.js +built-ins/Temporal/Calendar/prototype/dayOfYear/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js +built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/daysInWeek/builtin.js +built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/daysInWeek/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/daysInYear/builtin.js +built-ins/Temporal/Calendar/prototype/daysInYear/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/daysInYear/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/fields/builtin.js +built-ins/Temporal/Calendar/prototype/fields/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/id/branding.js +built-ins/Temporal/Calendar/prototype/inLeapYear/builtin.js +built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/inLeapYear/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/mergeFields/builtin.js +built-ins/Temporal/Calendar/prototype/mergeFields/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/month/builtin.js +built-ins/Temporal/Calendar/prototype/month/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/month/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/monthCode/builtin.js +built-ins/Temporal/Calendar/prototype/monthCode/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/monthCode/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/builtin.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/monthsInYear/builtin.js +built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/monthsInYear/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/toJSON/builtin.js +built-ins/Temporal/Calendar/prototype/toJSON/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/toJSON/prop-desc.js +built-ins/Temporal/Calendar/prototype/toString/builtin.js +built-ins/Temporal/Calendar/prototype/toString/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js +built-ins/Temporal/Calendar/prototype/weekOfYear/builtin.js +built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/weekOfYear/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/year/builtin.js +built-ins/Temporal/Calendar/prototype/year/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/year/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/builtin.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/not-a-constructor.js +intl402/Temporal/Calendar/prototype/era/builtin.js +intl402/Temporal/Calendar/prototype/era/not-a-constructor.js +intl402/Temporal/Calendar/prototype/eraYear/builtin.js +intl402/Temporal/Calendar/prototype/eraYear/not-a-constructor.js -# when creating calendar from datetime-like, .calendar should not be accessed, -# instead, an internal slot should be accessed +# internal property access +built-ins/Temporal/Calendar/from/calendar-object-operations.js built-ins/Temporal/Calendar/from/calendar-temporal-object.js - -# another required optimization to read internal slots -# checkPlainDateTimeConversionFastPath built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js - -# similar internal-slot-access-only problem built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js built-ins/Temporal/Calendar/prototype/dateAdd/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js +built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-plaindatetime.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-slots.js +built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js +built-ins/Temporal/Calendar/prototype/day/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/id/custom-calendar.js +built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js +built-ins/Temporal/Calendar/prototype/month/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js +built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/year/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js -# I'm going crazy with RangeError vs TypeError +# error types (ex: RangeError vs TypeError) built-ins/Temporal/Calendar/from/calendar-object-invalid.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js +built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/day/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/fields/long-input.js +built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/month/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/year/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js +intl402/Temporal/Calendar/prototype/era/argument-wrong-type.js +intl402/Temporal/Calendar/prototype/eraYear/argument-wrong-type.js +intl402/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js -# refactor parsing for `[u-ca=iso8601][!u-ca=discord]`, higher-level -built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js - -# refactor parsing so that strings that end with timezone info must have at least one time part +# parsing built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js - -# refactor parsing to allow arbitrary notation at end of any string +built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-date-with-utc-offset.js built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/day/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/day/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/day/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/month/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/month/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/month/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/year/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/year/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/year/argument-string-unknown-annotation.js +intl402/Temporal/Calendar/prototype/era/argument-string-calendar-annotation.js +intl402/Temporal/Calendar/prototype/era/argument-string-unknown-annotation.js +intl402/Temporal/Calendar/prototype/eraYear/argument-string-calendar-annotation.js +intl402/Temporal/Calendar/prototype/eraYear/argument-string-date-with-utc-offset.js +intl402/Temporal/Calendar/prototype/eraYear/argument-string-unknown-annotation.js -# i don't know how TimeZone::getOffsetNanosecondsFor WOULDN'T be called while instantiating -# a new ZonedDateTime, unless the spec wants the local fields to be lazy? +# TimeZone::getOffsetNanosecondsFor laziness/incorrectness built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js - -# error needs to be thrown for weird constant timezone offset, but it should happen when -# ZonedDateTime is instantiated built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js -# for debugging: -# class SpecificOffsetTimeZone extends Temporal.TimeZone { -# constructor() { -# super("UTC"); -# } -# getOffsetNanosecondsFor() { -# return 3600_000_000_000.5; -# } -# getPossibleInstantsFor() { -# return []; -# } -# } -# const timeZone = new SpecificOffsetTimeZone() -# const dateTime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone); - -# similar lazy-timezone-offset issue built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js - -# similar built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-convert.js +intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-convert.js +intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -# lame weird prototype stuff -built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js -built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js -built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js - -# NEXT: deal with `throw new TypeError("Must be a calendar");` +# Legit Calendar bugs +# +# monthCode +built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js +intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js +intl402/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js +intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js +# +# monthDayFromFields +intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js +# +# yearMonthFromFields +intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js +# +# out-of-range +built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +intl402/Temporal/Calendar/prototype/era/argument-string-date-with-utc-offset.js +intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +# +# calendars must match +built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/monthCode/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js +# +# Calendr::dateUntil +built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js +# +# Calendar::fields +built-ins/Temporal/Calendar/prototype/fields/argument-iterable-not-array.js +built-ins/Temporal/Calendar/prototype/fields/reverse.js +built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js +built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js +built-ins/Temporal/Calendar/prototype/fields/long-input.js +built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js +# +# Calendar::mergeFields +built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js +built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js +built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js +intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js +intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js +# +# Calendar id +# +intl402/Temporal/Calendar/calendar-case-insensitive.js +intl402/Temporal/Calendar/from/calendar-case-insensitive.js +# +# Calendar::yearOfWeek (not implemented) +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-leap-second.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-number.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-case-insensitive.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-instance-does-not-get-calendar-property.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-leap-second.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-number.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-string.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-year-zero.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-critical-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-invalid.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-time-zone.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-separators.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-zone-annotation.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-with-utc-designator.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-slots.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/basic.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/branding.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/builtin.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-datefromfields-called-with-options-undefined.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-fields-iterable.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/cross-year.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/length.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js From fd126abb690e6962a7b7ee968f5f884922a004ab Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 23 Mar 2023 14:14:38 -0400 Subject: [PATCH 003/805] add know timezone failures --- .../misc/expected-failures.txt | 115 ++++++++++++++++-- 1 file changed, 103 insertions(+), 12 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index c39a516f..7029a582 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -8,9 +8,10 @@ # fullcalendar/temporal notes # # pn test262 'Calendar/**' +# pn test262 'TimeZone/**' # -# opinionated class/prototype/defineProperty +# opinionated class/prototype/descriptor built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js @@ -74,6 +75,16 @@ intl402/Temporal/Calendar/prototype/era/builtin.js intl402/Temporal/Calendar/prototype/era/not-a-constructor.js intl402/Temporal/Calendar/prototype/eraYear/builtin.js intl402/Temporal/Calendar/prototype/eraYear/not-a-constructor.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-fields-iterable.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-fields-iterable.js +built-ins/Temporal/TimeZone/prototype/id/branding.js +built-ins/Temporal/TimeZone/prototype/toJSON/branding.js +built-ins/Temporal/TimeZone/prototype/toJSON/builtin.js +built-ins/Temporal/TimeZone/prototype/toJSON/name.js +built-ins/Temporal/TimeZone/prototype/toJSON/not-a-constructor.js +built-ins/Temporal/TimeZone/prototype/toJSON/prop-desc.js +built-ins/Temporal/TimeZone/prototype/toStringTag/prop-desc.js # internal property access built-ins/Temporal/Calendar/from/calendar-object-operations.js @@ -97,6 +108,21 @@ built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/year/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js +built-ins/Temporal/TimeZone/from/timezone-instance-does-not-get-timeZone-property.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-plaindate.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-temporal-object.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js +built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-zoneddatetime.js +built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-zoneddatetime.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-zoneddatetime.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-zoneddatetime.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-temporal-object.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-plaindate.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-temporal-object.js +built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-zoneddatetime.js +built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js +built-ins/Temporal/TimeZone/prototype/toJSON/tostring-call.js +built-ins/Temporal/TimeZone/prototype/toJSON/tostring-undefined-custom.js # error types (ex: RangeError vs TypeError) built-ins/Temporal/Calendar/from/calendar-object-invalid.js @@ -123,6 +149,19 @@ built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js intl402/Temporal/Calendar/prototype/era/argument-wrong-type.js intl402/Temporal/Calendar/prototype/eraYear/argument-wrong-type.js intl402/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js +built-ins/Temporal/TimeZone/from/argument-primitive.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-not-datetime.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-not-absolute-getOffsetNanosecondsFor-override.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-not-datetime.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-wrong-type.js # parsing built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js @@ -172,6 +211,28 @@ intl402/Temporal/Calendar/prototype/era/argument-string-unknown-annotation.js intl402/Temporal/Calendar/prototype/eraYear/argument-string-calendar-annotation.js intl402/Temporal/Calendar/prototype/eraYear/argument-string-date-with-utc-offset.js intl402/Temporal/Calendar/prototype/eraYear/argument-string-unknown-annotation.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-calendar-annotation.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-date-with-utc-offset.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-unknown-annotation.js +built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-calendar-annotation.js +built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-date-with-utc-offset.js +built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-unknown-annotation.js +built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-calendar-annotation.js +built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-date-with-utc-offset.js +built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-unknown-annotation.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-calendar-annotation.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-date-with-utc-offset.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-unknown-annotation.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-calendar-annotation.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-date-with-utc-offset.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-unknown-annotation.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-calendar-annotation.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-date-with-utc-offset.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-unknown-annotation.js +built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-calendar-annotation.js +built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js +built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-unknown-annotation.js +intl402/Temporal/TimeZone/from/timezone-string-datetime.js # TimeZone::getOffsetNanosecondsFor laziness/incorrectness built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js @@ -223,9 +284,14 @@ intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffse intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-convert.js intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -# Legit Calendar bugs # +# Legit bugs +# + # monthCode built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js @@ -236,13 +302,13 @@ built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js -# + # monthDayFromFields intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js -# + # yearMonthFromFields intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js -# + # out-of-range built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js @@ -276,7 +342,22 @@ intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffse intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -# +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string-limits.js +built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string-limits.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js + # calendars must match built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js @@ -284,10 +365,10 @@ built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/monthCode/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js -# + # Calendr::dateUntil built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js -# + # Calendar::fields built-ins/Temporal/Calendar/prototype/fields/argument-iterable-not-array.js built-ins/Temporal/Calendar/prototype/fields/reverse.js @@ -295,19 +376,18 @@ built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js built-ins/Temporal/Calendar/prototype/fields/long-input.js built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js -# + # Calendar::mergeFields built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js -# + # Calendar id -# intl402/Temporal/Calendar/calendar-case-insensitive.js intl402/Temporal/Calendar/from/calendar-case-insensitive.js -# + # Calendar::yearOfWeek (not implemented) built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-leap-second.js @@ -349,3 +429,14 @@ built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js + +# TimeZone parsing +built-ins/Temporal/TimeZone/from/timezone-string-datetime.js +built-ins/Temporal/TimeZone/from/timezone-string-leap-second.js +built-ins/Temporal/TimeZone/from/timezone-string-multiple-offsets.js +built-ins/Temporal/TimeZone/from/timezone-wrong-type.js + +# TimeZone transitions +intl402/Temporal/TimeZone/prototype/getNextTransition/subtract-second-and-nanosecond-from-last-transition.js +intl402/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/nanoseconds-subtracted-or-added-at-dst-transition.js +staging/Temporal/TimeZone/old/getInstantFor.js From 142b5246212a834008781a52c467132bae6be6c5 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 23 Mar 2023 17:44:04 -0400 Subject: [PATCH 004/805] more testing notes --- packages/temporal-polyfill/misc/NOTES.txt | 191 ++++++++++++++++++ .../misc/expected-failures.txt | 9 +- 2 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 packages/temporal-polyfill/misc/NOTES.txt diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/misc/NOTES.txt new file mode 100644 index 00000000..b087cd68 --- /dev/null +++ b/packages/temporal-polyfill/misc/NOTES.txt @@ -0,0 +1,191 @@ + +opinionated class/prototype/descriptor +-------------------------------------- + +failing on es5-compiled tests. also borked with ensureThisContext + assert.sameValue( + Temporal.Calendar.prototype.dateAdd.hasOwnProperty("prototype"), + false, + "prototype property" + ); + +remove ensureThisContext and then check this-context in EACH METHOD + will be like ensureObj calls. won't be that bad + +for calendar-fields-iterable, don't worry about weird iterable protocol, + just ensure calls to Calendar::fields use [...yoyoyo] + should fix everything + + +Internal Access +--------------- + +meta: fix Calendar parsing first!!! + +Calendar::from + "has outer.calendar" + "get outer.calendar" + "has inner.calendar" + "get inner.toString" + "call inner.toString" + + ToTemporalCalendar: (calendarLike) => { + if (ES.Type(calendarLike) === 'Object') { + if (ES.IsTemporalCalendar(calendarLike)) { + return calendarLike; // fast optimization + } + if (HasSlot(calendarLike, CALENDAR)) { + return GetSlot(calendarLike, CALENDAR); // optimization avoids calling .calendar! + } + if (ES.IsTemporalTimeZone(calendarLike)) { + throw new RangeError('Expected a calendar object but received a Temporal.TimeZone'); + } + if ('calendar' NOT-IN calendarLike)) { + return calendarLike; // assume object is a CalendarProtocol + } + + // assume object is datetime-like (but less formal b/c doesnt have slot)... + calendarLike = calendarLike.calendar; + + // same object-parsing as above but without optimizations + if (ES.Type(calendarLike) === 'Object') { + if (ES.IsTemporalTimeZone(calendarLike)) { + throw new RangeError('Expected a calendar object as the calendar property but received a Temporal.TimeZone'); + } + if ('calendar' NOT-IN calendarLike) { + return calendarLike; + } + } + } + // string parsing of calendarLike... + } + + +TypeError vs RangeError +----------------------- + +Temporal.Calendar.from DOCS + - If the value is another Temporal.Calendar object, + or object implementing the calendar protocol, + the same object is returned + - If the value is another Temporal object that carries a calendar or an object with a calendar + property, such as a Temporal.ZonedDateTime, the object's calendar is returned + - Any other value is converted to a string + +Calendar::from (accepts ID or object with calendar property) + assert.throws(RangeError, () => Temporal.Calendar.from({ calendar: "local" })); + --- invalid ISO 8601 string: local + assert.throws(RangeError, () => Temporal.Calendar.from({ calendar: { calendar: "iso8601" } })); + --- invalid ISO 8601 string: [object Object] --- way too nested + RangeError (as well as within { calendar: }) + null + true + "" + 1 + 1n + new Temporal.TimeZone("UTC") --- explicitly disallowed + TypeError (as well as within { calendar: }) + Symbol + +OVERFLOW/DISAMBIGUATION options + RangeError (all below convert to strings) + null + true + false + 2 + 2n + {} + TypeError + Symbol + +PlainDate::from (accepts bag) + RangeError + undefined + null + true + "" + 1 + 1n + TypeError + Symbol() + {} --- required property 'day' missing or undefined + Temporal.PlainDate - a "function" --- same + Temporal.PlainDate.prototype --- invalid receiver (brand check) + +PlainDateTime::from (accepts bag) + RangeError + undefined + null + true + "" + 5 + 5n + TypeError + Symbol() + { year: 2020 } --- required property 'day' missing or undefined + +Instant::from + RangeError + undefined + null + true + "", + 1 + 19761118 + 1n + {}, --- invalid ISO 8601 string: [object Object] + Temporal.Instant + TypeError + Symbol + Temporal.Instant.prototype --- will throw TypeError on toString b/c of branding + +TimeZone::from + RangeError + undefined, + null, + true, + "string", + "local", + "Z", + "-00:00[UTC]", + "+00:01.1", + "-01.1", + "1994-11-05T08:15:30+25:00", + "1994-11-05T13:15:30-25:00", + 7, + 4.2, + 12n, + TypeError + Symbol() + Success + {} --- just returns the object itself + + +parsing +------- + +smarter non-regexp parser +parse arbitrary ending [matter] + + +TimeZone::getOffsetNanosecondsFor laziness/incorrectness +-------------------------------------------------------- + +*-not-callable fix is easy + make sure getOffsetNanosecondsFor is callable first, otherwise throw TypeError + seems like we're not calling at all + +*-wrong-type fix is easy + ensure what's returned from getOffsetNanosecondsFor is legit + +what!? + class TZ extends Temporal.TimeZone { + constructor() { super("UTC") } + getOffsetNanosecondsFor(arg) { + console.log('CALLED IT!') + return super.getOffsetNanosecondsFor(arg) + } + } + d = new Temporal.ZonedDateTime(0n, new TZ()) + + // js-temporal polyfill calls getOffsetNanosecondsFor twice!!! diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 7029a582..5988adfc 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -136,8 +136,6 @@ built-ins/Temporal/Calendar/prototype/dayOfYear/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/daysInWeek/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/daysInYear/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/fields/long-input.js -built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js built-ins/Temporal/Calendar/prototype/inLeapYear/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/month/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/monthCode/argument-wrong-type.js @@ -148,7 +146,6 @@ built-ins/Temporal/Calendar/prototype/year/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js intl402/Temporal/Calendar/prototype/era/argument-wrong-type.js intl402/Temporal/Calendar/prototype/eraYear/argument-wrong-type.js -intl402/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js built-ins/Temporal/TimeZone/from/argument-primitive.js built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-not-datetime.js built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-wrong-type.js @@ -236,9 +233,7 @@ intl402/Temporal/TimeZone/from/timezone-string-datetime.js # TimeZone::getOffsetNanosecondsFor laziness/incorrectness built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js @@ -357,6 +352,8 @@ built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnano built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js # calendars must match built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js @@ -376,6 +373,7 @@ built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js built-ins/Temporal/Calendar/prototype/fields/long-input.js built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js +built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js # Calendar::mergeFields built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js @@ -429,6 +427,7 @@ built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js +intl402/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js # TimeZone parsing built-ins/Temporal/TimeZone/from/timezone-string-datetime.js From 39a964ae241c2ed46313d6f5cbed4bd90e470a8a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 12:54:09 -0400 Subject: [PATCH 005/805] fix bugs with Calendar::fields --- .../misc/expected-failures.txt | 19 ------------------- .../src/dateUtils/fromAndWith.ts | 13 +++++++++++-- .../temporal-polyfill/src/public/calendar.ts | 9 +++++++-- .../temporal-polyfill/src/public/plainDate.ts | 2 +- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 5988adfc..9d36f4a9 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -13,49 +13,37 @@ # opinionated class/prototype/descriptor built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js -built-ins/Temporal/Calendar/prototype/dateAdd/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js built-ins/Temporal/Calendar/prototype/dateFromFields/builtin.js built-ins/Temporal/Calendar/prototype/dateFromFields/not-a-constructor.js built-ins/Temporal/Calendar/prototype/dateUntil/builtin.js -built-ins/Temporal/Calendar/prototype/dateUntil/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/dateUntil/not-a-constructor.js built-ins/Temporal/Calendar/prototype/day/builtin.js -built-ins/Temporal/Calendar/prototype/day/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/day/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/dayOfWeek/not-a-constructor.js built-ins/Temporal/Calendar/prototype/dayOfYear/builtin.js -built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/dayOfWeek/builtin.js built-ins/Temporal/Calendar/prototype/dayOfYear/not-a-constructor.js built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js -built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js built-ins/Temporal/Calendar/prototype/daysInWeek/builtin.js -built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/daysInWeek/not-a-constructor.js built-ins/Temporal/Calendar/prototype/daysInYear/builtin.js -built-ins/Temporal/Calendar/prototype/daysInYear/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/daysInYear/not-a-constructor.js built-ins/Temporal/Calendar/prototype/fields/builtin.js built-ins/Temporal/Calendar/prototype/fields/not-a-constructor.js built-ins/Temporal/Calendar/prototype/id/branding.js built-ins/Temporal/Calendar/prototype/inLeapYear/builtin.js -built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/inLeapYear/not-a-constructor.js built-ins/Temporal/Calendar/prototype/mergeFields/builtin.js built-ins/Temporal/Calendar/prototype/mergeFields/not-a-constructor.js built-ins/Temporal/Calendar/prototype/month/builtin.js -built-ins/Temporal/Calendar/prototype/month/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/month/not-a-constructor.js built-ins/Temporal/Calendar/prototype/monthCode/builtin.js -built-ins/Temporal/Calendar/prototype/monthCode/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/monthCode/not-a-constructor.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/builtin.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/not-a-constructor.js built-ins/Temporal/Calendar/prototype/monthsInYear/builtin.js -built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/monthsInYear/not-a-constructor.js built-ins/Temporal/Calendar/prototype/toJSON/builtin.js built-ins/Temporal/Calendar/prototype/toJSON/not-a-constructor.js @@ -64,10 +52,8 @@ built-ins/Temporal/Calendar/prototype/toString/builtin.js built-ins/Temporal/Calendar/prototype/toString/not-a-constructor.js built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js built-ins/Temporal/Calendar/prototype/weekOfYear/builtin.js -built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/weekOfYear/not-a-constructor.js built-ins/Temporal/Calendar/prototype/year/builtin.js -built-ins/Temporal/Calendar/prototype/year/calendar-fields-iterable.js built-ins/Temporal/Calendar/prototype/year/not-a-constructor.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/builtin.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/not-a-constructor.js @@ -75,9 +61,7 @@ intl402/Temporal/Calendar/prototype/era/builtin.js intl402/Temporal/Calendar/prototype/era/not-a-constructor.js intl402/Temporal/Calendar/prototype/eraYear/builtin.js intl402/Temporal/Calendar/prototype/eraYear/not-a-constructor.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-fields-iterable.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-fields-iterable.js built-ins/Temporal/TimeZone/prototype/id/branding.js built-ins/Temporal/TimeZone/prototype/toJSON/branding.js built-ins/Temporal/TimeZone/prototype/toJSON/builtin.js @@ -367,8 +351,6 @@ built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # Calendar::fields -built-ins/Temporal/Calendar/prototype/fields/argument-iterable-not-array.js -built-ins/Temporal/Calendar/prototype/fields/reverse.js built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js built-ins/Temporal/Calendar/prototype/fields/long-input.js @@ -411,7 +393,6 @@ built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-slots.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js built-ins/Temporal/Calendar/prototype/yearOfWeek/basic.js diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 006f9e7d..3c8af959 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -252,9 +252,18 @@ function filterFieldsViaCalendar( ): any { let fieldNames = Object.keys(fieldMap) + // HACK: Calendar::fields doesn't like to accept era/eraYear + // instead, the fields() method of the Calendar will inject it + // TODO: adjust callers of this function + fieldNames = fieldNames.filter((fieldName) => fieldName !== 'era' && fieldName !== 'eraYear') + if (calendar.fields) { - // convert Iterable to string[]... better way? - fieldNames = Array.prototype.slice.call(calendar.fields(fieldNames)) + // conveniently orders what tests expect (day/month/monthCode/year) + fieldNames.sort() + + // convert to array and/or copy (done twice?) + // (convert `fieldNames` result to Iterable as well?) + fieldNames = [...calendar.fields(fieldNames)] } else { // a Calendar 'protocol' // filter by method names diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index d7a3e624..116ceb4e 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -349,9 +349,14 @@ export class Calendar implements Temporal.Calendar { Given a date-type's core field names, returns the field names that should be given to Calendar::yearMonthFromFields/monthDayFromFields/dateFromFields */ - // TODO: for inFields, use Iterable fields(inFields: string[]): string[] { - return inFields.slice() // copy + const outFields = [...inFields] // convert to array and/or copy (handles iterators) + + if (this.toString() !== 'iso8601' && outFields.indexOf('year') !== -1) { + outFields.push('era', 'eraYear') + } + + return outFields } /* diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 3bb465c0..b03fb53d 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -71,7 +71,7 @@ export class PlainDate implements Temporal.PlainDate { return createDate(arg.getISOFields()) // optimization } - if (typeof arg === 'object') { + if (typeof arg === 'object') { // TODO: ensure not null return processDateFromFields(arg, options) } From ba4339c4558e26b67fec95c4b2ee9024db12e11e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 12:56:00 -0400 Subject: [PATCH 006/805] kill ensureThisContext --- .../src/argParse/thisContext.ts | 50 ------------------- .../temporal-polyfill/src/public/calendar.ts | 3 -- 2 files changed, 53 deletions(-) delete mode 100644 packages/temporal-polyfill/src/argParse/thisContext.ts diff --git a/packages/temporal-polyfill/src/argParse/thisContext.ts b/packages/temporal-polyfill/src/argParse/thisContext.ts deleted file mode 100644 index 311b447c..00000000 --- a/packages/temporal-polyfill/src/argParse/thisContext.ts +++ /dev/null @@ -1,50 +0,0 @@ - -// TODO: apply to all other types of objects -export function ensureThisContext( - ObjClass: { prototype: Obj }, -): void { - const proto = ObjClass.prototype as any - - Object.getOwnPropertyNames(ObjClass.prototype).forEach((methodName: string) => { - if (methodName !== 'constructor') { - // not a getter - if (!Reflect.getOwnPropertyDescriptor(proto, methodName)?.get) { - const origMethod = proto[methodName] - - if (typeof origMethod === 'function') { // necessary? - // eslint-disable-next-line func-style - const newMethod = function(this: Obj) { - // https://stackoverflow.com/questions/367768/how-to-detect-if-a-function-is-called-as-constructor - if (new.target) { - throw new TypeError('Cannot call as constructor') - } - - if (!(this instanceof (ObjClass as any))) { - throw new TypeError(`this-context must be a ${proto[Symbol.toStringTag]}`) - } - // eslint-disable-next-line prefer-rest-params - return origMethod.apply(this, arguments as any) - } - - Object.defineProperty(newMethod, 'name', { - value: methodName, - // necessary options for a read-only property - writable: false, - enumerable: false, - configurable: true, - }) - - Object.defineProperty(newMethod, 'length', { - value: origMethod.length, - // necessary options for a read-only property - writable: false, - enumerable: false, - configurable: true, - }) - - proto[methodName] = newMethod - } - } - } - }) -} diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 116ceb4e..33fb8af7 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -3,7 +3,6 @@ import { calendarFromObj, ensureCalendarsEqual, getCommonCalendar } from '../arg import { dateFieldMap, monthDayFieldMap, yearMonthFieldMap } from '../argParse/fieldStr' import { parseOverflowOption } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike, refineFields } from '../argParse/refine' -import { ensureThisContext } from '../argParse/thisContext' import { parseUnit } from '../argParse/unitStr' import { checkEpochMilliBuggy } from '../calendarImpl/bugs' import { CalendarImpl, CalendarImplFields, convertEraYear } from '../calendarImpl/calendarImpl' @@ -379,8 +378,6 @@ mixinJsonMethods(Calendar) // export interface Calendar { [Symbol.toStringTag]: 'Temporal.Calendar' } attachStringTag(Calendar, 'Calendar') -// -ensureThisContext(Calendar) export function createDefaultCalendar(): Calendar { return new Calendar(isoCalendarID) From 07371bb95f9dafe3e0043d7c4df515c03d6ae2f1 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 13:25:25 -0400 Subject: [PATCH 007/805] needReceiver --- .../src/dateUtils/abstract.ts | 18 +++- .../temporal-polyfill/src/dateUtils/mixins.ts | 13 ++- .../temporal-polyfill/src/public/calendar.ts | 31 ++++++- .../temporal-polyfill/src/public/duration.ts | 88 +++++++++++++++---- .../temporal-polyfill/src/public/instant.ts | 13 ++- .../temporal-polyfill/src/public/plainDate.ts | 15 ++++ .../src/public/plainDateTime.ts | 39 +++++++- .../src/public/plainMonthDay.ts | 6 ++ .../temporal-polyfill/src/public/plainTime.ts | 13 +++ .../src/public/plainYearMonth.ts | 10 +++ .../temporal-polyfill/src/public/timeZone.ts | 12 ++- .../src/public/zonedDateTime.ts | 71 +++++++++++++-- 12 files changed, 291 insertions(+), 38 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index c209ec0c..9ff1155a 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -6,6 +6,15 @@ export const formatFactoryFactorySymbol = Symbol() // Functions +export function needReceiver( + ObjClass: { new(...constructorArgs: any[]): Obj }, + arg: Obj, +): void { + if (!(arg instanceof ObjClass)) { + throw new TypeError('Invalid receiver') + } +} + export function ensureObj( ObjClass: { new(...constructorArgs: any[]): Obj @@ -28,9 +37,10 @@ export interface JsonMethods { } export function mixinJsonMethods( - ObjClass: { prototype: Obj }, + ObjClass: { new(...constructorArgs: any[]): Obj }, ): void { ObjClass.prototype.toJSON = function(this: Obj) { + needReceiver(ObjClass, this) return this.toString() } } @@ -40,11 +50,12 @@ export interface NoValueMethods extends JsonMethods { } export function mixinNoValueMethods( - ObjClass: { prototype: Obj }, + ObjClass: { new(...constructorArgs: any[]): Obj }, ): void { mixinJsonMethods(ObjClass) ObjClass.prototype.valueOf = function(this: Obj) { + needReceiver(ObjClass, this) throw new Error('Cannot convert object using valueOf') } } @@ -56,11 +67,12 @@ export interface IsoMasterMethods extends NoValueMethods { const [getISOFields, setISOFields] = createWeakMap, any>() export function mixinIsoMasterMethods>( - ObjClass: { prototype: Obj }, + ObjClass: { new(...constructorArgs: any[]): Obj }, ): void { mixinNoValueMethods(ObjClass) ObjClass.prototype.getISOFields = function(this: Obj) { + needReceiver(ObjClass, this) return getISOFields(this) } } diff --git a/packages/temporal-polyfill/src/dateUtils/mixins.ts b/packages/temporal-polyfill/src/dateUtils/mixins.ts index 531afabe..193020c2 100644 --- a/packages/temporal-polyfill/src/dateUtils/mixins.ts +++ b/packages/temporal-polyfill/src/dateUtils/mixins.ts @@ -3,6 +3,7 @@ import { unitNames } from '../argParse/unitStr' import { LargeInt } from '../utils/largeInt' import { attachGetters, strArrayToHash } from '../utils/obj' import { capitalizeFirstLetter } from '../utils/string' +import { needReceiver } from './abstract' import { DateISOInstance } from './calendar' import { epochNanoSymbol } from './epoch' import { nanoInMicro, nanoInMilli, nanoInSecond } from './units' @@ -17,19 +18,23 @@ export interface ComputedEpochFields { } export function mixinEpochFields( - ObjClass: { prototype: Obj }, + ObjClass: { new(...constructorArgs: any[]): Obj }, ): void { attachGetters(ObjClass, { epochNanoseconds(): bigint { + needReceiver(ObjClass, this) return this[epochNanoSymbol].toBigInt() }, epochMicroseconds(): bigint { + needReceiver(ObjClass, this) return this[epochNanoSymbol].div(nanoInMicro).toBigInt() }, epochMilliseconds(): number { + needReceiver(ObjClass, this) return this[epochNanoSymbol].div(nanoInMilli).toNumber() }, epochSeconds(): number { + needReceiver(ObjClass, this) return this[epochNanoSymbol].div(nanoInSecond).toNumber() }, }) @@ -46,7 +51,7 @@ for (const unitName of unitNames) { // always mixes in `calendar` export function mixinISOFields( - ObjClass: { prototype: Obj }, + ObjClass: { new(...constructorArgs: any[]): Obj }, unitNames: Temporal.DateTimeUnit[] = [], ): void { attachGetters( @@ -54,6 +59,7 @@ export function mixinISOFields( strArrayToHash( (unitNames as string[]).concat('calendar'), (propName) => function(this: Obj) { + needReceiver(ObjClass, this) return this.getISOFields()[isoFieldMap[propName]] }, ), @@ -114,12 +120,13 @@ export const dateCalendarFields: (keyof DateCalendarFields)[] = [ ] export function mixinCalendarFields( - ObjClass: { prototype: Obj }, + ObjClass: { new(...constructorArgs: any[]): Obj }, propNames: (keyof DateCalendarFields)[], ): void { attachGetters( ObjClass, strArrayToHash(propNames, (propName) => function(this: Obj) { + needReceiver(ObjClass, this) const value = this.calendar[propName as keyof DateCalendarFields]( this as Temporal.PlainDateLike, ) diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 33fb8af7..19eb3a90 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -8,7 +8,7 @@ import { checkEpochMilliBuggy } from '../calendarImpl/bugs' import { CalendarImpl, CalendarImplFields, convertEraYear } from '../calendarImpl/calendarImpl' import { queryCalendarImpl } from '../calendarImpl/calendarImplQuery' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' -import { JsonMethods, ensureObj, mixinJsonMethods } from '../dateUtils/abstract' +import { JsonMethods, ensureObj, mixinJsonMethods, needReceiver } from '../dateUtils/abstract' import { computeDayOfYear, computeDaysInYear, @@ -66,6 +66,7 @@ export class Calendar implements Temporal.Calendar { era( arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, ): string | undefined { + needReceiver(Calendar, this) const isoFields = getExistingDateISOFields(arg, true) // disallowMonthDay=true return isoToEpochNanoSafe( getImpl(this), @@ -78,6 +79,7 @@ export class Calendar implements Temporal.Calendar { eraYear( arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, ): number | undefined { + needReceiver(Calendar, this) const isoFields = getExistingDateISOFields(arg, true) // disallowMonthDay=true return isoToEpochNanoSafe( getImpl(this), @@ -95,6 +97,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const isoFields = getExistingDateISOFields(arg, true) // disallowMonthDay=true return isoToEpochNanoSafe( getImpl(this), @@ -113,6 +116,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const isoFields = getExistingDateISOFields(arg, true) // disallowMonthDay=true return isoToEpochNanoSafe( getImpl(this), @@ -131,6 +135,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): string { + needReceiver(Calendar, this) const fields = queryDateFields(arg, this) return getImpl(this).monthCode(fields.month, fields.year) } @@ -143,6 +148,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const isoFields = getExistingDateISOFields(arg) return isoToEpochNanoSafe( getImpl(this), @@ -155,6 +161,7 @@ export class Calendar implements Temporal.Calendar { dayOfWeek( arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const isoFields = getExistingDateISOFields(arg, true) // disallowMonthDay=true return computeISODayOfWeek(isoFields.isoYear, isoFields.isoMonth, isoFields.isoDay) } @@ -162,6 +169,7 @@ export class Calendar implements Temporal.Calendar { dayOfYear( arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const fields = queryDateFields(arg, this, true) // disallowMonthDay=true return computeDayOfYear(getImpl(this), fields.year, fields.month, fields.day) } @@ -169,6 +177,7 @@ export class Calendar implements Temporal.Calendar { weekOfYear( arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const isoFields = getExistingDateISOFields(arg, true) // disallowMonthDay=true return computeWeekOfISOYear( isoFields.isoYear, @@ -182,6 +191,8 @@ export class Calendar implements Temporal.Calendar { daysInWeek( arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) + // will throw error if invalid type getExistingDateISOFields(arg, true) // disallowMonthDay=true @@ -197,6 +208,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const fields = queryDateFields(arg, this, true) // disallowMonthDay=true return getImpl(this).daysInMonth(fields.year, fields.month) } @@ -209,6 +221,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const fields = queryDateFields(arg, this, true) // disallowMonthDay=true return computeDaysInYear(getImpl(this), fields.year) } @@ -221,6 +234,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): number { + needReceiver(Calendar, this) const calFields = queryDateFields(arg, this, true) // disallowMonthDay=true return getImpl(this).monthsInYear(calFields.year) } @@ -233,6 +247,7 @@ export class Calendar implements Temporal.Calendar { | Temporal.PlainDateLike | string, ): boolean { + needReceiver(Calendar, this) return getImpl(this).inLeapYear(this.year(arg)) } @@ -240,6 +255,8 @@ export class Calendar implements Temporal.Calendar { fields: Temporal.YearOrEraAndEraYear & Temporal.MonthOrMonthCode & { day: number }, options?: Temporal.AssignmentOptions, ): Temporal.PlainDate { + needReceiver(Calendar, this) + const refinedFields = refineFields(fields, dateFieldMap) const isoFields = queryDateISOFields(refinedFields, getImpl(this), options) @@ -255,6 +272,8 @@ export class Calendar implements Temporal.Calendar { fields: Temporal.YearOrEraAndEraYear & Temporal.MonthOrMonthCode, options?: Temporal.AssignmentOptions, ): Temporal.PlainYearMonth { + needReceiver(Calendar, this) + const refinedFields = refineFields(fields, yearMonthFieldMap) const isoFields = queryDateISOFields({ ...refinedFields, day: 1 }, getImpl(this), options) @@ -270,6 +289,8 @@ export class Calendar implements Temporal.Calendar { fields: Temporal.MonthCodeOrMonthAndYear & { day: number }, options?: Temporal.AssignmentOptions, ): Temporal.PlainMonthDay { + needReceiver(Calendar, this) + const impl = getImpl(this) let { era, eraYear, year, month, monthCode, day } = refineFields(fields, monthDayFieldMap) @@ -310,6 +331,8 @@ export class Calendar implements Temporal.Calendar { durationArg: DurationArg, options?: Temporal.ArithmeticOptions, ): Temporal.PlainDate { + needReceiver(Calendar, this) + const impl = getImpl(this) const date = ensureObj(PlainDate, dateArg, options) const duration = ensureObj(Duration, durationArg) @@ -329,6 +352,8 @@ export class Calendar implements Temporal.Calendar { dateArg1: PlainDateArg, options?: Temporal.DifferenceOptions<'year' | 'month' | 'week' | 'day'>, ): Temporal.Duration { + needReceiver(Calendar, this) + const impl = getImpl(this) const d0 = ensureObj(PlainDate, dateArg0) const d1 = ensureObj(PlainDate, dateArg1) @@ -349,6 +374,8 @@ export class Calendar implements Temporal.Calendar { given to Calendar::yearMonthFromFields/monthDayFromFields/dateFromFields */ fields(inFields: string[]): string[] { + needReceiver(Calendar, this) + const outFields = [...inFields] // convert to array and/or copy (handles iterators) if (this.toString() !== 'iso8601' && outFields.indexOf('year') !== -1) { @@ -364,10 +391,12 @@ export class Calendar implements Temporal.Calendar { */ // TODO: use Record mergeFields(baseFields: any, additionalFields: any): any { + needReceiver(Calendar, this) return mergeCalFields(baseFields, additionalFields) } toString(): string { + needReceiver(Calendar, this) return getImpl(this).id } } diff --git a/packages/temporal-polyfill/src/public/duration.ts b/packages/temporal-polyfill/src/public/duration.ts index f35484fc..29fd2c7b 100644 --- a/packages/temporal-polyfill/src/public/duration.ts +++ b/packages/temporal-polyfill/src/public/duration.ts @@ -3,7 +3,7 @@ import { parseDiffOptions } from '../argParse/diffOptions' import { DurationToStringUnitInt, parseTimeToStringOptions } from '../argParse/isoFormatOptions' import { ensureOptionsObj, isObjectLike } from '../argParse/refine' import { parseTotalConfig } from '../argParse/totalOptions' -import { NoValueMethods, ensureObj, mixinNoValueMethods } from '../dateUtils/abstract' +import { NoValueMethods, ensureObj, mixinNoValueMethods, needReceiver } from '../dateUtils/abstract' import { compareDurations } from '../dateUtils/compare' import { DurationFields, @@ -84,20 +84,68 @@ export class Duration implements Temporal.Duration { ) } - get years(): number { return getFields(this).years } - get months(): number { return getFields(this).months } - get weeks(): number { return getFields(this).weeks } - get days(): number { return getFields(this).days } - get hours(): number { return getFields(this).hours } - get minutes(): number { return getFields(this).minutes } - get seconds(): number { return getFields(this).seconds } - get milliseconds(): number { return getFields(this).milliseconds } - get microseconds(): number { return getFields(this).microseconds } - get nanoseconds(): number { return getFields(this).nanoseconds } - get sign(): Temporal.ComparisonResult { return getFields(this).sign } - get blank(): boolean { return !this.sign } + get years(): number { + needReceiver(Duration, this) + return getFields(this).years + } + + get months(): number { + needReceiver(Duration, this) + return getFields(this).months + } + + get weeks(): number { + needReceiver(Duration, this) + return getFields(this).weeks + } + + get days(): number { + needReceiver(Duration, this) + return getFields(this).days + } + + get hours(): number { + needReceiver(Duration, this) + return getFields(this).hours + } + + get minutes(): number { + needReceiver(Duration, this) + return getFields(this).minutes + } + + get seconds(): number { + needReceiver(Duration, this) + return getFields(this).seconds + } + + get milliseconds(): number { + needReceiver(Duration, this) + return getFields(this).milliseconds + } + + get microseconds(): number { + needReceiver(Duration, this) + return getFields(this).microseconds + } + + get nanoseconds(): number { + needReceiver(Duration, this) + return getFields(this).nanoseconds + } + + get sign(): Temporal.ComparisonResult { + needReceiver(Duration, this) + return getFields(this).sign + } + + get blank(): boolean { + needReceiver(Duration, this) + return !this.sign + } with(fields: Temporal.DurationLike): Temporal.Duration { + needReceiver(Duration, this) return createDuration({ ...getFields(this), ...processDurationFields(fields), @@ -105,22 +153,28 @@ export class Duration implements Temporal.Duration { } negated(): Temporal.Duration { + needReceiver(Duration, this) return createDuration(negateDuration(getFields(this))) } abs(): Temporal.Duration { + needReceiver(Duration, this) return createDuration(absDuration(getFields(this))) } add(other: DurationArg, options?: Temporal.DurationArithmeticOptions): Temporal.Duration { + needReceiver(Duration, this) return addDurations(this, ensureObj(Duration, other), options) } subtract(other: DurationArg, options?: Temporal.DurationArithmeticOptions): Temporal.Duration { + needReceiver(Duration, this) return addDurations(this, negateDuration(ensureObj(Duration, other)), options) } round(options: Temporal.DurationRoundTo): Temporal.Duration { + needReceiver(Duration, this) + const optionsObj: DurationRoundingOptions = typeof options === 'string' ? { smallestUnit: options } : options @@ -150,6 +204,8 @@ export class Duration implements Temporal.Duration { } total(options: Temporal.DurationTotalOf): number { + needReceiver(Duration, this) + const totalConfig = parseTotalConfig(options) const relativeTo = extractRelativeTo(totalConfig.relativeTo) @@ -162,13 +218,13 @@ export class Duration implements Temporal.Duration { } toString(options?: Temporal.ToStringPrecisionOptions): string { - const formatConfig = parseTimeToStringOptions( - options, SECOND, - ) + needReceiver(Duration, this) + const formatConfig = parseTimeToStringOptions(options, SECOND) return formatDurationISO(getFields(this), formatConfig) } toLocaleString(_locales?: LocalesArg, _options?: unknown): string { + needReceiver(Duration, this) // the spec recommends this in the absence of Intl.DurationFormat return this.toString() } diff --git a/packages/temporal-polyfill/src/public/instant.ts b/packages/temporal-polyfill/src/public/instant.ts index cb4d1420..1a04a498 100644 --- a/packages/temporal-polyfill/src/public/instant.ts +++ b/packages/temporal-polyfill/src/public/instant.ts @@ -3,7 +3,7 @@ import { parseDiffOptions } from '../argParse/diffOptions' import { OVERFLOW_REJECT } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike } from '../argParse/refine' import { parseRoundingOptions } from '../argParse/roundingOptions' -import { NoValueMethods, ensureObj, mixinNoValueMethods } from '../dateUtils/abstract' +import { NoValueMethods, ensureObj, mixinNoValueMethods, needReceiver } from '../dateUtils/abstract' import { compareEpochObjs } from '../dateUtils/compare' import { constrainDateTimeISO } from '../dateUtils/constrain' import { diffEpochNanos } from '../dateUtils/diff' @@ -100,26 +100,32 @@ export class Instant implements Temporal.Instant { } add(durationArg: TranslateArg): Temporal.Instant { + needReceiver(Instant, this) return new Instant( translateEpochNano(this[epochNanoSymbol], ensureObj(Duration, durationArg)), ) } subtract(durationArg: TranslateArg): Temporal.Instant { + needReceiver(Instant, this) return new Instant( translateEpochNano(this[epochNanoSymbol], negateDuration(ensureObj(Duration, durationArg))), ) } until(other: InstantArg, options?: DiffOptions): Temporal.Duration { + needReceiver(Instant, this) return diffInstants(this, ensureObj(Instant, other), options) } since(other: InstantArg, options?: DiffOptions): Temporal.Duration { + needReceiver(Instant, this) return diffInstants(ensureObj(Instant, other), this, options) } round(options: RoundOptions): Temporal.Instant { + needReceiver(Instant, this) + const roundingConfig = parseRoundingOptions(options, NANOSECOND, HOUR, true) return new Instant( @@ -128,10 +134,12 @@ export class Instant implements Temporal.Instant { } equals(other: InstantArg): boolean { + needReceiver(Instant, this) return !compareEpochObjs(this, ensureObj(Instant, other)) } toString(options?: Temporal.InstantToStringOptions): string { + needReceiver(Instant, this) const timeZoneArg = ensureOptionsObj(options).timeZone const zonedDateTime = this.toZonedDateTimeISO(timeZoneArg ?? 'UTC') // TODO: don't use util!!! return zonedDateTime.toString({ @@ -142,10 +150,13 @@ export class Instant implements Temporal.Instant { } toZonedDateTimeISO(timeZoneArg: Temporal.TimeZoneLike): Temporal.ZonedDateTime { + needReceiver(Instant, this) return new ZonedDateTime(this.epochNanoseconds, timeZoneArg) } toZonedDateTime(options: ToZonedDateTimeOptions): Temporal.ZonedDateTime { + needReceiver(Instant, this) + // TODO: more official options-processing utils for this if (!isObjectLike(options)) { throw new TypeError('Must specify options') diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index b03fb53d..5cd6003d 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -8,6 +8,7 @@ import { ensureObj, initIsoMaster, mixinIsoMasterMethods, + needReceiver, } from '../dateUtils/abstract' import { compareDateTimes } from '../dateUtils/compare' import { constrainDateISO, constrainTimeISO } from '../dateUtils/constrain' @@ -92,10 +93,12 @@ export class PlainDate implements Temporal.PlainDate { } with(fields: Temporal.PlainDateLike, options?: Temporal.AssignmentOptions): Temporal.PlainDate { + needReceiver(PlainDate, this) return processDateWithFields(this, fields, options) } withCalendar(calendarArg: Temporal.CalendarLike): Temporal.PlainDate { + needReceiver(PlainDate, this) const isoFields = this.getISOFields() return new PlainDate( isoFields.isoYear, @@ -106,14 +109,17 @@ export class PlainDate implements Temporal.PlainDate { } add(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { + needReceiver(PlainDate, this) return this.calendar.dateAdd(this, durationArg, options) } subtract(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { + needReceiver(PlainDate, this) return this.calendar.dateAdd(this, ensureObj(Duration, durationArg).negated(), options) } until(other: PlainDateArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainDate, this) return diffPlainDates( this, ensureObj(PlainDate, other), @@ -123,6 +129,7 @@ export class PlainDate implements Temporal.PlainDate { } since(other: PlainDateArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainDate, this) return diffPlainDates( this, ensureObj(PlainDate, other), @@ -132,10 +139,13 @@ export class PlainDate implements Temporal.PlainDate { } equals(other: PlainDateArg): boolean { + needReceiver(PlainDate, this) return !compareDateTimes(this, ensureObj(PlainDate, other)) } toString(options?: Temporal.ShowCalendarOption): string { + needReceiver(PlainDate, this) + const calendarDisplay = parseCalendarDisplayOption(options) const fields = this.getISOFields() @@ -144,6 +154,8 @@ export class PlainDate implements Temporal.PlainDate { } toZonedDateTime(options: ToZonedDateTimeOptions): Temporal.ZonedDateTime { + needReceiver(PlainDate, this) + const refinedOptions = processToZonedDateTimeOptions(options) const timeZone = ensureObj(TimeZone, refinedOptions.timeZone) const plainTime = refinedOptions.plainTime === undefined @@ -158,6 +170,7 @@ export class PlainDate implements Temporal.PlainDate { } toPlainDateTime(timeArg?: PlainTimeArg): Temporal.PlainDateTime { + needReceiver(PlainDate, this) return createDateTime({ ...this.getISOFields(), ...ensureLooseTime(timeArg).getISOFields(), @@ -165,10 +178,12 @@ export class PlainDate implements Temporal.PlainDate { } toPlainYearMonth(): Temporal.PlainYearMonth { + needReceiver(PlainDate, this) return createYearMonth(this.getISOFields()) } toPlainMonthDay(): Temporal.PlainMonthDay { + needReceiver(PlainDate, this) return this.calendar.monthDayFromFields(this) } } diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/public/plainDateTime.ts index 80f20b35..d719f346 100644 --- a/packages/temporal-polyfill/src/public/plainDateTime.ts +++ b/packages/temporal-polyfill/src/public/plainDateTime.ts @@ -12,6 +12,7 @@ import { ensureObj, initIsoMaster, mixinIsoMasterMethods, + needReceiver, } from '../dateUtils/abstract' import { compareDateTimes, dateTimesEqual } from '../dateUtils/compare' import { constrainDateTimeISO } from '../dateUtils/constrain' @@ -115,6 +116,7 @@ export class PlainDateTime implements Temporal.PlainDateTime { fields: Temporal.PlainDateTimeLike, options?: Temporal.AssignmentOptions, ): Temporal.PlainDateTime { + needReceiver(PlainDateTime, this) const overflowHandling = parseOverflowOption(options) return createDateTime( processDateTimeWithFields(this, fields, overflowHandling, options), @@ -122,6 +124,7 @@ export class PlainDateTime implements Temporal.PlainDateTime { } withPlainDate(dateArg: PlainDateArg): Temporal.PlainDateTime { + needReceiver(PlainDateTime, this) const date = ensureObj(PlainDate, dateArg) return createDateTime({ ...this.getISOFields(), // provides time fields @@ -131,6 +134,7 @@ export class PlainDateTime implements Temporal.PlainDateTime { } withPlainTime(timeArg?: PlainTimeArg): Temporal.PlainDateTime { + needReceiver(PlainDateTime, this) return createDateTime({ ...this.getISOFields(), // provides date & calendar fields ...ensureLooseTime(timeArg).getISOFields(), @@ -138,6 +142,7 @@ export class PlainDateTime implements Temporal.PlainDateTime { } withCalendar(calendarArg: Temporal.CalendarLike): Temporal.PlainDateTime { + needReceiver(PlainDateTime, this) return createDateTime({ ...this.getISOFields(), calendar: ensureObj(Calendar, calendarArg), @@ -145,14 +150,17 @@ export class PlainDateTime implements Temporal.PlainDateTime { } add(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDateTime { + needReceiver(PlainDateTime, this) return translatePlainDateTime(this, ensureObj(Duration, durationArg), options) } subtract(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDateTime { + needReceiver(PlainDateTime, this) return translatePlainDateTime(this, negateDuration(ensureObj(Duration, durationArg)), options) } until(other: PlainDateTimeArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainDateTime, this) return diffPlainDateTimes( this, ensureObj(PlainDateTime, other), @@ -162,6 +170,7 @@ export class PlainDateTime implements Temporal.PlainDateTime { } since(other: PlainDateTimeArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainDateTime, this) return diffPlainDateTimes( this, ensureObj(PlainDateTime, other), @@ -171,6 +180,8 @@ export class PlainDateTime implements Temporal.PlainDateTime { } round(options: RoundOptions): Temporal.PlainDateTime { + needReceiver(PlainDateTime, this) + const roundingConfig = parseRoundingOptions( options, NANOSECOND, // minUnit @@ -184,10 +195,13 @@ export class PlainDateTime implements Temporal.PlainDateTime { } equals(other: PlainDateTimeArg): boolean { + needReceiver(PlainDateTime, this) return dateTimesEqual(this, ensureObj(PlainDateTime, other)) } toString(options?: Temporal.CalendarTypeToStringOptions): string { + needReceiver(PlainDateTime, this) + const formatConfig = parseTimeToStringOptions(options) const calendarDisplay = parseCalendarDisplayOption(options) const isoFields = roundDateTime(this.getISOFields(), formatConfig) @@ -200,6 +214,8 @@ export class PlainDateTime implements Temporal.PlainDateTime { timeZoneArg: Temporal.TimeZoneLike, options?: Temporal.ToInstantOptions, ): Temporal.ZonedDateTime { + needReceiver(PlainDateTime, this) + const timeZone = ensureObj(TimeZone, timeZoneArg) const instant = getInstantFor(timeZone, this, parseDisambigOption(options)) @@ -207,10 +223,25 @@ export class PlainDateTime implements Temporal.PlainDateTime { return new ZonedDateTime(instant.epochNanoseconds, timeZone, this.calendar) } - toPlainYearMonth(): Temporal.PlainYearMonth { return createYearMonth(this.getISOFields()) } - toPlainMonthDay(): Temporal.PlainMonthDay { return this.calendar.monthDayFromFields(this) } - toPlainDate(): Temporal.PlainDate { return createDate(this.getISOFields()) } - toPlainTime(): Temporal.PlainTime { return createTime(this.getISOFields()) } + toPlainYearMonth(): Temporal.PlainYearMonth { + needReceiver(PlainDateTime, this) + return createYearMonth(this.getISOFields()) + } + + toPlainMonthDay(): Temporal.PlainMonthDay { + needReceiver(PlainDateTime, this) + return this.calendar.monthDayFromFields(this) + } + + toPlainDate(): Temporal.PlainDate { + needReceiver(PlainDateTime, this) + return createDate(this.getISOFields()) + } + + toPlainTime(): Temporal.PlainTime { + needReceiver(PlainDateTime, this) + return createTime(this.getISOFields()) + } } // mixins diff --git a/packages/temporal-polyfill/src/public/plainMonthDay.ts b/packages/temporal-polyfill/src/public/plainMonthDay.ts index 68efd1fe..a7d106d3 100644 --- a/packages/temporal-polyfill/src/public/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/public/plainMonthDay.ts @@ -7,6 +7,7 @@ import { ensureObj, initIsoMaster, mixinIsoMasterMethods, + needReceiver, } from '../dateUtils/abstract' import { compareDateTimes } from '../dateUtils/compare' import { constrainDateISO } from '../dateUtils/constrain' @@ -68,14 +69,18 @@ export class PlainMonthDay implements Temporal.PlainMonthDay { fields: Temporal.PlainMonthDayLike, options?: Temporal.AssignmentOptions, ): Temporal.PlainMonthDay { + needReceiver(PlainMonthDay, this) return processMonthDayWithFields(this, fields, options) } equals(other: PlainMonthDayArg): boolean { + needReceiver(PlainMonthDay, this) return !compareDateTimes(this, ensureObj(PlainMonthDay, other)) } toString(options?: Temporal.ShowCalendarOption): string { + needReceiver(PlainMonthDay, this) + const fields = this.getISOFields() const calendarID = fields.calendar.toString() // see note in formatCalendarID const calendarDisplay = parseCalendarDisplayOption(options) @@ -88,6 +93,7 @@ export class PlainMonthDay implements Temporal.PlainMonthDay { } toPlainDate(fields: { year: number }): Temporal.PlainDate { + needReceiver(PlainMonthDay, this) return this.calendar.dateFromFields({ year: fields.year, monthCode: this.monthCode, diff --git a/packages/temporal-polyfill/src/public/plainTime.ts b/packages/temporal-polyfill/src/public/plainTime.ts index ab17bf43..8b3f61f2 100644 --- a/packages/temporal-polyfill/src/public/plainTime.ts +++ b/packages/temporal-polyfill/src/public/plainTime.ts @@ -9,6 +9,7 @@ import { ensureObj, initIsoMaster, mixinIsoMasterMethods, + needReceiver, } from '../dateUtils/abstract' import { compareTimes } from '../dateUtils/compare' import { constrainTimeISO } from '../dateUtils/constrain' @@ -89,28 +90,35 @@ export class PlainTime implements Temporal.PlainTime { } with(fields: Temporal.PlainTimeLike, options?: Temporal.AssignmentOptions): Temporal.PlainTime { + needReceiver(PlainTime, this) return createTime( processTimeWithFields(this, fields, parseOverflowOption(options)), ) } add(durationArg: Temporal.Duration | Temporal.DurationLike | string): Temporal.PlainTime { + needReceiver(PlainTime, this) return translatePlainTime(this, ensureObj(Duration, durationArg)) } subtract(durationArg: Temporal.Duration | Temporal.DurationLike | string): Temporal.PlainTime { + needReceiver(PlainTime, this) return translatePlainTime(this, negateDuration(ensureObj(Duration, durationArg))) } until(other: PlainTimeArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainTime, this) return diffPlainTimes(this, ensureObj(PlainTime, other), options) } since(other: PlainTimeArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainTime, this) return diffPlainTimes(ensureObj(PlainTime, other), this, options) } round(options: RoundOptions): Temporal.PlainTime { + needReceiver(PlainTime, this) + const roundingConfig = parseRoundingOptions( options, NANOSECOND, // minUnit @@ -121,16 +129,20 @@ export class PlainTime implements Temporal.PlainTime { } equals(other: Temporal.PlainTime | Temporal.PlainTimeLike | string): boolean { + needReceiver(PlainTime, this) return !compareTimes(this, ensureObj(PlainTime, other)) } toString(options?: Temporal.ToStringPrecisionOptions): string { + needReceiver(PlainTime, this) const formatConfig = parseTimeToStringOptions(options) const roundedISOFields: ISOTimeFields = roundTime(this.getISOFields(), formatConfig) return formatTimeISO(roundedISOFields, formatConfig) } toZonedDateTime(options: ToZonedDateTimeOptions): Temporal.ZonedDateTime { + needReceiver(PlainTime, this) + // TODO: ensure options object first? const plainDate = ensureObj(PlainDate, options.plainDate) const timeZone = ensureObj(TimeZone, options.timeZone) @@ -143,6 +155,7 @@ export class PlainTime implements Temporal.PlainTime { } toPlainDateTime(dateArg: PlainDateArg): Temporal.PlainDateTime { + needReceiver(PlainTime, this) return ensureObj(PlainDate, dateArg).toPlainDateTime(this) } } diff --git a/packages/temporal-polyfill/src/public/plainYearMonth.ts b/packages/temporal-polyfill/src/public/plainYearMonth.ts index cb0de8bb..d8d964bd 100644 --- a/packages/temporal-polyfill/src/public/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/public/plainYearMonth.ts @@ -9,6 +9,7 @@ import { ensureObj, initIsoMaster, mixinIsoMasterMethods, + needReceiver, } from '../dateUtils/abstract' import { compareDateTimes } from '../dateUtils/compare' import { constrainDateISO } from '../dateUtils/constrain' @@ -97,6 +98,7 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { fields: Temporal.PlainYearMonthLike, options?: Temporal.AssignmentOptions, ): Temporal.PlainYearMonth { + needReceiver(PlainYearMonth, this) return processYearMonthWithFields(this, fields, options) } @@ -104,6 +106,7 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { durationArg: DurationArg, options?: Temporal.ArithmeticOptions, ): Temporal.PlainYearMonth { + needReceiver(PlainYearMonth, this) return translatePlainYearMonth(this, ensureObj(Duration, durationArg), options) } @@ -111,22 +114,28 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { durationArg: DurationArg, options?: Temporal.ArithmeticOptions, ): Temporal.PlainYearMonth { + needReceiver(PlainYearMonth, this) return translatePlainYearMonth(this, negateDuration(ensureObj(Duration, durationArg)), options) } until(other: PlainYearMonthArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainYearMonth, this) return diffPlainYearMonths(this, ensureObj(PlainYearMonth, other), false, options) } since(other: PlainYearMonthArg, options?: DiffOptions): Temporal.Duration { + needReceiver(PlainYearMonth, this) return diffPlainYearMonths(this, ensureObj(PlainYearMonth, other), true, options) } equals(other: PlainYearMonthArg): boolean { + needReceiver(PlainYearMonth, this) return !compareDateTimes(this, ensureObj(PlainYearMonth, other)) } toString(options?: Temporal.ShowCalendarOption): string { + needReceiver(PlainYearMonth, this) + const fields = this.getISOFields() const calendarID = fields.calendar.toString() // see note in formatCalendarID const calendarDisplay = parseCalendarDisplayOption(options) @@ -139,6 +148,7 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { } toPlainDate(fields: { day: number }): Temporal.PlainDate { + needReceiver(PlainYearMonth, this) return this.calendar.dateFromFields({ year: this.year, month: this.month, diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index f7acc659..3163feab 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -2,7 +2,7 @@ import { Temporal } from 'temporal-spec' import { parseDisambigOption } from '../argParse/disambig' import { isObjectLike } from '../argParse/refine' import { timeZoneFromObj } from '../argParse/timeZone' -import { JsonMethods, ensureObj, mixinJsonMethods } from '../dateUtils/abstract' +import { JsonMethods, ensureObj, mixinJsonMethods, needReceiver } from '../dateUtils/abstract' import { epochNanoSymbol, epochNanoToISOFields, isoFieldsToEpochNano } from '../dateUtils/epoch' import { formatOffsetISO } from '../dateUtils/isoFormat' import { attachStringTag } from '../dateUtils/mixins' @@ -53,14 +53,17 @@ export class TimeZone implements Temporal.TimeZone { } get id(): string { + needReceiver(TimeZone, this) return this.toString() } getOffsetStringFor(instantArg: InstantArg): string { + needReceiver(TimeZone, this) return formatOffsetISO(this.getOffsetNanosecondsFor(instantArg)) } getOffsetNanosecondsFor(instantArg: InstantArg): number { + needReceiver(TimeZone, this) const instant = ensureObj(Instant, instantArg) return getImpl(this).getOffset(instant[epochNanoSymbol]) } @@ -69,6 +72,7 @@ export class TimeZone implements Temporal.TimeZone { instantArg: InstantArg, calendarArg: Temporal.CalendarLike = createDefaultCalendar(), ): Temporal.PlainDateTime { + needReceiver(TimeZone, this) const instant = ensureObj(Instant, instantArg) const isoFields = epochNanoToISOFields( instant[epochNanoSymbol].add(this.getOffsetNanosecondsFor(instant)), @@ -83,10 +87,13 @@ export class TimeZone implements Temporal.TimeZone { dateTimeArg: PlainDateTimeArg, options?: Temporal.ToInstantOptions, ): Temporal.Instant { + needReceiver(TimeZone, this) return getInstantFor(this, ensureObj(PlainDateTime, dateTimeArg), parseDisambigOption(options)) } getPossibleInstantsFor(dateTimeArg: PlainDateTimeArg): Temporal.Instant[] { + needReceiver(TimeZone, this) + const isoFields = ensureObj(PlainDateTime, dateTimeArg).getISOFields() const zoneNano = isoFieldsToEpochNano(isoFields) const possibleOffsetNanos = getImpl(this).getPossibleOffsets(zoneNano) @@ -97,6 +104,7 @@ export class TimeZone implements Temporal.TimeZone { } getPreviousTransition(instantArg: InstantArg): Temporal.Instant | null { + needReceiver(TimeZone, this) const instant = ensureObj(Instant, instantArg) const rawTransition = getImpl(this).getTransition(instant[epochNanoSymbol], -1) if (rawTransition) { @@ -106,6 +114,7 @@ export class TimeZone implements Temporal.TimeZone { } getNextTransition(instantArg: InstantArg): Temporal.Instant | null { + needReceiver(TimeZone, this) const instant = ensureObj(Instant, instantArg) const rawTransition = getImpl(this).getTransition(instant[epochNanoSymbol], 1) if (rawTransition) { @@ -115,6 +124,7 @@ export class TimeZone implements Temporal.TimeZone { } toString(): string { + needReceiver(TimeZone, this) return getImpl(this).id } } diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/public/zonedDateTime.ts index f8b854ae..66f99d6f 100644 --- a/packages/temporal-polyfill/src/public/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/public/zonedDateTime.ts @@ -20,6 +20,7 @@ import { ensureObj, initIsoMaster, mixinIsoMasterMethods, + needReceiver, } from '../dateUtils/abstract' import { compareEpochObjs, zonedDateTimesEqual } from '../dateUtils/compare' import { DayTimeUnit, zeroISOTimeFields } from '../dateUtils/dayAndTime' @@ -154,14 +155,27 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { ) } - get timeZone(): Temporal.TimeZoneProtocol { return this.getISOFields().timeZone } - get offsetNanoseconds(): number { return this[offsetNanoSymbol] } - get offset(): string { return this.getISOFields().offset } + get timeZone(): Temporal.TimeZoneProtocol { + needReceiver(ZonedDateTime, this) + return this.getISOFields().timeZone + } + + get offsetNanoseconds(): number { + needReceiver(ZonedDateTime, this) + return this[offsetNanoSymbol] + } + + get offset(): string { + needReceiver(ZonedDateTime, this) + return this.getISOFields().offset + } with( fields: Temporal.ZonedDateTimeLike, options?: Temporal.AssignmentOptions, ): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) + parseDisambigOption(options) // for validation const overflowHandling = parseOverflowOption(options) // for validation (?) const offsetHandling = parseOffsetHandlingOption(options, OFFSET_PREFER) @@ -171,6 +185,8 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { } withPlainDate(dateArg: PlainDateArg): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) + const date = ensureObj(PlainDate, dateArg) const dateTime = date.toPlainDateTime(this) // timeArg=this const { timeZone } = this @@ -184,6 +200,7 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { } withPlainTime(timeArg?: PlainTimeArg): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) return createZonedDateTimeFromFields({ ...this.getISOFields(), ...( @@ -195,6 +212,7 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { } withCalendar(calendarArg: Temporal.CalendarLike): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) return new ZonedDateTime( this.epochNanoseconds, this.timeZone, @@ -203,6 +221,7 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { } withTimeZone(timeZoneArg: Temporal.TimeZoneLike): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) return new ZonedDateTime( this.epochNanoseconds, timeZoneArg, @@ -211,22 +230,28 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { } add(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) return translateZonedDateTime(this, ensureObj(Duration, durationArg), options) } subtract(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) return translateZonedDateTime(this, negateDuration(ensureObj(Duration, durationArg)), options) } until(other: ZonedDateTimeArg, options?: DiffOptions): Temporal.Duration { + needReceiver(ZonedDateTime, this) return diffZonedDateTimes(this, ensureObj(ZonedDateTime, other), false, options) } since(other: ZonedDateTimeArg, options?: DiffOptions): Temporal.Duration { + needReceiver(ZonedDateTime, this) return diffZonedDateTimes(this, ensureObj(ZonedDateTime, other), true, options) } round(options: RoundOptions): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) + const roundingConfig = parseRoundingOptions( options, NANOSECOND, // minUnit @@ -237,10 +262,12 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { } equals(other: ZonedDateTimeArg): boolean { + needReceiver(ZonedDateTime, this) return zonedDateTimesEqual(this, ensureObj(ZonedDateTime, other)) } startOfDay(): Temporal.ZonedDateTime { + needReceiver(ZonedDateTime, this) return createZonedDateTimeFromFields({ ...this.getISOFields(), ...zeroISOTimeFields, @@ -250,10 +277,13 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { // TODO: turn into a lazy-getter, like what mixinCalendarFields does get hoursInDay(): number { + needReceiver(ZonedDateTime, this) return computeNanoInDay(this.getISOFields()) / nanoInHour } toString(options?: Temporal.CalendarTypeToStringOptions): string { + needReceiver(ZonedDateTime, this) + const formatConfig = parseTimeToStringOptions(options) const offsetDisplay = parseOffsetDisplayOption(options) const timeZoneDisplay = parseTimeZoneDisplayOption(options) @@ -269,12 +299,35 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { formatCalendarID(this.calendar.toString(), calendarDisplay) } - toPlainYearMonth(): Temporal.PlainYearMonth { return createYearMonth(this.getISOFields()) } - toPlainMonthDay(): Temporal.PlainMonthDay { return this.calendar.monthDayFromFields(this) } - toPlainDateTime(): Temporal.PlainDateTime { return createDateTime(this.getISOFields()) } - toPlainDate(): Temporal.PlainDate { return createDate(this.getISOFields()) } - toPlainTime(): Temporal.PlainTime { return createTime(this.getISOFields()) } - toInstant(): Temporal.Instant { return new Instant(this.epochNanoseconds) } + toPlainYearMonth(): Temporal.PlainYearMonth { + needReceiver(ZonedDateTime, this) + return createYearMonth(this.getISOFields()) + } + + toPlainMonthDay(): Temporal.PlainMonthDay { + needReceiver(ZonedDateTime, this) + return this.calendar.monthDayFromFields(this) + } + + toPlainDateTime(): Temporal.PlainDateTime { + needReceiver(ZonedDateTime, this) + return createDateTime(this.getISOFields()) + } + + toPlainDate(): Temporal.PlainDate { + needReceiver(ZonedDateTime, this) + return createDate(this.getISOFields()) + } + + toPlainTime(): Temporal.PlainTime { + needReceiver(ZonedDateTime, this) + return createTime(this.getISOFields()) + } + + toInstant(): Temporal.Instant { + needReceiver(ZonedDateTime, this) + return new Instant(this.epochNanoseconds) + } } // mixins From 32891373ee677dc4f1098945dac7328eecea78d4 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 13:39:12 -0400 Subject: [PATCH 008/805] fix prototype calling problems --- .../misc/expected-failures.txt | 51 ------------------- .../src/dateUtils/abstract.ts | 27 ++++++---- 2 files changed, 18 insertions(+), 60 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 9d36f4a9..31d493b4 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -12,61 +12,10 @@ # # opinionated class/prototype/descriptor -built-ins/Temporal/Calendar/prototype/dateAdd/builtin.js -built-ins/Temporal/Calendar/prototype/dateAdd/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/dateFromFields/builtin.js -built-ins/Temporal/Calendar/prototype/dateFromFields/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/dateUntil/builtin.js -built-ins/Temporal/Calendar/prototype/dateUntil/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/day/builtin.js -built-ins/Temporal/Calendar/prototype/day/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/dayOfYear/builtin.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/builtin.js -built-ins/Temporal/Calendar/prototype/dayOfYear/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js -built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/daysInWeek/builtin.js -built-ins/Temporal/Calendar/prototype/daysInWeek/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/daysInYear/builtin.js -built-ins/Temporal/Calendar/prototype/daysInYear/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/fields/builtin.js -built-ins/Temporal/Calendar/prototype/fields/not-a-constructor.js built-ins/Temporal/Calendar/prototype/id/branding.js -built-ins/Temporal/Calendar/prototype/inLeapYear/builtin.js -built-ins/Temporal/Calendar/prototype/inLeapYear/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/mergeFields/builtin.js -built-ins/Temporal/Calendar/prototype/mergeFields/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/month/builtin.js -built-ins/Temporal/Calendar/prototype/month/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/monthCode/builtin.js -built-ins/Temporal/Calendar/prototype/monthCode/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/builtin.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/monthsInYear/builtin.js -built-ins/Temporal/Calendar/prototype/monthsInYear/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/toJSON/builtin.js -built-ins/Temporal/Calendar/prototype/toJSON/not-a-constructor.js built-ins/Temporal/Calendar/prototype/toJSON/prop-desc.js -built-ins/Temporal/Calendar/prototype/toString/builtin.js -built-ins/Temporal/Calendar/prototype/toString/not-a-constructor.js built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js -built-ins/Temporal/Calendar/prototype/weekOfYear/builtin.js -built-ins/Temporal/Calendar/prototype/weekOfYear/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/year/builtin.js -built-ins/Temporal/Calendar/prototype/year/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/builtin.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/not-a-constructor.js -intl402/Temporal/Calendar/prototype/era/builtin.js -intl402/Temporal/Calendar/prototype/era/not-a-constructor.js -intl402/Temporal/Calendar/prototype/eraYear/builtin.js -intl402/Temporal/Calendar/prototype/eraYear/not-a-constructor.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/TimeZone/prototype/id/branding.js -built-ins/Temporal/TimeZone/prototype/toJSON/branding.js -built-ins/Temporal/TimeZone/prototype/toJSON/builtin.js -built-ins/Temporal/TimeZone/prototype/toJSON/name.js -built-ins/Temporal/TimeZone/prototype/toJSON/not-a-constructor.js built-ins/Temporal/TimeZone/prototype/toJSON/prop-desc.js built-ins/Temporal/TimeZone/prototype/toStringTag/prop-desc.js diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index 9ff1155a..731214ea 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -39,10 +39,13 @@ export interface JsonMethods { export function mixinJsonMethods( ObjClass: { new(...constructorArgs: any[]): Obj }, ): void { - ObjClass.prototype.toJSON = function(this: Obj) { - needReceiver(ObjClass, this) - return this.toString() + class JsonMixin { + toJSON(this: Obj) { + needReceiver(ObjClass, this) + return this.toString() + } } + ObjClass.prototype.toJSON = JsonMixin.prototype.toJSON } export interface NoValueMethods extends JsonMethods { @@ -54,10 +57,13 @@ export function mixinNoValueMethods( ): void { mixinJsonMethods(ObjClass) - ObjClass.prototype.valueOf = function(this: Obj) { - needReceiver(ObjClass, this) - throw new Error('Cannot convert object using valueOf') + class NoValueMixin { + valueOf(this: Obj) { + needReceiver(ObjClass, this) + throw new Error('Cannot convert object using valueOf') + } } + ObjClass.prototype.valueOf = NoValueMixin.prototype.valueOf } export interface IsoMasterMethods extends NoValueMethods { @@ -71,10 +77,13 @@ export function mixinIsoMasterMethods Date: Fri, 24 Mar 2023 13:57:20 -0400 Subject: [PATCH 009/805] fix mixing descriptors --- .../misc/expected-failures.txt | 6 ++---- .../src/dateUtils/abstract.ts | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 31d493b4..9bf30a93 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -12,11 +12,8 @@ # # opinionated class/prototype/descriptor -built-ins/Temporal/Calendar/prototype/id/branding.js -built-ins/Temporal/Calendar/prototype/toJSON/prop-desc.js built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/TimeZone/prototype/toJSON/prop-desc.js built-ins/Temporal/TimeZone/prototype/toStringTag/prop-desc.js # internal property access @@ -57,7 +54,8 @@ built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js built-ins/Temporal/TimeZone/prototype/toJSON/tostring-call.js built-ins/Temporal/TimeZone/prototype/toJSON/tostring-undefined-custom.js -# error types (ex: RangeError vs TypeError) +# input processing and error types (ex: RangeError vs TypeError) +built-ins/Temporal/Calendar/prototype/id/branding.js built-ins/Temporal/Calendar/from/calendar-object-invalid.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index 731214ea..8810a561 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -45,7 +45,11 @@ export function mixinJsonMethods( return this.toString() } } - ObjClass.prototype.toJSON = JsonMixin.prototype.toJSON + Object.defineProperty(ObjClass.prototype, 'toJSON', { + value: JsonMixin.prototype.toJSON, + writable: true, + configurable: true, + }) } export interface NoValueMethods extends JsonMethods { @@ -63,7 +67,11 @@ export function mixinNoValueMethods( throw new Error('Cannot convert object using valueOf') } } - ObjClass.prototype.valueOf = NoValueMixin.prototype.valueOf + Object.defineProperty(ObjClass.prototype, 'valueOf', { + value: NoValueMixin.prototype.valueOf, + writable: true, + configurable: true, + }) } export interface IsoMasterMethods extends NoValueMethods { @@ -83,7 +91,11 @@ export function mixinIsoMasterMethods Date: Fri, 24 Mar 2023 14:59:08 -0400 Subject: [PATCH 010/805] fix more fields() bugs --- packages/temporal-polyfill/misc/NOTES.txt | 20 ------------------- .../src/dateUtils/fromAndWith.ts | 11 +++++++--- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/misc/NOTES.txt index b087cd68..993c26c0 100644 --- a/packages/temporal-polyfill/misc/NOTES.txt +++ b/packages/temporal-polyfill/misc/NOTES.txt @@ -1,27 +1,7 @@ -opinionated class/prototype/descriptor --------------------------------------- - -failing on es5-compiled tests. also borked with ensureThisContext - assert.sameValue( - Temporal.Calendar.prototype.dateAdd.hasOwnProperty("prototype"), - false, - "prototype property" - ); - -remove ensureThisContext and then check this-context in EACH METHOD - will be like ensureObj calls. won't be that bad - -for calendar-fields-iterable, don't worry about weird iterable protocol, - just ensure calls to Calendar::fields use [...yoyoyo] - should fix everything - - Internal Access --------------- -meta: fix Calendar parsing first!!! - Calendar::from "has outer.calendar" "get outer.calendar" diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 3c8af959..90fe9047 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -66,7 +66,7 @@ function tryDateTimeFromFields( overflowHandling: OverflowHandlingInt, options?: Temporal.AssignmentOptions, ): Temporal.PlainDateTimeISOFields | undefined { - const dateRes = tryDateFromFields(rawFields, options) + const dateRes = tryDateFromFields(rawFields, options, true) const timeRes = tryTimeFromFields(rawFields, overflowHandling) if (dateRes) { @@ -80,9 +80,14 @@ function tryDateTimeFromFields( function tryDateFromFields( rawFields: Temporal.PlainDateLike, options?: Temporal.AssignmentOptions, + doingDateTime?: boolean, ): PlainDate | undefined { const calendar = extractCalendar(rawFields) - const filteredFields = filterFieldsViaCalendar(rawFields, dateFieldMap, calendar) + const filteredFields = filterFieldsViaCalendar( + rawFields, + doingDateTime ? { ...dateFieldMap, ...timeFieldMap } : dateFieldMap, + calendar, + ) if (hasAnyProps(filteredFields)) { return calendar.dateFromFields(filteredFields, options) @@ -258,7 +263,7 @@ function filterFieldsViaCalendar( fieldNames = fieldNames.filter((fieldName) => fieldName !== 'era' && fieldName !== 'eraYear') if (calendar.fields) { - // conveniently orders what tests expect (day/month/monthCode/year) + // Calendar::fields tests always expect alphabetical order fieldNames.sort() // convert to array and/or copy (done twice?) From 52891216dc7cb462bd060e285bf3f10e83c42c9d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 15:03:25 -0400 Subject: [PATCH 011/805] fix toStringTag --- packages/temporal-polyfill/misc/expected-failures.txt | 6 +----- packages/temporal-polyfill/src/dateUtils/mixins.ts | 8 +++++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 9bf30a93..8c3b53a3 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -11,11 +11,6 @@ # pn test262 'TimeZone/**' # -# opinionated class/prototype/descriptor -built-ins/Temporal/Calendar/prototype/toStringTag/prop-desc.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/TimeZone/prototype/toStringTag/prop-desc.js - # internal property access built-ins/Temporal/Calendar/from/calendar-object-operations.js built-ins/Temporal/Calendar/from/calendar-temporal-object.js @@ -213,6 +208,7 @@ intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-geto built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js # # Legit bugs diff --git a/packages/temporal-polyfill/src/dateUtils/mixins.ts b/packages/temporal-polyfill/src/dateUtils/mixins.ts index 193020c2..1687e09c 100644 --- a/packages/temporal-polyfill/src/dateUtils/mixins.ts +++ b/packages/temporal-polyfill/src/dateUtils/mixins.ts @@ -143,5 +143,11 @@ export function mixinCalendarFields( // TODO: make readonly somehow? export function attachStringTag(objOrClass: any, name: string): void { - (objOrClass.prototype || objOrClass)[Symbol.toStringTag] = 'Temporal.' + name + Object.defineProperty( + objOrClass.prototype || objOrClass, + Symbol.toStringTag, { + value: 'Temporal.' + name, + configurable: true, + }, + ) } From b3fb0c1b28b922233a8c3c23bcc52ee582540765 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 16:06:17 -0400 Subject: [PATCH 012/805] implement yearOfWeek --- .../misc/expected-failures.txt | 54 ++++--------------- .../temporal-polyfill/src/dateUtils/mixins.ts | 2 + .../temporal-polyfill/src/dateUtils/week.ts | 35 ++++++++++++ .../temporal-polyfill/src/public/calendar.ts | 16 +++++- packages/temporal-spec/index.d.ts | 5 ++ 5 files changed, 68 insertions(+), 44 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 8c3b53a3..15e46668 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -48,6 +48,7 @@ built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-zoneddateti built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js built-ins/Temporal/TimeZone/prototype/toJSON/tostring-call.js built-ins/Temporal/TimeZone/prototype/toJSON/tostring-undefined-custom.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js # input processing and error types (ex: RangeError vs TypeError) built-ins/Temporal/Calendar/prototype/id/branding.js @@ -85,6 +86,8 @@ built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnano built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-not-datetime.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-wrong-type.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js # parsing built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js @@ -156,6 +159,9 @@ built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-cale built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-unknown-annotation.js intl402/Temporal/TimeZone/from/timezone-string-datetime.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js # TimeZone::getOffsetNanosecondsFor laziness/incorrectness built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js @@ -209,6 +215,9 @@ built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timez built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js # # Legit bugs @@ -272,7 +281,6 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-out-of-range.js @@ -281,6 +289,8 @@ built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatet built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js # calendars must match built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js @@ -311,48 +321,6 @@ intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fiel intl402/Temporal/Calendar/calendar-case-insensitive.js intl402/Temporal/Calendar/from/calendar-case-insensitive.js -# Calendar::yearOfWeek (not implemented) -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-calendar-datefromfields-called-with-null-prototype-fields.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-leap-second.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-number.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-case-insensitive.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-instance-does-not-get-calendar-property.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-leap-second.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-number.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-string.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-propertybag-calendar-year-zero.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-critical-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-invalid.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-multiple-time-zone.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-separators.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-time-zone-annotation.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-with-utc-designator.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-slots.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/basic.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/branding.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/builtin.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-datefromfields-called-with-options-undefined.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-fields-iterable.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/cross-year.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/length.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/name.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/not-a-constructor.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/prop-desc.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/year-zero.js -intl402/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js - # TimeZone parsing built-ins/Temporal/TimeZone/from/timezone-string-datetime.js built-ins/Temporal/TimeZone/from/timezone-string-leap-second.js diff --git a/packages/temporal-polyfill/src/dateUtils/mixins.ts b/packages/temporal-polyfill/src/dateUtils/mixins.ts index 1687e09c..7e085c64 100644 --- a/packages/temporal-polyfill/src/dateUtils/mixins.ts +++ b/packages/temporal-polyfill/src/dateUtils/mixins.ts @@ -91,6 +91,7 @@ export interface DateCalendarFields extends YearMonthCalendarFields { dayOfWeek: number dayOfYear: number weekOfYear: number + yearOfWeek: number } export const yearMonthCalendarFields: (keyof YearMonthCalendarFields)[] = [ @@ -116,6 +117,7 @@ export const dateCalendarFields: (keyof DateCalendarFields)[] = [ 'dayOfWeek', 'dayOfYear', 'weekOfYear', + 'yearOfWeek', 'daysInWeek', ] diff --git a/packages/temporal-polyfill/src/dateUtils/week.ts b/packages/temporal-polyfill/src/dateUtils/week.ts index d5502b40..71ac9730 100644 --- a/packages/temporal-polyfill/src/dateUtils/week.ts +++ b/packages/temporal-polyfill/src/dateUtils/week.ts @@ -5,6 +5,41 @@ import { computeISODayOfWeek } from './epoch' // TODO: fix lots of 1-index problems!!! +// TODO: more DRY +export function computeYearOfISOWeek( + isoYear: number, + isoMonth: number, + isoDay: number, + firstDay: number, + minimalDays: number, +): number { + // Days to ignore till first week + const weekOffset = computeFirstWeekOffset( + isoYear, + firstDay, + minimalDays, + ) + // Current week # + const week = + Math.floor( + (computeDayOfYear(isoCalendarImpl, isoYear, isoMonth, isoDay) - weekOffset - 1) / 7, + ) + 1 + + // Go to previous year if 0 weeks + if (week < 1) { + return isoYear - 1 + } + + const weeksYear = computeWeeksInISOYear(isoYear, firstDay, minimalDays) + + // Go to next year if greater than weeks in current year + if (week > weeksYear) { + return isoYear + 1 + } + + return isoYear +} + export function computeWeekOfISOYear( isoYear: number, isoMonth: number, diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 19eb3a90..37fbb6df 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -22,7 +22,7 @@ import { attachStringTag } from '../dateUtils/mixins' import { tryParseDateTime } from '../dateUtils/parse' import { translateDate } from '../dateUtils/translate' import { DAY, DateUnitInt, YEAR } from '../dateUtils/units' -import { computeWeekOfISOYear } from '../dateUtils/week' +import { computeWeekOfISOYear, computeYearOfISOWeek } from '../dateUtils/week' import { createWeakMap } from '../utils/obj' import { Duration, DurationArg, createDuration } from './duration' import { PlainDate, PlainDateArg } from './plainDate' @@ -188,6 +188,20 @@ export class Calendar implements Temporal.Calendar { ) } + yearOfWeek( + arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, + ): number { + needReceiver(Calendar, this) + const isoFields = getExistingDateISOFields(arg, true) // disallowMonthDay=true + return computeYearOfISOWeek( + isoFields.isoYear, + isoFields.isoMonth, + isoFields.isoDay, + 1, // TODO: document what this means + 4, // " + ) + } + daysInWeek( arg: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainDateLike | string, ): number { diff --git a/packages/temporal-spec/index.d.ts b/packages/temporal-spec/index.d.ts index a5b530b8..adca675c 100644 --- a/packages/temporal-spec/index.d.ts +++ b/packages/temporal-spec/index.d.ts @@ -634,6 +634,7 @@ export namespace Temporal { dayOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; dayOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; weekOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; + yearOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInMonth( date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string @@ -714,6 +715,7 @@ export namespace Temporal { dayOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; dayOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; weekOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; + yearOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInMonth( date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string @@ -799,6 +801,7 @@ export namespace Temporal { readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; + readonly yearOfWeek: number; readonly daysInWeek: number; readonly daysInYear: number; readonly daysInMonth: number; @@ -913,6 +916,7 @@ export namespace Temporal { readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; + readonly yearOfWeek: number; readonly daysInWeek: number; readonly daysInYear: number; readonly daysInMonth: number; @@ -1260,6 +1264,7 @@ export namespace Temporal { readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; + readonly yearOfWeek: number; readonly hoursInDay: number; readonly daysInWeek: number; readonly daysInMonth: number; From 84c5b4f944b30898acc4eb334c9f0447f9ed80cd Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 17:11:46 -0400 Subject: [PATCH 013/805] fixes to ::from --- .../misc/expected-failures.txt | 32 ----------------- .../src/argParse/calendar.ts | 34 ------------------- .../src/argParse/timeZone.ts | 12 ------- .../temporal-polyfill/src/public/calendar.ts | 25 ++++++++++++-- .../temporal-polyfill/src/public/duration.ts | 14 +++++--- .../temporal-polyfill/src/public/instant.ts | 6 +++- .../temporal-polyfill/src/public/plainDate.ts | 8 +++-- .../src/public/plainDateTime.ts | 20 +++++++---- .../src/public/plainMonthDay.ts | 9 +++-- .../temporal-polyfill/src/public/plainTime.ts | 20 +++++++---- .../src/public/plainYearMonth.ts | 9 +++-- .../temporal-polyfill/src/public/timeZone.ts | 15 ++++++-- .../src/public/zonedDateTime.ts | 8 +++-- 13 files changed, 99 insertions(+), 113 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 15e46668..af7e2341 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -52,41 +52,12 @@ built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js # input processing and error types (ex: RangeError vs TypeError) built-ins/Temporal/Calendar/prototype/id/branding.js -built-ins/Temporal/Calendar/from/calendar-object-invalid.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/day/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/month/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/year/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js -intl402/Temporal/Calendar/prototype/era/argument-wrong-type.js -intl402/Temporal/Calendar/prototype/eraYear/argument-wrong-type.js -built-ins/Temporal/TimeZone/from/argument-primitive.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-not-datetime.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-wrong-type.js built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-not-absolute-getOffsetNanosecondsFor-override.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-wrong-type.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-not-datetime.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-wrong-type.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js # parsing @@ -158,7 +129,6 @@ built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-unk built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-calendar-annotation.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-unknown-annotation.js -intl402/Temporal/TimeZone/from/timezone-string-datetime.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js @@ -323,8 +293,6 @@ intl402/Temporal/Calendar/from/calendar-case-insensitive.js # TimeZone parsing built-ins/Temporal/TimeZone/from/timezone-string-datetime.js -built-ins/Temporal/TimeZone/from/timezone-string-leap-second.js -built-ins/Temporal/TimeZone/from/timezone-string-multiple-offsets.js built-ins/Temporal/TimeZone/from/timezone-wrong-type.js # TimeZone transitions diff --git a/packages/temporal-polyfill/src/argParse/calendar.ts b/packages/temporal-polyfill/src/argParse/calendar.ts index dd360911..bb914c24 100644 --- a/packages/temporal-polyfill/src/argParse/calendar.ts +++ b/packages/temporal-polyfill/src/argParse/calendar.ts @@ -2,40 +2,6 @@ import { Temporal } from 'temporal-spec' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' import { ensureObj } from '../dateUtils/abstract' import { Calendar, createDefaultCalendar } from '../public/calendar' -import { TimeZone } from '../public/timeZone' -import { isObjectLike } from './refine' - -// TODO: move to argParse like timeZoneFromObj? -export function calendarFromObj(obj: any): Temporal.CalendarProtocol { - if ('id' in obj) { - if (obj instanceof TimeZone) { - throw RangeError('Cannot be TimeZone') - } - return obj - } - - // a date-like object - if ('calendar' in obj) { - const objCalendar = obj.calendar - - if (typeof objCalendar === 'symbol') { - throw new TypeError('Calendar cannot be symbol') - } else if (isObjectLike(objCalendar)) { - if ('id' in objCalendar) { - if (objCalendar instanceof TimeZone) { - throw RangeError('Cannot be TimeZone') - } - return objCalendar as any - } else { - throw new TypeError('Must be a calendar') - } - } else { // objCalendar converted to string - return new Calendar(objCalendar) - } - } - - throw new TypeError('Must be a calendar') // TODO: improve error -} export function extractCalendar(input: any): Temporal.CalendarProtocol { if (input.calendar === undefined) { diff --git a/packages/temporal-polyfill/src/argParse/timeZone.ts b/packages/temporal-polyfill/src/argParse/timeZone.ts index f22c52c1..7aae8288 100644 --- a/packages/temporal-polyfill/src/argParse/timeZone.ts +++ b/packages/temporal-polyfill/src/argParse/timeZone.ts @@ -1,18 +1,6 @@ import { Temporal } from 'temporal-spec' import { ensureObj } from '../dateUtils/abstract' import { TimeZone } from '../public/timeZone' -import { isObjectLike } from './refine' - -export function timeZoneFromObj(obj: any): Temporal.TimeZoneProtocol { - const innerTimeZone = obj.timeZone - if (innerTimeZone === undefined) { - return obj - } - if (isObjectLike(innerTimeZone) && innerTimeZone.timeZone === undefined) { - return innerTimeZone as any - } - return new TimeZone(innerTimeZone) -} export function extractTimeZone(input: any): Temporal.TimeZoneProtocol { if (input.timeZone === undefined) { diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 37fbb6df..e7c719c2 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -1,5 +1,5 @@ import { Temporal } from 'temporal-spec' -import { calendarFromObj, ensureCalendarsEqual, getCommonCalendar } from '../argParse/calendar' +import { ensureCalendarsEqual, getCommonCalendar } from '../argParse/calendar' import { dateFieldMap, monthDayFieldMap, yearMonthFieldMap } from '../argParse/fieldStr' import { parseOverflowOption } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike, refineFields } from '../argParse/refine' @@ -28,6 +28,7 @@ import { Duration, DurationArg, createDuration } from './duration' import { PlainDate, PlainDateArg } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' +import { TimeZone } from './timeZone' // FYI: the Temporal.CalendarLike type includes `string`, // unlike many other object types @@ -45,12 +46,30 @@ export class Calendar implements Temporal.Calendar { static from(arg: Temporal.CalendarLike): Temporal.CalendarProtocol { if (isObjectLike(arg)) { - return calendarFromObj(arg) + if (arg instanceof Calendar) { + return arg as any + } + if (arg instanceof TimeZone) { + throw new RangeError('Expected a calendar object but received a Temporal.TimeZone') + } + if (!('calendar' in arg)) { + return arg + } else { + arg = arg.calendar + + if (arg instanceof TimeZone) { + throw new RangeError('Expected a calendar object but received a Temporal.TimeZone') + } + if (isObjectLike(arg) && !('calendar' in arg)) { + return arg as any + } + } } + + // parse as string... if (typeof arg === 'symbol') { throw new TypeError('Calendar cannot be symbol') } - const parsed = tryParseDateTime(String(arg), false, true) // allowZ=true return new Calendar( parsed // a date-time string? diff --git a/packages/temporal-polyfill/src/public/duration.ts b/packages/temporal-polyfill/src/public/duration.ts index 29fd2c7b..f3e415ca 100644 --- a/packages/temporal-polyfill/src/public/duration.ts +++ b/packages/temporal-polyfill/src/public/duration.ts @@ -65,11 +65,15 @@ export class Duration implements Temporal.Duration { } static from(arg: DurationArg): Temporal.Duration { - return createDuration( - typeof arg === 'object' - ? processDurationFields(arg) - : parseDuration(arg), - ) + if (isObjectLike(arg)) { + return createDuration(processDurationFields(arg)) + } + + // parse as string... + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } + return createDuration(parseDuration(String(arg))) } static compare( diff --git a/packages/temporal-polyfill/src/public/instant.ts b/packages/temporal-polyfill/src/public/instant.ts index 1a04a498..12037817 100644 --- a/packages/temporal-polyfill/src/public/instant.ts +++ b/packages/temporal-polyfill/src/public/instant.ts @@ -61,9 +61,13 @@ export class Instant implements Temporal.Instant { static from(arg: InstantArg): Instant { // okay to have return-type be Instant? needed if (arg instanceof Instant) { - return new Instant(arg.epochNanoseconds) + return new Instant(arg.epochNanoseconds) // optimization } + // parse as string... + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } const fields = parseZonedDateTime(String(arg)) const offsetNano = fields.offsetNanoseconds if (offsetNano === undefined) { diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 5cd6003d..b2bc1137 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -3,6 +3,7 @@ import { getCommonCalendar } from '../argParse/calendar' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { parseDiffOptions } from '../argParse/diffOptions' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' +import { isObjectLike } from '../argParse/refine' import { IsoMasterMethods, ensureObj, @@ -71,11 +72,14 @@ export class PlainDate implements Temporal.PlainDate { if (arg instanceof PlainDate) { return createDate(arg.getISOFields()) // optimization } - - if (typeof arg === 'object') { // TODO: ensure not null + if (isObjectLike(arg)) { return processDateFromFields(arg, options) } + // parse as string... + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } const parsed = parseDateTime(String(arg)) // reject out-of-bound time values if included in the string diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/public/plainDateTime.ts index d719f346..25372b28 100644 --- a/packages/temporal-polyfill/src/public/plainDateTime.ts +++ b/packages/temporal-polyfill/src/public/plainDateTime.ts @@ -5,6 +5,7 @@ import { parseDiffOptions } from '../argParse/diffOptions' import { parseDisambigOption } from '../argParse/disambig' import { parseTimeToStringOptions } from '../argParse/isoFormatOptions' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' +import { isObjectLike } from '../argParse/refine' import { parseRoundingOptions } from '../argParse/roundingOptions' import { timeUnitNames } from '../argParse/unitStr' import { @@ -96,13 +97,18 @@ export class PlainDateTime implements Temporal.PlainDateTime { static from(arg: PlainDateTimeArg, options?: Temporal.AssignmentOptions): Temporal.PlainDateTime { const overflowHandling = parseOverflowOption(options) - return createDateTime( - arg instanceof PlainDateTime - ? arg.getISOFields() // optimization - : typeof arg === 'object' - ? processDateTimeFromFields(arg, overflowHandling, options) - : refineBaseObj(parseDateTime(String(arg))), - ) + if (arg instanceof PlainDateTime) { + return createDateTime(arg.getISOFields()) // optimization + } + if (isObjectLike(arg)) { + return createDateTime(processDateTimeFromFields(arg, overflowHandling, options)) + } + + // parse as string + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } + return createDateTime(refineBaseObj(parseDateTime(String(arg)))) } static compare(a: PlainDateTimeArg, b: PlainDateTimeArg): Temporal.ComparisonResult { diff --git a/packages/temporal-polyfill/src/public/plainMonthDay.ts b/packages/temporal-polyfill/src/public/plainMonthDay.ts index a7d106d3..8cadedf0 100644 --- a/packages/temporal-polyfill/src/public/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/public/plainMonthDay.ts @@ -1,6 +1,7 @@ import { Temporal } from 'temporal-spec' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' +import { isObjectLike } from '../argParse/refine' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' import { IsoMasterMethods, @@ -48,12 +49,14 @@ export class PlainMonthDay implements Temporal.PlainMonthDay { if (arg instanceof PlainMonthDay) { return createMonthDay(arg.getISOFields()) // optimization } - - if (typeof arg === 'object') { + if (isObjectLike(arg)) { return processMonthDayFromFields(arg, options) } - // a string... + // parse as string... + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } const parsed = parseMonthDay(String(arg)) // for strings, force ISO year if no calendar specified diff --git a/packages/temporal-polyfill/src/public/plainTime.ts b/packages/temporal-polyfill/src/public/plainTime.ts index 8b3f61f2..759d5468 100644 --- a/packages/temporal-polyfill/src/public/plainTime.ts +++ b/packages/temporal-polyfill/src/public/plainTime.ts @@ -2,6 +2,7 @@ import { Temporal } from 'temporal-spec' import { parseDiffOptions } from '../argParse/diffOptions' import { parseTimeToStringOptions } from '../argParse/isoFormatOptions' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' +import { isObjectLike } from '../argParse/refine' import { parseRoundingOptions } from '../argParse/roundingOptions' import { timeUnitNames } from '../argParse/unitStr' import { @@ -76,13 +77,18 @@ export class PlainTime implements Temporal.PlainTime { static from(arg: PlainTimeArg, options?: Temporal.AssignmentOptions): Temporal.PlainTime { const overflowHandling = parseOverflowOption(options) - return createTime( - arg instanceof PlainTime - ? arg.getISOFields() // optimization - : typeof arg === 'object' - ? processTimeFromFields(arg, overflowHandling) - : parseTime(String(arg)), - ) + if (arg instanceof PlainTime) { + return createTime(arg.getISOFields()) + } + if (isObjectLike(arg)) { + return createTime(processTimeFromFields(arg, overflowHandling)) + } + + // parse as string... + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } + return createTime(parseTime(String(arg))) } static compare(a: PlainTimeArg, b: PlainTimeArg): Temporal.ComparisonResult { diff --git a/packages/temporal-polyfill/src/public/plainYearMonth.ts b/packages/temporal-polyfill/src/public/plainYearMonth.ts index d8d964bd..449853af 100644 --- a/packages/temporal-polyfill/src/public/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/public/plainYearMonth.ts @@ -3,6 +3,7 @@ import { getCommonCalendar } from '../argParse/calendar' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { parseDiffOptions } from '../argParse/diffOptions' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' +import { isObjectLike } from '../argParse/refine' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' import { IsoMasterMethods, @@ -71,12 +72,14 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { if (arg instanceof PlainYearMonth) { return createYearMonth(arg.getISOFields()) // optimization } - - if (typeof arg === 'object') { + if (isObjectLike(arg)) { return processYearMonthFromFields(arg, options) } - // a string... + // parse as string... + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } const parsed = parseYearMonth(String(arg)) // don't allow day-numbers in ISO strings diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index 3163feab..d439398e 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -1,7 +1,6 @@ import { Temporal } from 'temporal-spec' import { parseDisambigOption } from '../argParse/disambig' import { isObjectLike } from '../argParse/refine' -import { timeZoneFromObj } from '../argParse/timeZone' import { JsonMethods, ensureObj, mixinJsonMethods, needReceiver } from '../dateUtils/abstract' import { epochNanoSymbol, epochNanoToISOFields, isoFieldsToEpochNano } from '../dateUtils/epoch' import { formatOffsetISO } from '../dateUtils/isoFormat' @@ -32,9 +31,21 @@ export class TimeZone implements Temporal.TimeZone { static from(arg: Temporal.TimeZoneLike): Temporal.TimeZoneProtocol { if (isObjectLike(arg)) { - return timeZoneFromObj(arg) + if (!('timeZone' in arg)) { + return arg + } else { + arg = arg.timeZone + + if (isObjectLike(arg) && !('timeZone' in arg)) { + return arg as any + } + } } + // parse as a string... + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') + } const parsed = tryParseZonedDateTime(String(arg)) if (parsed) { diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/public/zonedDateTime.ts index 66f99d6f..06fd4e84 100644 --- a/packages/temporal-polyfill/src/public/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/public/zonedDateTime.ts @@ -12,6 +12,7 @@ import { parseOffsetHandlingOption, } from '../argParse/offsetHandling' import { parseOverflowOption } from '../argParse/overflowHandling' +import { isObjectLike } from '../argParse/refine' import { RoundingConfig, parseRoundingOptions } from '../argParse/roundingOptions' import { parseTimeZoneDisplayOption } from '../argParse/timeZoneDisplay' import { timeUnitNames } from '../argParse/unitStr' @@ -132,10 +133,13 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { const overflowHandling = parseOverflowOption(options) if (arg instanceof ZonedDateTime) { - return new ZonedDateTime(arg.epochNanoseconds, arg.timeZone, arg.calendar) + return new ZonedDateTime(arg.epochNanoseconds, arg.timeZone, arg.calendar) // optimization + } + if (typeof arg === 'symbol') { + throw new TypeError('cannot accept symbol') } - const isObject = typeof arg === 'object' + const isObject = isObjectLike(arg) const fields = isObject ? processZonedDateTimeFromFields(arg, overflowHandling, options) : refineZonedObj(parseZonedDateTime(String(arg))) From e085534fd3abb1d518b7fdcadcce0ee547701c44 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 17:27:10 -0400 Subject: [PATCH 014/805] more economical about String() while parsing --- packages/temporal-polyfill/misc/expected-failures.txt | 1 - packages/temporal-polyfill/src/public/calendar.ts | 5 +++-- packages/temporal-polyfill/src/public/timeZone.ts | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index af7e2341..47325c9d 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -12,7 +12,6 @@ # # internal property access -built-ins/Temporal/Calendar/from/calendar-object-operations.js built-ins/Temporal/Calendar/from/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index e7c719c2..e038027b 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -70,11 +70,12 @@ export class Calendar implements Temporal.Calendar { if (typeof arg === 'symbol') { throw new TypeError('Calendar cannot be symbol') } - const parsed = tryParseDateTime(String(arg), false, true) // allowZ=true + const strVal = String(arg) + const parsed = tryParseDateTime(strVal, false, true) // allowZ=true return new Calendar( parsed // a date-time string? ? parsed.calendar || isoCalendarID - : String(arg), // any other type of string + : strVal, // any other type of string ) } diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index d439398e..eaf80929 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -46,7 +46,8 @@ export class TimeZone implements Temporal.TimeZone { if (typeof arg === 'symbol') { throw new TypeError('cannot accept symbol') } - const parsed = tryParseZonedDateTime(String(arg)) + const strVal = String(arg) + const parsed = tryParseZonedDateTime(strVal) if (parsed) { if (parsed.timeZone) { @@ -60,7 +61,7 @@ export class TimeZone implements Temporal.TimeZone { } } - return new TimeZone(String(arg)) // consider arg the literal time zone ID string + return new TimeZone(strVal) // consider arg the literal time zone ID string } get id(): string { From 8de5230ae14f451428182067ea62f10443bdd0c6 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 17:36:27 -0400 Subject: [PATCH 015/805] ::from optimizations where we check internal slot --- .../temporal-polyfill/misc/expected-failures.txt | 13 ------------- .../temporal-polyfill/src/dateUtils/abstract.ts | 1 + packages/temporal-polyfill/src/public/calendar.ts | 12 +++++++++++- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 47325c9d..d766e6a9 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -12,42 +12,29 @@ # # internal property access -built-ins/Temporal/Calendar/from/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js -built-ins/Temporal/Calendar/prototype/dateAdd/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js built-ins/Temporal/Calendar/prototype/dateUntil/argument-plaindatetime.js built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-slots.js built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js -built-ins/Temporal/Calendar/prototype/day/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/daysInWeek/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/id/custom-calendar.js -built-ins/Temporal/Calendar/prototype/inLeapYear/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js -built-ins/Temporal/Calendar/prototype/month/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js -built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/year/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js built-ins/Temporal/TimeZone/from/timezone-instance-does-not-get-timeZone-property.js built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-plaindate.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/calendar-temporal-object.js built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-zoneddatetime.js built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-zoneddatetime.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-zoneddatetime.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-zoneddatetime.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-temporal-object.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-plaindate.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/calendar-temporal-object.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-zoneddatetime.js built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js built-ins/Temporal/TimeZone/prototype/toJSON/tostring-call.js built-ins/Temporal/TimeZone/prototype/toJSON/tostring-undefined-custom.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/calendar-temporal-object.js # input processing and error types (ex: RangeError vs TypeError) built-ins/Temporal/Calendar/prototype/id/branding.js diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index 8810a561..031cd474 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -79,6 +79,7 @@ export interface IsoMasterMethods extends NoValueMethods { } const [getISOFields, setISOFields] = createWeakMap, any>() +export { getISOFields } export function mixinIsoMasterMethods>( ObjClass: { new(...constructorArgs: any[]): Obj }, diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index e038027b..8513aa4d 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -8,7 +8,13 @@ import { checkEpochMilliBuggy } from '../calendarImpl/bugs' import { CalendarImpl, CalendarImplFields, convertEraYear } from '../calendarImpl/calendarImpl' import { queryCalendarImpl } from '../calendarImpl/calendarImplQuery' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' -import { JsonMethods, ensureObj, mixinJsonMethods, needReceiver } from '../dateUtils/abstract' +import { + JsonMethods, + ensureObj, + getISOFields, + mixinJsonMethods, + needReceiver, +} from '../dateUtils/abstract' import { computeDayOfYear, computeDaysInYear, @@ -49,6 +55,10 @@ export class Calendar implements Temporal.Calendar { if (arg instanceof Calendar) { return arg as any } + const secretCalendar = getISOFields(arg as any)?.calendar + if (secretCalendar) { + return secretCalendar + } if (arg instanceof TimeZone) { throw new RangeError('Expected a calendar object but received a Temporal.TimeZone') } From f1838a5d2323eb3124e6f47f27fba28545274f24 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 17:45:45 -0400 Subject: [PATCH 016/805] smarter ::from short-circuits --- packages/temporal-polyfill/misc/expected-failures.txt | 4 ---- packages/temporal-polyfill/src/public/plainDate.ts | 10 +++++++--- packages/temporal-polyfill/src/public/plainDateTime.ts | 5 ++++- packages/temporal-polyfill/src/public/plainTime.ts | 9 +++++++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index d766e6a9..07eaa32c 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -12,12 +12,8 @@ # # internal property access -built-ins/Temporal/Calendar/prototype/dateAdd/argument-plaindatetime.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-slots.js built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-plaindatetime.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-slots.js built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js built-ins/Temporal/Calendar/prototype/id/custom-calendar.js built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index b2bc1137..fc596e3a 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -32,11 +32,11 @@ import { createPlainFormatFactoryFactory } from '../native/intlFactory' import { ToLocaleStringMethods, mixinLocaleStringMethods } from '../native/intlMixins' import { Calendar, createDefaultCalendar } from './calendar' import { Duration, DurationArg, createDuration } from './duration' -import { createDateTime } from './plainDateTime' +import { PlainDateTime, createDateTime } from './plainDateTime' import { PlainTime, PlainTimeArg, ensureLooseTime } from './plainTime' import { createYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' -import { createZonedDateTimeFromFields } from './zonedDateTime' +import { ZonedDateTime, createZonedDateTimeFromFields } from './zonedDateTime' export type PlainDateArg = Temporal.PlainDate | Temporal.PlainDateLike | string @@ -69,7 +69,11 @@ export class PlainDate implements Temporal.PlainDate { static from(arg: PlainDateArg, options?: Temporal.AssignmentOptions): Temporal.PlainDate { parseOverflowOption(options) // unused, but need to validate, regardless of input type - if (arg instanceof PlainDate) { + if ( + arg instanceof PlainDate || + arg instanceof PlainDateTime || + arg instanceof ZonedDateTime + ) { return createDate(arg.getISOFields()) // optimization } if (isObjectLike(arg)) { diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/public/plainDateTime.ts index 25372b28..5e162f65 100644 --- a/packages/temporal-polyfill/src/public/plainDateTime.ts +++ b/packages/temporal-polyfill/src/public/plainDateTime.ts @@ -97,7 +97,10 @@ export class PlainDateTime implements Temporal.PlainDateTime { static from(arg: PlainDateTimeArg, options?: Temporal.AssignmentOptions): Temporal.PlainDateTime { const overflowHandling = parseOverflowOption(options) - if (arg instanceof PlainDateTime) { + if ( + arg instanceof PlainDateTime || + arg instanceof ZonedDateTime + ) { return createDateTime(arg.getISOFields()) // optimization } if (isObjectLike(arg)) { diff --git a/packages/temporal-polyfill/src/public/plainTime.ts b/packages/temporal-polyfill/src/public/plainTime.ts index 759d5468..1846eeb1 100644 --- a/packages/temporal-polyfill/src/public/plainTime.ts +++ b/packages/temporal-polyfill/src/public/plainTime.ts @@ -32,8 +32,9 @@ import { OrigDateTimeFormat } from '../native/intlUtils' import { createDefaultCalendar } from './calendar' import { Duration, createDuration } from './duration' import { PlainDate, PlainDateArg } from './plainDate' +import { PlainDateTime } from './plainDateTime' import { TimeZone } from './timeZone' -import { createZonedDateTimeFromFields } from './zonedDateTime' +import { ZonedDateTime, createZonedDateTimeFromFields } from './zonedDateTime' export type PlainTimeArg = Temporal.PlainTime | Temporal.PlainTimeLike | string @@ -77,7 +78,11 @@ export class PlainTime implements Temporal.PlainTime { static from(arg: PlainTimeArg, options?: Temporal.AssignmentOptions): Temporal.PlainTime { const overflowHandling = parseOverflowOption(options) - if (arg instanceof PlainTime) { + if ( + arg instanceof PlainTime || + arg instanceof PlainDateTime || + arg instanceof ZonedDateTime + ) { return createTime(arg.getISOFields()) } if (isObjectLike(arg)) { From daa591f90726bcc677e4fe91bfab3e8bab6f334d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 24 Mar 2023 18:24:04 -0400 Subject: [PATCH 017/805] more fixes with ::from and instantiation short-circuits --- .../misc/expected-failures.txt | 35 ++++++------------- .../src/dateUtils/abstract.ts | 2 +- .../temporal-polyfill/src/public/calendar.ts | 3 +- .../temporal-polyfill/src/public/instant.ts | 5 ++- .../src/public/plainDateTime.ts | 5 ++- .../temporal-polyfill/src/public/timeZone.ts | 5 ++- 6 files changed, 25 insertions(+), 30 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 07eaa32c..b57560a3 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -11,36 +11,14 @@ # pn test262 'TimeZone/**' # -# internal property access +# complicated internal property access built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js -built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js -built-ins/Temporal/Calendar/prototype/id/custom-calendar.js built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js -built-ins/Temporal/TimeZone/from/timezone-instance-does-not-get-timeZone-property.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-plaindate.js built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js -built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-zoneddatetime.js -built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-zoneddatetime.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-zoneddatetime.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-zoneddatetime.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-plaindate.js -built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-zoneddatetime.js -built-ins/Temporal/TimeZone/prototype/id/custom-timezone.js -built-ins/Temporal/TimeZone/prototype/toJSON/tostring-call.js -built-ins/Temporal/TimeZone/prototype/toJSON/tostring-undefined-custom.js - -# input processing and error types (ex: RangeError vs TypeError) -built-ins/Temporal/Calendar/prototype/id/branding.js -built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js +built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js # parsing built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js @@ -170,6 +148,8 @@ built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatet built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js # # Legit bugs @@ -243,6 +223,11 @@ built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-ge built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js +built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js +built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js +built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js +built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-wrong-type.js # calendars must match built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index 031cd474..0785a996 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -42,7 +42,7 @@ export function mixinJsonMethods( class JsonMixin { toJSON(this: Obj) { needReceiver(ObjClass, this) - return this.toString() + return String(this) // better than .toString, looks at [Symbol.toPrimitive] } } Object.defineProperty(ObjClass.prototype, 'toJSON', { diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 8513aa4d..72a92ff6 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -90,7 +90,8 @@ export class Calendar implements Temporal.Calendar { } get id(): string { - return this.toString() + needReceiver(Calendar, this) + return getImpl(this).id } era( diff --git a/packages/temporal-polyfill/src/public/instant.ts b/packages/temporal-polyfill/src/public/instant.ts index 12037817..f9ce3acd 100644 --- a/packages/temporal-polyfill/src/public/instant.ts +++ b/packages/temporal-polyfill/src/public/instant.ts @@ -60,7 +60,10 @@ export class Instant implements Temporal.Instant { } static from(arg: InstantArg): Instant { // okay to have return-type be Instant? needed - if (arg instanceof Instant) { + if ( + arg instanceof Instant || + arg instanceof ZonedDateTime + ) { return new Instant(arg.epochNanoseconds) // optimization } diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/public/plainDateTime.ts index 5e162f65..5187ed75 100644 --- a/packages/temporal-polyfill/src/public/plainDateTime.ts +++ b/packages/temporal-polyfill/src/public/plainDateTime.ts @@ -17,7 +17,7 @@ import { } from '../dateUtils/abstract' import { compareDateTimes, dateTimesEqual } from '../dateUtils/compare' import { constrainDateTimeISO } from '../dateUtils/constrain' -import { DayTimeUnit } from '../dateUtils/dayAndTime' +import { DayTimeUnit, zeroISOTimeFields } from '../dateUtils/dayAndTime' import { diffDateTimes } from '../dateUtils/diff' import { DurationFields, negateDuration } from '../dateUtils/durationFields' import { processDateTimeFromFields, processDateTimeWithFields } from '../dateUtils/fromAndWith' @@ -103,6 +103,9 @@ export class PlainDateTime implements Temporal.PlainDateTime { ) { return createDateTime(arg.getISOFields()) // optimization } + if (arg instanceof PlainDate) { + return createDateTime({ ...arg.getISOFields(), ...zeroISOTimeFields }) + } if (isObjectLike(arg)) { return createDateTime(processDateTimeFromFields(arg, overflowHandling, options)) } diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index eaf80929..52f43db8 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -31,6 +31,9 @@ export class TimeZone implements Temporal.TimeZone { static from(arg: Temporal.TimeZoneLike): Temporal.TimeZoneProtocol { if (isObjectLike(arg)) { + if (arg instanceof TimeZone) { + return arg as any + } if (!('timeZone' in arg)) { return arg } else { @@ -66,7 +69,7 @@ export class TimeZone implements Temporal.TimeZone { get id(): string { needReceiver(TimeZone, this) - return this.toString() + return getImpl(this).id } getOffsetStringFor(instantArg: InstantArg): string { From 5a700d68f37538e5934c380b9232e72e57ad82db Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 25 Mar 2023 15:03:22 -0400 Subject: [PATCH 018/805] smarter about parsing annotations --- .../misc/expected-failures.txt | 74 ------------------ .../temporal-polyfill/src/dateUtils/parse.ts | 64 +++++++++++++--- .../src/dateUtils/parseRegExp.ts | 75 ++++++++++--------- 3 files changed, 93 insertions(+), 120 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index b57560a3..855e5041 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -20,79 +20,6 @@ built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js -# parsing -built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/day/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/day/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/day/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/month/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/month/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/month/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/year/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/year/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/year/argument-string-unknown-annotation.js -intl402/Temporal/Calendar/prototype/era/argument-string-calendar-annotation.js -intl402/Temporal/Calendar/prototype/era/argument-string-unknown-annotation.js -intl402/Temporal/Calendar/prototype/eraYear/argument-string-calendar-annotation.js -intl402/Temporal/Calendar/prototype/eraYear/argument-string-date-with-utc-offset.js -intl402/Temporal/Calendar/prototype/eraYear/argument-string-unknown-annotation.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-calendar-annotation.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-date-with-utc-offset.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-string-unknown-annotation.js -built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-calendar-annotation.js -built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-date-with-utc-offset.js -built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-unknown-annotation.js -built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-calendar-annotation.js -built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-date-with-utc-offset.js -built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-unknown-annotation.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-calendar-annotation.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-date-with-utc-offset.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-unknown-annotation.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-calendar-annotation.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-date-with-utc-offset.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-unknown-annotation.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-calendar-annotation.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-date-with-utc-offset.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-string-unknown-annotation.js -built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-calendar-annotation.js -built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js -built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-unknown-annotation.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-calendar-annotation.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-date-with-utc-offset.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-string-unknown-annotation.js - # TimeZone::getOffsetNanosecondsFor laziness/incorrectness built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js @@ -200,7 +127,6 @@ built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -intl402/Temporal/Calendar/prototype/era/argument-string-date-with-utc-offset.js intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js diff --git a/packages/temporal-polyfill/src/dateUtils/parse.ts b/packages/temporal-polyfill/src/dateUtils/parse.ts index 99a770a2..6dcadaa0 100644 --- a/packages/temporal-polyfill/src/dateUtils/parse.ts +++ b/packages/temporal-polyfill/src/dateUtils/parse.ts @@ -7,7 +7,7 @@ import { dateTimeRegExp, monthDayRegExp, normalizeDashes, - offsetRegExp, + numericOffsetRegExp, timeRegExp, yearMonthRegExp, } from './parseRegExp' @@ -23,10 +23,10 @@ export interface DateParseResults extends ISODateFields { export interface DateTimeParseResult extends ISODateTimeFields { calendar: string | undefined + timeZone: string | undefined // not needed for most cases } export interface ZonedDateTimeParseResult extends DateTimeParseResult { - timeZone: string | undefined offsetNanoseconds: number | undefined Z: boolean | undefined // whether ISO8601 specified with 'Z' as offset indicator } @@ -142,9 +142,9 @@ function tryParseTime(str: string) { } export function tryParseOffsetNano(str: string): number | undefined { - const m = offsetRegExp.exec(normalizeDashes(str)) + const m = numericOffsetRegExp.exec(normalizeDashes(str)) if (m) { - return parseOffsetParts(m.slice(1)) + return parseNumericOffsetParts(m.slice(1)) } } @@ -159,12 +159,11 @@ function parseZonedDateTimeParts(parts: string[]): ZonedDateTimeParseResult { if (zOrOffset) { Z = zRE.test(zOrOffset) - offsetNanoseconds = Z ? 0 : parseOffsetParts(parts.slice(12)) + offsetNanoseconds = Z ? 0 : parseNumericOffsetParts(parts.slice(12)) } return { ...parseDateTimeParts(parts), - timeZone: parts[21], offsetNanoseconds, Z, } @@ -172,33 +171,35 @@ function parseZonedDateTimeParts(parts: string[]): ZonedDateTimeParseResult { function parseDateTimeParts(parts: string[]): DateTimeParseResult { return { - calendar: parts[23], isoYear: toInt1(parts[0]), isoMonth: toInt1(parts[1]), isoDay: toInt1(parts[2]), - ...parseTimeParts(parts.slice(4)), + ...parseTimeParts(parts.slice(4)), // parses annotations } } function parseYearMonthParts(parts: string[]): DateParseResults { return { - calendar: parts[14], isoYear: toInt1(parts[0]), isoMonth: toInt1(parts[1]), isoDay: 1, + ...parseAnnotations(parts[2]), } } function parseMonthDayParts(parts: string[]): DateParseResults { return { - calendar: parts[15], isoYear: isoEpochLeapYear, isoMonth: toInt1(parts[1]), isoDay: toInt1(parts[2]), + ...parseAnnotations(parts[3]), } } -function parseTimeParts(parts: string[]): ISOTimeFields { +function parseTimeParts(parts: string[]): ISOTimeFields & { + timeZone: string | undefined + calendar: string | undefined +} { const isoSecond = toInt0(parts[4]) return { @@ -206,10 +207,11 @@ function parseTimeParts(parts: string[]): ISOTimeFields { isoHour: toInt0(parts[0]), isoMinute: toInt0(parts[2]), isoSecond: isoSecond === 60 ? 59 : isoSecond, // massage lead-second + ...parseAnnotations(parts[16]), } } -function parseOffsetParts(parts: string[]): number { +function parseNumericOffsetParts(parts: string[]): number { return (parts[0] === '+' ? 1 : -1) * timePartsToNano(parts.slice(1)) } @@ -226,6 +228,44 @@ export function parseNanoAfterDecimal(str: string): number { return parseInt(padEnd(str, 9, '0')) } +// annotations + +function parseAnnotations(s: string): { + calendar: string | undefined + timeZone: string | undefined +} { + let calendar: string | undefined + let timeZone: string | undefined + + for (const chunk of s.split(']')) { + if (chunk) { // not the empty end chunk + let annotation = chunk.slice(1) // remove leading '[' + let isCritical = false + + if (annotation.charAt(0) === '!') { + isCritical = true + annotation = annotation.slice(1) + } + + const annotationParts = annotation.split('=') + if (annotationParts.length === 1) { + if (timeZone !== undefined) { + throw new RangeError('Cannot specify timeZone multiple times') + } + timeZone = annotation + } else if (annotationParts[0] === 'u-ca') { + if (calendar === undefined) { // ignore subsequent calendar annotations + calendar = annotationParts[1] + } + } else if (isCritical) { + throw new RangeError(`Critical annotation '${annotationParts[0]}' not used`) + } + } + } + + return { calendar, timeZone } +} + // general utils function toInt0(input: string | undefined): number { // 0-based diff --git a/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts b/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts index 7f177ab0..a820c245 100644 --- a/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts +++ b/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts @@ -1,49 +1,56 @@ const yearMonthRegExpStr = - '([+-]\\d{6}|\\d{4})' + // 0: year - '-?(\\d{2})' // 1: month - // ending... 12: timeZone, 14: calendar + '([+-]\\d{6}|\\d{4})' + // 0:year + '-?(\\d{2})' // 1:month + // 2:annotations const dateRegExpStr = - yearMonthRegExpStr + // 0-1: yearMonth - '-?(\\d{2})' // 2: day - // ending... 13: timeZone, 15: calendar + yearMonthRegExpStr + // 0:year, 1:month + '-?(\\d{2})' // 2:day + // 3:annotations const monthDayRegExpStr = - '(--)?(\\d{2})' + // 1: month - '-?(\\d{2})' // 2: day - // ending... 13: timeZone, 15: calendar + '(--)?(\\d{2})' + // 1:month + '-?(\\d{2})' // 2:day + // 3:annotations -const timeRegExpStr = - '(\\d{2})' + // 0: hour - '(:?(\\d{2})' + // 2: minute - '(:?(\\d{2})' + // 4: second - '([.,](\\d{1,9}))?' + // 6: afterDecimal +const numericTimeRegExpStr = + '(\\d{2})' + // 0:hour + '(:?(\\d{2})' + // 2:minute (NOTE: ':?' means optional ':') + '(:?(\\d{2})' + // 4:second + '([.,](\\d{1,9}))?' + // 6:afterDecimal ')?)?' +const numericOffsetRegExpStr = + '([+-])' + // 0:plusOrMinus + numericTimeRegExpStr // 1:hour, 3:minute, 5:second, 7:afterDecimal + +const offsetRegExpStr = + '(Z|' + // 0:zOrOffset + numericOffsetRegExpStr + // 1:plusOrMinus, 2:hour, 4:minute, 6:second, 8:afterDecimal + ')?' + +const timeRegExpStr = + numericTimeRegExpStr + // 0:hour, 2:minute, 4:second, 6:afterDecimal + offsetRegExpStr // 7:zOrOffset, 8:plusOrMinus, 9:hour, 11:minute, 13:second, 15:afterDecimal + // 16:annotations + const dateTimeRegExpStr = - dateRegExpStr + // 0-2: date - '([T ]' + // 3: timeEverything - timeRegExpStr + // 4-10: time + dateRegExpStr + // 0:year, 1:month, 2:day + '([T ]' + // 3:timeEverything + timeRegExpStr + + // 4:hour, 6:minute, 8:second, 10:afterDecimal + // 11:zOrOffset, 12:plusOrMinus, 13:hour, 15:minute, 17:second, 19:afterDecimal ')?' - // ending... 11: zOrOffset, 12-19: offset, 21: timeZone, 23: calendar + // 20:annotations -const offsetRegExpStr = - '([+-])' + // 0: plusOrMinus - timeRegExpStr // 1-7: time - -const endingRegExpStr = - '(Z|' + // 0: zOrOffset - offsetRegExpStr + // 1-8: offset - ')?' + - '(\\[([^=\\]]+)\\])?' + // 10: timeZone - '(\\[\\!?u-ca=([^\\]]+)\\])?' // 12: calendar - -export const yearMonthRegExp = createRegExp(yearMonthRegExpStr + endingRegExpStr) -export const monthDayRegExp = createRegExp(monthDayRegExpStr + endingRegExpStr) -export const dateTimeRegExp = createRegExp(dateTimeRegExpStr + endingRegExpStr) -export const timeRegExp = createRegExp('T?' + timeRegExpStr + endingRegExpStr) -export const offsetRegExp = createRegExp(offsetRegExpStr) +const annotationRegExpStr = '((\\[[^\\]]*\\])*)' + +export const yearMonthRegExp = createRegExp(yearMonthRegExpStr + annotationRegExpStr) +export const monthDayRegExp = createRegExp(monthDayRegExpStr + annotationRegExpStr) +export const dateTimeRegExp = createRegExp(dateTimeRegExpStr + annotationRegExpStr) +export const timeRegExp = createRegExp('T?' + timeRegExpStr + annotationRegExpStr) +export const numericOffsetRegExp = createRegExp(numericOffsetRegExpStr) // annotations not allowed // TODO: use same DRY technique as above export const durationRegExp = /^([-+])?P(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T((\d+)([.,](\d{1,9}))?H)?((\d+)([.,](\d{1,9}))?M)?((\d+)([.,](\d{1,9}))?S)?)?$/i From 6f5afba2cf0fb055be8d80c6dc37137e92601e98 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 25 Mar 2023 16:16:48 -0400 Subject: [PATCH 019/805] parse iso8601 annotations better, lazy-computed zdt fields, more tests passing --- .../misc/expected-failures.txt | 58 ------- .../src/dateUtils/abstract.ts | 2 +- .../temporal-polyfill/src/dateUtils/epoch.ts | 2 + .../src/dateUtils/timeZone.ts | 20 ++- .../temporal-polyfill/src/public/calendar.ts | 5 +- .../temporal-polyfill/src/public/instant.ts | 2 +- .../temporal-polyfill/src/public/timeZone.ts | 6 +- .../src/public/zonedDateTime.ts | 145 ++++++++++++------ 8 files changed, 129 insertions(+), 111 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 855e5041..9f5dac72 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -20,64 +20,6 @@ built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js -# TimeZone::getOffsetNanosecondsFor laziness/incorrectness -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-convert.js -intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-convert.js -intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-convert.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js - # # Legit bugs # diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index 0785a996..17c9c6ec 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -62,7 +62,7 @@ export function mixinNoValueMethods( mixinJsonMethods(ObjClass) class NoValueMixin { - valueOf(this: Obj) { + valueOf(this: Obj): never { needReceiver(ObjClass, this) throw new Error('Cannot convert object using valueOf') } diff --git a/packages/temporal-polyfill/src/dateUtils/epoch.ts b/packages/temporal-polyfill/src/dateUtils/epoch.ts index 1323cf03..bc67dd90 100644 --- a/packages/temporal-polyfill/src/dateUtils/epoch.ts +++ b/packages/temporal-polyfill/src/dateUtils/epoch.ts @@ -19,6 +19,8 @@ export const isoEpochLeapYear = 1972 // first ISO leap year after origin export type EpochableFields = ISODateFields & Partial +// TODO: phas this out. use WeakMap instead. like: +// https://github.com/js-temporal/temporal-polyfill/blob/main/lib/slots.ts#L153 export const epochNanoSymbol = Symbol() export interface EpochableObj { diff --git a/packages/temporal-polyfill/src/dateUtils/timeZone.ts b/packages/temporal-polyfill/src/dateUtils/timeZone.ts index 0fb73977..44673ceb 100644 --- a/packages/temporal-polyfill/src/dateUtils/timeZone.ts +++ b/packages/temporal-polyfill/src/dateUtils/timeZone.ts @@ -64,11 +64,27 @@ function computeGapNear( plainDateTime: PlainDateTime, ): number { const utcEpochNano = toEpochNano(plainDateTime) - const offsetDayBefore = timeZoneProtocol.getOffsetNanosecondsFor( + const offsetDayBefore = getSafeOffsetNanosecondsFor( + timeZoneProtocol, new Instant(utcEpochNano.sub(nanoInDay)), ) - const offsetDayAfter = timeZoneProtocol.getOffsetNanosecondsFor( + const offsetDayAfter = getSafeOffsetNanosecondsFor( + timeZoneProtocol, new Instant(utcEpochNano.add(nanoInDay)), ) return offsetDayAfter - offsetDayBefore } + +export function getSafeOffsetNanosecondsFor( + timeZone: Temporal.TimeZoneProtocol, + arg: Temporal.Instant | string, +): number { + // if (typeof timeZone.getOffsetNanosecondsFor !== 'function') { + // throw new TypeError('getOffsetNanosecondsFor should be callable') + // } + const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(arg) + if (typeof offsetNanoseconds !== 'number') { + throw new TypeError('Invalid return value from getOffsetNanosecondsFor') + } + return offsetNanoseconds +} diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 72a92ff6..59d81af7 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -35,6 +35,7 @@ import { PlainDate, PlainDateArg } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' +import { getZonedDateTimeInterals } from './zonedDateTime' // FYI: the Temporal.CalendarLike type includes `string`, // unlike many other object types @@ -55,7 +56,9 @@ export class Calendar implements Temporal.Calendar { if (arg instanceof Calendar) { return arg as any } - const secretCalendar = getISOFields(arg as any)?.calendar + const secretCalendar = + getZonedDateTimeInterals(arg as any)?.calendar || + getISOFields(arg as any)?.calendar if (secretCalendar) { return secretCalendar } diff --git a/packages/temporal-polyfill/src/public/instant.ts b/packages/temporal-polyfill/src/public/instant.ts index f9ce3acd..0db91d52 100644 --- a/packages/temporal-polyfill/src/public/instant.ts +++ b/packages/temporal-polyfill/src/public/instant.ts @@ -64,7 +64,7 @@ export class Instant implements Temporal.Instant { arg instanceof Instant || arg instanceof ZonedDateTime ) { - return new Instant(arg.epochNanoseconds) // optimization + return new Instant(arg.epochNanoseconds) // optimization. TODO: use slots } // parse as string... diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index 52f43db8..71b20341 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -8,7 +8,7 @@ import { attachStringTag } from '../dateUtils/mixins' import { checkInvalidOffset } from '../dateUtils/offset' import { tryParseZonedDateTime } from '../dateUtils/parse' import { refineZonedObj } from '../dateUtils/parseRefine' -import { getInstantFor } from '../dateUtils/timeZone' +import { getInstantFor, getSafeOffsetNanosecondsFor } from '../dateUtils/timeZone' import { TimeZoneImpl } from '../timeZoneImpl/timeZoneImpl' import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' import { createWeakMap } from '../utils/obj' @@ -74,7 +74,7 @@ export class TimeZone implements Temporal.TimeZone { getOffsetStringFor(instantArg: InstantArg): string { needReceiver(TimeZone, this) - return formatOffsetISO(this.getOffsetNanosecondsFor(instantArg)) + return formatOffsetISO(getSafeOffsetNanosecondsFor(this, instantArg)) } getOffsetNanosecondsFor(instantArg: InstantArg): number { @@ -90,7 +90,7 @@ export class TimeZone implements Temporal.TimeZone { needReceiver(TimeZone, this) const instant = ensureObj(Instant, instantArg) const isoFields = epochNanoToISOFields( - instant[epochNanoSymbol].add(this.getOffsetNanosecondsFor(instant)), + instant[epochNanoSymbol].add(getSafeOffsetNanosecondsFor(this, instant)), ) return createDateTime({ ...isoFields, diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/public/zonedDateTime.ts index 06fd4e84..3aa82a74 100644 --- a/packages/temporal-polyfill/src/public/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/public/zonedDateTime.ts @@ -16,13 +16,7 @@ import { isObjectLike } from '../argParse/refine' import { RoundingConfig, parseRoundingOptions } from '../argParse/roundingOptions' import { parseTimeZoneDisplayOption } from '../argParse/timeZoneDisplay' import { timeUnitNames } from '../argParse/unitStr' -import { - IsoMasterMethods, - ensureObj, - initIsoMaster, - mixinIsoMasterMethods, - needReceiver, -} from '../dateUtils/abstract' +import { ensureObj, needReceiver } from '../dateUtils/abstract' import { compareEpochObjs, zonedDateTimesEqual } from '../dateUtils/compare' import { DayTimeUnit, zeroISOTimeFields } from '../dateUtils/dayAndTime' import { diffDateTimes } from '../dateUtils/diff' @@ -58,7 +52,7 @@ import { import { parseZonedDateTime } from '../dateUtils/parse' import { refineZonedObj } from '../dateUtils/parseRefine' import { roundZonedDateTimeFields } from '../dateUtils/rounding' -import { getInstantFor } from '../dateUtils/timeZone' +import { getInstantFor, getSafeOffsetNanosecondsFor } from '../dateUtils/timeZone' import { translateZonedDateTimeFields } from '../dateUtils/translate' import { DAY, @@ -94,37 +88,71 @@ type RoundOptions = Temporal.RoundTo< 'millisecond' | 'microsecond' | 'nanosecond' > -const offsetNanoSymbol = Symbol() +// Internals +// ------------------------------------------------------------------------------------------------- + +interface ZonedDateTimeInternals { + epochNanoseconds: LargeInt + timeZone: TimeZone + calendar: Calendar +} + +interface ZonedDateTimeComputeds extends ISODateTimeFields { + offsetNanoseconds: number + offset: string +} export interface ZonedDateTime { - [offsetNanoSymbol]: number - [epochNanoSymbol]: LargeInt + [epochNanoSymbol]: LargeInt // for mixinEpochFields +} + +const internalsMap = new WeakMap() +const computedsMap = new WeakMap() + +function getInternals(zdt: ZonedDateTime): ZonedDateTimeInternals { + return internalsMap.get(zdt)! +} + +export { getInternals as getZonedDateTimeInterals } + +function getComputeds(zdt: ZonedDateTime): ZonedDateTimeComputeds { + let computeds = computedsMap.get(zdt) + if (computeds === undefined) { + computeds = buildComputeds(getInternals(zdt)) + computedsMap.set(zdt, computeds) + } + return computeds +} + +function buildComputeds(internals: ZonedDateTimeInternals): ZonedDateTimeComputeds { + const [isoFields, offsetNanoseconds] = buildZonedDateTimeISOFields( + internals.epochNanoseconds, + internals.timeZone, + ) + validateDateTime(isoFields, internals.calendar.toString()) + return { + ...isoFields, + offsetNanoseconds, + offset: formatOffsetISO(offsetNanoseconds), + } } + +// Public +// ------------------------------------------------------------------------------------------------- + export class ZonedDateTime implements Temporal.ZonedDateTime { constructor( epochNanoseconds: LargeIntArg, timeZoneArg: Temporal.TimeZoneLike, calendarArg: Temporal.CalendarLike = createDefaultCalendar(), ) { - // TODO: throw error when number? - const timeZone = ensureObj(TimeZone, timeZoneArg) - const calendar = ensureObj(Calendar, calendarArg) - const epochNano = createLargeInt(epochNanoseconds) // TODO: do strict, like Instant? - const [isoFields, offsetNano] = buildZonedDateTimeISOFields(epochNano, timeZone) - validateDateTime(isoFields, calendar.toString()) - - initIsoMaster(this, { - ...isoFields, - calendar, - timeZone, - // NOTE: must support TimeZone protocols that don't implement getOffsetStringFor - // TODO: more DRY with getOffsetStringFor - offset: formatOffsetISO(offsetNano), - }) - this[epochNanoSymbol] = epochNano - this[offsetNanoSymbol] = offsetNano + internalsMap.set(this, { + epochNanoseconds: epochNano, + timeZone: ensureObj(TimeZone, timeZoneArg) as TimeZone, + calendar: ensureObj(Calendar, calendarArg) as Calendar, + }) } // okay to have return-type be ZonedDateTime? needed @@ -161,17 +189,17 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { get timeZone(): Temporal.TimeZoneProtocol { needReceiver(ZonedDateTime, this) - return this.getISOFields().timeZone + return getInternals(this).timeZone } get offsetNanoseconds(): number { needReceiver(ZonedDateTime, this) - return this[offsetNanoSymbol] + return getComputeds(this).offsetNanoseconds } get offset(): string { needReceiver(ZonedDateTime, this) - return this.getISOFields().offset + return getComputeds(this).offset } with( @@ -206,7 +234,8 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { withPlainTime(timeArg?: PlainTimeArg): Temporal.ZonedDateTime { needReceiver(ZonedDateTime, this) return createZonedDateTimeFromFields({ - ...this.getISOFields(), + ...getInternals(this), + ...getComputeds(this), ...( timeArg === undefined ? zeroISOTimeFields @@ -273,7 +302,8 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { startOfDay(): Temporal.ZonedDateTime { needReceiver(ZonedDateTime, this) return createZonedDateTimeFromFields({ - ...this.getISOFields(), + ...getInternals(this), + ...getComputeds(this), ...zeroISOTimeFields, offsetNanoseconds: this.offsetNanoseconds, }, false, OFFSET_PREFER) @@ -282,7 +312,10 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { // TODO: turn into a lazy-getter, like what mixinCalendarFields does get hoursInDay(): number { needReceiver(ZonedDateTime, this) - return computeNanoInDay(this.getISOFields()) / nanoInHour + return computeNanoInDay({ + ...getInternals(this), + ...getComputeds(this), + }) / nanoInHour } toString(options?: Temporal.CalendarTypeToStringOptions): string { @@ -305,7 +338,10 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { toPlainYearMonth(): Temporal.PlainYearMonth { needReceiver(ZonedDateTime, this) - return createYearMonth(this.getISOFields()) + return createYearMonth({ + ...getInternals(this), + ...getComputeds(this), + }) } toPlainMonthDay(): Temporal.PlainMonthDay { @@ -315,29 +351,51 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { toPlainDateTime(): Temporal.PlainDateTime { needReceiver(ZonedDateTime, this) - return createDateTime(this.getISOFields()) + return createDateTime({ + ...getInternals(this), + ...getComputeds(this), + }) } toPlainDate(): Temporal.PlainDate { needReceiver(ZonedDateTime, this) - return createDate(this.getISOFields()) + return createDate({ + ...getInternals(this), + ...getComputeds(this), + }) } toPlainTime(): Temporal.PlainTime { needReceiver(ZonedDateTime, this) - return createTime(this.getISOFields()) + return createTime({ ...getComputeds(this) }) } toInstant(): Temporal.Instant { needReceiver(ZonedDateTime, this) return new Instant(this.epochNanoseconds) } + + getISOFields(): Temporal.ZonedDateTimeISOFields { + needReceiver(ZonedDateTime, this) + return { + ...getInternals(this), + ...getComputeds(this), + // TODO: remove some props right? + } + } + + valueOf(): never { + needReceiver(ZonedDateTime, this) + throw new Error('Cannot convert object using valueOf') + } + + toJSON(): string { + needReceiver(ZonedDateTime, this) + return String(this) // better than .toString, looks at [Symbol.toPrimitive] + } } // mixins -export interface ZonedDateTime extends IsoMasterMethods {} -mixinIsoMasterMethods(ZonedDateTime) -// export interface ZonedDateTime { [Symbol.toStringTag]: 'Temporal.ZonedDateTime' } attachStringTag(ZonedDateTime, 'ZonedDateTime') // @@ -383,10 +441,7 @@ export function buildZonedDateTimeISOFields( timeZone: Temporal.TimeZoneProtocol, ): [ISODateTimeFields, number] { const instant = new Instant(epochNano) // will do validation - const offsetNano = timeZone.getOffsetNanosecondsFor(instant) - if (typeof offsetNano !== 'number') { - throw new TypeError('Invalid return value from getOffsetNanosecondsFor') - } + const offsetNano = getSafeOffsetNanosecondsFor(timeZone, instant) const isoFields = epochNanoToISOFields(epochNano.add(offsetNano)) return [isoFields, offsetNano] } From 1529530f018d8aa8e0f675c70d49293ccac054f7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 02:10:06 -0400 Subject: [PATCH 020/805] better error on invalid timezone offset --- .../misc/expected-failures.txt | 21 ------------------- .../src/dateUtils/timeZone.ts | 7 +++++++ 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 9f5dac72..3827fc5f 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -43,53 +43,32 @@ intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js # out-of-range built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js diff --git a/packages/temporal-polyfill/src/dateUtils/timeZone.ts b/packages/temporal-polyfill/src/dateUtils/timeZone.ts index 44673ceb..d3587ad7 100644 --- a/packages/temporal-polyfill/src/dateUtils/timeZone.ts +++ b/packages/temporal-polyfill/src/dateUtils/timeZone.ts @@ -79,12 +79,19 @@ export function getSafeOffsetNanosecondsFor( timeZone: Temporal.TimeZoneProtocol, arg: Temporal.Instant | string, ): number { + // TODO: do a better error message? // if (typeof timeZone.getOffsetNanosecondsFor !== 'function') { // throw new TypeError('getOffsetNanosecondsFor should be callable') // } + const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(arg) + if (typeof offsetNanoseconds !== 'number') { throw new TypeError('Invalid return value from getOffsetNanosecondsFor') } + if (!Number.isInteger(offsetNanoseconds)) { + throw new RangeError('Invalid return value from getOffsetNanosecondsFor') + } + return offsetNanoseconds } From c5f1ccf12abc9387c54ab53998452733b9c4cc4c Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 02:13:57 -0400 Subject: [PATCH 021/805] police max timezone offset --- .../misc/expected-failures.txt | 21 ------------------- .../src/dateUtils/timeZone.ts | 6 +++++- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 3827fc5f..3729c0c7 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -43,33 +43,12 @@ intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js # out-of-range built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js -built-ins/Temporal/Calendar/prototype/dateUntil/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/day/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/dayOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/dayOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/daysInWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/daysInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/inLeapYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/month/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/monthCode/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/monthsInYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/year/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js -built-ins/Temporal/Calendar/prototype/dateAdd/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js -built-ins/Temporal/Calendar/prototype/yearOfWeek/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js diff --git a/packages/temporal-polyfill/src/dateUtils/timeZone.ts b/packages/temporal-polyfill/src/dateUtils/timeZone.ts index d3587ad7..279a177b 100644 --- a/packages/temporal-polyfill/src/dateUtils/timeZone.ts +++ b/packages/temporal-polyfill/src/dateUtils/timeZone.ts @@ -89,7 +89,11 @@ export function getSafeOffsetNanosecondsFor( if (typeof offsetNanoseconds !== 'number') { throw new TypeError('Invalid return value from getOffsetNanosecondsFor') } - if (!Number.isInteger(offsetNanoseconds)) { + + if ( + !Number.isInteger(offsetNanoseconds) || + Math.abs(offsetNanoseconds) >= nanoInDay + ) { throw new RangeError('Invalid return value from getOffsetNanosecondsFor') } From 12a33f1a7bf7b5a48d465f54110dd7016d0d18a7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 02:47:14 -0400 Subject: [PATCH 022/805] fix overflow parsing --- packages/temporal-polyfill/misc/expected-failures.txt | 5 ----- packages/temporal-polyfill/src/argParse/refine.ts | 8 ++++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 3729c0c7..e33666c8 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -49,11 +49,6 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js -built-ins/Temporal/Calendar/prototype/dateAdd/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/dateFromFields/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-wrong-type.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-wrong-type.js -built-ins/Temporal/TimeZone/prototype/getInstantFor/disambiguation-wrong-type.js # calendars must match built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index 3b167784..6238406a 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -30,10 +30,14 @@ export function createParser(nameForError: string, map: Map, defaultVal?: V } return d } - if (map[input] === undefined) { + if (typeof input === 'symbol') { + throw new TypeError('Invalid type') + } + const strInput = String(input) as keyof Map + if (map[strInput] === undefined) { throw new RangeError(`Invalid ${nameForError}: ${String(input)}`) } - return map[input] + return map[strInput] } } From 98b146a882cf142b873787316ac5d3b635679593 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 12:45:26 -0400 Subject: [PATCH 023/805] fix rangeerror for offsets beyond 24h --- packages/temporal-polyfill/misc/expected-failures.txt | 5 ----- packages/temporal-polyfill/src/public/instant.ts | 4 ++++ .../temporal-polyfill/src/timeZoneImpl/timeZoneImplQuery.ts | 4 +++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index e33666c8..cde95273 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -43,12 +43,7 @@ intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js # out-of-range built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js -built-ins/Temporal/TimeZone/prototype/getNextTransition/instant-string-limits.js -built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/instant-string-limits.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/instant-string-limits.js -built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string-limits.js -built-ins/Temporal/TimeZone/prototype/getPreviousTransition/instant-string-limits.js # calendars must match built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js diff --git a/packages/temporal-polyfill/src/public/instant.ts b/packages/temporal-polyfill/src/public/instant.ts index 0db91d52..6e2a4af3 100644 --- a/packages/temporal-polyfill/src/public/instant.ts +++ b/packages/temporal-polyfill/src/public/instant.ts @@ -18,6 +18,7 @@ import { HOUR, NANOSECOND, SECOND, + nanoInDay, nanoInMicro, nanoInMilli, nanoInSecond, @@ -76,6 +77,9 @@ export class Instant implements Temporal.Instant { if (offsetNano === undefined) { throw new RangeError('Must specify an offset') } + if (Math.abs(offsetNano) >= nanoInDay) { + throw new RangeError('Offset out of bounds') + } return new Instant( isoFieldsToEpochNano(constrainDateTimeISO(fields, OVERFLOW_REJECT)) diff --git a/packages/temporal-polyfill/src/timeZoneImpl/timeZoneImplQuery.ts b/packages/temporal-polyfill/src/timeZoneImpl/timeZoneImplQuery.ts index 541f30a7..9aba42df 100644 --- a/packages/temporal-polyfill/src/timeZoneImpl/timeZoneImplQuery.ts +++ b/packages/temporal-polyfill/src/timeZoneImpl/timeZoneImplQuery.ts @@ -20,9 +20,11 @@ export function queryTimeZoneImpl(id: string): TimeZoneImpl { // parse a literal time zone offset const offsetNano = tryParseOffsetNano(id) if (offsetNano !== undefined) { - if (Math.abs(offsetNano) > nanoInDay) { + // TODO: more DRY. search `>= nanoInDay` + if (Math.abs(offsetNano) >= nanoInDay) { throw new RangeError('Offset out of bounds') } + // don't store fixed-offset zones in cache. there could be many return new FixedTimeZoneImpl( formatOffsetISO(offsetNano), From 68a313e9d2db74b1d11f823c2b19798c2876adfd Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 14:17:57 -0400 Subject: [PATCH 024/805] more compliance --- packages/temporal-polyfill/misc/NOTES.txt | 172 +----------------- .../src/argParse/calendar.ts | 5 +- .../src/dateUtils/fromAndWith.ts | 9 +- .../temporal-polyfill/src/public/calendar.ts | 2 +- 4 files changed, 11 insertions(+), 177 deletions(-) diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/misc/NOTES.txt index 993c26c0..cc3c615d 100644 --- a/packages/temporal-polyfill/misc/NOTES.txt +++ b/packages/temporal-polyfill/misc/NOTES.txt @@ -1,171 +1,3 @@ -Internal Access ---------------- - -Calendar::from - "has outer.calendar" - "get outer.calendar" - "has inner.calendar" - "get inner.toString" - "call inner.toString" - - ToTemporalCalendar: (calendarLike) => { - if (ES.Type(calendarLike) === 'Object') { - if (ES.IsTemporalCalendar(calendarLike)) { - return calendarLike; // fast optimization - } - if (HasSlot(calendarLike, CALENDAR)) { - return GetSlot(calendarLike, CALENDAR); // optimization avoids calling .calendar! - } - if (ES.IsTemporalTimeZone(calendarLike)) { - throw new RangeError('Expected a calendar object but received a Temporal.TimeZone'); - } - if ('calendar' NOT-IN calendarLike)) { - return calendarLike; // assume object is a CalendarProtocol - } - - // assume object is datetime-like (but less formal b/c doesnt have slot)... - calendarLike = calendarLike.calendar; - - // same object-parsing as above but without optimizations - if (ES.Type(calendarLike) === 'Object') { - if (ES.IsTemporalTimeZone(calendarLike)) { - throw new RangeError('Expected a calendar object as the calendar property but received a Temporal.TimeZone'); - } - if ('calendar' NOT-IN calendarLike) { - return calendarLike; - } - } - } - // string parsing of calendarLike... - } - - -TypeError vs RangeError ------------------------ - -Temporal.Calendar.from DOCS - - If the value is another Temporal.Calendar object, - or object implementing the calendar protocol, - the same object is returned - - If the value is another Temporal object that carries a calendar or an object with a calendar - property, such as a Temporal.ZonedDateTime, the object's calendar is returned - - Any other value is converted to a string - -Calendar::from (accepts ID or object with calendar property) - assert.throws(RangeError, () => Temporal.Calendar.from({ calendar: "local" })); - --- invalid ISO 8601 string: local - assert.throws(RangeError, () => Temporal.Calendar.from({ calendar: { calendar: "iso8601" } })); - --- invalid ISO 8601 string: [object Object] --- way too nested - RangeError (as well as within { calendar: }) - null - true - "" - 1 - 1n - new Temporal.TimeZone("UTC") --- explicitly disallowed - TypeError (as well as within { calendar: }) - Symbol - -OVERFLOW/DISAMBIGUATION options - RangeError (all below convert to strings) - null - true - false - 2 - 2n - {} - TypeError - Symbol - -PlainDate::from (accepts bag) - RangeError - undefined - null - true - "" - 1 - 1n - TypeError - Symbol() - {} --- required property 'day' missing or undefined - Temporal.PlainDate - a "function" --- same - Temporal.PlainDate.prototype --- invalid receiver (brand check) - -PlainDateTime::from (accepts bag) - RangeError - undefined - null - true - "" - 5 - 5n - TypeError - Symbol() - { year: 2020 } --- required property 'day' missing or undefined - -Instant::from - RangeError - undefined - null - true - "", - 1 - 19761118 - 1n - {}, --- invalid ISO 8601 string: [object Object] - Temporal.Instant - TypeError - Symbol - Temporal.Instant.prototype --- will throw TypeError on toString b/c of branding - -TimeZone::from - RangeError - undefined, - null, - true, - "string", - "local", - "Z", - "-00:00[UTC]", - "+00:01.1", - "-01.1", - "1994-11-05T08:15:30+25:00", - "1994-11-05T13:15:30-25:00", - 7, - 4.2, - 12n, - TypeError - Symbol() - Success - {} --- just returns the object itself - - -parsing -------- - -smarter non-regexp parser -parse arbitrary ending [matter] - - -TimeZone::getOffsetNanosecondsFor laziness/incorrectness --------------------------------------------------------- - -*-not-callable fix is easy - make sure getOffsetNanosecondsFor is callable first, otherwise throw TypeError - seems like we're not calling at all - -*-wrong-type fix is easy - ensure what's returned from getOffsetNanosecondsFor is legit - -what!? - class TZ extends Temporal.TimeZone { - constructor() { super("UTC") } - getOffsetNanosecondsFor(arg) { - console.log('CALLED IT!') - return super.getOffsetNanosecondsFor(arg) - } - } - d = new Temporal.ZonedDateTime(0n, new TZ()) - - // js-temporal polyfill calls getOffsetNanosecondsFor twice!!! +complicated internal property access +------------------------------------ diff --git a/packages/temporal-polyfill/src/argParse/calendar.ts b/packages/temporal-polyfill/src/argParse/calendar.ts index bb914c24..a026db79 100644 --- a/packages/temporal-polyfill/src/argParse/calendar.ts +++ b/packages/temporal-polyfill/src/argParse/calendar.ts @@ -4,10 +4,11 @@ import { ensureObj } from '../dateUtils/abstract' import { Calendar, createDefaultCalendar } from '../public/calendar' export function extractCalendar(input: any): Temporal.CalendarProtocol { - if (input.calendar === undefined) { + const { calendar } = input // access right away. don't use `has` + if (calendar === undefined) { return createDefaultCalendar() } - return ensureObj(Calendar, input.calendar) + return ensureObj(Calendar, calendar) } export function getCommonCalendar( diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 90fe9047..346b9d56 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -262,13 +262,14 @@ function filterFieldsViaCalendar( // TODO: adjust callers of this function fieldNames = fieldNames.filter((fieldName) => fieldName !== 'era' && fieldName !== 'eraYear') - if (calendar.fields) { + const fieldsMethod = calendar.fields // access right away (no `has`) + if (fieldsMethod) { // Calendar::fields tests always expect alphabetical order fieldNames.sort() // convert to array and/or copy (done twice?) // (convert `fieldNames` result to Iterable as well?) - fieldNames = [...calendar.fields(fieldNames)] + fieldNames = [...fieldsMethod.call(calendar, fieldNames)] } else { // a Calendar 'protocol' // filter by method names @@ -328,10 +329,10 @@ function buildSafeFunc( if (!isObjectLike(rawFields)) { throw new TypeError('must be object-like') } - if (rawFields.calendar !== undefined) { + if (rawFields.calendar !== undefined) { // TODO: use `in` ? throw new TypeError('calendar not allowed') } - if (rawFields.timeZone !== undefined) { + if (rawFields.timeZone !== undefined) { // TODO: use `in` ? throw new TypeError('timeZone not allowed') } } diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 59d81af7..b686cecd 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -382,7 +382,7 @@ export class Calendar implements Temporal.Calendar { needReceiver(Calendar, this) const impl = getImpl(this) - const date = ensureObj(PlainDate, dateArg, options) + const date = ensureObj(PlainDate, dateArg) const duration = ensureObj(Duration, durationArg) const overflowHandling = parseOverflowOption(options) const isoFields = translateDate(date, duration, impl, overflowHandling) From 01576573ef318175335a91a90133247b4928cf30 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 16:29:41 -0400 Subject: [PATCH 025/805] more member access order improvements --- packages/temporal-polyfill/misc/NOTES.txt | 11 +++++++++++ .../temporal-polyfill/src/argParse/refine.ts | 6 ++++-- .../src/dateUtils/fromAndWith.ts | 19 +++++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/misc/NOTES.txt index cc3c615d..7546fb16 100644 --- a/packages/temporal-polyfill/misc/NOTES.txt +++ b/packages/temporal-polyfill/misc/NOTES.txt @@ -1,3 +1,14 @@ complicated internal property access ------------------------------------ + +order of day/month/year access, + whitelist and refine propertybag props in once pass (hack in place) + ensure proper refining of duration fields + why parsing these fields after parsing options? + 51: 'get date.calendar.year' + 52: 'call date.calendar.year' + 53: 'get date.calendar.month' + 54: 'call date.calendar.month' + 55: 'get date.calendar.day' + 56: 'call date.calendar.day' diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index 6238406a..bd7ec86f 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -74,8 +74,10 @@ export function refineFields } = {} for (const fieldName in refinerMap) { - if (input[fieldName] !== undefined) { - res[fieldName] = refinerMap[fieldName](input[fieldName]) + const val = input[fieldName] // only query once + + if (val !== undefined) { + res[fieldName] = refinerMap[fieldName](val) } } diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 346b9d56..1718c75b 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -286,8 +286,23 @@ function filterFieldsViaWhitelist(objOrFields: any, whitelist: string[]): any { const filtered = Object.create(null) as any for (const propName of whitelist) { - if (propName in objOrFields) { - filtered[propName] = objOrFields[propName] + let val = objOrFields[propName] + if (val !== undefined) { + // HACK until refactor + // must refine props at same time as whitelist + if ( + propName === 'monthCode' + ) { + val = String(val) + } else if ( + propName !== 'calendar' && + propName !== 'timeZone' && + propName !== 'offset' + ) { + val = Number(val) + } + + filtered[propName] = val } } From 1fc5ea51ec0afc9d64aae48ac5ba24cda3446ca8 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 22:50:59 -0400 Subject: [PATCH 026/805] more fixes --- packages/temporal-polyfill/misc/NOTES.txt | 14 +-- .../misc/expected-failures.txt | 9 +- .../src/argParse/fieldStr.ts | 37 +++++-- .../temporal-polyfill/src/argParse/refine.ts | 15 ++- .../src/dateUtils/fromAndWith.ts | 103 +++++++----------- .../src/dateUtils/localFields.ts | 1 + .../temporal-polyfill/src/public/calendar.ts | 59 ++++++++-- 7 files changed, 137 insertions(+), 101 deletions(-) diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/misc/NOTES.txt index 7546fb16..ff322d81 100644 --- a/packages/temporal-polyfill/misc/NOTES.txt +++ b/packages/temporal-polyfill/misc/NOTES.txt @@ -1,14 +1,6 @@ complicated internal property access ------------------------------------ - -order of day/month/year access, - whitelist and refine propertybag props in once pass (hack in place) - ensure proper refining of duration fields - why parsing these fields after parsing options? - 51: 'get date.calendar.year' - 52: 'call date.calendar.year' - 53: 'get date.calendar.month' - 54: 'call date.calendar.month' - 55: 'get date.calendar.day' - 56: 'call date.calendar.day' +failing because we need to bypass constructor when creating internal instances, +to avoid re-parsing input. technique: +https://github.com/js-temporal/temporal-polyfill/blob/main/lib/ecmascript.ts#L1826-L1827 diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index cde95273..4da7bd9e 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -12,13 +12,7 @@ # # complicated internal property access -built-ins/Temporal/Calendar/prototype/dateAdd/order-of-operations.js -built-ins/Temporal/Calendar/prototype/dateUntil/order-of-operations.js -built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js -built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties.js # # Legit bugs @@ -34,6 +28,7 @@ built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js +built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js # monthDayFromFields intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js @@ -46,7 +41,6 @@ built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js # calendars must match -built-ins/Temporal/Calendar/prototype/dateUntil/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js @@ -66,6 +60,7 @@ built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js # Calendar::mergeFields built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js +built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js diff --git a/packages/temporal-polyfill/src/argParse/fieldStr.ts b/packages/temporal-polyfill/src/argParse/fieldStr.ts index 46953a22..5c882ac2 100644 --- a/packages/temporal-polyfill/src/argParse/fieldStr.ts +++ b/packages/temporal-polyfill/src/argParse/fieldStr.ts @@ -1,19 +1,44 @@ import { strArrayToHash } from '../utils/obj' import { durationUnitNames } from './unitStr' -export const yearMonthFieldMap = { +const eraFieldMap = { era: String, eraYear: refineNumber, +} + +export const yearMonthFieldMap = { year: refineNumber, month: refineNumber, monthCode: String, } +export const allYearMonthFieldMap = { + ...eraFieldMap, + ...yearMonthFieldMap, +} + +export const monthDayFieldMap = { + year: refineNumber, + month: refineNumber, + monthCode: String, + day: refineNumber, +} + +export const allMonthDayFieldMap = { + ...eraFieldMap, + ...monthDayFieldMap, +} + export const dateFieldMap = { ...yearMonthFieldMap, day: refineNumber, } +export const allDateFieldMap = { + ...eraFieldMap, + ...dateFieldMap, +} + export const timeFieldMap = { hour: refineNumber, minute: refineNumber, @@ -23,13 +48,9 @@ export const timeFieldMap = { nanosecond: refineNumber, } -export const monthDayFieldMap = { - era: String, - eraYear: refineNumber, - year: refineNumber, - month: refineNumber, - monthCode: String, - day: refineNumber, +export const dateTimeFieldMap = { + ...dateFieldMap, + ...timeFieldMap, } // TODO: more DRY with constrainInt diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index bd7ec86f..febc16f2 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -70,13 +70,22 @@ export function constrainInt( export function refineFields any }>( input: { [FieldName in keyof Map]?: unknown }, refinerMap: Map, + isRequiredMap: any = {}, ): { [FieldName in keyof Map]?: ReturnType } { - const res: { [FieldName in keyof Map]?: ReturnType } = {} + const res: any = {} - for (const fieldName in refinerMap) { + // guarantees strict order + // very suboptimal! + const fieldNames = Object.keys(refinerMap).sort() + + for (const fieldName of fieldNames) { const val = input[fieldName] // only query once - if (val !== undefined) { + if (val === undefined) { + if (isRequiredMap[fieldName]) { + throw new TypeError(`Prop ${fieldName} is required`) + } + } else { res[fieldName] = refinerMap[fieldName](val) } } diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 1718c75b..e61b42fb 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -1,7 +1,9 @@ import { Temporal } from 'temporal-spec' import { extractCalendar } from '../argParse/calendar' import { + allDateFieldMap, dateFieldMap, + dateTimeFieldMap, durationFieldMap, monthDayFieldMap, timeFieldMap, @@ -17,7 +19,7 @@ import { PlainYearMonth } from '../public/plainYearMonth' import { ZonedDateTime } from '../public/zonedDateTime' import { mapHash } from '../utils/obj' import { constrainTimeISO } from './constrain' -import { partialLocalTimeToISO, zeroISOTimeFields } from './dayAndTime' +import { partialLocalTimeToISO } from './dayAndTime' import { DurationFields } from './durationFields' import { isoEpochLeapYear } from './epoch' import { ISOTimeFields } from './isoFields' @@ -66,13 +68,17 @@ function tryDateTimeFromFields( overflowHandling: OverflowHandlingInt, options?: Temporal.AssignmentOptions, ): Temporal.PlainDateTimeISOFields | undefined { - const dateRes = tryDateFromFields(rawFields, options, true) - const timeRes = tryTimeFromFields(rawFields, overflowHandling) + const calendar = extractCalendar(rawFields) + const refinedFields = refineFieldsViaCalendar(rawFields, dateTimeFieldMap, calendar) - if (dateRes) { + if (hasAnyProps(refinedFields)) { return { - ...dateRes.getISOFields(), - ...(timeRes || zeroISOTimeFields), + // TODO: more DRY with tryTimeFromFields + // ALSO: very important time-fields are read from refinedFields before passing + // refinedFields to dateFromFields, because dateFromFields has potential to mutate it + ...constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling), + // + ...calendar.dateFromFields(refinedFields, options).getISOFields(), } } } @@ -80,17 +86,12 @@ function tryDateTimeFromFields( function tryDateFromFields( rawFields: Temporal.PlainDateLike, options?: Temporal.AssignmentOptions, - doingDateTime?: boolean, ): PlainDate | undefined { const calendar = extractCalendar(rawFields) - const filteredFields = filterFieldsViaCalendar( - rawFields, - doingDateTime ? { ...dateFieldMap, ...timeFieldMap } : dateFieldMap, - calendar, - ) + const refinedFields = refineFieldsViaCalendar(rawFields, dateFieldMap, calendar) - if (hasAnyProps(filteredFields)) { - return calendar.dateFromFields(filteredFields, options) + if (hasAnyProps(refinedFields)) { + return calendar.dateFromFields(refinedFields, options) } } @@ -99,10 +100,10 @@ function tryYearMonthFromFields( options?: Temporal.AssignmentOptions, ): PlainYearMonth | undefined { const calendar = extractCalendar(rawFields) - const filteredFields = filterFieldsViaCalendar(rawFields, yearMonthFieldMap, calendar) + const refinedFields = refineFieldsViaCalendar(rawFields, yearMonthFieldMap, calendar) - if (hasAnyProps(filteredFields)) { - return calendar.yearMonthFromFields(filteredFields, options) + if (hasAnyProps(refinedFields)) { + return calendar.yearMonthFromFields(refinedFields, options) } } @@ -111,14 +112,14 @@ function tryMonthDayFromFields( options?: Temporal.AssignmentOptions, ): PlainMonthDay | undefined { const calendar = extractCalendar(rawFields) - const filteredFields = filterFieldsViaCalendar(rawFields, monthDayFieldMap, calendar) + const refinedFields = refineFieldsViaCalendar(rawFields, monthDayFieldMap, calendar) - if (hasAnyProps(filteredFields)) { + if (hasAnyProps(refinedFields)) { if (rawFields.year === undefined && rawFields.calendar === undefined) { - filteredFields.year = isoEpochLeapYear + refinedFields.year = isoEpochLeapYear } - return calendar.monthDayFromFields(filteredFields, options) + return calendar.monthDayFromFields(refinedFields, options) } } @@ -179,7 +180,7 @@ function tryDateWithFields( options?: Temporal.AssignmentOptions, ): PlainDate | undefined { const calendar: Calendar = plainDate.calendar - const filteredFields = filterFieldsViaCalendar(rawFields, dateFieldMap, calendar) + const filteredFields = refineFieldsViaCalendar(rawFields, dateFieldMap, calendar) if (hasAnyProps(filteredFields)) { const mergedFields = mergeFieldsViaCalendar(plainDate, filteredFields, dateFieldMap, calendar) @@ -193,7 +194,7 @@ function tryYearMonthWithFields( options?: Temporal.AssignmentOptions, ): PlainYearMonth | undefined { const calendar: Calendar = plainYearMonth.calendar - const filteredFields = filterFieldsViaCalendar(rawFields, yearMonthFieldMap, calendar) + const filteredFields = refineFieldsViaCalendar(rawFields, yearMonthFieldMap, calendar) if (hasAnyProps(filteredFields)) { const mergedFields = mergeFieldsViaCalendar( @@ -212,7 +213,7 @@ function tryMonthDayWithFields( options?: Temporal.AssignmentOptions, ): PlainMonthDay | undefined { const calendar: Calendar = plainMonthDay.calendar - const filteredFields = filterFieldsViaCalendar(rawFields, monthDayFieldMap, calendar) + const filteredFields = refineFieldsViaCalendar(rawFields, monthDayFieldMap, calendar) if (hasAnyProps(filteredFields)) { const mergedFields = mergeFieldsViaCalendar( @@ -250,18 +251,13 @@ function tryDurationFields(rawFields: any): DurationFields | undefined { // utils -function filterFieldsViaCalendar( +function refineFieldsViaCalendar( objOrFields: any, fieldMap: any, calendar: Temporal.CalendarProtocol, ): any { let fieldNames = Object.keys(fieldMap) - // HACK: Calendar::fields doesn't like to accept era/eraYear - // instead, the fields() method of the Calendar will inject it - // TODO: adjust callers of this function - fieldNames = fieldNames.filter((fieldName) => fieldName !== 'era' && fieldName !== 'eraYear') - const fieldsMethod = calendar.fields // access right away (no `has`) if (fieldsMethod) { // Calendar::fields tests always expect alphabetical order @@ -270,43 +266,22 @@ function filterFieldsViaCalendar( // convert to array and/or copy (done twice?) // (convert `fieldNames` result to Iterable as well?) fieldNames = [...fieldsMethod.call(calendar, fieldNames)] - } else { - // a Calendar 'protocol' - // filter by method names - fieldNames = Object.keys(filterFieldsViaWhitelist(calendar, fieldNames)) } - return filterFieldsViaWhitelist(objOrFields, fieldNames) -} - -function filterFieldsViaWhitelist(objOrFields: any, whitelist: string[]): any { - /* - needed for "* should be called with null-prototype fields object" - */ - const filtered = Object.create(null) as any - - for (const propName of whitelist) { - let val = objOrFields[propName] - if (val !== undefined) { - // HACK until refactor - // must refine props at same time as whitelist - if ( - propName === 'monthCode' - ) { - val = String(val) - } else if ( - propName !== 'calendar' && - propName !== 'timeZone' && - propName !== 'offset' - ) { - val = Number(val) - } - - filtered[propName] = val + // TODO: more DRY with refineFields + const refinedFields: any = Object.create(null) // must be null-prototype for dateFromFields,etc + for (const fieldName of fieldNames) { + const rawValue = objOrFields[fieldName] + if (rawValue !== undefined) { + refinedFields[fieldName] = (fieldMap[fieldName] || identifyFunc)(rawValue) } } - return filtered + return refinedFields +} + +function identifyFunc(a: any): any { + return a } function mergeFieldsViaCalendar( @@ -315,9 +290,9 @@ function mergeFieldsViaCalendar( fieldMap: any, calendar: Temporal.CalendarProtocol, ): any { - const existingFields = filterFieldsViaCalendar(existingObj, fieldMap, calendar) + const existingFields = refineFieldsViaCalendar(existingObj, fieldMap, calendar) - if (calendar.mergeFields) { + if (calendar.mergeFields) { // TODO: more frugal querying? return calendar.mergeFields(existingFields, fields) } diff --git a/packages/temporal-polyfill/src/dateUtils/localFields.ts b/packages/temporal-polyfill/src/dateUtils/localFields.ts index 611e350a..9fd31c0e 100644 --- a/packages/temporal-polyfill/src/dateUtils/localFields.ts +++ b/packages/temporal-polyfill/src/dateUtils/localFields.ts @@ -1,5 +1,6 @@ // local essentials // special note about not doing spreads +// BAD: is "local" the best name? nothing to do with timezones export interface LocalYearFields { year: number; diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index b686cecd..491201e7 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -1,6 +1,6 @@ import { Temporal } from 'temporal-spec' import { ensureCalendarsEqual, getCommonCalendar } from '../argParse/calendar' -import { dateFieldMap, monthDayFieldMap, yearMonthFieldMap } from '../argParse/fieldStr' +import { allDateFieldMap, allMonthDayFieldMap, allYearMonthFieldMap } from '../argParse/fieldStr' import { parseOverflowOption } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike, refineFields } from '../argParse/refine' import { parseUnit } from '../argParse/unitStr' @@ -305,7 +305,13 @@ export class Calendar implements Temporal.Calendar { ): Temporal.PlainDate { needReceiver(Calendar, this) - const refinedFields = refineFields(fields, dateFieldMap) + const refinedFields = refineFields( + fields, + allDateFieldMap, + getImpl(this).id === 'iso8601' + ? { year: true, day: true } + : {}, + ) const isoFields = queryDateISOFields(refinedFields, getImpl(this), options) return new PlainDate( @@ -322,7 +328,13 @@ export class Calendar implements Temporal.Calendar { ): Temporal.PlainYearMonth { needReceiver(Calendar, this) - const refinedFields = refineFields(fields, yearMonthFieldMap) + const refinedFields = refineFields( + fields, + allYearMonthFieldMap, + getImpl(this).id === 'iso8601' + ? { year: true } + : {}, + ) const isoFields = queryDateISOFields({ ...refinedFields, day: 1 }, getImpl(this), options) return new PlainYearMonth( @@ -340,7 +352,13 @@ export class Calendar implements Temporal.Calendar { needReceiver(Calendar, this) const impl = getImpl(this) - let { era, eraYear, year, month, monthCode, day } = refineFields(fields, monthDayFieldMap) + let { era, eraYear, year, month, monthCode, day } = refineFields( + fields, + allMonthDayFieldMap, + getImpl(this).id === 'iso8601' + ? { day: true } + : {}, + ) if (day === undefined) { throw new TypeError('required property \'day\' missing or undefined') @@ -385,12 +403,21 @@ export class Calendar implements Temporal.Calendar { const date = ensureObj(PlainDate, dateArg) const duration = ensureObj(Duration, durationArg) const overflowHandling = parseOverflowOption(options) - const isoFields = translateDate(date, duration, impl, overflowHandling) - return new PlainDate( + // TODO: make less verbose. ALSO, cache cal dates in WeakMap for use by non-iso calImpl + const isoFields = getExistingDateISOFields(date, true) // disallowMonthDay=true + const calFields = isoToEpochNanoSafe( + getImpl(this), isoFields.isoYear, isoFields.isoMonth, isoFields.isoDay, + ) + const translatedIsoFields = translateDate(calFields, duration, impl, overflowHandling) + + return new PlainDate( + translatedIsoFields.isoYear, + translatedIsoFields.isoMonth, + translatedIsoFields.isoDay, this, ) } @@ -410,10 +437,26 @@ export class Calendar implements Temporal.Calendar { ? DAY // TODO: util for this? : parseUnit(largestUnitStr, DAY, DAY, YEAR) - ensureCalendarsEqual(this, getCommonCalendar(d0, d1)) + // ensureCalendarsEqual(this, getCommonCalendar(d0, d1)) + + // TODO: make less verbose. ALSO, cache cal dates in WeakMap for use by non-iso calImpl + const isoFields0 = getExistingDateISOFields(d0, true) // disallowMonthDay=true + const calFields0 = isoToEpochNanoSafe( + getImpl(this), + isoFields0.isoYear, + isoFields0.isoMonth, + isoFields0.isoDay, + ) + const isoFields1 = getExistingDateISOFields(d1, true) // disallowMonthDay=true + const calFields1 = isoToEpochNanoSafe( + getImpl(this), + isoFields1.isoYear, + isoFields1.isoMonth, + isoFields1.isoDay, + ) return createDuration( - diffDateFields(d0, d1, impl, largestUnit), + diffDateFields(calFields0, calFields1, impl, largestUnit), ) } From 73b88ed03f82c44f2d97a889e3a7854d757009ac Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 26 Mar 2023 23:14:24 -0400 Subject: [PATCH 027/805] change where calendar-specific bugs are checked --- .../src/dateUtils/isoFieldValidation.ts | 17 ++++------------- .../temporal-polyfill/src/public/plainDate.ts | 3 +-- .../src/public/plainDateTime.ts | 2 +- .../src/public/plainYearMonth.ts | 3 --- .../src/public/zonedDateTime.ts | 2 +- 5 files changed, 7 insertions(+), 20 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/isoFieldValidation.ts b/packages/temporal-polyfill/src/dateUtils/isoFieldValidation.ts index 2783f285..e148e1b7 100644 --- a/packages/temporal-polyfill/src/dateUtils/isoFieldValidation.ts +++ b/packages/temporal-polyfill/src/dateUtils/isoFieldValidation.ts @@ -1,4 +1,3 @@ -import { checkEpochNanoBuggy } from '../calendarImpl/bugs' import { LargeInt, compareLargeInts, createLargeInt } from '../utils/largeInt' import { isoFieldsToEpochNano, throwOutOfRange } from './epoch' import { ISODateFields, ISODateTimeFields } from './isoFields' @@ -29,30 +28,22 @@ const minInstantBI = maxInstantBI.mult(-1) const maxPlainBI = maxInstantBI.add(almostDay) const minPlainBI = minInstantBI.sub(almostDay) -export function validateYearMonth(isoFields: ISODateFields, calendarID: string): void { - // might throw an error - // moves between days in month - const epochNano = isoFieldsToEpochNano(isoFields) - - checkEpochNanoBuggy(epochNano, calendarID) -} - -export function validateDate(isoFields: ISODateFields, calendarID: string): void { +export function validateDate(isoFields: ISODateFields): void { const epochNano = isoFieldsToEpochNano(isoFields) validatePlain( // if potentially very negative, measure last nanosecond of day // to increase chances it's in-bounds + // TODO: checkout how js-temporal uses 12:00 + // ALSO, js-temporal might just police years, not epochNano epochNano.add(epochNano.sign() < 0 ? almostDay : 0), ) - checkEpochNanoBuggy(epochNano, calendarID) } -export function validateDateTime(isoFields: ISODateTimeFields, calendarID: string): void { +export function validateDateTime(isoFields: ISODateTimeFields): void { const epochNano = isoFieldsToEpochNano(isoFields) validatePlain(epochNano) - checkEpochNanoBuggy(epochNano, calendarID) } export function validateInstant(epochNano: LargeInt): void { diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index fc596e3a..dc7e4235 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -58,8 +58,7 @@ export class PlainDate implements Temporal.PlainDate { const constrained = constrainDateISO({ isoYear, isoMonth, isoDay }, OVERFLOW_REJECT) const calendar = ensureObj(Calendar, calendarArg) - validateDate(constrained, calendar.toString()) - + validateDate(constrained) initIsoMaster(this, { ...constrained, calendar, diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/public/plainDateTime.ts index 5187ed75..4363d728 100644 --- a/packages/temporal-polyfill/src/public/plainDateTime.ts +++ b/packages/temporal-polyfill/src/public/plainDateTime.ts @@ -86,7 +86,7 @@ export class PlainDateTime implements Temporal.PlainDateTime { const calendar = ensureObj(Calendar, calendarArg) - validateDateTime(constrained, calendar.toString()) + validateDateTime(constrained) initIsoMaster(this, { ...constrained, diff --git a/packages/temporal-polyfill/src/public/plainYearMonth.ts b/packages/temporal-polyfill/src/public/plainYearMonth.ts index 449853af..dcf8eae0 100644 --- a/packages/temporal-polyfill/src/public/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/public/plainYearMonth.ts @@ -17,7 +17,6 @@ import { constrainDateISO } from '../dateUtils/constrain' import { diffDates } from '../dateUtils/diff' import { DurationFields, negateDuration } from '../dateUtils/durationFields' import { processYearMonthFromFields, processYearMonthWithFields } from '../dateUtils/fromAndWith' -import { validateYearMonth } from '../dateUtils/isoFieldValidation' import { formatCalendarID, formatDateISO, formatYearMonthISO } from '../dateUtils/isoFormat' import { YearMonthCalendarFields, @@ -55,8 +54,6 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { }, OVERFLOW_REJECT) const calendar = ensureObj(Calendar, calendarArg) - validateYearMonth(constrained, calendar.toString()) - initIsoMaster(this, { ...constrained, calendar, diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/public/zonedDateTime.ts index 3aa82a74..77b4d78b 100644 --- a/packages/temporal-polyfill/src/public/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/public/zonedDateTime.ts @@ -129,7 +129,7 @@ function buildComputeds(internals: ZonedDateTimeInternals): ZonedDateTimeCompute internals.epochNanoseconds, internals.timeZone, ) - validateDateTime(isoFields, internals.calendar.toString()) + validateDateTime(isoFields) return { ...isoFields, offsetNanoseconds, From 116f6b9a42014f8b1aa5710588d484c0ddd8a69a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 14:23:18 -0400 Subject: [PATCH 028/805] stricter monthCode parsing --- .../temporal-polyfill/misc/expected-failures.txt | 15 ++++----------- .../src/calendarImpl/calendarImpl.ts | 16 ++++++++-------- .../src/calendarImpl/intlCalendarImpl.ts | 12 ++++++++---- .../temporal-polyfill/src/dateUtils/calendar.ts | 5 +++++ .../temporal-polyfill/src/dateUtils/constrain.ts | 8 ++++++++ .../temporal-polyfill/src/public/calendar.ts | 1 - 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 4da7bd9e..6e6fde8b 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -13,23 +13,17 @@ # complicated internal property access built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js - -# -# Legit bugs -# - -# monthCode built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/monthcode-invalid.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/overflow-constrain.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/monthcode-invalid.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/overflow-constrain.js intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js +# +# Legit bugs +# + # monthDayFromFields intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js @@ -37,7 +31,6 @@ intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js # out-of-range -built-ins/Temporal/Calendar/prototype/dateFromFields/throws-range-error.js built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js # calendars must match diff --git a/packages/temporal-polyfill/src/calendarImpl/calendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl/calendarImpl.ts index bb0817cd..a06d62ab 100644 --- a/packages/temporal-polyfill/src/calendarImpl/calendarImpl.ts +++ b/packages/temporal-polyfill/src/calendarImpl/calendarImpl.ts @@ -49,15 +49,15 @@ export abstract class CalendarImpl { number, // month boolean, // unusedLeap (a valid 'L', but not used in this year) ] { - // TODO: more DRY - const monthCodeIsLeap = /L$/.test(monthCode) - const monthCodeInt = parseInt(monthCode.substr(1)) // chop off 'M' - - if (monthCodeIsLeap) { - throw new RangeError('Calendar system doesnt support leap months') // TODO: more DRY + // TODO: more DRY with intlCalendarImpl + const m = monthCode.match(/^M(\d{2})(L?)$/) + if (!m) { + throw new RangeError('Invalid monthCode format') } - - return [monthCodeInt, false] + if (m[2]) { + throw new RangeError('Calendar system doesnt support leap months') + } + return [parseInt(m[1]), false] } } diff --git a/packages/temporal-polyfill/src/calendarImpl/intlCalendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl/intlCalendarImpl.ts index 781d8970..ad2ccd0c 100644 --- a/packages/temporal-polyfill/src/calendarImpl/intlCalendarImpl.ts +++ b/packages/temporal-polyfill/src/calendarImpl/intlCalendarImpl.ts @@ -94,13 +94,17 @@ export class IntlCalendarImpl extends CalendarImpl { convertMonthCode(monthCode: string, year: number): [number, boolean] { const leapMonth = this.queryLeapMonthByYear(year) // 0 if none - // TODO: more DRY - let monthCodeIsLeap = /L$/.test(monthCode) - let monthCodeInt = parseInt(monthCode.substr(1)) // chop off 'M' + // TODO: more DRY with calendarImpl + const m = monthCode.match(/^M(\d{2})(L?)$/) + if (!m) { + throw new RangeError('Invalid monthCode format') + } + let monthCodeInt = parseInt(m[1]) + let monthCodeIsLeap: string | boolean = m[2] let unusedLeap = false // validate the leap-month - if (monthCodeIsLeap) { + if (m[2]) { const presetLeapMonth = calLeapMonths[this.id] // TODO: use base ID? if (presetLeapMonth === undefined) { diff --git a/packages/temporal-polyfill/src/dateUtils/calendar.ts b/packages/temporal-polyfill/src/dateUtils/calendar.ts index 87551914..acb916e0 100644 --- a/packages/temporal-polyfill/src/dateUtils/calendar.ts +++ b/packages/temporal-polyfill/src/dateUtils/calendar.ts @@ -103,6 +103,11 @@ export function queryDateISOFields( month = tryMonth + // always throw RangeError for out-of-range monthCode, regardless of 'constrain' option + if (month < 1 || month > calendarImpl.monthsInYear(year)) { + throw new RangeError('monthCode out of range') + } + if (unusedLeap) { if (overflow === OVERFLOW_REJECT) { throw new RangeError('Month code out of range') diff --git a/packages/temporal-polyfill/src/dateUtils/constrain.ts b/packages/temporal-polyfill/src/dateUtils/constrain.ts index 06a31ea6..7e438622 100644 --- a/packages/temporal-polyfill/src/dateUtils/constrain.ts +++ b/packages/temporal-polyfill/src/dateUtils/constrain.ts @@ -11,6 +11,14 @@ export function constrainDateFields( calendarImpl: CalendarImpl, overflow: OverflowHandlingInt, ): [number, number, number] { + // regardless of overflow option + if (month < 1) { + throw new RangeError('Month must be positive') + } + if (day < 1) { + throw new RangeError('Day must be positive') + } + year = Number(year) // not using constrainValue, which converts to a number month = constrainInt(month, 1, calendarImpl.monthsInYear(year), overflow) day = constrainInt(day, 1, calendarImpl.daysInMonth(year, month), overflow) diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 491201e7..47167cf7 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -1,5 +1,4 @@ import { Temporal } from 'temporal-spec' -import { ensureCalendarsEqual, getCommonCalendar } from '../argParse/calendar' import { allDateFieldMap, allMonthDayFieldMap, allYearMonthFieldMap } from '../argParse/fieldStr' import { parseOverflowOption } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike, refineFields } from '../argParse/refine' From da2bd1d361fe0a94268fa85877e21c97f40ea5c1 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 14:52:02 -0400 Subject: [PATCH 029/805] stricter field parsing --- .../misc/expected-failures.txt | 1 - .../src/argParse/fieldStr.ts | 98 ++++++++++++++++--- .../temporal-polyfill/src/argParse/refine.ts | 6 +- .../src/dateUtils/relativeTo.ts | 10 +- .../temporal-polyfill/src/public/calendar.ts | 12 ++- .../temporal-polyfill/src/public/duration.ts | 8 +- .../temporal-polyfill/src/public/instant.ts | 6 +- .../temporal-polyfill/src/public/plainDate.ts | 6 +- .../src/public/plainDateTime.ts | 8 +- .../src/public/plainMonthDay.ts | 6 +- .../temporal-polyfill/src/public/plainTime.ts | 6 +- .../src/public/plainYearMonth.ts | 6 +- .../temporal-polyfill/src/public/timeZone.ts | 6 +- .../src/public/zonedDateTime.ts | 7 +- 14 files changed, 114 insertions(+), 72 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 6e6fde8b..067a6772 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -16,7 +16,6 @@ built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js -intl402/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js diff --git a/packages/temporal-polyfill/src/argParse/fieldStr.ts b/packages/temporal-polyfill/src/argParse/fieldStr.ts index 5c882ac2..c23cb1e8 100644 --- a/packages/temporal-polyfill/src/argParse/fieldStr.ts +++ b/packages/temporal-polyfill/src/argParse/fieldStr.ts @@ -7,9 +7,9 @@ const eraFieldMap = { } export const yearMonthFieldMap = { - year: refineNumber, - month: refineNumber, - monthCode: String, + year: toIntNoInfinity, + month: toPositiveInt, + monthCode: toString, } export const allYearMonthFieldMap = { @@ -17,11 +17,11 @@ export const allYearMonthFieldMap = { ...yearMonthFieldMap, } -export const monthDayFieldMap = { - year: refineNumber, - month: refineNumber, - monthCode: String, - day: refineNumber, +export const monthDayFieldMap = { // YUCK, a lot of redefining + year: toIntNoInfinity, + month: toPositiveInt, + monthCode: toString, + day: toPositiveInt, } export const allMonthDayFieldMap = { @@ -31,7 +31,7 @@ export const allMonthDayFieldMap = { export const dateFieldMap = { ...yearMonthFieldMap, - day: refineNumber, + day: toPositiveInt, } export const allDateFieldMap = { @@ -40,12 +40,12 @@ export const allDateFieldMap = { } export const timeFieldMap = { - hour: refineNumber, - minute: refineNumber, - second: refineNumber, - millisecond: refineNumber, - microsecond: refineNumber, - nanosecond: refineNumber, + hour: toIntNoFrac, + minute: toIntNoFrac, + second: toIntNoFrac, + millisecond: toIntNoFrac, + microsecond: toIntNoFrac, + nanosecond: toIntNoFrac, } export const dateTimeFieldMap = { @@ -54,6 +54,8 @@ export const dateTimeFieldMap = { } // TODO: more DRY with constrainInt +// ... + function refineNumber(input: any): number { const num = Number(input) @@ -64,4 +66,70 @@ function refineNumber(input: any): number { return num } +function toPositiveInt(valueParam: unknown, property?: string): number { + const value = toInt(valueParam) + if (!Number.isFinite(value)) { + throw new RangeError('infinity is out of range') + } + if (value < 1) { + if (property !== undefined) { + throw new RangeError(`property '${property}' cannot be a a number less than one`) + } + throw new RangeError('Cannot convert a number less than one to a positive integer') + } + return value +} + +/* +throws on infinity +throws on fractional values +*/ +function toIntNoFrac(valueParam: unknown): number { + const value = toNumber(valueParam) + if (isNaN(value)) return 0 + if (!Number.isFinite(value)) { + throw new RangeError('infinity is out of range') + } + if (!Number.isInteger(value)) { + throw new RangeError(`unsupported fractional value ${value}`) + } + return toInt(value) +} + +/* +throws on infinity +truncates on fractional values +*/ +function toIntNoInfinity(value: unknown): number { + const integer = toInt(value) + if (!Number.isFinite(integer)) { + throw new RangeError('infinity is out of range') + } + return integer +} + +/* +allows infinity +truncates on fractional values +*/ +function toInt(value: unknown): number { // truncates fraction values to integers + const num = toNumber(value) + if (isNaN(num)) return 0 + const integer = Math.trunc(num) + if (num === 0) return 0 // prevents -0. TODO: remove other places that do this + return integer +} + +function toNumber(value: unknown): number { + if (typeof value === 'bigint') throw new TypeError('Cannot convert BigInt to number') + return Number(value) +} + +export function toString(value: unknown): string { + if (typeof value === 'symbol') { + throw new TypeError('Cannot convert a Symbol value to a String') + } + return String(value) +} + export const durationFieldMap = strArrayToHash(durationUnitNames, () => Number) diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index febc16f2..f6801366 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -1,4 +1,5 @@ import { ValueOf } from '../utils/obj' +import { toString } from './fieldStr' import { OVERFLOW_REJECT, OverflowHandlingInt } from './overflowHandling' export function createOptionParser(propName: string, map: Map, defaultVal?: ValueOf): ( @@ -30,10 +31,7 @@ export function createParser(nameForError: string, map: Map, defaultVal?: V } return d } - if (typeof input === 'symbol') { - throw new TypeError('Invalid type') - } - const strInput = String(input) as keyof Map + const strInput = toString(input) as keyof Map if (map[strInput] === undefined) { throw new RangeError(`Invalid ${nameForError}: ${String(input)}`) } diff --git a/packages/temporal-polyfill/src/dateUtils/relativeTo.ts b/packages/temporal-polyfill/src/dateUtils/relativeTo.ts index 8716ae04..30f1ffb4 100644 --- a/packages/temporal-polyfill/src/dateUtils/relativeTo.ts +++ b/packages/temporal-polyfill/src/dateUtils/relativeTo.ts @@ -1,4 +1,5 @@ import { Temporal } from 'temporal-spec' +import { toString } from '../argParse/fieldStr' import { isObjectLike } from '../argParse/refine' import { PlainDateTime, PlainDateTimeArg, createDateTime } from '../public/plainDateTime' import { @@ -29,14 +30,7 @@ export function extractRelativeTo( ) } - // assume a string... - // TODO: general toString util for ALL parsing that prevents parsing symbols - // https://github.com/ljharb/es-abstract/blob/main/2020/ToString.js - if (typeof arg === 'symbol') { - throw new TypeError('Incorrect relativeTo type') - } - - const parsed = tryParseZonedDateTime(String(arg)) + const parsed = tryParseZonedDateTime(toString(arg)) if (parsed) { if (parsed.timeZone !== undefined) { return createZonedDateTimeFromFields(refineZonedObj(parsed), true) diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 47167cf7..d89c367f 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -1,5 +1,10 @@ import { Temporal } from 'temporal-spec' -import { allDateFieldMap, allMonthDayFieldMap, allYearMonthFieldMap } from '../argParse/fieldStr' +import { + allDateFieldMap, + allMonthDayFieldMap, + allYearMonthFieldMap, + toString, +} from '../argParse/fieldStr' import { parseOverflowOption } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike, refineFields } from '../argParse/refine' import { parseUnit } from '../argParse/unitStr' @@ -79,10 +84,7 @@ export class Calendar implements Temporal.Calendar { } // parse as string... - if (typeof arg === 'symbol') { - throw new TypeError('Calendar cannot be symbol') - } - const strVal = String(arg) + const strVal = toString(arg) const parsed = tryParseDateTime(strVal, false, true) // allowZ=true return new Calendar( parsed // a date-time string? diff --git a/packages/temporal-polyfill/src/public/duration.ts b/packages/temporal-polyfill/src/public/duration.ts index f3e415ca..6d735e64 100644 --- a/packages/temporal-polyfill/src/public/duration.ts +++ b/packages/temporal-polyfill/src/public/duration.ts @@ -1,5 +1,6 @@ import { Temporal } from 'temporal-spec' import { parseDiffOptions } from '../argParse/diffOptions' +import { toString } from '../argParse/fieldStr' import { DurationToStringUnitInt, parseTimeToStringOptions } from '../argParse/isoFormatOptions' import { ensureOptionsObj, isObjectLike } from '../argParse/refine' import { parseTotalConfig } from '../argParse/totalOptions' @@ -68,12 +69,7 @@ export class Duration implements Temporal.Duration { if (isObjectLike(arg)) { return createDuration(processDurationFields(arg)) } - - // parse as string... - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - return createDuration(parseDuration(String(arg))) + return createDuration(parseDuration(toString(arg))) } static compare( diff --git a/packages/temporal-polyfill/src/public/instant.ts b/packages/temporal-polyfill/src/public/instant.ts index 6e2a4af3..12467e84 100644 --- a/packages/temporal-polyfill/src/public/instant.ts +++ b/packages/temporal-polyfill/src/public/instant.ts @@ -1,5 +1,6 @@ import { Temporal } from 'temporal-spec' import { parseDiffOptions } from '../argParse/diffOptions' +import { toString } from '../argParse/fieldStr' import { OVERFLOW_REJECT } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike } from '../argParse/refine' import { parseRoundingOptions } from '../argParse/roundingOptions' @@ -69,10 +70,7 @@ export class Instant implements Temporal.Instant { } // parse as string... - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - const fields = parseZonedDateTime(String(arg)) + const fields = parseZonedDateTime(toString(arg)) const offsetNano = fields.offsetNanoseconds if (offsetNano === undefined) { throw new RangeError('Must specify an offset') diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index dc7e4235..1e16c059 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -2,6 +2,7 @@ import { Temporal } from 'temporal-spec' import { getCommonCalendar } from '../argParse/calendar' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { parseDiffOptions } from '../argParse/diffOptions' +import { toString } from '../argParse/fieldStr' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' import { isObjectLike } from '../argParse/refine' import { @@ -80,10 +81,7 @@ export class PlainDate implements Temporal.PlainDate { } // parse as string... - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - const parsed = parseDateTime(String(arg)) + const parsed = parseDateTime(toString(arg)) // reject out-of-bound time values if included in the string // the date values will be checked in constructor diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/public/plainDateTime.ts index 4363d728..39c969ae 100644 --- a/packages/temporal-polyfill/src/public/plainDateTime.ts +++ b/packages/temporal-polyfill/src/public/plainDateTime.ts @@ -3,6 +3,7 @@ import { getCommonCalendar, getStrangerCalendar } from '../argParse/calendar' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { parseDiffOptions } from '../argParse/diffOptions' import { parseDisambigOption } from '../argParse/disambig' +import { toString } from '../argParse/fieldStr' import { parseTimeToStringOptions } from '../argParse/isoFormatOptions' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' import { isObjectLike } from '../argParse/refine' @@ -110,11 +111,8 @@ export class PlainDateTime implements Temporal.PlainDateTime { return createDateTime(processDateTimeFromFields(arg, overflowHandling, options)) } - // parse as string - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - return createDateTime(refineBaseObj(parseDateTime(String(arg)))) + // parse as string... + return createDateTime(refineBaseObj(parseDateTime(toString(arg)))) } static compare(a: PlainDateTimeArg, b: PlainDateTimeArg): Temporal.ComparisonResult { diff --git a/packages/temporal-polyfill/src/public/plainMonthDay.ts b/packages/temporal-polyfill/src/public/plainMonthDay.ts index 8cadedf0..bbf33b82 100644 --- a/packages/temporal-polyfill/src/public/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/public/plainMonthDay.ts @@ -1,5 +1,6 @@ import { Temporal } from 'temporal-spec' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' +import { toString } from '../argParse/fieldStr' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' import { isObjectLike } from '../argParse/refine' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' @@ -54,10 +55,7 @@ export class PlainMonthDay implements Temporal.PlainMonthDay { } // parse as string... - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - const parsed = parseMonthDay(String(arg)) + const parsed = parseMonthDay(toString(arg)) // for strings, force ISO year if no calendar specified // TODO: more DRY with processMonthDayLike? diff --git a/packages/temporal-polyfill/src/public/plainTime.ts b/packages/temporal-polyfill/src/public/plainTime.ts index 1846eeb1..e3c6cdf7 100644 --- a/packages/temporal-polyfill/src/public/plainTime.ts +++ b/packages/temporal-polyfill/src/public/plainTime.ts @@ -1,5 +1,6 @@ import { Temporal } from 'temporal-spec' import { parseDiffOptions } from '../argParse/diffOptions' +import { toString } from '../argParse/fieldStr' import { parseTimeToStringOptions } from '../argParse/isoFormatOptions' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' import { isObjectLike } from '../argParse/refine' @@ -90,10 +91,7 @@ export class PlainTime implements Temporal.PlainTime { } // parse as string... - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - return createTime(parseTime(String(arg))) + return createTime(parseTime(toString(arg))) } static compare(a: PlainTimeArg, b: PlainTimeArg): Temporal.ComparisonResult { diff --git a/packages/temporal-polyfill/src/public/plainYearMonth.ts b/packages/temporal-polyfill/src/public/plainYearMonth.ts index dcf8eae0..c8ed00c9 100644 --- a/packages/temporal-polyfill/src/public/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/public/plainYearMonth.ts @@ -2,6 +2,7 @@ import { Temporal } from 'temporal-spec' import { getCommonCalendar } from '../argParse/calendar' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { parseDiffOptions } from '../argParse/diffOptions' +import { toString } from '../argParse/fieldStr' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' import { isObjectLike } from '../argParse/refine' import { isoCalendarID } from '../calendarImpl/isoCalendarImpl' @@ -74,10 +75,7 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { } // parse as string... - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - const parsed = parseYearMonth(String(arg)) + const parsed = parseYearMonth(toString(arg)) // don't allow day-numbers in ISO strings if (parsed.calendar === undefined) { diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index 71b20341..1e4d69b6 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -1,5 +1,6 @@ import { Temporal } from 'temporal-spec' import { parseDisambigOption } from '../argParse/disambig' +import { toString } from '../argParse/fieldStr' import { isObjectLike } from '../argParse/refine' import { JsonMethods, ensureObj, mixinJsonMethods, needReceiver } from '../dateUtils/abstract' import { epochNanoSymbol, epochNanoToISOFields, isoFieldsToEpochNano } from '../dateUtils/epoch' @@ -46,10 +47,7 @@ export class TimeZone implements Temporal.TimeZone { } // parse as a string... - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } - const strVal = String(arg) + const strVal = toString(arg) const parsed = tryParseZonedDateTime(strVal) if (parsed) { diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/public/zonedDateTime.ts index 77b4d78b..4be2a042 100644 --- a/packages/temporal-polyfill/src/public/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/public/zonedDateTime.ts @@ -3,6 +3,7 @@ import { getCommonCalendar, getStrangerCalendar } from '../argParse/calendar' import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { parseDiffOptions } from '../argParse/diffOptions' import { parseDisambigOption } from '../argParse/disambig' +import { toString } from '../argParse/fieldStr' import { parseTimeToStringOptions } from '../argParse/isoFormatOptions' import { OFFSET_DISPLAY_AUTO, parseOffsetDisplayOption } from '../argParse/offsetDisplay' import { @@ -163,14 +164,12 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { if (arg instanceof ZonedDateTime) { return new ZonedDateTime(arg.epochNanoseconds, arg.timeZone, arg.calendar) // optimization } - if (typeof arg === 'symbol') { - throw new TypeError('cannot accept symbol') - } + const strVal = toString(arg) const isObject = isObjectLike(arg) const fields = isObject ? processZonedDateTimeFromFields(arg, overflowHandling, options) - : refineZonedObj(parseZonedDateTime(String(arg))) + : refineZonedObj(parseZonedDateTime(strVal)) return createZonedDateTimeFromFields( fields, From 7ae1e48471882677158e8403582aea55a5a99f91 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 15:02:09 -0400 Subject: [PATCH 030/805] iso calendars shouldnt access era/eraYear --- .../misc/expected-failures.txt | 3 --- .../temporal-polyfill/src/public/calendar.ts | 26 +++++++++---------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 067a6772..293e1814 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -13,11 +13,8 @@ # complicated internal property access built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js -built-ins/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js -built-ins/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js -built-ins/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js # # Legit bugs diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index d89c367f..3ce65898 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -3,7 +3,10 @@ import { allDateFieldMap, allMonthDayFieldMap, allYearMonthFieldMap, + dateFieldMap, + monthDayFieldMap, toString, + yearMonthFieldMap, } from '../argParse/fieldStr' import { parseOverflowOption } from '../argParse/overflowHandling' import { ensureOptionsObj, isObjectLike, refineFields } from '../argParse/refine' @@ -306,12 +309,11 @@ export class Calendar implements Temporal.Calendar { ): Temporal.PlainDate { needReceiver(Calendar, this) + const isIso = getImpl(this).id === 'iso8601' const refinedFields = refineFields( fields, - allDateFieldMap, - getImpl(this).id === 'iso8601' - ? { year: true, day: true } - : {}, + isIso ? dateFieldMap : allDateFieldMap, + isIso ? { year: true, day: true } : {}, ) const isoFields = queryDateISOFields(refinedFields, getImpl(this), options) @@ -329,12 +331,11 @@ export class Calendar implements Temporal.Calendar { ): Temporal.PlainYearMonth { needReceiver(Calendar, this) + const isIso = getImpl(this).id === 'iso8601' const refinedFields = refineFields( fields, - allYearMonthFieldMap, - getImpl(this).id === 'iso8601' - ? { year: true } - : {}, + isIso ? yearMonthFieldMap : allYearMonthFieldMap, + isIso ? { year: true } : {}, ) const isoFields = queryDateISOFields({ ...refinedFields, day: 1 }, getImpl(this), options) @@ -353,13 +354,12 @@ export class Calendar implements Temporal.Calendar { needReceiver(Calendar, this) const impl = getImpl(this) + const isIso = getImpl(this).id === 'iso8601' let { era, eraYear, year, month, monthCode, day } = refineFields( fields, - allMonthDayFieldMap, - getImpl(this).id === 'iso8601' - ? { day: true } - : {}, - ) + isIso ? monthDayFieldMap : allMonthDayFieldMap, + isIso ? { day: true } : {}, + ) as any // HACK for era/eraYear if (day === undefined) { throw new TypeError('required property \'day\' missing or undefined') From 7586ef687cfb6d4a07034305c7921acbe8aaf8b9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 15:12:18 -0400 Subject: [PATCH 031/805] forgot to strip out refineNumber --- .../temporal-polyfill/misc/expected-failures.txt | 2 -- packages/temporal-polyfill/src/argParse/fieldStr.ts | 12 +----------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 293e1814..472b7bca 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -13,8 +13,6 @@ # complicated internal property access built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js -intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js -intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js # # Legit bugs diff --git a/packages/temporal-polyfill/src/argParse/fieldStr.ts b/packages/temporal-polyfill/src/argParse/fieldStr.ts index c23cb1e8..21d60dfb 100644 --- a/packages/temporal-polyfill/src/argParse/fieldStr.ts +++ b/packages/temporal-polyfill/src/argParse/fieldStr.ts @@ -3,7 +3,7 @@ import { durationUnitNames } from './unitStr' const eraFieldMap = { era: String, - eraYear: refineNumber, + eraYear: toIntNoInfinity, } export const yearMonthFieldMap = { @@ -56,16 +56,6 @@ export const dateTimeFieldMap = { // TODO: more DRY with constrainInt // ... -function refineNumber(input: any): number { - const num = Number(input) - - if (!Number.isFinite(num)) { - throw new RangeError('Number must be finite') - } - - return num -} - function toPositiveInt(valueParam: unknown, property?: string): number { const value = toInt(valueParam) if (!Number.isFinite(value)) { From 3c61e2aab65d50bfbae91776665bf6120f2bac26 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 15:18:37 -0400 Subject: [PATCH 032/805] dont always ensure same calendar --- .../misc/expected-failures.txt | 18 +----------------- .../src/dateUtils/calendar.ts | 2 -- .../temporal-polyfill/src/public/calendar.ts | 2 -- 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 472b7bca..c35d0583 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -1,8 +1,3 @@ -# Failures in this file are expected to fail for all Test262 tests. To record -# expected test failures for the transpiled or optimized builds of the polyfill, -# see expected-failures-es5.txt and expected-failures-opt.txt respectively. - -# https://github.com/tc39/test262/pull/3548 # # fullcalendar/temporal notes @@ -11,13 +6,9 @@ # pn test262 'TimeZone/**' # -# complicated internal property access +# complicated internal property access (needs class refactor) built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js -# -# Legit bugs -# - # monthDayFromFields intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js @@ -27,13 +18,6 @@ intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js # out-of-range built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js -# calendars must match -built-ins/Temporal/Calendar/prototype/dayOfYear/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/daysInYear/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/monthCode/calendar-temporal-object.js -built-ins/Temporal/Calendar/prototype/monthsInYear/calendar-temporal-object.js - # Calendr::dateUntil built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js diff --git a/packages/temporal-polyfill/src/dateUtils/calendar.ts b/packages/temporal-polyfill/src/dateUtils/calendar.ts index acb916e0..56f9ee71 100644 --- a/packages/temporal-polyfill/src/dateUtils/calendar.ts +++ b/packages/temporal-polyfill/src/dateUtils/calendar.ts @@ -1,5 +1,4 @@ import { Temporal } from 'temporal-spec' -import { ensureCalendarsEqual } from '../argParse/calendar' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' import { CalendarImpl, convertEraYear } from '../calendarImpl/calendarImpl' import { PlainDate, PlainDateArg, createDate } from '../public/plainDate' @@ -54,7 +53,6 @@ export function queryDateFields( date = PlainDate.from(arg) } - ensureCalendarsEqual(date.calendar, calendar) return date } diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 3ce65898..67f10861 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -438,8 +438,6 @@ export class Calendar implements Temporal.Calendar { ? DAY // TODO: util for this? : parseUnit(largestUnitStr, DAY, DAY, YEAR) - // ensureCalendarsEqual(this, getCommonCalendar(d0, d1)) - // TODO: make less verbose. ALSO, cache cal dates in WeakMap for use by non-iso calImpl const isoFields0 = getExistingDateISOFields(d0, true) // disallowMonthDay=true const calFields0 = isoToEpochNanoSafe( From 000ecb24aa2f6c30748b816de75957164954affe Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 15:32:42 -0400 Subject: [PATCH 033/805] validation of Calendar::fields --- .../misc/expected-failures.txt | 7 ------- .../temporal-polyfill/src/public/calendar.ts | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index c35d0583..820adb08 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -21,13 +21,6 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g # Calendr::dateUntil built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js -# Calendar::fields -built-ins/Temporal/Calendar/prototype/fields/argument-throws-duplicate-keys.js -built-ins/Temporal/Calendar/prototype/fields/argument-throws-invalid-keys.js -built-ins/Temporal/Calendar/prototype/fields/long-input.js -built-ins/Temporal/Calendar/prototype/fields/non-string-element-throws.js -built-ins/Temporal/Calendar/prototype/fields/repeated-throw.js - # Calendar::mergeFields built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 67f10861..58b53db5 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -4,6 +4,7 @@ import { allMonthDayFieldMap, allYearMonthFieldMap, dateFieldMap, + dateTimeFieldMap, monthDayFieldMap, toString, yearMonthFieldMap, @@ -466,7 +467,22 @@ export class Calendar implements Temporal.Calendar { fields(inFields: string[]): string[] { needReceiver(Calendar, this) - const outFields = [...inFields] // convert to array and/or copy (handles iterators) + const outFields: string[] = [] + const outFieldMap: any = {} + + for (const fieldName of inFields) { // inField could be iterator! TODO: adjust type + if (typeof fieldName !== 'string') { + throw new TypeError('Field must be string') + } + if (!(fieldName in dateTimeFieldMap)) { + throw new RangeError('Invalid field') + } + if (outFieldMap[fieldName]) { + throw new RangeError('Cannot have duplicate field') + } + outFieldMap[fieldName] = true + outFields.push(fieldName) + } if (this.toString() !== 'iso8601' && outFields.indexOf('year') !== -1) { outFields.push('era', 'eraYear') From e895c93003e480dcfda8a3dd912b6d76b85ff527 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 16:28:54 -0400 Subject: [PATCH 034/805] rewrite mergefields --- .../misc/expected-failures.txt | 2 - .../temporal-polyfill/src/public/calendar.ts | 61 ++++++------------- 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 820adb08..7191f5ef 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -22,9 +22,7 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # Calendar::mergeFields -built-ins/Temporal/Calendar/prototype/mergeFields/arguments-empty-object.js built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js -built-ins/Temporal/Calendar/prototype/mergeFields/order-of-operations.js built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 58b53db5..7021c0e6 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -498,7 +498,8 @@ export class Calendar implements Temporal.Calendar { // TODO: use Record mergeFields(baseFields: any, additionalFields: any): any { needReceiver(Calendar, this) - return mergeCalFields(baseFields, additionalFields) + const isIso = getImpl(this).id === 'iso8601' + return mergeCalFields(baseFields, additionalFields, isIso) } toString(): string { @@ -518,55 +519,27 @@ export function createDefaultCalendar(): Calendar { return new Calendar(isoCalendarID) } -// TODO: better types? -export function mergeCalFields(baseFields: any, additionalFields: any): any { - const merged = { ...baseFields, ...additionalFields } as any - - if (baseFields.year !== undefined) { - delete merged.era - delete merged.eraYear - delete merged.year - - let anyAdditionalYear = false +export function mergeCalFields(baseFields: any, additionalFields: any, isIso: boolean): any { + const baseFieldsCopy = { ...baseFields } // don't access mult times + const additionalFieldsCopy = { ...additionalFields } // " + const combinedFields = { ...baseFieldsCopy, ...additionalFieldsCopy } - if (additionalFields.era !== undefined || additionalFields.eraYear !== undefined) { - merged.era = additionalFields.era - merged.eraYear = additionalFields.eraYear - anyAdditionalYear = true - } - if (additionalFields.year !== undefined) { - merged.year = additionalFields.year - anyAdditionalYear = true - } - if (!anyAdditionalYear) { - merged.year = baseFields.year - } + if (additionalFieldsCopy.monthCode !== undefined) { + delete combinedFields.month + } else if (additionalFieldsCopy.month !== undefined) { + delete combinedFields.monthCode } - if (baseFields.monthCode !== undefined) { - delete merged.monthCode - delete merged.month - - let anyAdditionalMonth = false - - if (additionalFields.month !== undefined) { - merged.month = additionalFields.month - anyAdditionalMonth = true - } - if (additionalFields.monthCode !== undefined) { - merged.monthCode = additionalFields.monthCode - anyAdditionalMonth = true + if (!isIso) { + if (additionalFieldsCopy.era !== undefined || additionalFieldsCopy.eraYear !== undefined) { + delete combinedFields.year + } else if (additionalFields.year !== undefined) { + delete combinedFields.era + delete combinedFields.eraYear } - if (!anyAdditionalMonth) { - merged.monthCode = baseFields.monthCode - } - } - - if (baseFields.day !== undefined) { - merged.day = additionalFields.day ?? baseFields.day } - return merged + return combinedFields } // utils From 0ff02eef0e3e60055495fc736ed90b18102b4f5b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 16:43:05 -0400 Subject: [PATCH 035/805] typecheck Calendar::mergeFields --- packages/temporal-polyfill/misc/expected-failures.txt | 1 - packages/temporal-polyfill/src/public/calendar.ts | 10 +++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 7191f5ef..4c88e53c 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -22,7 +22,6 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # Calendar::mergeFields -built-ins/Temporal/Calendar/prototype/mergeFields/arguments-not-object.js built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 7021c0e6..db8b4e15 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -498,6 +498,12 @@ export class Calendar implements Temporal.Calendar { // TODO: use Record mergeFields(baseFields: any, additionalFields: any): any { needReceiver(Calendar, this) + if ( + baseFields == null || + additionalFields == null + ) { + throw new TypeError('Both arguments must be coercible into objects') + } const isIso = getImpl(this).id === 'iso8601' return mergeCalFields(baseFields, additionalFields, isIso) } @@ -522,7 +528,9 @@ export function createDefaultCalendar(): Calendar { export function mergeCalFields(baseFields: any, additionalFields: any, isIso: boolean): any { const baseFieldsCopy = { ...baseFields } // don't access mult times const additionalFieldsCopy = { ...additionalFields } // " - const combinedFields = { ...baseFieldsCopy, ...additionalFieldsCopy } + + // way to spread together while having null-prototype required by tests + const combinedFields = Object.assign(Object.create(null), baseFieldsCopy, additionalFieldsCopy) if (additionalFieldsCopy.monthCode !== undefined) { delete combinedFields.month From 8d7f1782578dc73212dfc194dc19b87d2a9611fc Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 16:53:26 -0400 Subject: [PATCH 036/805] fix more monthCode bugs --- .../misc/expected-failures.txt | 1 - .../temporal-polyfill/src/public/calendar.ts | 20 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 4c88e53c..db33dd8c 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -22,7 +22,6 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # Calendar::mergeFields -built-ins/Temporal/Calendar/prototype/mergeFields/iso8601-calendar-month-monthCode.js intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index db8b4e15..e1c24435 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -532,18 +532,26 @@ export function mergeCalFields(baseFields: any, additionalFields: any, isIso: bo // way to spread together while having null-prototype required by tests const combinedFields = Object.assign(Object.create(null), baseFieldsCopy, additionalFieldsCopy) - if (additionalFieldsCopy.monthCode !== undefined) { + if (additionalFieldsCopy.monthCode !== undefined && additionalFieldsCopy.month === undefined) { delete combinedFields.month - } else if (additionalFieldsCopy.month !== undefined) { + } + if (additionalFieldsCopy.month !== undefined && additionalFieldsCopy.monthCode === undefined) { delete combinedFields.monthCode } if (!isIso) { - if (additionalFieldsCopy.era !== undefined || additionalFieldsCopy.eraYear !== undefined) { + if ( + (additionalFieldsCopy.era !== undefined || additionalFieldsCopy.eraYear !== undefined) && + additionalFieldsCopy.year === undefined + ) { delete combinedFields.year - } else if (additionalFields.year !== undefined) { - delete combinedFields.era - delete combinedFields.eraYear + } else if (additionalFieldsCopy.year !== undefined) { + if (additionalFieldsCopy.era === undefined) { + delete combinedFields.era + } + if (additionalFieldsCopy.eraYear === undefined) { + delete combinedFields.eraYear + } } } From 741210088c2c17878587d810c11ac805ad536a52 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 17:39:40 -0400 Subject: [PATCH 037/805] further correct mergeFields algorithm --- .../misc/expected-failures.txt | 1 - .../src/dateUtils/fromAndWith.ts | 7 ++- .../temporal-polyfill/src/public/calendar.ts | 50 ++++++++----------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index db33dd8c..ae57b004 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -22,7 +22,6 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # Calendar::mergeFields -intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js # Calendar id diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index e61b42fb..dc0f49f2 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -1,7 +1,6 @@ import { Temporal } from 'temporal-spec' import { extractCalendar } from '../argParse/calendar' import { - allDateFieldMap, dateFieldMap, dateTimeFieldMap, durationFieldMap, @@ -296,7 +295,11 @@ function mergeFieldsViaCalendar( return calendar.mergeFields(existingFields, fields) } - return mergeCalFields(existingFields, fields) + return mergeCalFields( + existingFields, + fields, + true, // isIso. TODO: know this for sure + ) } function mergeLocalTimeFields( diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index e1c24435..397dff46 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -525,37 +525,31 @@ export function createDefaultCalendar(): Calendar { return new Calendar(isoCalendarID) } -export function mergeCalFields(baseFields: any, additionalFields: any, isIso: boolean): any { - const baseFieldsCopy = { ...baseFields } // don't access mult times - const additionalFieldsCopy = { ...additionalFields } // " - - // way to spread together while having null-prototype required by tests - const combinedFields = Object.assign(Object.create(null), baseFieldsCopy, additionalFieldsCopy) - - if (additionalFieldsCopy.monthCode !== undefined && additionalFieldsCopy.month === undefined) { - delete combinedFields.month - } - if (additionalFieldsCopy.month !== undefined && additionalFieldsCopy.monthCode === undefined) { - delete combinedFields.monthCode +export function mergeCalFields(baseFields: any, newFields: any, isIso: boolean): any { + const baseFieldsCopy = { ...baseFields } + const newFieldsCopy = { ...newFields } + + const hasNewMonth = + newFieldsCopy.month !== undefined || + newFieldsCopy.monthCode !== undefined + + const hasNewYear = !isIso && ( + newFieldsCopy.era !== undefined || + newFieldsCopy.eraYear !== undefined || + newFieldsCopy.year !== undefined + ) + + if (hasNewMonth) { + delete baseFieldsCopy.month + delete baseFieldsCopy.monthCode } - - if (!isIso) { - if ( - (additionalFieldsCopy.era !== undefined || additionalFieldsCopy.eraYear !== undefined) && - additionalFieldsCopy.year === undefined - ) { - delete combinedFields.year - } else if (additionalFieldsCopy.year !== undefined) { - if (additionalFieldsCopy.era === undefined) { - delete combinedFields.era - } - if (additionalFieldsCopy.eraYear === undefined) { - delete combinedFields.eraYear - } - } + if (hasNewYear) { + delete baseFieldsCopy.era + delete baseFieldsCopy.eraYear + delete baseFieldsCopy.year } - return combinedFields + return Object.assign(Object.create(null), baseFieldsCopy, newFieldsCopy) } // utils From 09c56bee0d740f1be9f74f7f7849b282956b7795 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 18:01:21 -0400 Subject: [PATCH 038/805] fix japanese calendar bug --- .../misc/expected-failures.txt | 3 -- .../src/dateUtils/fromAndWith.ts | 4 +- .../temporal-polyfill/src/public/calendar.ts | 37 ++++++++++++------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index ae57b004..0643b799 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -21,9 +21,6 @@ built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-g # Calendr::dateUntil built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js -# Calendar::mergeFields -intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js - # Calendar id intl402/Temporal/Calendar/calendar-case-insensitive.js intl402/Temporal/Calendar/from/calendar-case-insensitive.js diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index dc0f49f2..d747a551 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -11,7 +11,7 @@ import { import { OverflowHandlingInt } from '../argParse/overflowHandling' import { isObjectLike, refineFields } from '../argParse/refine' import { extractTimeZone } from '../argParse/timeZone' -import { Calendar, mergeCalFields } from '../public/calendar' +import { Calendar, getCalendarImpl, mergeCalFields } from '../public/calendar' import { PlainDate } from '../public/plainDate' import { PlainMonthDay } from '../public/plainMonthDay' import { PlainYearMonth } from '../public/plainYearMonth' @@ -298,7 +298,7 @@ function mergeFieldsViaCalendar( return mergeCalFields( existingFields, fields, - true, // isIso. TODO: know this for sure + getCalendarImpl(calendar as any)?.id || calendar.toString(), // HACK ) } diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 397dff46..cc985f2b 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -49,6 +49,7 @@ import { getZonedDateTimeInterals } from './zonedDateTime' // unlike many other object types const [getImpl, setImpl] = createWeakMap() +export { getImpl as getCalendarImpl } export class Calendar implements Temporal.Calendar { constructor(id: string) { @@ -504,8 +505,7 @@ export class Calendar implements Temporal.Calendar { ) { throw new TypeError('Both arguments must be coercible into objects') } - const isIso = getImpl(this).id === 'iso8601' - return mergeCalFields(baseFields, additionalFields, isIso) + return mergeCalFields(baseFields, additionalFields, getImpl(this).id) } toString(): string { @@ -525,30 +525,41 @@ export function createDefaultCalendar(): Calendar { return new Calendar(isoCalendarID) } -export function mergeCalFields(baseFields: any, newFields: any, isIso: boolean): any { +export function mergeCalFields(baseFields: any, newFields: any, calendarID: string): any { const baseFieldsCopy = { ...baseFields } const newFieldsCopy = { ...newFields } - const hasNewMonth = + if ( newFieldsCopy.month !== undefined || newFieldsCopy.monthCode !== undefined - - const hasNewYear = !isIso && ( - newFieldsCopy.era !== undefined || - newFieldsCopy.eraYear !== undefined || - newFieldsCopy.year !== undefined - ) - - if (hasNewMonth) { + ) { delete baseFieldsCopy.month delete baseFieldsCopy.monthCode } - if (hasNewYear) { + + if ( + calendarID !== 'iso8601' && ( + newFieldsCopy.era !== undefined || + newFieldsCopy.eraYear !== undefined || + newFieldsCopy.year !== undefined + ) + ) { delete baseFieldsCopy.era delete baseFieldsCopy.eraYear delete baseFieldsCopy.year } + if ( + calendarID === 'japanese' && ( // erasBeginMidYear? + newFieldsCopy.day !== undefined || + newFieldsCopy.monthCode !== undefined || + newFieldsCopy.month !== undefined + ) + ) { + delete baseFieldsCopy.era + delete baseFieldsCopy.eraYear + } + return Object.assign(Object.create(null), baseFieldsCopy, newFieldsCopy) } From d4b3b642d1ee5ab21c47d69504cc0dcdf1f2cfb9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 18:13:14 -0400 Subject: [PATCH 039/805] fix getOffsetNanosecondsFor bug --- packages/temporal-polyfill/misc/expected-failures.txt | 3 --- packages/temporal-polyfill/src/dateUtils/timeZone.ts | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 0643b799..fc1f9feb 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -15,9 +15,6 @@ intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js # yearMonthFromFields intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js -# out-of-range -built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js - # Calendr::dateUntil built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js diff --git a/packages/temporal-polyfill/src/dateUtils/timeZone.ts b/packages/temporal-polyfill/src/dateUtils/timeZone.ts index 279a177b..0fc086cc 100644 --- a/packages/temporal-polyfill/src/dateUtils/timeZone.ts +++ b/packages/temporal-polyfill/src/dateUtils/timeZone.ts @@ -8,6 +8,7 @@ import { } from '../argParse/disambig' import { Instant } from '../public/instant' import { PlainDateTime } from '../public/plainDateTime' +import { ensureObj } from './abstract' import { toEpochNano } from './epoch' import { nanoInDay } from './units' @@ -84,7 +85,10 @@ export function getSafeOffsetNanosecondsFor( // throw new TypeError('getOffsetNanosecondsFor should be callable') // } - const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(arg) + // important that arg-parsing failure happens here, before getOffsetNanosecondsFor called + const instant = ensureObj(Instant, arg) + + const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(instant) if (typeof offsetNanoseconds !== 'number') { throw new TypeError('Invalid return value from getOffsetNanosecondsFor') From 1a5267eb47c496e9fbb169f1254dc3e9477c5e93 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 18:17:55 -0400 Subject: [PATCH 040/805] remove comment --- packages/temporal-polyfill/src/dateUtils/timeZone.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/timeZone.ts b/packages/temporal-polyfill/src/dateUtils/timeZone.ts index 0fc086cc..e7fae519 100644 --- a/packages/temporal-polyfill/src/dateUtils/timeZone.ts +++ b/packages/temporal-polyfill/src/dateUtils/timeZone.ts @@ -80,11 +80,6 @@ export function getSafeOffsetNanosecondsFor( timeZone: Temporal.TimeZoneProtocol, arg: Temporal.Instant | string, ): number { - // TODO: do a better error message? - // if (typeof timeZone.getOffsetNanosecondsFor !== 'function') { - // throw new TypeError('getOffsetNanosecondsFor should be callable') - // } - // important that arg-parsing failure happens here, before getOffsetNanosecondsFor called const instant = ensureObj(Instant, arg) From 71722414f7acc8c94d66c8abebfbfff7bd09ad14 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 18:29:36 -0400 Subject: [PATCH 041/805] calendar id always normalized to lowercase --- packages/temporal-polyfill/misc/expected-failures.txt | 8 ++++---- .../src/calendarImpl/calendarImplQuery.ts | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index fc1f9feb..cb13eee2 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -18,10 +18,6 @@ intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js # Calendr::dateUntil built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js -# Calendar id -intl402/Temporal/Calendar/calendar-case-insensitive.js -intl402/Temporal/Calendar/from/calendar-case-insensitive.js - # TimeZone parsing built-ins/Temporal/TimeZone/from/timezone-string-datetime.js built-ins/Temporal/TimeZone/from/timezone-wrong-type.js @@ -30,3 +26,7 @@ built-ins/Temporal/TimeZone/from/timezone-wrong-type.js intl402/Temporal/TimeZone/prototype/getNextTransition/subtract-second-and-nanosecond-from-last-transition.js intl402/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/nanoseconds-subtracted-or-added-at-dst-transition.js staging/Temporal/TimeZone/old/getInstantFor.js + +# Intl.DateTimeFormat +# (even PlainDate should be reduced to timestamp, should have be displayable with timeZone options) +#intl402/DateTimeFormat/prototype/format/temporal-objects-timezone-getoffsetnanosecondsfor-not-callable.js diff --git a/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts b/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts index 5f9cb4b1..e4df0b61 100644 --- a/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts +++ b/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts @@ -17,7 +17,7 @@ const implCache: { [calendarID: string]: CalendarImpl } = { } export function queryCalendarImpl(id: string): CalendarImpl { - id = String(id) + id = String(id).toLocaleLowerCase() // always normalized to lowercase // TODO: more DRY with Calendar::from const parsedDateTime = tryParseDateTime(id, false, true) // allowZ=true @@ -25,11 +25,9 @@ export function queryCalendarImpl(id: string): CalendarImpl { id = parsedDateTime.calendar || 'iso8601' } - const key = id.toLocaleLowerCase() // lowercase matches isoCalendarID - - return implCache[key] || - (implCache[key] = new ( - implClasses[getCalendarIDBase(key)] || + return implCache[id] || + (implCache[id] = new ( + implClasses[getCalendarIDBase(id)] || IntlCalendarImpl )(id)) } From 993ee172a6d86daa92ce0f97883d0d88ad53b381 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 18:37:34 -0400 Subject: [PATCH 042/805] can have mismatching offset/timezone-name --- .../temporal-polyfill/misc/expected-failures.txt | 1 - packages/temporal-polyfill/src/dateUtils/offset.ts | 13 ------------- packages/temporal-polyfill/src/public/timeZone.ts | 2 -- 3 files changed, 16 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index cb13eee2..e3f74de0 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -19,7 +19,6 @@ intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # TimeZone parsing -built-ins/Temporal/TimeZone/from/timezone-string-datetime.js built-ins/Temporal/TimeZone/from/timezone-wrong-type.js # TimeZone transitions diff --git a/packages/temporal-polyfill/src/dateUtils/offset.ts b/packages/temporal-polyfill/src/dateUtils/offset.ts index 21bd7f9b..c4ac5701 100644 --- a/packages/temporal-polyfill/src/dateUtils/offset.ts +++ b/packages/temporal-polyfill/src/dateUtils/offset.ts @@ -24,19 +24,6 @@ export interface OffsetComputableFields extends ISODateTimeFields { Z?: boolean } -export function checkInvalidOffset(isoFields: OffsetComputableFields): void { - const { offsetNanoseconds: offsetNano, timeZone, Z } = isoFields - - // a non-Z offset defined? (for ALWAYS use Z as zero offset) - if (offsetNano !== undefined && !Z) { - const matchingEpochNano = findMatchingEpochNano(isoFields, offsetNano, timeZone, true) - - if (matchingEpochNano === undefined) { - throw new RangeError('Mismatching offset/timezone') // TODO: more DRY - } - } -} - export function computeZonedDateTimeEpochNano( isoFields: OffsetComputableFields, fuzzyMatching?: boolean, diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index 1e4d69b6..4f96e48d 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -6,7 +6,6 @@ import { JsonMethods, ensureObj, mixinJsonMethods, needReceiver } from '../dateU import { epochNanoSymbol, epochNanoToISOFields, isoFieldsToEpochNano } from '../dateUtils/epoch' import { formatOffsetISO } from '../dateUtils/isoFormat' import { attachStringTag } from '../dateUtils/mixins' -import { checkInvalidOffset } from '../dateUtils/offset' import { tryParseZonedDateTime } from '../dateUtils/parse' import { refineZonedObj } from '../dateUtils/parseRefine' import { getInstantFor, getSafeOffsetNanosecondsFor } from '../dateUtils/timeZone' @@ -53,7 +52,6 @@ export class TimeZone implements Temporal.TimeZone { if (parsed) { if (parsed.timeZone) { const refined = refineZonedObj(parsed) // TODO: we don't need the calendar - checkInvalidOffset(refined) return refined.timeZone } else if (parsed.Z) { return new TimeZone('UTC') From adae0e425ef364bff4e1062179e34a1a292cfb45 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 18:44:58 -0400 Subject: [PATCH 043/805] fail on instantiating TimeZone from Calendar --- packages/temporal-polyfill/misc/expected-failures.txt | 3 --- packages/temporal-polyfill/src/public/timeZone.ts | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index e3f74de0..a9f82c52 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -18,9 +18,6 @@ intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js # Calendr::dateUntil built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js -# TimeZone parsing -built-ins/Temporal/TimeZone/from/timezone-wrong-type.js - # TimeZone transitions intl402/Temporal/TimeZone/prototype/getNextTransition/subtract-second-and-nanosecond-from-last-transition.js intl402/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/nanoseconds-subtracted-or-added-at-dst-transition.js diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/public/timeZone.ts index 4f96e48d..628ecd9e 100644 --- a/packages/temporal-polyfill/src/public/timeZone.ts +++ b/packages/temporal-polyfill/src/public/timeZone.ts @@ -34,11 +34,17 @@ export class TimeZone implements Temporal.TimeZone { if (arg instanceof TimeZone) { return arg as any } + if (arg instanceof Calendar) { + throw new RangeError('Cant create TimeZone from Calendar') + } if (!('timeZone' in arg)) { return arg } else { arg = arg.timeZone + if (arg instanceof Calendar) { + throw new RangeError('Cant create TimeZone from Calendar') + } if (isObjectLike(arg) && !('timeZone' in arg)) { return arg as any } From 43d1f8e7962420f8e8997122348bf37f6b404280 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 27 Mar 2023 18:57:26 -0400 Subject: [PATCH 044/805] comment to self --- packages/temporal-polyfill/misc/expected-failures.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index a9f82c52..1389fe46 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -26,3 +26,7 @@ staging/Temporal/TimeZone/old/getInstantFor.js # Intl.DateTimeFormat # (even PlainDate should be reduced to timestamp, should have be displayable with timeZone options) #intl402/DateTimeFormat/prototype/format/temporal-objects-timezone-getoffsetnanosecondsfor-not-callable.js + +# NOTE: tests related to func.length fail because optional params need default values to make sure +# they're not included in func.length +#built-ins/Temporal/Calendar/prototype/dateAdd/length.js From e80314569086e9ee75b432ab4af9fdc89e83a712 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 09:38:11 -0400 Subject: [PATCH 045/805] fix plaindate creation --- .../temporal-polyfill/misc/expected-failures.txt | 1 + .../temporal-polyfill/src/argParse/fieldStr.ts | 13 +++++++++---- packages/temporal-polyfill/src/argParse/refine.ts | 12 ++++++------ .../temporal-polyfill/src/dateUtils/constrain.ts | 15 ++++----------- .../temporal-polyfill/src/public/plainDate.ts | 10 ++++++++++ 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 1389fe46..116b9320 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -4,6 +4,7 @@ # # pn test262 'Calendar/**' # pn test262 'TimeZone/**' +# pn test262 'PlainDate/**' # # complicated internal property access (needs class refactor) diff --git a/packages/temporal-polyfill/src/argParse/fieldStr.ts b/packages/temporal-polyfill/src/argParse/fieldStr.ts index 21d60dfb..da40769b 100644 --- a/packages/temporal-polyfill/src/argParse/fieldStr.ts +++ b/packages/temporal-polyfill/src/argParse/fieldStr.ts @@ -90,8 +90,8 @@ function toIntNoFrac(valueParam: unknown): number { throws on infinity truncates on fractional values */ -function toIntNoInfinity(value: unknown): number { - const integer = toInt(value) +export function toIntNoInfinity(value: unknown, throwOnNaN?: boolean): number { + const integer = toInt(value, throwOnNaN) if (!Number.isFinite(integer)) { throw new RangeError('infinity is out of range') } @@ -102,9 +102,14 @@ function toIntNoInfinity(value: unknown): number { allows infinity truncates on fractional values */ -function toInt(value: unknown): number { // truncates fraction values to integers +export function toInt(value: unknown, throwOnNaN?: boolean): number { const num = toNumber(value) - if (isNaN(num)) return 0 + if (isNaN(num)) { + if (throwOnNaN) { + throw new RangeError('Invalid number') + } + return 0 + } const integer = Math.trunc(num) if (num === 0) return 0 // prevents -0. TODO: remove other places that do this return integer diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index f6801366..ffd89bb3 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -1,5 +1,5 @@ import { ValueOf } from '../utils/obj' -import { toString } from './fieldStr' +import { toInt, toString } from './fieldStr' import { OVERFLOW_REJECT, OverflowHandlingInt } from './overflowHandling' export function createOptionParser(propName: string, map: Map, defaultVal?: ValueOf): ( @@ -45,17 +45,17 @@ export function constrainInt( min: number, // inclusive. serves as default max: number, // inclusive overflowHandling: OverflowHandlingInt, + mustBePositive?: boolean, ): number { if (val === undefined) { return min } - if (!Number.isFinite(val)) { - throw new RangeError('Number must be finite') - } + val = toInt(val, overflowHandling === OVERFLOW_REJECT) - // convert floating-point to integer - val = Math.trunc(val) + if (mustBePositive && val < 0) { + throw new RangeError('Int must be positive') + } const newVal = Math.min(Math.max(val, min), max) if (newVal !== val && overflowHandling === OVERFLOW_REJECT) { diff --git a/packages/temporal-polyfill/src/dateUtils/constrain.ts b/packages/temporal-polyfill/src/dateUtils/constrain.ts index 7e438622..76824ec4 100644 --- a/packages/temporal-polyfill/src/dateUtils/constrain.ts +++ b/packages/temporal-polyfill/src/dateUtils/constrain.ts @@ -1,3 +1,4 @@ +import { toIntNoInfinity } from '../argParse/fieldStr' import { OVERFLOW_REJECT, OverflowHandlingInt } from '../argParse/overflowHandling' import { constrainInt } from '../argParse/refine' import { CalendarImpl } from '../calendarImpl/calendarImpl' @@ -11,17 +12,9 @@ export function constrainDateFields( calendarImpl: CalendarImpl, overflow: OverflowHandlingInt, ): [number, number, number] { - // regardless of overflow option - if (month < 1) { - throw new RangeError('Month must be positive') - } - if (day < 1) { - throw new RangeError('Day must be positive') - } - - year = Number(year) // not using constrainValue, which converts to a number - month = constrainInt(month, 1, calendarImpl.monthsInYear(year), overflow) - day = constrainInt(day, 1, calendarImpl.daysInMonth(year, month), overflow) + year = toIntNoInfinity(year, true) + month = constrainInt(month, 1, calendarImpl.monthsInYear(year), overflow, true) + day = constrainInt(day, 1, calendarImpl.daysInMonth(year, month), overflow, true) return [year, month, day] } diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 1e16c059..47242318 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -56,6 +56,16 @@ export class PlainDate implements Temporal.PlainDate { isoDay: number, calendarArg: Temporal.CalendarLike = createDefaultCalendar(), ) { + if (isoYear === undefined) { + throw new RangeError('Invalid isoYear') + } + if (isoMonth === undefined) { + throw new RangeError('Invalid isoMonth') + } + if (isoDay === undefined) { + throw new RangeError('Invalid isoDay') + } + const constrained = constrainDateISO({ isoYear, isoMonth, isoDay }, OVERFLOW_REJECT) const calendar = ensureObj(Calendar, calendarArg) From d6ab462973ac678acec6b887f48dc3fbc1f1bdb9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 09:43:35 -0400 Subject: [PATCH 046/805] dont internally call Calendar::from --- .../temporal-polyfill/src/public/calendar.ts | 74 ++++++++++--------- .../temporal-polyfill/src/public/plainDate.ts | 4 +- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index cc985f2b..fff42594 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -61,41 +61,7 @@ export class Calendar implements Temporal.Calendar { } static from(arg: Temporal.CalendarLike): Temporal.CalendarProtocol { - if (isObjectLike(arg)) { - if (arg instanceof Calendar) { - return arg as any - } - const secretCalendar = - getZonedDateTimeInterals(arg as any)?.calendar || - getISOFields(arg as any)?.calendar - if (secretCalendar) { - return secretCalendar - } - if (arg instanceof TimeZone) { - throw new RangeError('Expected a calendar object but received a Temporal.TimeZone') - } - if (!('calendar' in arg)) { - return arg - } else { - arg = arg.calendar - - if (arg instanceof TimeZone) { - throw new RangeError('Expected a calendar object but received a Temporal.TimeZone') - } - if (isObjectLike(arg) && !('calendar' in arg)) { - return arg as any - } - } - } - - // parse as string... - const strVal = toString(arg) - const parsed = tryParseDateTime(strVal, false, true) // allowZ=true - return new Calendar( - parsed // a date-time string? - ? parsed.calendar || isoCalendarID - : strVal, // any other type of string - ) + return calendarFrom(arg) } get id(): string { @@ -525,6 +491,44 @@ export function createDefaultCalendar(): Calendar { return new Calendar(isoCalendarID) } +export function calendarFrom(arg: Temporal.CalendarLike): Temporal.CalendarProtocol { + if (isObjectLike(arg)) { + if (arg instanceof Calendar) { + return arg as any + } + const secretCalendar = + getZonedDateTimeInterals(arg as any)?.calendar || + getISOFields(arg as any)?.calendar + if (secretCalendar) { + return secretCalendar + } + if (arg instanceof TimeZone) { + throw new RangeError('Expected a calendar object but received a Temporal.TimeZone') + } + if (!('calendar' in arg)) { + return arg + } else { + arg = arg.calendar + + if (arg instanceof TimeZone) { + throw new RangeError('Expected a calendar object but received a Temporal.TimeZone') + } + if (isObjectLike(arg) && !('calendar' in arg)) { + return arg as any + } + } + } + + // parse as string... + const strVal = toString(arg) + const parsed = tryParseDateTime(strVal, false, true) // allowZ=true + return new Calendar( + parsed // a date-time string? + ? parsed.calendar || isoCalendarID + : strVal, // any other type of string + ) +} + export function mergeCalFields(baseFields: any, newFields: any, calendarID: string): any { const baseFieldsCopy = { ...baseFields } const newFieldsCopy = { ...newFields } diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 47242318..458227fa 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -31,7 +31,7 @@ import { refineBaseObj } from '../dateUtils/parseRefine' import { DAY, DateUnitInt, YEAR } from '../dateUtils/units' import { createPlainFormatFactoryFactory } from '../native/intlFactory' import { ToLocaleStringMethods, mixinLocaleStringMethods } from '../native/intlMixins' -import { Calendar, createDefaultCalendar } from './calendar' +import { calendarFrom, createDefaultCalendar } from './calendar' import { Duration, DurationArg, createDuration } from './duration' import { PlainDateTime, createDateTime } from './plainDateTime' import { PlainTime, PlainTimeArg, ensureLooseTime } from './plainTime' @@ -67,7 +67,7 @@ export class PlainDate implements Temporal.PlainDate { } const constrained = constrainDateISO({ isoYear, isoMonth, isoDay }, OVERFLOW_REJECT) - const calendar = ensureObj(Calendar, calendarArg) + const calendar = calendarFrom(calendarArg) validateDate(constrained) initIsoMaster(this, { From 856d88150efd1c3ac74c40985741585591aeee98 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 10:54:08 -0400 Subject: [PATCH 047/805] fix how Calendar::fields and related works --- .../src/dateUtils/fromAndWith.ts | 90 ++++++++----------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index d747a551..04464318 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -70,15 +70,13 @@ function tryDateTimeFromFields( const calendar = extractCalendar(rawFields) const refinedFields = refineFieldsViaCalendar(rawFields, dateTimeFieldMap, calendar) - if (hasAnyProps(refinedFields)) { - return { - // TODO: more DRY with tryTimeFromFields - // ALSO: very important time-fields are read from refinedFields before passing - // refinedFields to dateFromFields, because dateFromFields has potential to mutate it - ...constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling), - // - ...calendar.dateFromFields(refinedFields, options).getISOFields(), - } + return { + // TODO: more DRY with tryTimeFromFields + // ALSO: very important time-fields are read from refinedFields before passing + // refinedFields to dateFromFields, because dateFromFields has potential to mutate it + ...constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling), + // + ...calendar.dateFromFields(refinedFields, options).getISOFields(), } } @@ -89,9 +87,7 @@ function tryDateFromFields( const calendar = extractCalendar(rawFields) const refinedFields = refineFieldsViaCalendar(rawFields, dateFieldMap, calendar) - if (hasAnyProps(refinedFields)) { - return calendar.dateFromFields(refinedFields, options) - } + return calendar.dateFromFields(refinedFields, options) } function tryYearMonthFromFields( @@ -101,9 +97,7 @@ function tryYearMonthFromFields( const calendar = extractCalendar(rawFields) const refinedFields = refineFieldsViaCalendar(rawFields, yearMonthFieldMap, calendar) - if (hasAnyProps(refinedFields)) { - return calendar.yearMonthFromFields(refinedFields, options) - } + return calendar.yearMonthFromFields(refinedFields, options) } function tryMonthDayFromFields( @@ -113,13 +107,11 @@ function tryMonthDayFromFields( const calendar = extractCalendar(rawFields) const refinedFields = refineFieldsViaCalendar(rawFields, monthDayFieldMap, calendar) - if (hasAnyProps(refinedFields)) { - if (rawFields.year === undefined && rawFields.calendar === undefined) { - refinedFields.year = isoEpochLeapYear - } - - return calendar.monthDayFromFields(refinedFields, options) + if (rawFields.year === undefined && rawFields.calendar === undefined) { + refinedFields.year = isoEpochLeapYear } + + return calendar.monthDayFromFields(refinedFields, options) } function tryTimeFromFields( @@ -127,10 +119,7 @@ function tryTimeFromFields( overflowHandling: OverflowHandlingInt, ): ISOTimeFields | undefined { const refinedFields = refineFields(rawFields, timeFieldMap) - - if (hasAnyProps(refinedFields)) { - return constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling) - } + return constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling) } // ::with (UNSAFE versions) @@ -161,8 +150,8 @@ function tryDateTimeWithFields( overflowHandling: OverflowHandlingInt, options?: Temporal.AssignmentOptions, ): Temporal.PlainDateTimeISOFields | undefined { - const dateRes = tryDateWithFields(plainDateTime, rawFields, options) - const timeRes = tryTimeWithFields(plainDateTime, rawFields, overflowHandling) + const dateRes = tryDateWithFields(plainDateTime, rawFields, options, true) + const timeRes = tryTimeWithFields(plainDateTime, rawFields, overflowHandling, true) if (dateRes || timeRes) { return { @@ -177,11 +166,12 @@ function tryDateWithFields( plainDate: any, rawFields: any, options?: Temporal.AssignmentOptions, + undefinedIfEmpty?: boolean, ): PlainDate | undefined { const calendar: Calendar = plainDate.calendar const filteredFields = refineFieldsViaCalendar(rawFields, dateFieldMap, calendar) - if (hasAnyProps(filteredFields)) { + if (!undefinedIfEmpty || hasAnyProps(filteredFields)) { const mergedFields = mergeFieldsViaCalendar(plainDate, filteredFields, dateFieldMap, calendar) return calendar.dateFromFields(mergedFields, options) } @@ -193,17 +183,13 @@ function tryYearMonthWithFields( options?: Temporal.AssignmentOptions, ): PlainYearMonth | undefined { const calendar: Calendar = plainYearMonth.calendar - const filteredFields = refineFieldsViaCalendar(rawFields, yearMonthFieldMap, calendar) - - if (hasAnyProps(filteredFields)) { - const mergedFields = mergeFieldsViaCalendar( - plainYearMonth, - rawFields, - yearMonthFieldMap, - calendar, - ) - return calendar.yearMonthFromFields(mergedFields, options) - } + const mergedFields = mergeFieldsViaCalendar( + plainYearMonth, + rawFields, + yearMonthFieldMap, + calendar, + ) + return calendar.yearMonthFromFields(mergedFields, options) } function tryMonthDayWithFields( @@ -212,27 +198,24 @@ function tryMonthDayWithFields( options?: Temporal.AssignmentOptions, ): PlainMonthDay | undefined { const calendar: Calendar = plainMonthDay.calendar - const filteredFields = refineFieldsViaCalendar(rawFields, monthDayFieldMap, calendar) - - if (hasAnyProps(filteredFields)) { - const mergedFields = mergeFieldsViaCalendar( - plainMonthDay, - rawFields, - monthDayFieldMap, - calendar, - ) - return calendar.monthDayFromFields(mergedFields, options) - } + const mergedFields = mergeFieldsViaCalendar( + plainMonthDay, + rawFields, + monthDayFieldMap, + calendar, + ) + return calendar.monthDayFromFields(mergedFields, options) } function tryTimeWithFields( plainTime: any, rawFields: any, overflowHandling: OverflowHandlingInt, + undefinedIfEmpty?: boolean, ): ISOTimeFields | undefined { const refinedFields = refineFields(rawFields, timeFieldMap) - if (hasAnyProps(refinedFields)) { + if (!undefinedIfEmpty || hasAnyProps(refinedFields)) { const mergedFields = mergeLocalTimeFields(plainTime, refinedFields) return constrainTimeISO(partialLocalTimeToISO(mergedFields), overflowHandling) } @@ -265,6 +248,9 @@ function refineFieldsViaCalendar( // convert to array and/or copy (done twice?) // (convert `fieldNames` result to Iterable as well?) fieldNames = [...fieldsMethod.call(calendar, fieldNames)] + + // guarantee order of access later + fieldNames.sort() } // TODO: more DRY with refineFields @@ -273,6 +259,8 @@ function refineFieldsViaCalendar( const rawValue = objOrFields[fieldName] if (rawValue !== undefined) { refinedFields[fieldName] = (fieldMap[fieldName] || identifyFunc)(rawValue) + } else { + refinedFields[fieldName] = undefined } } From 5f9cdc7769b037f1c119be1e44c1150eb36b16b8 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 10:57:53 -0400 Subject: [PATCH 048/805] when PlainDate option processing happens --- packages/temporal-polyfill/src/public/plainDate.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 458227fa..3ceda9e3 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -77,19 +77,20 @@ export class PlainDate implements Temporal.PlainDate { } static from(arg: PlainDateArg, options?: Temporal.AssignmentOptions): Temporal.PlainDate { - parseOverflowOption(options) // unused, but need to validate, regardless of input type - if ( arg instanceof PlainDate || arg instanceof PlainDateTime || arg instanceof ZonedDateTime ) { + parseOverflowOption(options) // unused, but must validate return createDate(arg.getISOFields()) // optimization } if (isObjectLike(arg)) { - return processDateFromFields(arg, options) + return processDateFromFields(arg, options) // will parse options } + parseOverflowOption(options) // unused, but must validate + // parse as string... const parsed = parseDateTime(toString(arg)) From 974c6b69dc5b7642cc69f204ad8d5717292b35a9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 11:07:30 -0400 Subject: [PATCH 049/805] change how undefineds are parsed --- packages/temporal-polyfill/src/argParse/refine.ts | 2 +- packages/temporal-polyfill/src/public/plainDate.ts | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index ffd89bb3..4edbd7d1 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -47,7 +47,7 @@ export function constrainInt( overflowHandling: OverflowHandlingInt, mustBePositive?: boolean, ): number { - if (val === undefined) { + if (val === undefined && overflowHandling !== OVERFLOW_REJECT) { return min } diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 3ceda9e3..96f69f1a 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -56,16 +56,6 @@ export class PlainDate implements Temporal.PlainDate { isoDay: number, calendarArg: Temporal.CalendarLike = createDefaultCalendar(), ) { - if (isoYear === undefined) { - throw new RangeError('Invalid isoYear') - } - if (isoMonth === undefined) { - throw new RangeError('Invalid isoMonth') - } - if (isoDay === undefined) { - throw new RangeError('Invalid isoDay') - } - const constrained = constrainDateISO({ isoYear, isoMonth, isoDay }, OVERFLOW_REJECT) const calendar = calendarFrom(calendarArg) From b9a387bf2a773da4410ca83cd0ca8382f277a40d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 11:16:45 -0400 Subject: [PATCH 050/805] validate duration arg right away --- packages/temporal-polyfill/src/public/plainDate.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 96f69f1a..3b9bc6f8 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -116,12 +116,14 @@ export class PlainDate implements Temporal.PlainDate { add(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { needReceiver(PlainDate, this) - return this.calendar.dateAdd(this, durationArg, options) + const duration = ensureObj(Duration, durationArg) + return this.calendar.dateAdd(this, duration, options) } subtract(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { needReceiver(PlainDate, this) - return this.calendar.dateAdd(this, ensureObj(Duration, durationArg).negated(), options) + const duration = ensureObj(Duration, durationArg).negated() + return this.calendar.dateAdd(this, duration, options) } until(other: PlainDateArg, options?: DiffOptions): Temporal.Duration { From dfd1dc3572c781a35d3649cf3d740215fee60721 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 11:21:29 -0400 Subject: [PATCH 051/805] validate whats returned from Calendar::dateAdd --- packages/temporal-polyfill/src/public/plainDate.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 3b9bc6f8..c0d61bca 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -117,13 +117,21 @@ export class PlainDate implements Temporal.PlainDate { add(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { needReceiver(PlainDate, this) const duration = ensureObj(Duration, durationArg) - return this.calendar.dateAdd(this, duration, options) + const plainDate = this.calendar.dateAdd(this, duration, options) + if (!(plainDate instanceof PlainDate)) { + throw new TypeError('Invalid return type') + } + return plainDate } subtract(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { needReceiver(PlainDate, this) const duration = ensureObj(Duration, durationArg).negated() - return this.calendar.dateAdd(this, duration, options) + const plainDate = this.calendar.dateAdd(this, duration, options) + if (!(plainDate instanceof PlainDate)) { + throw new TypeError('Invalid return type') + } + return plainDate } until(other: PlainDateArg, options?: DiffOptions): Temporal.Duration { From 2218937ca3833a9b72202ce26d9ab4466da72e4b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 11:32:54 -0400 Subject: [PATCH 052/805] more careful about options object --- packages/temporal-polyfill/src/argParse/refine.ts | 10 ++++++++++ packages/temporal-polyfill/src/public/plainDate.ts | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index 4edbd7d1..0f5b1b1f 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -2,6 +2,16 @@ import { ValueOf } from '../utils/obj' import { toInt, toString } from './fieldStr' import { OVERFLOW_REJECT, OverflowHandlingInt } from './overflowHandling' +export function ensureOptionsObject(obj: any): any { + if (obj === undefined) { + return Object.create(null) + } + if (!isObjectLike(obj)) { + throw new TypeError('Options must be object') + } + return Object.assign(Object.create(null), obj) +} + export function createOptionParser(propName: string, map: Map, defaultVal?: ValueOf): ( options: Record | undefined, // TODO: better type runtimeDefaultVal?: ValueOf, diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index c0d61bca..9c9397bb 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -4,7 +4,7 @@ import { parseCalendarDisplayOption } from '../argParse/calendarDisplay' import { parseDiffOptions } from '../argParse/diffOptions' import { toString } from '../argParse/fieldStr' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' -import { isObjectLike } from '../argParse/refine' +import { ensureOptionsObject, isObjectLike } from '../argParse/refine' import { IsoMasterMethods, ensureObj, @@ -117,7 +117,7 @@ export class PlainDate implements Temporal.PlainDate { add(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { needReceiver(PlainDate, this) const duration = ensureObj(Duration, durationArg) - const plainDate = this.calendar.dateAdd(this, duration, options) + const plainDate = this.calendar.dateAdd(this, duration, ensureOptionsObject(options)) if (!(plainDate instanceof PlainDate)) { throw new TypeError('Invalid return type') } @@ -127,7 +127,7 @@ export class PlainDate implements Temporal.PlainDate { subtract(durationArg: DurationArg, options?: Temporal.ArithmeticOptions): Temporal.PlainDate { needReceiver(PlainDate, this) const duration = ensureObj(Duration, durationArg).negated() - const plainDate = this.calendar.dateAdd(this, duration, options) + const plainDate = this.calendar.dateAdd(this, duration, ensureOptionsObject(options)) if (!(plainDate instanceof PlainDate)) { throw new TypeError('Invalid return type') } From 6f0956aaa7d49b8794c815924e0f1168ea2cb68e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 11:37:33 -0400 Subject: [PATCH 053/805] dont coerce to null-prototype --- packages/temporal-polyfill/src/argParse/refine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/argParse/refine.ts index 0f5b1b1f..d84605e7 100644 --- a/packages/temporal-polyfill/src/argParse/refine.ts +++ b/packages/temporal-polyfill/src/argParse/refine.ts @@ -9,7 +9,7 @@ export function ensureOptionsObject(obj: any): any { if (!isObjectLike(obj)) { throw new TypeError('Options must be object') } - return Object.assign(Object.create(null), obj) + return obj } export function createOptionParser(propName: string, map: Map, defaultVal?: ValueOf): ( From 0e3d7032b811fdf985d096294ad0d229116037ba Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 11:57:22 -0400 Subject: [PATCH 054/805] stricter about calendar methods like day --- .../temporal-polyfill/src/dateUtils/mixins.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/src/dateUtils/mixins.ts b/packages/temporal-polyfill/src/dateUtils/mixins.ts index 7e085c64..71825dc9 100644 --- a/packages/temporal-polyfill/src/dateUtils/mixins.ts +++ b/packages/temporal-polyfill/src/dateUtils/mixins.ts @@ -129,9 +129,28 @@ export function mixinCalendarFields( ObjClass, strArrayToHash(propNames, (propName) => function(this: Obj) { needReceiver(ObjClass, this) - const value = this.calendar[propName as keyof DateCalendarFields]( + const calendar = this.calendar + const value = calendar[propName as keyof DateCalendarFields]( this as Temporal.PlainDateLike, ) + + if ( + // things that are allowed to be non-integers + propName !== 'monthCode' && + propName !== 'era' && // can be undefined + propName !== 'eraYear' // can be undefined + ) { + if (typeof value !== 'number') { + throw new TypeError('bad number') + } + if (!Number.isInteger(value)) { + throw new RangeError('bad range') + } + if (propName !== 'year' && value <= 0) { + throw new RangeError('bad range') + } + } + Object.defineProperty(this, propName, { // cache the value on the object value, configurable: true, // what classes do. TODO: ensure everywhere From 367150733690fa8a0e13299f4f8cbd263324c770 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 12:19:05 -0400 Subject: [PATCH 055/805] plaindate equality must consider calendar --- packages/temporal-polyfill/src/public/plainDate.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 9c9397bb..3551e0ca 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -156,7 +156,9 @@ export class PlainDate implements Temporal.PlainDate { equals(other: PlainDateArg): boolean { needReceiver(PlainDate, this) - return !compareDateTimes(this, ensureObj(PlainDate, other)) + const otherPlainDate = ensureObj(PlainDate, other) + return !compareDateTimes(this, otherPlainDate) && + this.calendar.toString() === otherPlainDate.calendar.toString() } toString(options?: Temporal.ShowCalendarOption): string { From 2606e0fc97e34739900b316b6a34d7c5f23f60fe Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 13:15:56 -0400 Subject: [PATCH 056/805] getISOFields subtleties --- packages/temporal-polyfill/src/dateUtils/abstract.ts | 4 ++-- packages/temporal-polyfill/src/dateUtils/constrain.ts | 3 ++- packages/temporal-polyfill/src/public/plainDate.ts | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index 17c9c6ec..39c5ec3f 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -89,7 +89,7 @@ export function mixinIsoMasterMethods( obj: IsoMasterMethods, isoFields: ISOFields, ): void { - setISOFields(obj, Object.freeze(isoFields)) + setISOFields(obj, isoFields) } diff --git a/packages/temporal-polyfill/src/dateUtils/constrain.ts b/packages/temporal-polyfill/src/dateUtils/constrain.ts index 76824ec4..3f9bec3b 100644 --- a/packages/temporal-polyfill/src/dateUtils/constrain.ts +++ b/packages/temporal-polyfill/src/dateUtils/constrain.ts @@ -30,7 +30,8 @@ export function constrainDateISO( // also ensures numbers isoCalendarImpl, overflow, ) - return { isoYear, isoMonth, isoDay } + // order matters for getISOFields() + return { isoDay, isoMonth, isoYear } } export function isValidDateISO(isoFields: ISODateFields): boolean { diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 3551e0ca..c665712d 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -61,8 +61,9 @@ export class PlainDate implements Temporal.PlainDate { validateDate(constrained) initIsoMaster(this, { - ...constrained, + // order matters for getISOFIelds calendar, + ...constrained, }) } From d2528f7e6e487af52f70cefb4db50135accf387f Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 28 Mar 2023 13:22:33 -0400 Subject: [PATCH 057/805] better Calendar return type check --- .../temporal-polyfill/src/dateUtils/mixins.ts | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/mixins.ts b/packages/temporal-polyfill/src/dateUtils/mixins.ts index 71825dc9..866c5a70 100644 --- a/packages/temporal-polyfill/src/dateUtils/mixins.ts +++ b/packages/temporal-polyfill/src/dateUtils/mixins.ts @@ -134,21 +134,32 @@ export function mixinCalendarFields( this as Temporal.PlainDateLike, ) - if ( - // things that are allowed to be non-integers - propName !== 'monthCode' && - propName !== 'era' && // can be undefined - propName !== 'eraYear' // can be undefined - ) { - if (typeof value !== 'number') { - throw new TypeError('bad number') - } - if (!Number.isInteger(value)) { - throw new RangeError('bad range') - } - if (propName !== 'year' && value <= 0) { - throw new RangeError('bad range') - } + switch (propName) { + case 'inLeapYear': + if (typeof value !== 'boolean') { + throw new TypeError('Must be boolean') + } + break + case 'monthCode': + if (typeof value !== 'string') { + throw new TypeError('Must be string') + } + break + default: + if ( + propName !== 'era' && // can be undefined + propName !== 'eraYear' // can be undefined + ) { + if (typeof value !== 'number') { + throw new TypeError('bad number') + } + if (!Number.isInteger(value)) { + throw new RangeError('bad range') + } + if (propName !== 'year' && value <= 0) { + throw new RangeError('bad range') + } + } } Object.defineProperty(this, propName, { // cache the value on the object From 95f8341b4553c2f2a119a0fd0fbff1d4110a9ce0 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 13:19:16 -0400 Subject: [PATCH 058/805] more fixes --- .../misc/expected-failures.txt | 6 +++++ .../src/argParse/diffOptions.ts | 3 ++- .../src/argParse/roundingOptions.ts | 3 ++- .../temporal-polyfill/src/dateUtils/diff.ts | 22 +++++++++++++++---- .../src/dateUtils/durationSpan.ts | 14 +++++++++--- .../temporal-polyfill/src/public/plainDate.ts | 4 ++-- 6 files changed, 41 insertions(+), 11 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 116b9320..ecb3c2df 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -31,3 +31,9 @@ staging/Temporal/TimeZone/old/getInstantFor.js # NOTE: tests related to func.length fail because optional params need default values to make sure # they're not included in func.length #built-ins/Temporal/Calendar/prototype/dateAdd/length.js + +# Calendar::dateUntil shouldn't be called so often during diffing +built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js +built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js +built-ins/Temporal/PlainDate/prototype/since/custom.js +built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js diff --git a/packages/temporal-polyfill/src/argParse/diffOptions.ts b/packages/temporal-polyfill/src/argParse/diffOptions.ts index 0fdb7de6..1fea606e 100644 --- a/packages/temporal-polyfill/src/argParse/diffOptions.ts +++ b/packages/temporal-polyfill/src/argParse/diffOptions.ts @@ -1,6 +1,7 @@ import { Temporal } from 'temporal-spec' import { DAY, UnitInt, nanoIn } from '../dateUtils/units' import { RoundingFunc } from '../utils/math' +import { toInt } from './fieldStr' import { ensureOptionsObj } from './refine' import { parseRoundingModeOption } from './roundingMode' import { parseUnit } from './unitStr' @@ -24,7 +25,7 @@ export function parseDiffOptions< forDurationRounding?: boolean, // TODO: change to 'defaultRoundingFunc' ): DiffConfig { const ensuredOptions = ensureOptionsObj(options) - const roundingIncrement = ensuredOptions.roundingIncrement ?? 1 + const roundingIncrement = toInt(ensuredOptions.roundingIncrement ?? 1, true) const smallestUnit = parseUnit(ensuredOptions.smallestUnit, smallestUnitDefault, minUnit, maxUnit) const roundingFunc = parseRoundingModeOption( ensuredOptions, diff --git a/packages/temporal-polyfill/src/argParse/roundingOptions.ts b/packages/temporal-polyfill/src/argParse/roundingOptions.ts index 25453204..67ad1371 100644 --- a/packages/temporal-polyfill/src/argParse/roundingOptions.ts +++ b/packages/temporal-polyfill/src/argParse/roundingOptions.ts @@ -2,6 +2,7 @@ import { Temporal } from 'temporal-spec' import { DayTimeUnit } from '../dateUtils/dayAndTime' import { DAY, DayTimeUnitInt, nanoIn, nanoInDay } from '../dateUtils/units' import { RoundingFunc } from '../utils/math' +import { toInt } from './fieldStr' import { ensureOptionsObj } from './refine' import { parseRoundingModeOption } from './roundingMode' import { parseUnit } from './unitStr' @@ -27,7 +28,7 @@ export function parseRoundingOptions< : options const ensuredOptions = ensureOptionsObj(optionsObj, true) // strict=true - const roundingIncrement = ensuredOptions.roundingIncrement ?? 1 + const roundingIncrement = toInt(ensuredOptions.roundingIncrement ?? 1, true) const smallestUnit = parseUnit(ensuredOptions.smallestUnit, undefined, minUnit, maxUnit) const roundingFunc = parseRoundingModeOption(ensuredOptions, Math.round) const incNano = nanoIn[smallestUnit] * roundingIncrement diff --git a/packages/temporal-polyfill/src/dateUtils/diff.ts b/packages/temporal-polyfill/src/dateUtils/diff.ts index d070c682..bb9691d6 100644 --- a/packages/temporal-polyfill/src/dateUtils/diff.ts +++ b/packages/temporal-polyfill/src/dateUtils/diff.ts @@ -3,6 +3,7 @@ import { DiffConfig } from '../argParse/diffOptions' import { OVERFLOW_CONSTRAIN } from '../argParse/overflowHandling' import { unitNames } from '../argParse/unitStr' import { CalendarImpl } from '../calendarImpl/calendarImpl' +import { Duration } from '../public/duration' import { createDate } from '../public/plainDate' import { LargeInt, createLargeInt } from '../utils/largeInt' import { compareValues, roundToIncrement, roundToIncrementBI } from '../utils/math' @@ -55,9 +56,16 @@ export function diffDates( flip: boolean, diffConfig: DiffConfig, ): DurationFields { - const balancedDuration = calendar.dateUntil(d0, d1, { - largestUnit: unitNames[diffConfig.largestUnit] as Temporal.DateUnit, - }) + const balancedDuration = calendar.dateUntil( + d0, + d1, + Object.assign(Object.create(null), { + largestUnit: unitNames[diffConfig.largestUnit] as Temporal.DateUnit, + }), + ) + if (!(balancedDuration instanceof Duration)) { + throw new TypeError('Wrong return type for dateUntil') + } return roundDurationSpan(balancedDuration, d0, d1, calendar, flip, diffConfig) } @@ -217,8 +225,14 @@ export function diffAccurate( bigDuration = calendar.dateUntil( dateStart, dateMiddle, - { largestUnit: unitNames[largestUnit] as Temporal.DateUnit }, + Object.assign(Object.create(null), { + largestUnit: unitNames[largestUnit] as Temporal.DateUnit, + }), ) + if (!(bigDuration instanceof Duration)) { + throw new TypeError('Wrong return type for dateUntil') + } + dateTimeMiddle = dt0.add(bigDuration) timeDuration = diffTimeScale(dateTimeMiddle, dt1, HOUR) bigSign = bigDuration.sign diff --git a/packages/temporal-polyfill/src/dateUtils/durationSpan.ts b/packages/temporal-polyfill/src/dateUtils/durationSpan.ts index abff9cae..cd5e7709 100644 --- a/packages/temporal-polyfill/src/dateUtils/durationSpan.ts +++ b/packages/temporal-polyfill/src/dateUtils/durationSpan.ts @@ -1,5 +1,6 @@ import { Temporal } from 'temporal-spec' import { unitNames } from '../argParse/unitStr' +import { Duration } from '../public/duration' import { PlainDate } from '../public/plainDate' import { DiffableObj, diffAccurate } from './diff' import { DurationFields, overrideDuration } from './durationFields' @@ -32,9 +33,16 @@ export function spanDurationFromDate( calendar: Temporal.CalendarProtocol, ): [DurationFields, DiffableObj] { const translated = relativeTo.add(duration) - const newDuration = calendar.dateUntil(relativeTo, translated, { - largestUnit: unitNames[largestUnit] as Temporal.DateUnit, - }) + const newDuration = calendar.dateUntil( + relativeTo, + translated, + Object.assign(Object.create(null), { + largestUnit: unitNames[largestUnit] as Temporal.DateUnit, + }), + ) + if (!(newDuration instanceof Duration)) { + throw new TypeError('Wrong return type for dateUntil') + } return [newDuration, translated] } diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index c665712d..cf997645 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -141,7 +141,7 @@ export class PlainDate implements Temporal.PlainDate { this, ensureObj(PlainDate, other), false, - options, + ensureOptionsObject(options), ) } @@ -151,7 +151,7 @@ export class PlainDate implements Temporal.PlainDate { this, ensureObj(PlainDate, other), true, - options, + ensureOptionsObject(options), ) } From dfc18e2d3a09e19940aeac9757899603df6b1bf4 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 13:26:40 -0400 Subject: [PATCH 059/805] more rounding-increment validation --- packages/temporal-polyfill/misc/expected-failures.txt | 3 +++ packages/temporal-polyfill/src/argParse/diffOptions.ts | 9 +++++++-- packages/temporal-polyfill/src/argParse/fieldStr.ts | 4 ++-- .../temporal-polyfill/src/argParse/roundingOptions.ts | 9 +++++++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index ecb3c2df..f1c41829 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -37,3 +37,6 @@ built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js built-ins/Temporal/PlainDate/prototype/since/custom.js built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js + +# new crazy rounding options +built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.js diff --git a/packages/temporal-polyfill/src/argParse/diffOptions.ts b/packages/temporal-polyfill/src/argParse/diffOptions.ts index 1fea606e..361e57cc 100644 --- a/packages/temporal-polyfill/src/argParse/diffOptions.ts +++ b/packages/temporal-polyfill/src/argParse/diffOptions.ts @@ -1,7 +1,7 @@ import { Temporal } from 'temporal-spec' import { DAY, UnitInt, nanoIn } from '../dateUtils/units' import { RoundingFunc } from '../utils/math' -import { toInt } from './fieldStr' +import { toPositiveInt } from './fieldStr' import { ensureOptionsObj } from './refine' import { parseRoundingModeOption } from './roundingMode' import { parseUnit } from './unitStr' @@ -25,7 +25,12 @@ export function parseDiffOptions< forDurationRounding?: boolean, // TODO: change to 'defaultRoundingFunc' ): DiffConfig { const ensuredOptions = ensureOptionsObj(options) - const roundingIncrement = toInt(ensuredOptions.roundingIncrement ?? 1, true) + + const roundingIncrement = toPositiveInt(ensuredOptions.roundingIncrement ?? 1) + if (roundingIncrement > 1e9) { // what spec says + throw new RangeError('Out-of-range roundingIncrement') + } + const smallestUnit = parseUnit(ensuredOptions.smallestUnit, smallestUnitDefault, minUnit, maxUnit) const roundingFunc = parseRoundingModeOption( ensuredOptions, diff --git a/packages/temporal-polyfill/src/argParse/fieldStr.ts b/packages/temporal-polyfill/src/argParse/fieldStr.ts index da40769b..64164b40 100644 --- a/packages/temporal-polyfill/src/argParse/fieldStr.ts +++ b/packages/temporal-polyfill/src/argParse/fieldStr.ts @@ -56,10 +56,10 @@ export const dateTimeFieldMap = { // TODO: more DRY with constrainInt // ... -function toPositiveInt(valueParam: unknown, property?: string): number { +export function toPositiveInt(valueParam: unknown, property?: string): number { const value = toInt(valueParam) if (!Number.isFinite(value)) { - throw new RangeError('infinity is out of range') + throw new RangeError('infinity is out of range') // TODO: message about fractions } if (value < 1) { if (property !== undefined) { diff --git a/packages/temporal-polyfill/src/argParse/roundingOptions.ts b/packages/temporal-polyfill/src/argParse/roundingOptions.ts index 67ad1371..3431eae6 100644 --- a/packages/temporal-polyfill/src/argParse/roundingOptions.ts +++ b/packages/temporal-polyfill/src/argParse/roundingOptions.ts @@ -2,7 +2,7 @@ import { Temporal } from 'temporal-spec' import { DayTimeUnit } from '../dateUtils/dayAndTime' import { DAY, DayTimeUnitInt, nanoIn, nanoInDay } from '../dateUtils/units' import { RoundingFunc } from '../utils/math' -import { toInt } from './fieldStr' +import { toPositiveInt } from './fieldStr' import { ensureOptionsObj } from './refine' import { parseRoundingModeOption } from './roundingMode' import { parseUnit } from './unitStr' @@ -28,7 +28,12 @@ export function parseRoundingOptions< : options const ensuredOptions = ensureOptionsObj(optionsObj, true) // strict=true - const roundingIncrement = toInt(ensuredOptions.roundingIncrement ?? 1, true) + + const roundingIncrement = toPositiveInt(ensuredOptions.roundingIncrement ?? 1) + if (roundingIncrement > 1e9) { // what spec says + throw new RangeError('Out-of-range roundingIncrement') + } + const smallestUnit = parseUnit(ensuredOptions.smallestUnit, undefined, minUnit, maxUnit) const roundingFunc = parseRoundingModeOption(ensuredOptions, Math.round) const incNano = nanoIn[smallestUnit] * roundingIncrement From 7fb7bf813cc35b2b9583dc257cfecf6a07316362 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 13:37:10 -0400 Subject: [PATCH 060/805] further refind roundingIncrement parsing --- packages/temporal-polyfill/src/argParse/diffOptions.ts | 5 ++++- packages/temporal-polyfill/src/argParse/roundingOptions.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/temporal-polyfill/src/argParse/diffOptions.ts b/packages/temporal-polyfill/src/argParse/diffOptions.ts index 361e57cc..f46d7693 100644 --- a/packages/temporal-polyfill/src/argParse/diffOptions.ts +++ b/packages/temporal-polyfill/src/argParse/diffOptions.ts @@ -26,7 +26,10 @@ export function parseDiffOptions< ): DiffConfig { const ensuredOptions = ensureOptionsObj(options) - const roundingIncrement = toPositiveInt(ensuredOptions.roundingIncrement ?? 1) + const roundingIncrementInput = ensuredOptions.roundingIncrement + const roundingIncrement = toPositiveInt( + roundingIncrementInput === undefined ? 1 : roundingIncrementInput, + ) if (roundingIncrement > 1e9) { // what spec says throw new RangeError('Out-of-range roundingIncrement') } diff --git a/packages/temporal-polyfill/src/argParse/roundingOptions.ts b/packages/temporal-polyfill/src/argParse/roundingOptions.ts index 3431eae6..da71c97d 100644 --- a/packages/temporal-polyfill/src/argParse/roundingOptions.ts +++ b/packages/temporal-polyfill/src/argParse/roundingOptions.ts @@ -29,7 +29,10 @@ export function parseRoundingOptions< const ensuredOptions = ensureOptionsObj(optionsObj, true) // strict=true - const roundingIncrement = toPositiveInt(ensuredOptions.roundingIncrement ?? 1) + const roundingIncrementInput = ensuredOptions.roundingIncrement + const roundingIncrement = toPositiveInt( + roundingIncrementInput === undefined ? 1 : roundingIncrementInput, + ) if (roundingIncrement > 1e9) { // what spec says throw new RangeError('Out-of-range roundingIncrement') } From dbed3104df73898b629ee11c69a4136a5b458f27 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 13:42:44 -0400 Subject: [PATCH 061/805] fix year formatting --- packages/temporal-polyfill/misc/expected-failures.txt | 5 +++++ packages/temporal-polyfill/src/dateUtils/isoFormat.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index f1c41829..6ed067d6 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -40,3 +40,8 @@ built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js # new crazy rounding options built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.js +built-ins/Temporal/PlainDate/prototype/since/roundingmode-expand.js +built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfCeil.js +built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfEven.js +built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfFloor.js +built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfTrunc.js diff --git a/packages/temporal-polyfill/src/dateUtils/isoFormat.ts b/packages/temporal-polyfill/src/dateUtils/isoFormat.ts index 17c8cf5a..c21cabae 100644 --- a/packages/temporal-polyfill/src/dateUtils/isoFormat.ts +++ b/packages/temporal-polyfill/src/dateUtils/isoFormat.ts @@ -37,7 +37,7 @@ export function formatDateISO(fields: ISODateFields): string { export function formatYearMonthISO(fields: ISODateFields): string { const { isoYear } = fields return ( - (isoYear < 1000 || isoYear > 9999) + (isoYear < 0 || isoYear > 9999) ? getSignStr(isoYear) + padZeros(Math.abs(isoYear), 6) : padZeros(isoYear, 4) ) + '-' + padZeros(fields.isoMonth, 2) From b0de07aa061590bde1c85d52202a5709c112e3e8 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 16:18:52 -0400 Subject: [PATCH 062/805] more fixes --- .../misc/expected-failures.txt | 3 ++ .../src/dateUtils/fromAndWith.ts | 16 +++++++- .../src/native/intlMixins.ts | 37 +++++++++++-------- .../temporal-polyfill/src/public/plainDate.ts | 4 +- .../temporal-polyfill/src/public/plainTime.ts | 4 +- 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 6ed067d6..2acc1ccf 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -45,3 +45,6 @@ built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfCeil.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfEven.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfFloor.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfTrunc.js + +# OrigDateTimeFormat bugs +built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 04464318..ac05ebcc 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -11,7 +11,7 @@ import { import { OverflowHandlingInt } from '../argParse/overflowHandling' import { isObjectLike, refineFields } from '../argParse/refine' import { extractTimeZone } from '../argParse/timeZone' -import { Calendar, getCalendarImpl, mergeCalFields } from '../public/calendar' +import { Calendar, calendarFrom, getCalendarImpl, mergeCalFields } from '../public/calendar' import { PlainDate } from '../public/plainDate' import { PlainMonthDay } from '../public/plainMonthDay' import { PlainYearMonth } from '../public/plainYearMonth' @@ -117,9 +117,21 @@ function tryMonthDayFromFields( function tryTimeFromFields( rawFields: any, overflowHandling: OverflowHandlingInt, + undefinedIfEmpty?: boolean, ): ISOTimeFields | undefined { const refinedFields = refineFields(rawFields, timeFieldMap) - return constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling) + + let { calendar } = rawFields + if (calendar !== undefined) { + calendar = calendarFrom(calendar) + if (calendar.toString() !== 'iso8601') { + throw new RangeError('Cannot specify non-iso calendar for time') + } + } + + if (!undefinedIfEmpty || hasAnyProps(refinedFields)) { + return constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling) + } } // ::with (UNSAFE versions) diff --git a/packages/temporal-polyfill/src/native/intlMixins.ts b/packages/temporal-polyfill/src/native/intlMixins.ts index 5002f699..3a29833e 100644 --- a/packages/temporal-polyfill/src/native/intlMixins.ts +++ b/packages/temporal-polyfill/src/native/intlMixins.ts @@ -10,23 +10,28 @@ export function mixinLocaleStringMethods, ): void { - ObjClass.prototype.toLocaleString = function( - this: Entity, - localesArg?: LocalesArg, - options?: Intl.DateTimeFormatOptions, - ): string { - const formatFactory = buildFormatFactory( - normalizeAndCopyLocalesArg(localesArg), - options || {}, - ) - return formatFactory.buildFormat( - ...formatFactory.buildKey(this), - ).format( - formatFactory.buildEpochMilli(this), - ) + class LocaleStringMixin { + toLocaleString( + this: Entity, + localesArg?: LocalesArg, + options?: Intl.DateTimeFormatOptions, + ): string { + const formatFactory = buildFormatFactory( + normalizeAndCopyLocalesArg(localesArg), + options || {}, + ) + return formatFactory.buildFormat( + ...formatFactory.buildKey(this), + ).format( + formatFactory.buildEpochMilli(this), + ) + } } - - ;(ObjClass.prototype as any)[formatFactoryFactorySymbol] = buildFormatFactory + Object.defineProperty(ObjClass.prototype, 'toLocaleString', { + value: LocaleStringMixin.prototype.toLocaleString, + writable: true, + configurable: true, + }) } export function extractFormatFactoryFactory( diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index cf997645..bc3ae413 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -191,8 +191,8 @@ export class PlainDate implements Temporal.PlainDate { toPlainDateTime(timeArg?: PlainTimeArg): Temporal.PlainDateTime { needReceiver(PlainDate, this) return createDateTime({ - ...this.getISOFields(), - ...ensureLooseTime(timeArg).getISOFields(), + ...ensureLooseTime(timeArg).getISOFields(), // always provides iso8601 calendar! + ...this.getISOFields(), // put this second to prevent overriding! }) } diff --git a/packages/temporal-polyfill/src/public/plainTime.ts b/packages/temporal-polyfill/src/public/plainTime.ts index e3c6cdf7..d9bc0d26 100644 --- a/packages/temporal-polyfill/src/public/plainTime.ts +++ b/packages/temporal-polyfill/src/public/plainTime.ts @@ -87,7 +87,7 @@ export class PlainTime implements Temporal.PlainTime { return createTime(arg.getISOFields()) } if (isObjectLike(arg)) { - return createTime(processTimeFromFields(arg, overflowHandling)) + return createTime(processTimeFromFields(arg, overflowHandling, true)) } // parse as string... @@ -220,7 +220,7 @@ export function createTime(isoFields: ISOTimeFields): PlainTime { // Normally ensureObj and ::from would fail when undefined is specified // Fallback to 00:00 time export function ensureLooseTime(arg: PlainTimeArg | undefined): PlainTime { - return ensureObj(PlainTime, arg ?? { hour: 0 }) + return ensureObj(PlainTime, arg === undefined ? { hour: 0 } : arg) } function translatePlainTime(pt: PlainTime, dur: DurationFields): PlainTime { From 5b0d395a88b68a652c2c7e329ce4dd0a62375b84 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 16:49:31 -0400 Subject: [PATCH 063/805] more fixes --- packages/temporal-polyfill/misc/expected-failures.txt | 9 ++++++++- packages/temporal-polyfill/src/dateUtils/fromAndWith.ts | 6 +++--- packages/temporal-polyfill/src/public/plainDate.ts | 7 ++++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 2acc1ccf..c4e08e4a 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -22,7 +22,6 @@ built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # TimeZone transitions intl402/Temporal/TimeZone/prototype/getNextTransition/subtract-second-and-nanosecond-from-last-transition.js intl402/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/nanoseconds-subtracted-or-added-at-dst-transition.js -staging/Temporal/TimeZone/old/getInstantFor.js # Intl.DateTimeFormat # (even PlainDate should be reduced to timestamp, should have be displayable with timeZone options) @@ -48,3 +47,11 @@ built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfTrunc.js # OrigDateTimeFormat bugs built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js + +# Calendar::monthDayFromFields needs to call Calendar::fields somehow +built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js + +# dateFromFields/yearMonthFromFields/monthDayFromFields +# First `fields` argument must be plain object with null-prototype, not Temporal object +built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js +built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index ac05ebcc..39a24075 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -111,7 +111,7 @@ function tryMonthDayFromFields( refinedFields.year = isoEpochLeapYear } - return calendar.monthDayFromFields(refinedFields, options) + return calendar.monthDayFromFields(refinedFields, Object.assign(Object.create(null), options)) } function tryTimeFromFields( @@ -201,7 +201,7 @@ function tryYearMonthWithFields( yearMonthFieldMap, calendar, ) - return calendar.yearMonthFromFields(mergedFields, options) + return calendar.yearMonthFromFields(mergedFields, Object.assign(Object.create(null), options)) } function tryMonthDayWithFields( @@ -216,7 +216,7 @@ function tryMonthDayWithFields( monthDayFieldMap, calendar, ) - return calendar.monthDayFromFields(mergedFields, options) + return calendar.monthDayFromFields(mergedFields, Object.assign(Object.create(null), options)) } function tryTimeWithFields( diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index bc3ae413..d85f4bef 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -34,6 +34,7 @@ import { ToLocaleStringMethods, mixinLocaleStringMethods } from '../native/intlM import { calendarFrom, createDefaultCalendar } from './calendar' import { Duration, DurationArg, createDuration } from './duration' import { PlainDateTime, createDateTime } from './plainDateTime' +import { PlainMonthDay } from './plainMonthDay' import { PlainTime, PlainTimeArg, ensureLooseTime } from './plainTime' import { createYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' @@ -203,7 +204,11 @@ export class PlainDate implements Temporal.PlainDate { toPlainMonthDay(): Temporal.PlainMonthDay { needReceiver(PlainDate, this) - return this.calendar.monthDayFromFields(this) + const res = this.calendar.monthDayFromFields(this, undefined) // important we comply to 2 args! + if (!(res instanceof PlainMonthDay)) { + throw new TypeError('Invalid return type') + } + return res } } From ebe9a5f43ecccd03445670594faa84c8f45422ff Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 17:56:02 -0400 Subject: [PATCH 064/805] more fixes yo --- .../misc/expected-failures.txt | 22 +++++++++- .../src/dateUtils/totalUnits.ts | 4 ++ .../temporal-polyfill/src/public/duration.ts | 1 + .../temporal-polyfill/src/public/plainDate.ts | 40 ++++++++++++------- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index c4e08e4a..fef0357a 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -22,6 +22,7 @@ built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js # TimeZone transitions intl402/Temporal/TimeZone/prototype/getNextTransition/subtract-second-and-nanosecond-from-last-transition.js intl402/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/nanoseconds-subtracted-or-added-at-dst-transition.js +built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor-iterable.js # Intl.DateTimeFormat # (even PlainDate should be reduced to timestamp, should have be displayable with timeZone options) @@ -44,14 +45,33 @@ built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfCeil.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfEven.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfFloor.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfTrunc.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfFloor.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfExpand.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfEven.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfCeil.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-expand.js +built-ins/Temporal/PlainDate/prototype/until/roundingincrement-non-integer.js # OrigDateTimeFormat bugs built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js +intl402/Temporal/PlainDate/prototype/toLocaleString/options-conflict.js -# Calendar::monthDayFromFields needs to call Calendar::fields somehow +# Calendar::monthDayFromFields needs to call Calendar::fields somehow. similar problems built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fields-iterable.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-invalid-return.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js # dateFromFields/yearMonthFromFields/monthDayFromFields # First `fields` argument must be plain object with null-prototype, not Temporal object built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fromfields-called-with-null-prototype-fields.js + +# far-future, far-past, out-of-range problems +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/limits.js +built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.js + +# toString options (calendarName:critical) +built-ins/Temporal/PlainDate/prototype/toString/calendar-tostring.js +built-ins/Temporal/PlainDate/prototype/toString/calendarname-critical.js diff --git a/packages/temporal-polyfill/src/dateUtils/totalUnits.ts b/packages/temporal-polyfill/src/dateUtils/totalUnits.ts index 07f73293..0f176f3a 100644 --- a/packages/temporal-polyfill/src/dateUtils/totalUnits.ts +++ b/packages/temporal-polyfill/src/dateUtils/totalUnits.ts @@ -1,5 +1,6 @@ import { Temporal } from 'temporal-spec' import { durationUnitNames } from '../argParse/unitStr' +import { Duration, getDurationFields } from '../public/duration' import { durationDayTimeToNano } from './dayAndTime' import { DiffableObj } from './diff' import { @@ -63,6 +64,9 @@ export function computeExactDuration( const { sign } = balancedDuration if (!sign) { // prevents division by zero + if (balancedDuration instanceof Duration) { // hack because caller needs writeable obj + return getDurationFields(balancedDuration) + } return balancedDuration } diff --git a/packages/temporal-polyfill/src/public/duration.ts b/packages/temporal-polyfill/src/public/duration.ts index 6d735e64..e78bcc00 100644 --- a/packages/temporal-polyfill/src/public/duration.ts +++ b/packages/temporal-polyfill/src/public/duration.ts @@ -36,6 +36,7 @@ type DurationRoundingOptions = Temporal.DifferenceOptions } const [getFields, setFields] = createWeakMap() +export { getFields as getDurationFields } export class Duration implements Temporal.Duration { constructor( diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index d85f4bef..01f60af7 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -170,7 +170,10 @@ export class PlainDate implements Temporal.PlainDate { const fields = this.getISOFields() return formatDateISO(fields) + - formatCalendarID(fields.calendar.toString(), calendarDisplay) + formatCalendarID( + String(fields.calendar), // important for [Symbol.toPrimitive] access + calendarDisplay, + ) } toZonedDateTime(options: ToZonedDateTimeOptions): Temporal.ZonedDateTime { @@ -183,8 +186,8 @@ export class PlainDate implements Temporal.PlainDate { : ensureObj(PlainTime, refinedOptions.plainTime) return createZonedDateTimeFromFields({ - ...this.getISOFields(), - ...(plainTime ? plainTime.getISOFields() : zeroISOTimeFields), + ...(plainTime ? plainTime.getISOFields() : zeroISOTimeFields), // always iso8601 calendar! + ...this.getISOFields(), // put this second to prevent overriding! timeZone, }) } @@ -199,7 +202,10 @@ export class PlainDate implements Temporal.PlainDate { toPlainYearMonth(): Temporal.PlainYearMonth { needReceiver(PlainDate, this) - return createYearMonth(this.getISOFields()) + return createYearMonth({ + ...this.getISOFields(), + isoDay: 1, + }) } toPlainMonthDay(): Temporal.PlainMonthDay { @@ -255,20 +261,24 @@ function processToZonedDateTimeOptions( let plainTime: PlainTimeArg | undefined let timeZone: Temporal.TimeZoneLike | undefined - if (typeof options === 'string') { - timeZone = options - } else if (typeof options === 'object') { - if ((options as Temporal.TimeZoneProtocol).id !== undefined) { - timeZone = options as Temporal.TimeZoneProtocol + if (isObjectLike(options)) { + if (options instanceof TimeZone) { + timeZone = options as any } else { - timeZone = options.timeZone - plainTime = (options as { plainTime?: PlainTimeArg }).plainTime - } - if (timeZone === undefined) { - throw new TypeError('Invalid timeZone argument') + const timeZoneLike = options.timeZone + if (timeZoneLike === undefined) { + timeZone = options + } else { + timeZone = timeZoneLike + plainTime = options.plainTime + } } } else { - throw new TypeError('Invalid options/timeZone argument') + timeZone = options + } + + if (timeZone === undefined) { + throw new TypeError('Invalid timezone argument') } return { plainTime, timeZone } From 801017ac23b60a100ef45943320841ed5aa4d22a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 18:18:09 -0400 Subject: [PATCH 065/805] more errors --- packages/temporal-polyfill/misc/expected-failures.txt | 10 ++++++++++ packages/temporal-polyfill/src/dateUtils/abstract.ts | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index fef0357a..7ed9534d 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -37,6 +37,10 @@ built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js built-ins/Temporal/PlainDate/prototype/since/custom.js built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js +built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js +built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js +built-ins/Temporal/PlainDate/prototype/until/custom.js +built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js # new crazy rounding options built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.js @@ -51,6 +55,12 @@ built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfEven.js built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfCeil.js built-ins/Temporal/PlainDate/prototype/until/roundingmode-expand.js built-ins/Temporal/PlainDate/prototype/until/roundingincrement-non-integer.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfTrunc.js + +# rounding with weeks returns -0 for some reason +built-ins/Temporal/PlainDate/prototype/until/roundingmode-ceil.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-floor.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-trunc.js # OrigDateTimeFormat bugs built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/dateUtils/abstract.ts index 39c5ec3f..975c58d0 100644 --- a/packages/temporal-polyfill/src/dateUtils/abstract.ts +++ b/packages/temporal-polyfill/src/dateUtils/abstract.ts @@ -64,7 +64,7 @@ export function mixinNoValueMethods( class NoValueMixin { valueOf(this: Obj): never { needReceiver(ObjClass, this) - throw new Error('Cannot convert object using valueOf') + throw new TypeError('Cannot convert object using valueOf') } } Object.defineProperty(ObjClass.prototype, 'valueOf', { From df77f40eebb31c41b856d39544f3aee442b4ac5e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 19:03:18 -0400 Subject: [PATCH 066/805] more things --- .../misc/expected-failures.txt | 9 +++++++++ .../src/dateUtils/calendar.ts | 15 ++++++++++++++ .../src/dateUtils/fromAndWith.ts | 12 ++++++----- .../temporal-polyfill/src/public/calendar.ts | 11 +++++++++- .../src/public/plainMonthDay.ts | 20 ++++++++++++------- .../src/public/plainYearMonth.ts | 15 +++++++++----- 6 files changed, 64 insertions(+), 18 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 7ed9534d..470a0f2f 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -41,6 +41,8 @@ built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-null built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js built-ins/Temporal/PlainDate/prototype/until/custom.js built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js +built-ins/Temporal/PlainDate/prototype/with/calendar-fields-iterable.js +built-ins/Temporal/PlainDate/prototype/with/calendar-merge-fields-returns-primitive.js # new crazy rounding options built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.js @@ -85,3 +87,10 @@ built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.js # toString options (calendarName:critical) built-ins/Temporal/PlainDate/prototype/toString/calendar-tostring.js built-ins/Temporal/PlainDate/prototype/toString/calendarname-critical.js + +# I don't undersand why the result of Calendar::mergeFields being fed into Calendar::dateFromFields +# has anything to do with copying +built-ins/Temporal/PlainDate/prototype/with/copies-merge-fields-object.js + +# exact internal-call ordering of ::with (hard, needs refactor) +built-ins/Temporal/PlainDate/prototype/with/order-of-operations.js diff --git a/packages/temporal-polyfill/src/dateUtils/calendar.ts b/packages/temporal-polyfill/src/dateUtils/calendar.ts index 56f9ee71..0c3190bb 100644 --- a/packages/temporal-polyfill/src/dateUtils/calendar.ts +++ b/packages/temporal-polyfill/src/dateUtils/calendar.ts @@ -1,6 +1,7 @@ import { Temporal } from 'temporal-spec' import { OVERFLOW_REJECT, parseOverflowOption } from '../argParse/overflowHandling' import { CalendarImpl, convertEraYear } from '../calendarImpl/calendarImpl' +import { Calendar } from '../public/calendar' import { PlainDate, PlainDateArg, createDate } from '../public/plainDate' import { PlainDateTime } from '../public/plainDateTime' import { PlainMonthDay } from '../public/plainMonthDay' @@ -33,6 +34,20 @@ function isDateISOInstance(arg: unknown): arg is DateISOInstance { ) } +// ah + +export function safeDateFromFields( + calendar: Temporal.CalendarProtocol, + fields: Temporal.YearOrEraAndEraYear & Temporal.MonthOrMonthCode & { day: number }, + options?: Temporal.AssignmentOptions, +): PlainDate { + const res = calendar.dateFromFields(fields, options) + if (!(res instanceof PlainDate)) { + throw new TypeError('dateFromFields must return PlainDate') + } + return res +} + // Calendar-dependent Field Querying export function queryDateFields( diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 39a24075..e7a046c5 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -17,6 +17,7 @@ import { PlainMonthDay } from '../public/plainMonthDay' import { PlainYearMonth } from '../public/plainYearMonth' import { ZonedDateTime } from '../public/zonedDateTime' import { mapHash } from '../utils/obj' +import { safeDateFromFields } from './calendar' import { constrainTimeISO } from './constrain' import { partialLocalTimeToISO } from './dayAndTime' import { DurationFields } from './durationFields' @@ -76,7 +77,7 @@ function tryDateTimeFromFields( // refinedFields to dateFromFields, because dateFromFields has potential to mutate it ...constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling), // - ...calendar.dateFromFields(refinedFields, options).getISOFields(), + ...safeDateFromFields(calendar, refinedFields, options).getISOFields(), } } @@ -87,7 +88,7 @@ function tryDateFromFields( const calendar = extractCalendar(rawFields) const refinedFields = refineFieldsViaCalendar(rawFields, dateFieldMap, calendar) - return calendar.dateFromFields(refinedFields, options) + return safeDateFromFields(calendar, refinedFields, options) } function tryYearMonthFromFields( @@ -185,7 +186,7 @@ function tryDateWithFields( if (!undefinedIfEmpty || hasAnyProps(filteredFields)) { const mergedFields = mergeFieldsViaCalendar(plainDate, filteredFields, dateFieldMap, calendar) - return calendar.dateFromFields(mergedFields, options) + return safeDateFromFields(calendar, mergedFields, options) } } @@ -291,8 +292,9 @@ function mergeFieldsViaCalendar( ): any { const existingFields = refineFieldsViaCalendar(existingObj, fieldMap, calendar) - if (calendar.mergeFields) { // TODO: more frugal querying? - return calendar.mergeFields(existingFields, fields) + const mergeFields = calendar.mergeFields + if (mergeFields) { + return mergeFields.call(calendar, existingFields, fields) } return mergeCalFields( diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index fff42594..5de5296b 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -564,7 +564,16 @@ export function mergeCalFields(baseFields: any, newFields: any, calendarID: stri delete baseFieldsCopy.eraYear } - return Object.assign(Object.create(null), baseFieldsCopy, newFieldsCopy) + // HACK against undefined values + const definedNewFields = {} as any + for (const fieldName in newFieldsCopy) { + const v = newFieldsCopy[fieldName] + if (v !== undefined) { + definedNewFields[fieldName] = v + } + } + + return Object.assign(Object.create(null), baseFieldsCopy, definedNewFields) } // utils diff --git a/packages/temporal-polyfill/src/public/plainMonthDay.ts b/packages/temporal-polyfill/src/public/plainMonthDay.ts index bbf33b82..eb574c85 100644 --- a/packages/temporal-polyfill/src/public/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/public/plainMonthDay.ts @@ -11,6 +11,7 @@ import { mixinIsoMasterMethods, needReceiver, } from '../dateUtils/abstract' +import { safeDateFromFields } from '../dateUtils/calendar' import { compareDateTimes } from '../dateUtils/compare' import { constrainDateISO } from '../dateUtils/constrain' import { isoEpochLeapYear } from '../dateUtils/epoch' @@ -95,13 +96,18 @@ export class PlainMonthDay implements Temporal.PlainMonthDay { toPlainDate(fields: { year: number }): Temporal.PlainDate { needReceiver(PlainMonthDay, this) - return this.calendar.dateFromFields({ - year: fields.year, - monthCode: this.monthCode, - day: this.day, - }, { - overflow: 'reject', // always reject - }) + + return safeDateFromFields( + this.calendar, + { + year: fields.year, + monthCode: this.monthCode, + day: this.day, + }, + { + overflow: 'reject', // always reject + }, + ) } } diff --git a/packages/temporal-polyfill/src/public/plainYearMonth.ts b/packages/temporal-polyfill/src/public/plainYearMonth.ts index c8ed00c9..7d4ddd9d 100644 --- a/packages/temporal-polyfill/src/public/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/public/plainYearMonth.ts @@ -13,6 +13,7 @@ import { mixinIsoMasterMethods, needReceiver, } from '../dateUtils/abstract' +import { safeDateFromFields } from '../dateUtils/calendar' import { compareDateTimes } from '../dateUtils/compare' import { constrainDateISO } from '../dateUtils/constrain' import { diffDates } from '../dateUtils/diff' @@ -147,11 +148,15 @@ export class PlainYearMonth implements Temporal.PlainYearMonth { toPlainDate(fields: { day: number }): Temporal.PlainDate { needReceiver(PlainYearMonth, this) - return this.calendar.dateFromFields({ - year: this.year, - month: this.month, - day: fields.day, - }) + + return safeDateFromFields( + this.calendar, + { + year: this.year, + month: this.month, + day: fields.day, + }, + ) } } From 4a2fef312ee9fb542f255880cd5fbfed4785dacc Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 19:15:22 -0400 Subject: [PATCH 067/805] stuff --- .../temporal-polyfill/misc/expected-failures.txt | 3 +++ .../temporal-polyfill/src/dateUtils/fromAndWith.ts | 14 +++++++++++++- packages/temporal-polyfill/src/public/plainDate.ts | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index 470a0f2f..dd70a88c 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -94,3 +94,6 @@ built-ins/Temporal/PlainDate/prototype/with/copies-merge-fields-object.js # exact internal-call ordering of ::with (hard, needs refactor) built-ins/Temporal/PlainDate/prototype/with/order-of-operations.js + +# side-effect of our hack of filtering away undefines, accidentally filters away symbol keys +built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index e7a046c5..7ca1f0f3 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -340,5 +340,17 @@ function buildSafeFunc( } function hasAnyProps(fields: any): boolean { - return Object.keys(fields).length > 0 + return Object.keys(filterAwayUndefined(fields)).length > 0 +} + +// hack +function filterAwayUndefined(obj: any) { + const res: any = {} + for (const key in obj) { + const val = obj[key] + if (val !== undefined) { + res[key] = val + } + } + return res } diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 01f60af7..35705ec9 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -102,7 +102,7 @@ export class PlainDate implements Temporal.PlainDate { with(fields: Temporal.PlainDateLike, options?: Temporal.AssignmentOptions): Temporal.PlainDate { needReceiver(PlainDate, this) - return processDateWithFields(this, fields, options) + return processDateWithFields(this, fields, options, true) // failIfEmpty } withCalendar(calendarArg: Temporal.CalendarLike): Temporal.PlainDate { From 2259ec02e4917136046f057a9f5fd0a8de1f9f4a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 19:30:13 -0400 Subject: [PATCH 068/805] more validation --- .../temporal-polyfill/src/dateUtils/mixins.ts | 28 +++++++++++++------ .../temporal-polyfill/src/public/plainDate.ts | 3 ++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/mixins.ts b/packages/temporal-polyfill/src/dateUtils/mixins.ts index 866c5a70..120717a6 100644 --- a/packages/temporal-polyfill/src/dateUtils/mixins.ts +++ b/packages/temporal-polyfill/src/dateUtils/mixins.ts @@ -145,20 +145,32 @@ export function mixinCalendarFields( throw new TypeError('Must be string') } break - default: - if ( - propName !== 'era' && // can be undefined - propName !== 'eraYear' // can be undefined - ) { + case 'era': + if (value !== undefined) { + if (typeof value !== 'string') { + throw new TypeError('bad era') + } + } + break + case 'eraYear': + if (value !== undefined) { if (typeof value !== 'number') { throw new TypeError('bad number') } if (!Number.isInteger(value)) { throw new RangeError('bad range') } - if (propName !== 'year' && value <= 0) { - throw new RangeError('bad range') - } + } + break + default: + if (typeof value !== 'number') { + throw new TypeError('bad number') + } + if (!Number.isInteger(value)) { + throw new RangeError('bad range') + } + if (propName !== 'year' && value <= 0) { + throw new RangeError('bad range') } } diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/public/plainDate.ts index 35705ec9..76cd7dac 100644 --- a/packages/temporal-polyfill/src/public/plainDate.ts +++ b/packages/temporal-polyfill/src/public/plainDate.ts @@ -106,6 +106,9 @@ export class PlainDate implements Temporal.PlainDate { } withCalendar(calendarArg: Temporal.CalendarLike): Temporal.PlainDate { + if (calendarArg === undefined) { + throw new RangeError('Missing calendar') + } needReceiver(PlainDate, this) const isoFields = this.getISOFields() return new PlainDate( From 8bb583b121dc0d623c0b9bb0a283997db3138d8f Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 19:40:58 -0400 Subject: [PATCH 069/805] fix intl.datetimeformat bug --- packages/temporal-polyfill/src/native/intlMixins.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/temporal-polyfill/src/native/intlMixins.ts b/packages/temporal-polyfill/src/native/intlMixins.ts index 3a29833e..663028d5 100644 --- a/packages/temporal-polyfill/src/native/intlMixins.ts +++ b/packages/temporal-polyfill/src/native/intlMixins.ts @@ -27,11 +27,14 @@ export function mixinLocaleStringMethods( From 3851fa0eda79f80da0c377f7612286d95709002b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 19:43:38 -0400 Subject: [PATCH 070/805] more stuff --- packages/temporal-polyfill/misc/expected-failures.txt | 1 + packages/temporal-polyfill/src/dateUtils/timeZone.ts | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index dd70a88c..baca7ee0 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -27,6 +27,7 @@ built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinsta # Intl.DateTimeFormat # (even PlainDate should be reduced to timestamp, should have be displayable with timeZone options) #intl402/DateTimeFormat/prototype/format/temporal-objects-timezone-getoffsetnanosecondsfor-not-callable.js +intl402/Temporal/PlainDate/prototype/toLocaleString/timezone-getoffsetnanosecondsfor-not-callable.js # NOTE: tests related to func.length fail because optional params need default values to make sure # they're not included in func.length diff --git a/packages/temporal-polyfill/src/dateUtils/timeZone.ts b/packages/temporal-polyfill/src/dateUtils/timeZone.ts index e7fae519..1e12eebc 100644 --- a/packages/temporal-polyfill/src/dateUtils/timeZone.ts +++ b/packages/temporal-polyfill/src/dateUtils/timeZone.ts @@ -83,7 +83,11 @@ export function getSafeOffsetNanosecondsFor( // important that arg-parsing failure happens here, before getOffsetNanosecondsFor called const instant = ensureObj(Instant, arg) - const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(instant) + const { getOffsetNanosecondsFor } = timeZone + if (typeof getOffsetNanosecondsFor !== 'function') { + throw new TypeError('getOffsetNanosecondsFor must be callable') + } + const offsetNanoseconds = getOffsetNanosecondsFor.call(timeZone, instant) if (typeof offsetNanoseconds !== 'number') { throw new TypeError('Invalid return value from getOffsetNanosecondsFor') From 1fe9ab5b6c81147b8279c2913e861d389e50a56c Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 20:00:44 -0400 Subject: [PATCH 071/805] some zdt fixes --- packages/temporal-polyfill/src/dateUtils/compare.ts | 11 ++++++----- .../temporal-polyfill/src/dateUtils/fromAndWith.ts | 2 ++ .../temporal-polyfill/src/public/zonedDateTime.ts | 13 ++++++++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/temporal-polyfill/src/dateUtils/compare.ts b/packages/temporal-polyfill/src/dateUtils/compare.ts index e25b34df..63a7aacc 100644 --- a/packages/temporal-polyfill/src/dateUtils/compare.ts +++ b/packages/temporal-polyfill/src/dateUtils/compare.ts @@ -25,12 +25,13 @@ export interface ComparableEpochObj { // ------------------------------------------------------------------------------------------------- type EqualityTestObj = ComparableDateTime & { calendar: Temporal.CalendarProtocol } -type ZonedEqualityTestObj = EqualityTestObj & { timeZone: Temporal.TimeZoneProtocol } -export function zonedDateTimesEqual(a: ZonedEqualityTestObj, b: ZonedEqualityTestObj): boolean { - return dateTimesEqual(a, b) && - a.timeZone.toString() === b.timeZone.toString() -} +// type ZonedEqualityTestObj = EqualityTestObj & { timeZone: Temporal.TimeZoneProtocol } +// +// export function zonedDateTimesEqual(a: ZonedEqualityTestObj, b: ZonedEqualityTestObj): boolean { +// return dateTimesEqual(a, b) && +// a.timeZone.toString() === b.timeZone.toString() +// } export function dateTimesEqual(a: EqualityTestObj, b: EqualityTestObj): boolean { return !compareDateTimes(a, b) && diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts index 7ca1f0f3..10ff8108 100644 --- a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts +++ b/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts @@ -78,6 +78,8 @@ function tryDateTimeFromFields( ...constrainTimeISO(partialLocalTimeToISO(refinedFields), overflowHandling), // ...safeDateFromFields(calendar, refinedFields, options).getISOFields(), + // ahh.. + calendar, } } diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/public/zonedDateTime.ts index 4be2a042..7eac794d 100644 --- a/packages/temporal-polyfill/src/public/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/public/zonedDateTime.ts @@ -18,7 +18,7 @@ import { RoundingConfig, parseRoundingOptions } from '../argParse/roundingOption import { parseTimeZoneDisplayOption } from '../argParse/timeZoneDisplay' import { timeUnitNames } from '../argParse/unitStr' import { ensureObj, needReceiver } from '../dateUtils/abstract' -import { compareEpochObjs, zonedDateTimesEqual } from '../dateUtils/compare' +import { compareEpochObjs } from '../dateUtils/compare' import { DayTimeUnit, zeroISOTimeFields } from '../dateUtils/dayAndTime' import { diffDateTimes } from '../dateUtils/diff' import { DurationFields, negateDuration } from '../dateUtils/durationFields' @@ -66,7 +66,7 @@ import { } from '../dateUtils/units' import { createZonedFormatFactoryFactory } from '../native/intlFactory' import { ToLocaleStringMethods, mixinLocaleStringMethods } from '../native/intlMixins' -import { LargeInt, LargeIntArg, createLargeInt } from '../utils/largeInt' +import { LargeInt, LargeIntArg, compareLargeInts, createLargeInt } from '../utils/largeInt' import { roundToMinute } from '../utils/math' import { Calendar, createDefaultCalendar } from './calendar' import { Duration, DurationArg, createDuration } from './duration' @@ -295,7 +295,14 @@ export class ZonedDateTime implements Temporal.ZonedDateTime { equals(other: ZonedDateTimeArg): boolean { needReceiver(ZonedDateTime, this) - return zonedDateTimesEqual(this, ensureObj(ZonedDateTime, other)) + const otherZdt = ensureObj(ZonedDateTime, other) + + return !compareLargeInts( + getInternals(this).epochNanoseconds, + getInternals(otherZdt).epochNanoseconds, + ) && + getInternals(this).calendar.toString() === getInternals(otherZdt).calendar.toString() && + getInternals(this).timeZone.toString() === getInternals(otherZdt).timeZone.toString() } startOfDay(): Temporal.ZonedDateTime { From af7cee5b9b5d812aa6164b5a0c6a86d884feeb14 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 29 Mar 2023 20:07:31 -0400 Subject: [PATCH 072/805] more ignores --- .../misc/expected-failures.txt | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index baca7ee0..dfe435a4 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -52,18 +52,42 @@ built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfCeil.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfEven.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfFloor.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-halfTrunc.js -built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfFloor.js -built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfExpand.js -built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfEven.js -built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfCeil.js -built-ins/Temporal/PlainDate/prototype/until/roundingmode-expand.js built-ins/Temporal/PlainDate/prototype/until/roundingincrement-non-integer.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-expand.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfCeil.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfEven.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfFloor.js built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfTrunc.js +built-ins/Temporal/PlainDateTime/prototype/since/roundingincrement-non-integer.js +built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-expand.js +built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfCeil.js +built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfEven.js +built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfFloor.js +built-ins/Temporal/PlainDateTime/prototype/since/roundingmode-halfTrunc.js +built-ins/Temporal/PlainDateTime/prototype/until/roundingincrement-non-integer.js +built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-expand.js +built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfCeil.js +built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfEven.js +built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfFloor.js +built-ins/Temporal/PlainDateTime/prototype/until/roundingmode-halfTrunc.js +built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-non-integer.js +built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-expand.js +built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfCeil.js +built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfEven.js +built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfFloor.js +built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfTrunc.js +built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-non-integer.js +built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-expand.js +built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfCeil.js +built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfEven.js +built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfFloor.js +built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfTrunc.js # rounding with weeks returns -0 for some reason built-ins/Temporal/PlainDate/prototype/until/roundingmode-ceil.js built-ins/Temporal/PlainDate/prototype/until/roundingmode-floor.js built-ins/Temporal/PlainDate/prototype/until/roundingmode-trunc.js +built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfExpand.js # OrigDateTimeFormat bugs built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js From d9c95f08404d0354cbec446d3ece716b874fb038 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 22 Apr 2023 11:23:29 -0400 Subject: [PATCH 073/805] scratch --- packages/temporal-polyfill/misc/NOTES.txt | 102 +++++ .../misc/expected-failures.txt | 117 +++-- .../temporal-polyfill/src/new/calendar.js | 90 ++++ .../src/new/calendarAdapter.js | 132 ++++++ .../src/new/calendarFields.js | 106 +++++ .../temporal-polyfill/src/new/calendarImpl.js | 99 +++++ packages/temporal-polyfill/src/new/cast.js | 68 +++ packages/temporal-polyfill/src/new/convert.js | 406 ++++++++++++++++++ packages/temporal-polyfill/src/new/diff.js | 312 ++++++++++++++ .../temporal-polyfill/src/new/duration.js | 106 +++++ .../src/new/durationFields.js | 82 ++++ packages/temporal-polyfill/src/new/format.js | 53 +++ packages/temporal-polyfill/src/new/instant.js | 176 ++++++++ .../temporal-polyfill/src/new/isoFields.js | 82 ++++ .../temporal-polyfill/src/new/largeInt.js | 14 + packages/temporal-polyfill/src/new/move.js | 136 ++++++ packages/temporal-polyfill/src/new/move2.js | 2 + .../temporal-polyfill/src/new/nanoseconds.js | 36 ++ packages/temporal-polyfill/src/new/now.js | 2 + packages/temporal-polyfill/src/new/obj.js | 30 ++ packages/temporal-polyfill/src/new/options.js | 72 ++++ packages/temporal-polyfill/src/new/parse.js | 188 ++++++++ .../temporal-polyfill/src/new/plainDate.js | 170 ++++++++ .../src/new/plainDateTime.js | 219 ++++++++++ .../src/new/plainMonthDay.js | 81 ++++ .../temporal-polyfill/src/new/plainTime.js | 155 +++++++ .../src/new/plainYearMonth.js | 138 ++++++ packages/temporal-polyfill/src/new/round.js | 63 +++ .../temporal-polyfill/src/new/temporal.js | 26 ++ .../src/new/temporalClass.js | 89 ++++ .../temporal-polyfill/src/new/timeZone.js | 76 ++++ .../src/new/timeZoneProtocol.js | 73 ++++ .../src/new/timeZoneProtocol2.js | 2 + .../src/new/zonedDateTime.js | 347 +++++++++++++++ 34 files changed, 3810 insertions(+), 40 deletions(-) create mode 100644 packages/temporal-polyfill/src/new/calendar.js create mode 100644 packages/temporal-polyfill/src/new/calendarAdapter.js create mode 100644 packages/temporal-polyfill/src/new/calendarFields.js create mode 100644 packages/temporal-polyfill/src/new/calendarImpl.js create mode 100644 packages/temporal-polyfill/src/new/cast.js create mode 100644 packages/temporal-polyfill/src/new/convert.js create mode 100644 packages/temporal-polyfill/src/new/diff.js create mode 100644 packages/temporal-polyfill/src/new/duration.js create mode 100644 packages/temporal-polyfill/src/new/durationFields.js create mode 100644 packages/temporal-polyfill/src/new/format.js create mode 100644 packages/temporal-polyfill/src/new/instant.js create mode 100644 packages/temporal-polyfill/src/new/isoFields.js create mode 100644 packages/temporal-polyfill/src/new/largeInt.js create mode 100644 packages/temporal-polyfill/src/new/move.js create mode 100644 packages/temporal-polyfill/src/new/move2.js create mode 100644 packages/temporal-polyfill/src/new/nanoseconds.js create mode 100644 packages/temporal-polyfill/src/new/now.js create mode 100644 packages/temporal-polyfill/src/new/obj.js create mode 100644 packages/temporal-polyfill/src/new/options.js create mode 100644 packages/temporal-polyfill/src/new/parse.js create mode 100644 packages/temporal-polyfill/src/new/plainDate.js create mode 100644 packages/temporal-polyfill/src/new/plainDateTime.js create mode 100644 packages/temporal-polyfill/src/new/plainMonthDay.js create mode 100644 packages/temporal-polyfill/src/new/plainTime.js create mode 100644 packages/temporal-polyfill/src/new/plainYearMonth.js create mode 100644 packages/temporal-polyfill/src/new/round.js create mode 100644 packages/temporal-polyfill/src/new/temporal.js create mode 100644 packages/temporal-polyfill/src/new/temporalClass.js create mode 100644 packages/temporal-polyfill/src/new/timeZone.js create mode 100644 packages/temporal-polyfill/src/new/timeZoneProtocol.js create mode 100644 packages/temporal-polyfill/src/new/timeZoneProtocol2.js create mode 100644 packages/temporal-polyfill/src/new/zonedDateTime.js diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/misc/NOTES.txt index ff322d81..27a23b02 100644 --- a/packages/temporal-polyfill/misc/NOTES.txt +++ b/packages/temporal-polyfill/misc/NOTES.txt @@ -4,3 +4,105 @@ complicated internal property access failing because we need to bypass constructor when creating internal instances, to avoid re-parsing input. technique: https://github.com/js-temporal/temporal-polyfill/blob/main/lib/ecmascript.ts#L1826-L1827 + + + +TODO: move to global builtin casts!!!! + +now = Temporal.PlainDate.from('2022-01-01') +then = Temporal.PlainDate.from('2023-12-25') + +duration = now.until(then, { largestUnit: 'year', smallestUnit: 'month', roundingMode: 'ceil' }) +console.log(duration.toString()) + +roundedDuration = duration.round({ relativeTo: now, largestUnit: 'year', smallestUnit: 'month', roundingMode: 'ceil' }) +console.log(roundedDuration.toString()) + + + +now = Temporal.PlainDate.from('2022-01-01') +then = Temporal.PlainDate.from('2023-12-25') +now.until(then, { largestUnit: 'year', smallestUnit: 'month', roundingIncrement: 3 }) +# +# ^^^ this actually does work +# + +now = Temporal.PlainDate.from('2022-01-01') +then = Temporal.PlainDate.from('2023-12-25') +now.until(then, { largestUnit: 'month', smallestUnit: 'day', roundingIncrement: 3 }) +# +# ^^^ works too +# + +# +# our bug with diffing Februaries +# correct behavior (direction matters): +# +Temporal.PlainDate.from('2022-01-31').until('2022-02-28', { largestUnit: 'year' }).toString() +-> 'P1M' +Temporal.PlainDate.from('2022-02-28').until('2022-01-31', { largestUnit: 'year' }).toString() +-> '-P28D' +Temporal.PlainDate.from('2022-03-31').until('2022-02-28', { largestUnit: 'year' }).toString() +-> '-P1M' + + + +The following tests took a long time: + timezone: + 133 ms: test262/test/intl402/Temporal/TimeZone/prototype/getPlainDateTimeFor/basic.js + 188 ms: test262/test/staging/Temporal/ZonedDateTime/old/dst-math.js + duration rounding: + 115 ms: test262/test/staging/Temporal/Duration/old/round.js + + +The roundingMode option controls how the rounding is performed: +- ceil, expand: Always round up, towards 23:59:59.999999999. +- floor, trunc: Always round down, towards 00:00. +- halfCeil, halfExpand: Round to the nearest of the values allowed by roundingIncrement and smallestUnit. When there is a tie, round up, like ceil. +- halfFloor, halfTrunc: Round to the nearest of the allowed values, like halfExpand, but when there is a tie, round down, like floor. +- halfEven: Round to the nearest of the allowed values, but when there is a tie, round towards the value that is an even multiple of roundingIncrement. For example, with a roundingIncrement of 2, the number 7 would round up to 8 instead of down to 6, because 8 is an even multiple of 2 (2 × 4 = 8, and 4 is even), whereas 6 is an odd multiple (2 × 3 = 6, and 3 is odd). + +https://github.com/tc39/proposal-temporal/blob/84d1b184ac200a81a6648f2d148082f69ae0547b/polyfill/lib/ecmascript.mjs#L4492 + +function RoundNumberToIncrement(quantity, increment, mode) { + if (increment === 1) return quantity; + let quotient = Math.floor(quantity / increment); + let remainder = quantity % increment; + if (remainder === 0) return quantity; + const sign = remainder < 0 ? -1 : 1; + const tiebreaker = Math.abs(remainder) * 2; + const tie = tiebreaker === increment; + const expandIsNearer = tiebreaker > increment; + switch (mode) { + case 'ceil': + if (sign > 0) quotient += sign; + break; + case 'floor': + if (sign < 0) quotient += sign; + break; + case 'expand': + // always expand if there is a remainder + quotient += sign; + break; + case 'trunc': + // no change needed, because divmod is a truncation + break; + case 'halfCeil': + if (expandIsNearer || (tie && sign > 0)) quotient += sign; + break; + case 'halfFloor': + if (expandIsNearer || (tie && sign < 0)) quotient += sign; + break; + case 'halfExpand': + // "half up away from zero" + if (expandIsNearer || tie) quotient += sign; + break; + case 'halfTrunc': + if (expandIsNearer) quotient += sign; + break; + case 'halfEven': + if (expandIsNearer || (tie && quotient % 2 === 1)) quotient += sign; + break; + } + return quotient * increment; +} diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/misc/expected-failures.txt index dfe435a4..471ee1ef 100644 --- a/packages/temporal-polyfill/misc/expected-failures.txt +++ b/packages/temporal-polyfill/misc/expected-failures.txt @@ -1,4 +1,11 @@ +# NEXT: see where all refining/parsing/validating happens. +# sometimes date-time fields are massaged into strings (with/from/constructor) +# other times they throw errors (Calendar::day) +# same validations between calendarFields and isoFields? +# +# start writing PlainDate::from/with + # # fullcalendar/temporal notes # @@ -7,33 +14,78 @@ # pn test262 'PlainDate/**' # -# complicated internal property access (needs class refactor) -built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js +### with/from OBJECTS -# monthDayFromFields -intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js +# exact internal-call ordering of ::with (hard, needs refactor) +built-ins/Temporal/PlainDate/prototype/with/order-of-operations.js + +# side-effect of our hack of filtering away undefines, accidentally filters away symbol keys +built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js + + +### dateFromFields, etc -# yearMonthFromFields +# monthDayFromFields/yearMonthFromFields must work off calendar-fields (not iso fields) +# thus, must follow from/with flow +built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fields-iterable.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-invalid-return.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js + +# before calling dateFromFields, use result of fields() as a whitelist after merging-in partial +built-ins/Temporal/PlainDate/prototype/with/copies-merge-fields-object.js + +# First `fields` argument must be plain object with null-prototype, not Temporal object +built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fromfields-called-with-null-prototype-fields.js + +# actual bugs? +intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js -# Calendr::dateUntil -built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js + +### validation + +# far-future, far-past, out-of-range problems +built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/limits.js +built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.js + +## ecmascript.mjs +#const DAY_SECONDS = 86400; +#const DAY_NANOS = bigInt(DAY_SECONDS).multiply(1e9); +#const NS_MIN = bigInt(-DAY_SECONDS).multiply(1e17); +#const NS_MAX = bigInt(DAY_SECONDS).multiply(1e17); +#const YEAR_MIN = -271821; +#const YEAR_MAX = 275760; +#const BEFORE_FIRST_DST = bigInt(-388152).multiply(1e13); // 1847-01-01T00:00:00Z +## will also check if GetUTCEpochNanoseconds(...) === null + +# is my isoToEpochMilli overly complicated? +# YES. BETTER: https://github.com/tc39/proposal-temporal/blob/84d1b184ac200a81a6648f2d148082f69ae0547b/polyfill/lib/ecmascript.mjs#L2393 + + +### timezone/instant + +# complicated internal property access (needs class refactor) +built-ins/Temporal/TimeZone/prototype/getInstantFor/order-of-operations.js # TimeZone transitions intl402/Temporal/TimeZone/prototype/getNextTransition/subtract-second-and-nanosecond-from-last-transition.js intl402/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/nanoseconds-subtracted-or-added-at-dst-transition.js built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor-iterable.js -# Intl.DateTimeFormat -# (even PlainDate should be reduced to timestamp, should have be displayable with timeZone options) -#intl402/DateTimeFormat/prototype/format/temporal-objects-timezone-getoffsetnanosecondsfor-not-callable.js -intl402/Temporal/PlainDate/prototype/toLocaleString/timezone-getoffsetnanosecondsfor-not-callable.js -# NOTE: tests related to func.length fail because optional params need default values to make sure -# they're not included in func.length -#built-ins/Temporal/Calendar/prototype/dateAdd/length.js +### diffing/rounding -# Calendar::dateUntil shouldn't be called so often during diffing +# Calendar::dateUntil shouldn't be called so often during since/until (because of rounding!) +# SOLUTION: rewrite roundDuration. but it's crazy: +# https://github.com/tc39/proposal-temporal/blob/main/polyfill/lib/ecmascript.mjs#L4780 +# compare to my `roundDurationSpan` +# +# it's all because of the "balancing" +# Temporal.PlainDate.from('2022-01-01').until('2022-12-24', { largestUnit: 'year', smallestUnit: 'month', roundingMode: 'ceil' }).toString() +# WOAH. doesn't round up to next year!? gives 12months, not 1year!!! weird, but easier! +# built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js built-ins/Temporal/PlainDate/prototype/since/custom.js @@ -45,6 +97,9 @@ built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js built-ins/Temporal/PlainDate/prototype/with/calendar-fields-iterable.js built-ins/Temporal/PlainDate/prototype/with/calendar-merge-fields-returns-primitive.js +# Calendar::dateUntil +built-ins/Temporal/Calendar/prototype/dateUntil/largest-unit-week.js + # new crazy rounding options built-ins/Temporal/PlainDate/prototype/since/roundingincrement-non-integer.js built-ins/Temporal/PlainDate/prototype/since/roundingmode-expand.js @@ -89,36 +144,18 @@ built-ins/Temporal/PlainDate/prototype/until/roundingmode-floor.js built-ins/Temporal/PlainDate/prototype/until/roundingmode-trunc.js built-ins/Temporal/PlainDate/prototype/until/roundingmode-halfExpand.js + +### formatting + # OrigDateTimeFormat bugs built-ins/Temporal/PlainDate/prototype/toLocaleString/return-string.js intl402/Temporal/PlainDate/prototype/toLocaleString/options-conflict.js -# Calendar::monthDayFromFields needs to call Calendar::fields somehow. similar problems -built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js -built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fields-iterable.js -built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-invalid-return.js -built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-yearmonthfromfields-called-with-options-undefined.js - -# dateFromFields/yearMonthFromFields/monthDayFromFields -# First `fields` argument must be plain object with null-prototype, not Temporal object -built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fields-iterable.js -built-ins/Temporal/PlainDate/prototype/toPlainMonthDay/calendar-fromfields-called-with-null-prototype-fields.js -built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/calendar-fromfields-called-with-null-prototype-fields.js - -# far-future, far-past, out-of-range problems -built-ins/Temporal/PlainDate/prototype/toPlainYearMonth/limits.js -built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.js - # toString options (calendarName:critical) built-ins/Temporal/PlainDate/prototype/toString/calendar-tostring.js built-ins/Temporal/PlainDate/prototype/toString/calendarname-critical.js -# I don't undersand why the result of Calendar::mergeFields being fed into Calendar::dateFromFields -# has anything to do with copying -built-ins/Temporal/PlainDate/prototype/with/copies-merge-fields-object.js - -# exact internal-call ordering of ::with (hard, needs refactor) -built-ins/Temporal/PlainDate/prototype/with/order-of-operations.js - -# side-effect of our hack of filtering away undefines, accidentally filters away symbol keys -built-ins/Temporal/Calendar/prototype/mergeFields/non-string-properties.js +# Intl.DateTimeFormat +# (even PlainDate should be reduced to timestamp, should have be displayable with timeZone options) +intl402/DateTimeFormat/prototype/format/temporal-objects-timezone-getoffsetnanosecondsfor-not-callable.js +intl402/Temporal/PlainDate/prototype/toLocaleString/timezone-getoffsetnanosecondsfor-not-callable.js diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js new file mode 100644 index 00000000..fada4408 --- /dev/null +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -0,0 +1,90 @@ +import { queryCalendarImpl } from '../calendarImpl/calendarImplQuery' // ah +import { dateCalendarRefiners } from './calendarFields' +import { createComplexBagRefiner } from './convert' +import { createDuration, toDurationInternals } from './duration' +import { mapProps } from './obj' +import { optionsToLargestUnit, optionsToOverflow } from './options' +import { stringToCalendarId } from './parse' +import { createPlainDate, toPlainDateInternals } from './plainDate' +import { createPlainMonthDay } from './plainMonthDay' +import { createPlainYearMonth } from './plainYearMonth' +import { createTemporalClass } from './temporalClass' +import { TimeZone } from './timeZone' + +export const [Calendar] = createTemporalClass( + 'Calendar', + + // Creation + // ----------------------------------------------------------------------------------------------- + + (id) => { + return queryCalendarImpl(id) + }, + {}, + createComplexBagRefiner('calendar', TimeZone), + stringToCalendarId, + undefined, + + // Getters + // ----------------------------------------------------------------------------------------------- + + { + id(impl) { + return impl.id // TODO: more DRY with toString() + }, + }, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + ...mapProps(dateCalendarRefiners, (refiner, methodName) => { + return (impl, plainDateArg) => { + return impl[methodName](toPlainDateInternals(plainDateArg)) + } + }), + + dateAdd(impl, plainDateArg, durationArg, options) { + return createPlainDate( + impl.dateAdd( + toPlainDateInternals(plainDateArg), + toDurationInternals(durationArg), + optionsToLargestUnit(options), + ), + ) + }, + + dateUntil(impl, startPlainDateArg, endPlainDateArg, options) { + return createDuration( + impl.dateUntil( + toPlainDateInternals(startPlainDateArg), + toPlainDateInternals(endPlainDateArg), + optionsToOverflow(options), + ), + ) + }, + + ...mapProps({ + dateFromFields: createPlainDate, + yearMonthFromFields: createPlainYearMonth, + monthDayFromFields: createPlainMonthDay, + fields: identityFunc, + mergeFields: identityFunc, + }, transformInternalMethod), + + toString(impl) { + return impl.id // TODO: more DRY with toString() + }, + }, +) + +// Misc +// ---- + +function identityFunc(input) { return input } + +function transformInternalMethod(transformRes, methodName) { + return (impl, ...args) => { + return transformRes(impl[methodName](...args)) + } +} diff --git a/packages/temporal-polyfill/src/new/calendarAdapter.js b/packages/temporal-polyfill/src/new/calendarAdapter.js new file mode 100644 index 00000000..bcc239ba --- /dev/null +++ b/packages/temporal-polyfill/src/new/calendarAdapter.js @@ -0,0 +1,132 @@ +import { strictArrayOfStrings, strictInstanceOf, toObject } from './cast' +import { createDuration } from './duration' +import { mapProps } from './obj' +import { PlainDate, createPlainDate } from './plainDate' +import { PlainMonthDay } from './plainMonthDay' +import { PlainYearMonth } from './plainYearMonth' +import { getInternals } from './temporalClass' + +// first attempt +// ------------- + +export const moveDate = createCalendarFallback( + 'dateAdd', + createInternalGetter(PlainDate), + (isoDateFields, durationFields, overflow) => [ + createPlainDate(isoDateFields), + createDuration(durationFields), + { overflow }, + ], +) + +export const diffExactDates = createCalendarFallback( + 'dateUntil', + createInternalGetter(PlainDate), + (startIsoDateFields, endIsoDateFields, largestUnit) => [ + createPlainDate(startIsoDateFields), + createPlainDate(endIsoDateFields), + { largestUnit }, + ], +) + +export const dateFieldsToIso = createCalendarFallback( + 'dateFromFields', + createInternalGetter(PlainDate), +) + +export const yearMonthFieldsToIso = createCalendarFallback( + 'yearMonthFromFields', + createInternalGetter(PlainYearMonth), +) + +export const monthDayFieldsToIso = createCalendarFallback( + 'monthDayFields', + createInternalGetter(PlainMonthDay), +) + +export const mergeFields = createCalendarFallback('mergeFields', toObject) + +export const transformFieldNames = createCalendarFallback('fields', strictArrayOfStrings) + +function createCalendarFallback( + methodName, + transformRes, + transformArgs = identityFunc, +) { + return (calendar, ...args) => { + if (typeof calendar === 'string') { + return queryCalendarImpl(calendar)[methodName](...args) + } + return transformRes(calendar[methodName](...transformArgs(...args))) + } +} + +// second attempt +// -------------- +// CHOOSE THIS APPROACH +// All methods will query this adapter once in the beginning +// Better than querying adapter-ness multiple times throughout a multi-step operation + +const getStrictPlainDateInternals = createInternalGetter(PlainDate) + +export const CalendarOpsAdapter = createInternalClass({ + dateAdd(calendar, isoDateFields, durationFields, overflow) { + return getStrictPlainDateInternals( + calendar.dateAdd( + createPlainDate(isoDateFields), // hopefully won't look at blank .calendar + createDuration(durationFields), + { overflow }, + ), + ) + }, + + dateUntil(calendar, startIsoDateFields, endIsoDateFields, largestUnit) { + return getStrictPlainDateInternals( + calendar.dateUntil( + createPlainDate(startIsoDateFields), // hopefully won't look at blank .calendar + createPlainDate(endIsoDateFields), // hopefully won't look at blank .calendar + { largestUnit }, + ), + ) + }, + + ...mapProps({ + dateFromFields: getStrictPlainDateInternals, + yearMonthFromFields: createInternalGetter(PlainYearMonth), + monthDayFields: createInternalGetter(PlainMonthDay), + mergeFields: toObject, + fields: strictArrayOfStrings, + }, transformInternalMethod), +}) + +// Misc +// ---- + +// same thing used in calendar.js +function transformInternalMethod(transformRes, methodName) { + return (impl, ...args) => { + return transformRes(impl[methodName](...args)) + } +} + +function createInternalClass() { + +} + +function createInternalGetter(Class) { + return (res) => getInternals(strictInstanceOf(Class), res) +} + +function queryCalendarImpl() { +} + +export const isoCalendarId = 'iso8601' + +export function getCommonCalendar(internals0, internals1) { +} + +export function toCalendarSlot() { + +} + +function identityFunc(input) { return input } diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js new file mode 100644 index 00000000..854fe4b9 --- /dev/null +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -0,0 +1,106 @@ +import { toIntegerThrowOnInfinity, toPositiveInteger } from './cast' +import { isoTimeFieldDefaults, isoTimeFieldNames } from './isoFields' +import { mapProps, remapProps } from './obj' + +export const yearMonthFieldRefiners = { + // sorted alphabetically + month: toPositiveInteger, + monthCode: toString, + year: toIntegerThrowOnInfinity, +} + +export const dateFieldRefiners = { + // sorted alphabetically + day: toPositiveInteger, + ...yearMonthFieldRefiners, +} + +export const monthDayFieldRefiners = { + // sorted alphabetically + day: toPositiveInteger, // not DRY + monthCode: toString, // not DRY +} + +export const timeFieldRefiners = { + // sorted alphabetically + hour: toIntegerThrowOnInfinity, + microsecond: toIntegerThrowOnInfinity, + millisecond: toIntegerThrowOnInfinity, + minute: toIntegerThrowOnInfinity, + nanosecond: toIntegerThrowOnInfinity, + second: toIntegerThrowOnInfinity, +} + +export const dateTimeFieldRefiners = { + // keys must be resorted + ...dateFieldRefiners, + ...timeFieldRefiners, +} + +export const yearMonthStatRefiners = { + daysInMonth: toPositiveInteger, + daysInYear: toPositiveInteger, + monthsInYear: toPositiveInteger, + inLeapYear: toPositiveInteger, +} + +export const dateStatRefiners = { + ...yearMonthStatRefiners, + dayOfWeek: toPositiveInteger, + dayOfYear: toPositiveInteger, + weekOfYear: toPositiveInteger, + yearOfWeek: toPositiveInteger, + daysInWeek: toPositiveInteger, +} + +export const dateFieldNames = Object.keys(dateFieldRefiners) +export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) // month/monthCode/year +export const yearMonthBasicNames = yearMonthFieldNames.slice(1) // monthCode/year +export const monthDayFieldNames = dateFieldNames.slice(0, 3) // day/month/monthCode +export const monthDayBasicNames = ['day', 'monthCode'] +export const dateTimeFieldNames = Object.keys(dateTimeFieldRefiners).sort() +export const timeFieldNames = Object.keys(timeFieldRefiners) + +export const yearMonthGetters = createCalendarGetters({ + ...yearMonthFieldRefiners, + ...yearMonthStatRefiners, +}) + +export const monthDayGetters = createCalendarGetters(monthDayFieldRefiners) + +export const dateCalendarRefiners = { + ...dateFieldRefiners, + ...dateStatRefiners, +} + +export const dateGetters = createCalendarGetters(dateCalendarRefiners) + +export const timeGetters = isoTimeFieldNames.reduce((accum, isoTimeField, i) => { + accum[timeFieldNames[i]] = function(internals) { + return internals[isoTimeField] + } + return accum +}, {}) // TODO: somehow leverage remapProps instead? + +export const dateTimeGetters = { + ...dateGetters, + ...timeGetters, +} + +function createCalendarGetters(refiners) { + const getters = mapProps(refiners, (refiner, fieldName) => { + return function(internals) { + return refiner(internals.calendar[fieldName][this]) + } + }) + getters.calendar = function(internals) { + return internals.calendar + } + return getters +} + +export function timeFieldsToIso(timeFields) { + return remapProps(timeFields, timeFieldNames, isoTimeFieldNames) +} + +export const timeFieldDefaults = remapProps(isoTimeFieldDefaults, isoTimeFieldNames, timeFieldNames) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js new file mode 100644 index 00000000..4869bae9 --- /dev/null +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -0,0 +1,99 @@ + +/* +If we don't use a class, we can pile-in iso util methods like: +- getIsoDayOfWeek +*/ + +export class CalendarImpl { + era(isoDateFields) { + // return string + } + + eraYear(isoDateFields) { + // return number + } + + year(isoDateFields) { + // return number + } + + month(isoDateFields) { + // return number + } + + monthCode(isoDateFields) { + // return string + } + + day(isoDateFields) { + // return number + } + + dayOfWeek(isoDateFields) { + // return number + } + + dayOfYear(isoDateFields) { + // return number + } + + weekOfYear(isoDateFields) { + // return number + } + + yearOfWeek(isoDateFields) { + // return number + } + + daysInWeek(isoDateFields) { + // return number + } + + daysInMonth(isoDateFields) { + // return number + } + + daysInYear(isoDateFields) { + // return number + } + + monthsInYear(isoDateFields) { + // return number + } + + inLeapYear(isoDateFields) { + // return boolean + } + + // should return IsoFields+calendar props! + dateFromFields(fields, overflow) { + // return isoDateFields + } + + // should return IsoFields+calendar props! + yearMonthFromFields(fields, overflow) { + // return isoDateFields. should be very similar to what's already in calendar.ts + } + + // should return IsoFields+calendar props! + monthDayFromFields(fields, overflow) { + // return isoDateFields. should be very similar to what's already in calendar.ts + } + + // should return IsoFields+calendar props! + dateAdd(isoDateFields, durationFields, overflow) { + // return isoDateFields + } + + dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { + // return durationFields + } + + fields(fieldNames) { + // return string[] + } + + mergeFields(baseFieldNames, additionalFieldNames) { + // return object + } +} diff --git a/packages/temporal-polyfill/src/new/cast.js b/packages/temporal-polyfill/src/new/cast.js new file mode 100644 index 00000000..42d14a16 --- /dev/null +++ b/packages/temporal-polyfill/src/new/cast.js @@ -0,0 +1,68 @@ + +export function strictInstanceOf(obj, Class) { +} + +export function strictArrayOfStrings(obj) { +} + +export function strictArrayOfType(obj) { +} + +export function toObject() { +} + +export function toNumber(value) { + if (typeof value === 'bigint') { + throw new TypeError('Cannot convert BigInt to number') + } + return Number(value) +} + +export function toInteger(value) { + const num = toNumber(value) + if (isNaN(num)) return 0 + const integer = Math.trunc(num) + if (num === 0) return 0 + return integer +} + +export function toString(value) { + if (typeof value === 'symbol') { + throw new TypeError('Cannot convert a Symbol value to a String') + } + return String(value) +} + +export function toIntegerThrowOnInfinity(value) { + const integer = toInteger(value) + if (!Number.isFinite(integer)) { + throw new RangeError('infinity is out of range') + } + return integer +} + +export function toPositiveInteger(valueParam, property) { + const value = toInteger(valueParam) + if (!Number.isFinite(value)) { + throw new RangeError('infinity is out of range') + } + if (value < 1) { + if (property !== undefined) { + throw new RangeError(`property '${property}' cannot be a a number less than one`) + } + throw new RangeError('Cannot convert a number less than one to a positive integer') + } + return value +} + +export function toIntegerWithoutRounding(valueParam) { + const value = toNumber(valueParam) + if (isNaN(value)) return 0 + if (!Number.isFinite(value)) { + throw new RangeError('infinity is out of range') + } + if (!Number.isInteger(value)) { + throw new RangeError(`unsupported fractional value ${value}`) + } + return toInteger(value) // ℝ(value) in spec text; converts -0 to 0 +} diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js new file mode 100644 index 00000000..d37583aa --- /dev/null +++ b/packages/temporal-polyfill/src/new/convert.js @@ -0,0 +1,406 @@ +import { + dateFieldsToIso, + isoCalendarId, + mergeFields, + monthDayFieldsToIso, + toCalendarSlot, + transformFieldNames, + yearMonthFieldsToIso, +} from './calendarAdapter' +import { + dateFieldNames, + dateTimeFieldNames, + dateTimeFieldRefiners, + monthDayBasicNames, + timeFieldDefaults, + timeFieldNames, + timeFieldsToIso, + yearMonthBasicNames, + yearMonthFieldNames, +} from './calendarFields' +import { toInteger, toObject } from './cast' +import { + durationFieldDefaults, + durationFieldRefiners, + refineDurationFields, +} from './durationFields' +import { + regulateIsoDateTimeFields, + regulateIsoTimeFields, +} from './isoFields' +import { isObjectLike, pluckProps, removeDuplicateStrings } from './obj' +import { toDisambiguation, toOffsetHandling, toOverflowOptions } from './options' +import { parseOffsetNanoseconds } from './parse' +import { createPlainDate } from './plainDate' +import { createPlainDateTime } from './plainDateTime' +import { createPlainMonthDay } from './plainMonthDay' +import { createPlainTime } from './plainTime' +import { createPlainYearMonth } from './plainYearMonth' +import { getInternals } from './temporalClass' +import { + computeIsoFieldEpochNanoseconds, + plainDateTimeToEpochNanoseconds, + toTimeZoneSlot, +} from './timeZoneProtocol' +import { createZonedDateTime } from './zonedDateTime' + +// Duration +// ------------------------------------------------------------------------------------------------- + +export function bagToDurationFields(bag) { + return refineDurationFields({ ...durationFieldDefaults, ...bag }) +} + +// high level yo +// ------------------------------------------------------------------------------------------------- + +export function bagToZonedDateTimeInternals(bag, options) { + const [calendar, fields] = refineBag( + bag, + dateTimeFieldNames, + ['offset'], + ['timeZone'], + ) + + const timeZone = toTimeZoneSlot(fields.timeZone) + const isoFields = dateFieldsToIso(calendar, fields, options) // overflow options + + const epochNanoseconds = computeIsoFieldEpochNanoseconds( + { ...isoFields, ...timeFieldsToIso(fields) }, + timeZone, + fields.offset !== undefined ? parseOffsetNanoseconds(fields.offset) : undefined, + false, // z? + toOffsetHandling(options), + toDisambiguation(options), + false, // fuzzy + ) + + return { + epochNanoseconds, + timeZone, + calendar, + } +} + +export function zonedDateTimeWithBag(zonedDateTime, bag, options) { + const { timeZone } = getInternals(zonedDateTime) + const [calendar, fields] = mergeBag(zonedDateTime, bag, dateTimeFieldNames, ['offset']) + const isoFields = dateFieldsToIso(calendar, fields, options) + + const epochNanoseconds = computeIsoFieldEpochNanoseconds( + { ...isoFields, ...timeFieldsToIso(fields) }, + timeZone, + parseOffsetNanoseconds(fields.offset), + false, // z? + toOffsetHandling(options), + toDisambiguation(options), + false, // fuzzy + ) + + return createZonedDateTime({ + epochNanoseconds, + timeZone, + calendar, + }) +} + +export function bagToPlainMonthDayInternals(bag, options) { + let calendar = extractCalendar(bag) + let calendarAbsent = !calendar + + if (calendarAbsent) { + calendar = bag.calendar + calendarAbsent = calendar === undefined + + if (calendarAbsent) { + calendar = isoCalendarId + } else { + calendar = toCalendarSlot(calendar) + } + } + + const fieldNames = transformFieldNames(calendar, ['day', 'month', 'monthCode', 'year']) + const fields = prepareFields(bag, fieldNames, []) + + // Callers who omit the calendar are not writing calendar-independent + // code. In that case, `monthCode`/`year` can be omitted; `month` and + // `day` are sufficient. Add a `year` to satisfy calendar validation. + if ( + calendarAbsent && + fields.month !== undefined && + fields.monthCode === undefined && + fields.year === undefined + ) { + fields.year = 1972 + } + + return monthDayFieldsToIso(calendar, fields, options) +} + +export function plainMonthDayWithBag(plainMonthDay, bag, options) { + return monthDayFieldsToIso( + ...mergeBag(plainMonthDay, bag, ['month', 'monthCode', 'year']), + options, + ) +} + +export function bagToPlainYearMonthInternals(bag, options) { + return yearMonthFieldsToIso(...refineBag(bag, yearMonthFieldNames), options) +} + +export function plainYearMonthWithBag(plainYearMonth, bag, options) { + return yearMonthFieldsToIso( + ...mergeBag(plainYearMonth, bag, yearMonthFieldNames), + options, + ) +} + +export function bagToPlainTimeInternals(bag, options) { + const overflowOpt = toOverflowOptions(options) // TODO: single opt! + + return regulateIsoTimeFields( + timeFieldsToIso( + prepareFields(bag, timeFieldNames, []), + ), + overflowOpt, + ) +} + +export function plainTimeWithBag(plainTime, bag, options) { + const overflowOpt = toOverflowOptions(options) // TODO: single opt! + const fields = pluckProps(plainTime, timeFieldNames) + const additionalFields = prepareFields(bag, timeFieldNames) + const newInternals = timeFieldsToIso({ + ...fields, + ...additionalFields, + }) + return createPlainTime( + regulateIsoTimeFields(newInternals, overflowOpt), + ) +} + +export function bagToPlainDateSlots(bag, options) { + return dateFieldsToIso(...refineBag(bag, dateFieldNames), options) +} + +export function plainDateWithBag(plainDate, bag, options) { + return dateFieldsToIso(...mergeBag(plainDate, bag, dateFieldNames), options) +} + +export function bagToPlainDateTimeInternals(bag, options) { + const [calendar, fields] = refineBag(bag, dateTimeFieldNames) + const plainDateTimeInternals = dateFieldsToIso(calendar, fields, options) + + return regulateIsoDateTimeFields({ + ...plainDateTimeInternals, + ...timeFieldsToIso(fields), + }) +} + +export function plainDateTimeWithBag(plainDate, bag, options) { + const [calendar, fields] = mergeBag(plainDate, bag, dateTimeFieldNames) + const plainDateTimeInternals = dateFieldsToIso(calendar, fields, options) + + return regulateIsoDateTimeFields({ + ...plainDateTimeInternals, + ...timeFieldsToIso(fields), + }) +} + +// to PlainYearMonth/PlainMonthDay +// ------------------------------------------------------------------------------------------------- + +export function dateToPlainYearMonth( + dateObj, // PlainDate/PlainDateTime/ZonedDateTime +) { + return createPlainYearMonth(yearMonthFieldsToIso(...pluckFields(dateObj, yearMonthBasicNames))) +} + +export function dateToPlainMonthDay( + dateObj, // PlainDate/PlainDateTime/ZonedDateTime +) { + return createPlainMonthDay(monthDayFieldsToIso(...pluckFields(dateObj, monthDayBasicNames))) +} + +// to PlainDate +// ------------------------------------------------------------------------------------------------- + +export function plainYearMonthToPlainDateFirst(plainYearMonth) { + return plainYearMonthToPlainDate(plainYearMonth, { day: 1 }) +} + +export function plainYearMonthToPlainDate(plainYearMonth, bag) { + return mergeToPlainDate(plainYearMonth, yearMonthBasicNames, bag, ['day']) +} + +export function plainMonthDayToPlainDate(plainMonthDay, bag) { + return mergeToPlainDate(plainMonthDay, monthDayBasicNames, bag, ['year']) +} + +// to PlainDateTime +// ------------------------------------------------------------------------------------------------- + +// bad name now. should have something with 'slots' +export function zonedDateTimeInternalsToIso(internals) { + // use timeZone2.js + /* + return instantToPlainDateTime( + internals.timeZone, + internals.calendar, + createInstant(internals.epochNanoseconds), + ) + */ +} + +// to ZonedDateTime +// ------------------------------------------------------------------------------------------------- + +export function createZonedDateTimeConverter(getRequiredInternals) { + return (internals, options) => { + const refinedOptions = toObject(options) // required!!! + const epochNanoseconds = plainDateTimeToEpochNanoseconds( + refinedOptions.timeZone, + createPlainDateTime({ + ...internals, + ...getRequiredInternals(refinedOptions), + }), + ) + + return createZonedDateTime({ + epochNanoseconds, + timeZone: internals.timeZone, + calendar: internals.calendar, + }) + } +} + +// Calendar-field processing +// ------------------------------------------------------------------------------------------------- + +export function refineBag( + bag, + validFieldNames, + requiredFieldNames = [], + forcedValidFieldNames = [], +) { + const calendar = extractCalendar(bag) || isoCalendarId + const fieldNames = transformFieldNames(calendar, validFieldNames) + .concat(requiredFieldNames, forcedValidFieldNames) + const fields = prepareFields(bag, fieldNames, requiredFieldNames) + return [calendar, fields] +} + +export function mergeBag( + obj, + bag, + validFieldNames, + requiredFieldNames = [], +) { + // TODO: check bag doesn't have timezone/calendar + const { calendar } = getInternals(obj) + const fieldNames = transformFieldNames(calendar, validFieldNames) + fieldNames.push(...requiredFieldNames) + let fields = prepareFields(obj, fieldNames, requiredFieldNames) + const additionalFields = prepareFields(bag, fieldNames) // partial + fields = mergeFields(calendar, fields, additionalFields) + fields = prepareFields(fields, fieldNames, requiredFieldNames) + return [calendar, fields] +} + +function mergeToPlainDate( + obj, + objFieldNames, + other, // bag or obj + otherFieldNames, +) { + const { calendar } = getInternals(obj) + const receiverFieldNames = transformFieldNames(calendar, objFieldNames) + const receiverFields = pluckProps(obj, receiverFieldNames) + const inputFieldNames = transformFieldNames(calendar, otherFieldNames) + const inputFields = prepareFields(other, inputFieldNames, []) + const mergedFieldNames = removeDuplicateStrings(receiverFieldNames.concat(inputFieldNames)) + let mergedFields = mergeFields(calendar, receiverFields, inputFields) + mergedFields = prepareFields(mergedFields, mergedFieldNames, []) + return createPlainDate(mergedFields, { overflow: 'reject' }) +} + +function pluckFields(obj, validFieldNames) { + const { calendar } = getInternals(obj) + const fieldNames = transformFieldNames(calendar, validFieldNames) + return [calendar, pluckProps(obj, fieldNames)] +} + +// ahhh +// ------------------------------------------------------------------------------------------------- + +const builtinRefiners = { + ...dateTimeFieldRefiners, + ...durationFieldRefiners, + era: toString, + eraYear: toInteger, + offset: toString, +} + +const builtinDefaults = timeFieldDefaults + +export function createComplexBagRefiner(key, ForbiddenClass) { + return function(bag) { + const internalArg = getInternals(bag)?.[key] + if (internalArg) { + return internalArg + } + + forbidInstanceClass(bag, ForbiddenClass) + + if (!(key in bag)) { + return bag + } else { + bag = bag[key] + + forbidInstanceClass(bag, ForbiddenClass) + + if (isObjectLike(bag) && !(key in bag)) { + return bag + } + } + } +} + +function forbidInstanceClass(obj, Class) { + if (obj instanceof Class) { + throw new RangeError(`Unexpected ${Class.prototype[Symbol.toStringTag]}`) + } +} + +/* +If requiredFields not given, then assumed to be 'partial' +*/ +export function prepareFields(bag, fieldNames, requiredFields) { + console.log(builtinRefiners) + console.log(builtinDefaults) + // TODO: error-out if no valid vields +} + +export function isStringCastsEqual(obj0, obj1) { + return obj0 === obj1 || // optimization + String(obj0) === String(obj1) +} + +/* +Won't default to iso +*/ +function extractCalendar(bag) { + const internals = getInternals(bag) + const { calendar } = internals || {} + if (calendar) { + return calendar + } + ({ calendar }) = bag + if (calendar) { + return toCalendarSlot(calendar) + } +} + +export function mapRefiners(input, refinerMap) { + // loops get driven props of input +} diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js new file mode 100644 index 00000000..bdb09ce6 --- /dev/null +++ b/packages/temporal-polyfill/src/new/diff.js @@ -0,0 +1,312 @@ +import { addDaysToIsoFields, pluckIsoTimeFields } from './isoFields' +import { compareLargeInts } from './largeInt' +import { nanosecondsInDay } from './nanoseconds' + +// Diffing & Rounding +// ------------------------------------------------------------------------------------------------- + +export function diffEpochNanoseconds( + startEpochNanoseconds, + endEpochNanoseconds, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, +) { + return diffExactLargeNanoseconds( + roundLargeNanoseconds( + endEpochNanoseconds.subtract(startEpochNanoseconds), + smallestUnit, + roundingMode, + roundingIncrement, + ), + largestUnit, + ) +} + +export function diffZoneEpochNanoseconds( + startEpochNanoseconds, + endEpochNanoseconds, + timeZone, + calendar, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, +) { + if (smallestUnit < 'day') { // TODO + return diffEpochNanoseconds( + startEpochNanoseconds, + endEpochNanoseconds, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ) + } + + function isoToZoneEpochNanoseconds(isoFields) { + return isoToEpochNanoseconds(isoFields, timeZone) + } + + const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) + const startIsoFields = epochNanosecondsToIso(startEpochNanoseconds, timeZone) + const startIsoTimeFields = pluckIsoTimeFields(startIsoFields) + const endIsoFields = epochNanosecondsToIso(endEpochNanoseconds, timeZone) + let midIsoFields = { ...endIsoFields, ...startIsoTimeFields } + let midEpochNanoseconds = isoToZoneEpochNanoseconds(midIsoFields) + const midSign = compareLargeInts(midEpochNanoseconds, endEpochNanoseconds) + + if (midSign === -sign) { + midIsoFields = { + ...addDaysToIsoFields(endIsoFields, -sign), + ...startIsoTimeFields, + } + midEpochNanoseconds = isoToZoneEpochNanoseconds(midIsoFields) + } + + const dateDiff = diffExactDates( + startIsoFields, + midIsoFields, + calendar, + largestUnit, + ) + const timeDiff = diffExactLargeNanoseconds( + endEpochNanoseconds.subtract(midEpochNanoseconds), + 'hours', // largestUnit (default?) + ) + + return roundRelativeDuration( + { ...dateDiff, ...timeDiff, sign }, + startIsoFields, + startEpochNanoseconds, + endIsoFields, + endEpochNanoseconds, + isoToZoneEpochNanoseconds, + calendar, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ) +} + +export function diffDateTimes( + startIsoFields, + endIsoFields, + calendar, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, +) { + const startEpochNanoseconds = isoToUtcEpochNanoseconds(startIsoFields) + const endEpochNanoseconds = isoToUtcEpochNanoseconds(endIsoFields) + + if (smallestUnit < 'day') { // TODO + return diffEpochNanoseconds( + startEpochNanoseconds, + endEpochNanoseconds, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ) + } + + const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) + const startTimeNanoseconds = isoTimeToNanoseconds(startIsoFields) // number + const endTimeNanoseconds = isoTimeToNanoseconds(endIsoFields) // number + let timeNanosecondDiff = endTimeNanoseconds - startTimeNanoseconds + const timeSign = numberSign(timeNanosecondDiff) + let midIsoFields = startIsoFields + + if (timeSign === -sign) { + midIsoFields = { + ...addDaysToIsoFields(startIsoFields, sign), + ...pluckIsoTimeFields(startIsoFields), + } + timeNanosecondDiff += nanosecondsInDay + } + + const dateDiff = diffExactDates( + midIsoFields, + endIsoFields, + calendar, + largestUnit, + ) + const timeDiff = nanosecondsToTimeDuration( + timeNanosecondDiff, + 'hours', // largestUnit (default?) + ) + + return roundRelativeDuration( + { ...dateDiff, ...timeDiff, sign }, + startIsoFields, + startEpochNanoseconds, + endIsoFields, + endEpochNanoseconds, + isoToUtcEpochNanoseconds, + calendar, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ) +} + +export function diffDates( + startIsoDateFields, + endIsoDateFields, + calendar, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, +) { + const startEpochNanoseconds = isoToUtcEpochNanoseconds(startIsoDateFields) + const endEpochNanoseconds = isoToUtcEpochNanoseconds(endIsoDateFields) + + if (smallestUnit < 'day') { // TODO + return diffEpochNanoseconds( + startEpochNanoseconds, + endEpochNanoseconds, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ) + } + + const dateDiff = diffExactDates( + startIsoDateFields, + endIsoDateFields, + calendar, + largestUnit, + ) + + return roundRelativeDuration( + dateDiff, + startIsoDateFields, + startEpochNanoseconds, + endIsoDateFields, + endEpochNanoseconds, + isoToUtcEpochNanoseconds, + calendar, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ) +} + +export function diffTimes() { + +} + +// Public Duration Stuff +// ------------------------------------------------------------------------------------------------- + +export function roundDuration( + durationFields, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + relativeTo, +) { + +} + +export function computeDurationTotal( + durationFields, + unit, + relativeTo, +) { + +} + +// Exact Diffing +// ------------------------------------------------------------------------------------------------- + +function diffExactDates( + startIsoDateFields, + endIsoDateFields, + calendar, + largestUnit, +) { + // defers to CalendarProtocol +} + +function diffExactLargeNanoseconds( + nanoseconds, + largestUnit, +) { + +} + +// Rounding +// ------------------------------------------------------------------------------------------------- + +function roundRelativeDuration( + durationFields, + startIsoFields, + startEpochNanoseconds, + endIsoFields, + endEpochNanoseconds, + isoToZoneEpochNanoseconds, + calendar, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, +) { + // TOOO: figure out edge case where time fields round up past end of zoned day, + // and then must be rerounded with the next day's reference frame +} + +function roundLargeNanoseconds( + nanoseconds, + smallestUnit, + roundingMode, + roundingIncrement, +) { + +} + +// Epoch/Time +// ------------------------------------------------------------------------------------------------- + +function isoToUtcEpochNanoseconds(isoFields) { + +} + +function isoTimeToNanoseconds(isoTimeFields) { + +} + +function nanosecondsToTimeDuration(nanoseconds) { // nanoseconds is a number + +} + +// TimeZone Conversions +// ------------------------------------------------------------------------------------------------- + +function epochNanosecondsToIso(epochNanoseconds, timeZone) { + +} + +function isoToEpochNanoseconds(isoFields, timeZone, disambig) { + return isoToPossibleEpochNanoseconds(isoFields, timeZone)[0] // example +} + +function isoToPossibleEpochNanoseconds(isoFields, timeZone) { + +} + +// Random Utils +// ------------------------------------------------------------------------------------------------- + +function numberSign(number) { + +} diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js new file mode 100644 index 00000000..c24b9272 --- /dev/null +++ b/packages/temporal-polyfill/src/new/duration.js @@ -0,0 +1,106 @@ +import { bagToDurationFields } from './convert' +import { + absolutizeDurationFields, + durationFieldGetters, + negateDurationFields, + refineDurationFields, +} from './durationFields' +import { stringToDurationFields } from './parse' +import { createTemporalClass, neverValueOf } from './temporalClass' + +export const [ + Duration, + createDuration, + toDurationInternals, +] = createTemporalClass( + 'Duration', + + // Creation + // ----------------------------------------------------------------------------------------------- + + ( + years = 0, + months = 0, + weeks = 0, + days = 0, + hours = 0, + minutes = 0, + seconds = 0, + milliseconds = 0, + microseconds = 0, + nanoseconds = 0, + ) => { + return refineDurationFields({ + years, + months, + weeks, + days, + hours, + minutes, + seconds, + milliseconds, + microseconds, + nanoseconds, + }) + }, + {}, + bagToDurationFields, + stringToDurationFields, + undefined, + + // Getters + // ----------------------------------------------------------------------------------------------- + + { + ...durationFieldGetters, + + blank(internals) { + return !internals.sign + }, + }, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + with(someDurationFields) { + // TODO + // TODO: will need to recompute sign!!! + }, + + add(internals, options) { + // TODO + }, + + subtract(internals, options) { + // TODO + }, + + negated(internals) { + return createDuration(negateDurationFields(internals)) + }, + + abs(internals) { + return createDuration(absolutizeDurationFields(internals)) + }, + + round(internals, options) { + // TODO + }, + + total(internals, unit) { + // TODO + }, + + valueOf: neverValueOf, + }, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + compare(durationArg0, durationArg1) { + // TODO + }, + }, +) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js new file mode 100644 index 00000000..33742f97 --- /dev/null +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -0,0 +1,82 @@ +import { toIntegerWithoutRounding } from './cast' +import { mapRefiners } from './convert' +import { isoTimeFieldDefaults, isoTimeFieldNames } from './isoFields' +import { remapProps } from './obj' + +const durationDateFieldRefiners = { + // sorted alphabetically + days: toIntegerWithoutRounding, + months: toIntegerWithoutRounding, + weeks: toIntegerWithoutRounding, + years: toIntegerWithoutRounding, + // does not have 'sign' +} + +const durationTimeFieldRefiners = { + // sorted alphabetically + hours: toIntegerWithoutRounding, + microseconds: toIntegerWithoutRounding, + milliseconds: toIntegerWithoutRounding, + minutes: toIntegerWithoutRounding, + nanoseconds: toIntegerWithoutRounding, + seconds: toIntegerWithoutRounding, +} + +export const durationFieldRefiners = { // does not include 'sign' + // keys must be resorted + ...durationDateFieldRefiners, + ...durationTimeFieldRefiners, +} + +export const durationDateFieldNames = Object.keys(durationDateFieldRefiners) +export const durationTimeFieldNames = Object.keys(durationTimeFieldRefiners) +export const durationFieldNames = Object.keys(durationFieldRefiners).sort() + +export const durationTimeFieldDefaults = remapProps( + isoTimeFieldDefaults, + isoTimeFieldNames, + durationTimeFieldNames, +) + +export const durationFieldDefaults = { // does not include 'sign' + years: 0, + months: 0, + days: 0, + ...durationTimeFieldDefaults, +} + +export const durationFieldGetters = durationFieldNames + .concat(['sign']) + .reduce((accum, durationFieldName, i) => { + accum[durationFieldName] = function(internals) { + return internals[durationFieldName] + } + return accum + }, {}) // TODO: somehow leverage remapProps instead? + +export function negateDurationFields(internals) { + // recomputes sign +} + +export function absolutizeDurationFields(internals) { + // recomputes sign +} + +export function durationHasDateParts(internals) { + return Boolean(computeDurationFieldsSign(internals, durationDateFieldNames)) +} + +export function durationTimeFieldsToIso(durationFields0) { + return remapProps(durationFields0, durationTimeFieldNames, isoTimeFieldNames) +} + +export function refineDurationFields(input) { + const obj = mapRefiners(input, durationFieldRefiners) + obj.sign = computeDurationFieldsSign(obj) + return obj +} + +function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { + // should throw error if mismatch + // TODO: audit repeat uses of this +} diff --git a/packages/temporal-polyfill/src/new/format.js b/packages/temporal-polyfill/src/new/format.js new file mode 100644 index 00000000..4a48fc70 --- /dev/null +++ b/packages/temporal-polyfill/src/new/format.js @@ -0,0 +1,53 @@ +import { isoCalendarId } from './calendarAdapter' +import { toCalendarNameOption } from './options' + +export function formatPossibleDate(internals, options, formatSimple) { + const calendarNameOpt = toCalendarNameOption(options) + const showCalendar = + calendarNameOpt === 'always' || + calendarNameOpt === 'critical' || + String(internals.calendar) !== isoCalendarId + + if (showCalendar) { + return formatIsoDateFields(internals) + + formatCalendarWithSingleOpt(internals.calendar, calendarNameOpt) + } else { + return formatSimple(internals) + } +} + +export function formatIsoDateTimeFields(isoFields, options) { + return formatIsoDateFields(isoFields) + 'T' + formatIsoTimeFields(isoFields, options) +} + +export function formatIsoDateFields(isoDateFields) { + +} + +export function formatIsoYearMonthFields(isoDateFields) { + +} + +export function formatIsoMonthDayFields(isoDateFields) { + +} + +export function formatIsoTimeFields(isoTimeFields, options) { + +} + +export function formatOffsetNanoseconds(offsetNanoseconds) { + +} + +export function formatTimeZone(timeZoneProtocol, options) { + +} + +export function formatCalendar(calendarProtocol, options) { + return formatCalendarWithSingleOpt(calendarProtocol, toCalendarNameOption(options)) +} + +function formatCalendarWithSingleOpt(calendarProtocol, calendarNameOpt) { + +} diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js new file mode 100644 index 00000000..736b3225 --- /dev/null +++ b/packages/temporal-polyfill/src/new/instant.js @@ -0,0 +1,176 @@ +import { isoCalendarId, toCalendarSlot } from './calendarAdapter' +import { toObject } from './cast' +import { diffEpochNanoseconds } from './diff' +import { toDurationInternals } from './duration' +import { negateDurationFields } from './durationFields' +import { + formatCalendar, + formatIsoDateTimeFields, + formatOffsetNanoseconds, + formatTimeZone, +} from './format' +import { compareLargeInts, createLargeInt, toLargeInt } from './largeInt' +import { moveEpochNanoseconds } from './move' +import { + epochGetters, + nanosecondsInMicrosecond, + nanosecondsInMillisecond, + nanosecondsInSecond, + regulateEpochNanoseconds, +} from './nanoseconds' +import { roundEpochNanoseconds } from './round' +import { createTemporalClass, neverValueOf } from './temporalClass' +import { + instantToOffsetNanoseconds, + instantToPlainDateTimeInternals, + toTimeZoneSlot, +} from './timeZoneProtocol' +import { createZonedDateTime } from './zonedDateTime' + +export const [ + Instant, + createInstant, + toInstantEpochNanoseconds, +] = createTemporalClass( + 'Instant', + + // Creation + // ----------------------------------------------------------------------------------------------- + + (epochNanoseconds) => { + return regulateEpochNanoseconds(toLargeInt(epochNanoseconds)) + }, + { + ZonedDateTime: (internals) => internals.epochNanoseconds, + }, + undefined, // bagToInternals + stringToEpochNanoseconds, + undefined, // parseOptions + + // Getters + // ----------------------------------------------------------------------------------------------- + + epochGetters, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + toZonedDateTimeISO(epochNanoseconds, timeZoneArg) { + createZonedDateTime({ + epochNanoseconds, + timeZone: toTimeZoneSlot(timeZoneArg), + calendar: isoCalendarId, + }) + }, + + toZonedDateTime(epochNanoseconds, options) { + const refinedObj = toObject(options) + + return createZonedDateTime({ + epochNanoseconds, + timeZone: toTimeZoneSlot(refinedObj.timeZone), + calendar: toCalendarSlot(refinedObj.calendar), + }) + }, + + add(epochNanoseconds, durationArg) { + return createInstant( + moveEpochNanoseconds( + epochNanoseconds, + toDurationInternals(durationArg), + ), + ) + }, + + subtract(epochNanoseconds, durationArg) { + return createInstant( + moveEpochNanoseconds( + epochNanoseconds, + negateDurationFields(toDurationInternals(durationArg)), + ), + ) + }, + + until(epochNanoseconds, otherArg, options) { + return diffEpochNanoseconds( + epochNanoseconds, + toInstantEpochNanoseconds(otherArg), + options, // TODO: must be given better options??? + ) + }, + + since(epochNanoseconds, otherArg, options) { + return diffEpochNanoseconds( + toInstantEpochNanoseconds(otherArg), + epochNanoseconds, + options, // TODO: reverse rounding option + ) + }, + + round(epochNanoseconds, options) { + return createInstant(roundEpochNanoseconds(epochNanoseconds, options)) + }, + + equals(epochNanoseconds, otherArg) { + return !compareLargeInts( + epochNanoseconds, + toInstantEpochNanoseconds(otherArg), + ) + }, + + toString(epochNanoseconds, options) { // has rounding options too + const refinedOptions = toObject(options) // TODO: make optional + // ^important for destructuring options because used once for rounding, second for formatting + + const calendar = refinedOptions.calendar !== undefined + ? toCalendarSlot(refinedOptions.calendar) + : isoCalendarId + + const timeZone = refinedOptions.timeZone !== undefined + ? toTimeZoneSlot(refinedOptions.timeZone) + : 'UTC' + + epochNanoseconds = roundEpochNanoseconds(epochNanoseconds, refinedOptions) + const instant = createInstant(epochNanoseconds) + const offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) + const isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + + return formatIsoDateTimeFields(isoFields, refinedOptions) + + formatOffsetNanoseconds(offsetNanoseconds) + + formatTimeZone(timeZone, options) + + formatCalendar(calendar, options) + }, + + toLocaleString(epochNanoseconds, locales, options) { + return '' + }, + + valueOf: neverValueOf, + }, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + fromEpochSeconds(epochSeconds) { + return createInstant(createLargeInt(epochSeconds).mult(nanosecondsInSecond)) + }, + + fromEpochMilliseconds(epochMilliseconds) { + return createInstant(createLargeInt(epochMilliseconds).mult(nanosecondsInMillisecond)) + }, + + fromEpochMicroseconds(epochMicroseconds) { + return createInstant(toLargeInt(epochMicroseconds).mult(nanosecondsInMicrosecond)) + }, + + fromEpochNanoseconds(epochNanoseconds) { + return createInstant(toLargeInt(epochNanoseconds)) + }, + }, +) + +function stringToEpochNanoseconds(str) { + // TODO +} diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js new file mode 100644 index 00000000..ae39fe86 --- /dev/null +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -0,0 +1,82 @@ +import { toCalendarSlot } from './calendarAdapter' +import { toIntegerThrowOnInfinity, toIntegerWithoutRounding, toPositiveInteger } from './cast' +import { pluckProps } from './obj' + +export const isoDateSlotRefiners = { + // sorted alphabetically + calendar: toCalendarSlot, + isoDay: toPositiveInteger, + isoMonth: toPositiveInteger, + isoYear: toIntegerWithoutRounding, +} + +export const isoTimeFieldRefiners = { + // sorted alphabetically + isoHour: toIntegerThrowOnInfinity, + isoMicrosecond: toIntegerThrowOnInfinity, + isoMillisecond: toIntegerThrowOnInfinity, + isoMinute: toIntegerThrowOnInfinity, + isoNanosecond: toPositiveInteger, // why different? + isoSecond: toPositiveInteger, // why different? +} + +export const isoDateTimeSlotRefiners = { + // keys must be resorted + ...isoDateSlotRefiners, + ...isoTimeFieldRefiners, +} + +export const isoDateSlotNames = Object.keys(isoDateSlotRefiners) +export const isoTimeFieldNames = Object.keys(isoTimeFieldRefiners) // no calendar +export const isoDateTimeSlotNames = Object.keys(isoDateTimeSlotRefiners).sort() + +export const isoTimeFieldDefaults = { + isoHour: 0, + isoMicrosecond: 0, + isoMillisecond: 0, + isoMinute: 0, + isoNanosecond: 0, + isoSecond: 0, +} + +export function pluckIsoDateTimeSlots(isoFields) { + return pluckProps(isoFields, isoDateTimeSlotNames) +} + +export function pluckIsoDateSlots(isoFields) { + return pluckProps(isoFields, isoDateSlotNames) +} + +export function pluckIsoTimeFields(isoFields) { + return pluckProps(isoFields, isoTimeFieldNames) +} + +export function compareIsoFields() { + // uses Date.UTC +} + +export function compareIsoTimeFields() { + // uses conversion to milliseconds +} + +// TODO: make distinction between "regulate" (which considers overflow) and "reject" (throws error) + +export function regulateIsoDateTimeFields() { + +} + +export function regulateIsoDateFields() { + +} + +export function regulateIsoTimeFields() { + +} + +export function addDaysToIsoFields() { + +} + +export function isValidIsoFields() { + +} diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js new file mode 100644 index 00000000..c35a5937 --- /dev/null +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -0,0 +1,14 @@ + +export const LargeInt = null + +export function createLargeInt() { + +} + +export function toLargeInt() { + +} + +export function compareLargeInts() { + +} diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js new file mode 100644 index 00000000..1f46249d --- /dev/null +++ b/packages/temporal-polyfill/src/new/move.js @@ -0,0 +1,136 @@ +import { moveDate } from './calendarAdapter' +import { + dateToPlainYearMonth, + plainYearMonthToPlainDate, +} from './convert' +import { + durationHasDateParts, + durationTimeFieldDefaults, + durationTimeFieldsToIso, +} from './durationFields' +import { createInstant } from './instant' +import { isoTimeFieldsToNanoseconds, nanosecondsToIsoTimeFields } from './nanoseconds' +import { createPlainDateTime } from './plainDateTime' +import { createPlainTime } from './plainTime' +import { getInternals } from './temporalClass' +import { + instantToPlainDateTimeInternals, + plainDateTimeToEpochNanoseconds, +} from './timeZoneProtocol' + +/* +!!! all sorts of confusion in this file about internals/plain +*/ + +// High-level objects +// ------------------------------------------------------------------------------------------------- + +export function moveZonedDateTimeInternals(internals, durationFields, options) { + let { epochNanoseconds, calendar, timeZone } = internals + const durationTimeNanoseconds = isoTimeFieldsToNanoseconds( + durationTimeFieldsToIso(durationFields), + ) + + if (!durationHasDateParts(durationFields)) { + epochNanoseconds = epochNanoseconds.add(durationTimeNanoseconds) + } else { + const plainDateTimeInternals = instantToPlainDateTimeInternals( + timeZone, + calendar, + createInstant(epochNanoseconds), + ) + const movedPlainDateInternals = moveDate( + calendar, + plainDateTimeInternals, + { + ...durationFields, // date parts + ...durationTimeFieldDefaults, // time parts + }, + options, + ) + const movedPlainDateTime = createPlainDateTime({ + ...plainDateTimeInternals, // time parts + ...movedPlainDateInternals, // date parts + }) + epochNanoseconds = plainDateTimeToEpochNanoseconds(timeZone, movedPlainDateTime, 'compatible') + .add(durationTimeNanoseconds) + } + + return { + epochNanoseconds, + timeZone, + calendar, + } +} + +export function movePlainYearMonth(plainYearMonth, durationFields, options) { + const { calendar } = getInternals(plainYearMonth) + let plainDate = plainYearMonthToPlainDate(plainYearMonth, { + day: durationFields.sign < 0 + ? calendar.daysInMonth(plainYearMonth) + : 1, + }) + plainDate = moveDate(calendar, plainDate, durationFields, options) + return dateToPlainYearMonth(plainDate) +} + +export function movePlainDateTime(plainDateTime, durationFields, options) { + const internals = getInternals(plainDateTime) + const [movedIsoTimeFields, dayDelta] = addIsoTimeFields( + internals, + durationTimeFieldsToIso(durationFields), + ) + + const movedPlainDate = moveDate( + internals.calendar, + internals, // only date parts will be used + { + ...durationFields, // date parts + ...durationTimeFieldDefaults, // time parts (must be zero so calendar doesn't round) + days: durationFields.days + dayDelta, + }, + options, + ) + + return createPlainDateTime({ + ...getInternals(movedPlainDate), + ...movedIsoTimeFields, + }) +} + +// Used internally by Calendar::dateAdd (aka movePlainDate) +// ------------------------------------------------------------------------------------------------- + +// TODO + +// Epoch/Time +// ------------------------------------------------------------------------------------------------- + +export function moveEpochNanoseconds(epochNanoseconds, durationFields) { + return epochNanoseconds.add(onlyDurationTimeFieldsToIso(durationFields)) +} + +/* +Accepts internals but returns PlainTime +*/ +export function movePlainTime(internals, durationFields) { + const [movedIsoTimeFields] = addIsoTimeFields( + internals, + onlyDurationTimeFieldsToIso(durationFields), + ) + return createPlainTime(movedIsoTimeFields) +} + +function onlyDurationTimeFieldsToIso(durationFields) { + if (durationHasDateParts(durationFields)) { + throw new RangeError('Cant have date parts') + } + return durationTimeFieldsToIso(durationFields) +} + +function addIsoTimeFields(isoTimeFields0, isoTimeFields1) { + return nanosecondsToIsoTimeFields( // returns [movedIsoTimeFields, dayDelta] + isoTimeFieldsToNanoseconds(isoTimeFields0) + + isoTimeFieldsToNanoseconds(isoTimeFields1), + ) +} diff --git a/packages/temporal-polyfill/src/new/move2.js b/packages/temporal-polyfill/src/new/move2.js new file mode 100644 index 00000000..0ade447e --- /dev/null +++ b/packages/temporal-polyfill/src/new/move2.js @@ -0,0 +1,2 @@ + +// TODO diff --git a/packages/temporal-polyfill/src/new/nanoseconds.js b/packages/temporal-polyfill/src/new/nanoseconds.js new file mode 100644 index 00000000..9ac4b7da --- /dev/null +++ b/packages/temporal-polyfill/src/new/nanoseconds.js @@ -0,0 +1,36 @@ +export const nanosecondsInMicrosecond = 1000 +export const nanosecondsInMillisecond = 1000000 +export const nanosecondsInSecond = 1000000000 +export const nanosecondsInMinute = 60000000000 // used? +export const nanosecondsInHour = 3600000000000 +export const nanosecondsInDay = 86400000000000 // used? + +export const epochGetters = { + epochNanoseconds(epochNanoseconds) { + return epochNanoseconds.toBigInt() + }, + + epochMicroseconds(epochNanoseconds) { + return epochNanoseconds.div(nanosecondsInMicrosecond).toBigInt() + }, + + epochMilliseconds(epochNanoseconds) { + return epochNanoseconds.div(nanosecondsInMillisecond).toBigInt() + }, + + epochSeconds(epochNanoseconds) { + return epochNanoseconds.div(nanosecondsInSecond).toBigInt() + }, +} + +export function regulateEpochNanoseconds(epochNanoseconds) { + +} + +export function isoTimeFieldsToNanoseconds() { + +} + +export function nanosecondsToIsoTimeFields() { + // return [isoTimeFields, dayDelta] +} diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js new file mode 100644 index 00000000..084087ff --- /dev/null +++ b/packages/temporal-polyfill/src/new/now.js @@ -0,0 +1,2 @@ + +export const Now = null diff --git a/packages/temporal-polyfill/src/new/obj.js b/packages/temporal-polyfill/src/new/obj.js new file mode 100644 index 00000000..464dcf1f --- /dev/null +++ b/packages/temporal-polyfill/src/new/obj.js @@ -0,0 +1,30 @@ + +export function isObjectLike() { + +} + +export function mapProps() { + +} + +export function remapProps(obj, oldKeys, newKeys) { + +} + +export function defineProps(obj, props) { + return Object.defineProperties( + obj, + mapProps(props, (value) => ({ + value, + writable: true, + configurable: true, + })), + ) +} + +export function pluckProps(obj, props) { +} + +export function removeDuplicateStrings(a0, a1) { + +} diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js new file mode 100644 index 00000000..35af1906 --- /dev/null +++ b/packages/temporal-polyfill/src/new/options.js @@ -0,0 +1,72 @@ + +export function largestOfTwoUnits() { + +} + +export function toOffsetHandling() { + +} + +export function toDisambiguation() { + +} + +export function toLargestUnit() { + +} + +export function toSmallestUnit() { +} + +export function isTimeUnit(unit) { + return unit !== 'year' && + unit !== 'month' && + unit !== 'week' && + unit !== 'day' +} + +export function toCalendarNameOption() { + +} + +export function toDiffOptions() { + +} + +export function toOverflowOptions() { + +} + +export function validateRoundingOptions(options) { + /* + if (roundTo === undefined) throw new TypeError('options parameter is required'); + if (ES.Type(roundTo) === 'String') { + const stringParam = roundTo; + roundTo = ObjectCreate(null); + roundTo.smallestUnit = stringParam; + } else { + roundTo = ES.GetOptionsObject(roundTo); + } + const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo); + const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand'); + const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED, ['day']); + const maximumIncrements = { + day: 1, + hour: 24, + minute: 60, + second: 60, + millisecond: 1000, + microsecond: 1000, + nanosecond: 1000 + }; + const maximum = maximumIncrements[smallestUnit]; + const inclusive = maximum === 1; + ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive); + */ +} + +export function optionsToLargestUnit() { +} + +export function optionsToOverflow() { +} diff --git a/packages/temporal-polyfill/src/new/parse.js b/packages/temporal-polyfill/src/new/parse.js new file mode 100644 index 00000000..70b57cd6 --- /dev/null +++ b/packages/temporal-polyfill/src/new/parse.js @@ -0,0 +1,188 @@ +import { isoCalendarId, toCalendarSlot } from './calendarAdapter' +import { + isValidIsoFields, + pluckIsoDateSlots, + pluckIsoDateTimeSlots, + pluckIsoTimeFields, +} from './isoFields' +import { computeIsoFieldEpochNanoseconds, toTimeZoneSlot } from './timeZoneProtocol' +import { createZonedDateTime } from './zonedDateTime' + +// High-level +// ------------------------------------------------------------------------------------------------- + +export function stringToZonedDateTimeInternals(s) { + const parsed = parseDateTime(s) + if (parsed) { + if (!parsed.timeZoneId) { + throw new Error() + } + + const calendar = toCalendarSlot(parsed.calendarId || isoCalendarId) + const timeZone = toTimeZoneSlot(parsed.timeZoneId) + + const epochNanoseconds = computeIsoFieldEpochNanoseconds( + parsed, + timeZone, + parsed.offset !== undefined ? parseOffsetNanoseconds(parsed.offset) : undefined, + parsed.z, + 'reject', + 'compatible', + true, // fuzzy + ) + + return createZonedDateTime({ + epochNanoseconds, + timeZone, + calendar, + }) + } + + throw new Error() +} + +export function stringToPlainDateTimeInternals(s) { + const parsed = parseDateTime(s) + if (parsed) { + return pluckIsoDateTimeSlots(parsed) + } + + throw new Error() +} + +export function stringToPlainDateInternals(s) { + const parsed = parseDateTime(s) + if (parsed) { + return parsed + } + + throw new Error() +} + +export function stringToPlainYearMonthInternals(s) { + let parsed = parseYearMonth(s) + if (!parsed) { + parsed = parseDateTime(s) + if (parsed) { + parsed = pluckIsoDateSlots(parsed) + } + } + + if (parsed) { + return parsed + } + + throw new Error() +} + +export function stringToMonthDayInternals(s) { + let parsed = parseMonthDay(s) + if (!parsed) { + parsed = parseDateTime(s) + if (parsed) { + parsed = pluckIsoDateSlots(parsed) + } + } + + if (parsed) { + return parsed + } + + throw new Error() +} + +export function stringToPlainTimeInternals(s) { + let parsed = parseTime(s) + + if (!parsed) { + parsed = parseDateTime(s) + + if (parsed && !parsed.hasTime) { + throw new Error() + } + } + + if (parsed) { + if (parsed.hasZ) { + throw new Error() + } + if (parsed.calendarId !== undefined && parsed.calendarId !== isoCalendarId) { + throw new Error() + } + + let otherParsed = parseMonthDay(s) + if (otherParsed && isValidIsoFields(otherParsed)) { + throw new Error() + } + otherParsed = parseYearMonth(s) + if (otherParsed && isValidIsoFields(otherParsed)) { + throw new Error() + } + + return pluckIsoTimeFields(parsed) + } + + throw new Error() +} + +export function stringToCalendarId(s) { + if (s !== isoCalendarId) { + s = ( + parseDateTime(s) || parseYearMonth(s) || parseMonthDay(s) + )?.calendarId || isoCalendarId + } + + return s +} + +export function stringToTimeZoneId(s) { + const parsed = parseDateTime(s) + if (parsed !== undefined) { + if (parsed.timeZonedId) { + return parsed.timeZonedId // TODO: need to canonicalize (run through DateTimeFormat) + } + if (parsed.hasZ) { + return 'UTC' + } + if (parsed.offset) { + return parsed.offset + } + } + + return s +} + +// Low-level +// ------------------------------------------------------------------------------------------------- + +export function parseDateTime(s) { + // { isYear, isoMonth, isoDay, + // isoHour, isMinute, isoSecond, etc... + // hasTime, hasZ, offset, + // calendar, timeZone } + // + // TODO: make calendar default to ISO! +} + +export function parseYearMonth(s) { + // { isYear, isoMonth, isoDay + // calendar, timeZone } +} + +export function parseMonthDay(s) { + // { isYear, isoMonth, isoDay + // calendar, timeZone } +} + +export function parseTime(s) { + // { isoHour, isoMinute, isoSecond, etc... + // calendar, timeZone } +} + +export function parseOffsetNanoseconds(s) { + // number +} + +export function stringToDurationFields(s) { + +} diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js new file mode 100644 index 00000000..4b5ed65b --- /dev/null +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -0,0 +1,170 @@ +import { + getCommonCalendar, + isoCalendarId, + moveDate, + toCalendarSlot, +} from './calendarAdapter' +import { dateGetters } from './calendarFields' +import { + bagToPlainDateSlots, + createZonedDateTimeConverter, + dateToPlainMonthDay, + dateToPlainYearMonth, + isStringCastsEqual, + mapRefiners, + plainDateWithBag, + zonedDateTimeInternalsToIso, +} from './convert' +import { diffDates } from './diff' +import { toDurationInternals } from './duration' +import { negateDurationFields } from './durationFields' +import { formatCalendar, formatIsoDateFields } from './format' +import { + compareIsoFields, + isoDateSlotRefiners, + isoTimeFieldDefaults, + pluckIsoDateSlots, + regulateIsoDateFields, +} from './isoFields' +import { optionsToOverflow } from './options' +import { stringToPlainDateInternals } from './parse' +import { createPlainDateTime } from './plainDateTime' +import { toPlainTimeInternals } from './plainTime' +import { createTemporalClass, neverValueOf } from './temporalClass' + +export const [ + PlainDate, + createPlainDate, + toPlainDateInternals, +] = createTemporalClass( + 'PlainDate', + + // Creation + // ----------------------------------------------------------------------------------------------- + + (isoYear, isoMonth, isoDay, calendarArg = isoCalendarId) => { + return regulateIsoDateFields( + mapRefiners({ + isoYear, + isoMonth, + isoDay, + calendar: calendarArg, + }, isoDateSlotRefiners), + ) + }, + { + PlainDateTime: pluckIsoDateSlots, + ZonedDateTime: zonedDateTimeInternalsToIso, + }, + bagToPlainDateSlots, + stringToPlainDateInternals, + optionsToOverflow, + + // Getters + // ----------------------------------------------------------------------------------------------- + + dateGetters, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + with(internals, bag, options) { + return createPlainDate(plainDateWithBag(this, bag, options)) + }, + + withCalendar(internals, calendarArg) { + return createPlainDate({ + ...internals, + calendar: toCalendarSlot(calendarArg), + }) + }, + + add(internals, durationArg, options) { + return moveDate( + internals.calendar, + internals, + toDurationInternals(durationArg), + options, + ) + }, + + subtract(internals, durationArg, options) { + return moveDate( + internals.calendar, + internals, + negateDurationFields(toDurationInternals(durationArg)), + options, + ) + }, + + until(internals, otherArg, options) { + const otherInternals = toPlainDateInternals(otherArg) + const calendar = getCommonCalendar(internals, otherInternals) + return diffDates(calendar, internals, otherInternals, options, 1) + }, + + since(internals, otherArg, options) { + const otherInternals = toPlainDateInternals(otherArg) + const calendar = getCommonCalendar(internals, otherInternals) + return diffDates(calendar, internals, otherInternals, options, -1) + }, + + equals(internals, other) { + const otherInternals = toPlainDateInternals(other) + return !compareIsoFields(internals, otherInternals) && + isStringCastsEqual(internals.calendar, otherInternals.calendar) + }, + + toString(internals, options) { + return formatIsoDateFields(internals) + + formatCalendar(internals.calendar, options) + }, + + toLocaleString(internals, locales, options) { + return '' + }, + + valueOf: neverValueOf, + + toZonedDateTime: createZonedDateTimeConverter((options) => { + return optionalToPlainTimeInternals(options.time) + }), + + toPlainDateTime(internals, timeArg) { + return createPlainDateTime({ + ...internals, + ...optionalToPlainTimeInternals(timeArg), + }) + }, + + toPlainYearMonth() { + return dateToPlainYearMonth(this) + }, + + toPlainMonthDay() { + return dateToPlainMonthDay(this) + }, + + getISOFields: pluckIsoDateSlots, + }, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + compare(arg0, arg1) { + return compareIsoFields( + toPlainDateInternals(arg0), + toPlainDateInternals(arg1), + ) + }, + }, +) + +// Utils +// ------------------------------------------------------------------------------------------------- + +function optionalToPlainTimeInternals(timeArg) { + return timeArg === undefined ? isoTimeFieldDefaults : toPlainTimeInternals(timeArg) +} diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js new file mode 100644 index 00000000..dc109f2f --- /dev/null +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -0,0 +1,219 @@ +import { isoCalendarId, toCalendarSlot } from './calendarAdapter' +import { dateTimeGetters } from './calendarFields' +import { + bagToPlainDateTimeInternals, + dateToPlainMonthDay, + dateToPlainYearMonth, + isStringCastsEqual, + mapRefiners, + plainDateTimeWithBag, + zonedDateTimeInternalsToIso, +} from './convert' +import { diffDateTimes } from './diff' +import { toDurationInternals } from './duration' +import { negateDurationFields } from './durationFields' +import { formatCalendar, formatIsoDateTimeFields } from './format' +import { + compareIsoFields, + isoDateTimeSlotRefiners, + isoTimeFieldDefaults, + pluckIsoDateSlots, + pluckIsoDateTimeSlots, + pluckIsoTimeFields, + regulateIsoDateTimeFields, +} from './isoFields' +import { movePlainDateTime } from './move' +import { optionsToOverflow, validateRoundingOptions } from './options' +import { stringToPlainDateTimeInternals } from './parse' +import { createPlainDate, toPlainDateInternals } from './plainDate' +import { createPlainTime, toPlainTimeInternals } from './plainTime' +import { roundIsoDateTimeFields } from './round' +import { createTemporalClass, neverValueOf } from './temporalClass' +import { plainDateTimeToEpochNanoseconds, toTimeZoneSlot } from './timeZoneProtocol' +import { createZonedDateTime } from './zonedDateTime' + +export const [ + PlainDateTime, + createPlainDateTime, + toPlainDateTimeInternals, +] = createTemporalClass( + 'PlainDateTime', + + // Creation + // ----------------------------------------------------------------------------------------------- + + ( + isoYear, + isoMonth, + isoDay, + isoHour = 0, + isoMinute = 0, + isoSecond = 0, + isoMillisecond = 0, + isoMicrosecond = 0, + isoNanosecond = 0, + calendarArg = isoCalendarId, + ) => { + return regulateIsoDateTimeFields( + mapRefiners({ + isoYear, + isoMonth, + isoDay, + isoHour, + isoMinute, + isoSecond, + isoMillisecond, + isoMicrosecond, + isoNanosecond, + calendar: toCalendarSlot(calendarArg), + }, isoDateTimeSlotRefiners), + ) + }, + { + PlainDate: (internals) => ({ ...internals, ...isoTimeFieldDefaults }), + ZonedDateTime: zonedDateTimeInternalsToIso, + }, + bagToPlainDateTimeInternals, + stringToPlainDateTimeInternals, + optionsToOverflow, + + // Getters + // ----------------------------------------------------------------------------------------------- + + dateTimeGetters, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + with(internals, bag, options) { + return createPlainDateTime(plainDateTimeWithBag(this, bag, options)) + }, + + withPlainTime(internals, plainTimeArg) { + return createPlainDateTime({ + ...internals, + ...toPlainTimeInternals(plainTimeArg), + }) + }, + + withPlainDate(internals, plainDateArg) { + return createPlainDateTime({ + ...internals, + ...toPlainDateInternals(plainDateArg), + }) + }, + + withCalendar(internals, calendarArg) { + return createPlainDateTime({ + ...internals, + calendar: toCalendarSlot(calendarArg), + }) + }, + + add(internals, durationArg, options) { + return movePlainDateTime( + internals, + toDurationInternals(durationArg), + options, + ) + }, + + subtract(internals, durationArg, options) { + return movePlainDateTime( + internals, + negateDurationFields(toDurationInternals(durationArg)), + options, + ) + }, + + until(internals, otherArg, options) { + return diffDateTimes( + internals, + toPlainDateTimeInternals(otherArg), + options, // TODO: spread out lots of options!!! + ) + }, + + since(internals, otherArg, options) { + return diffDateTimes( + toPlainDateTimeInternals(otherArg), + internals, + options, // TODO: flip rounding options + ) + }, + + round(internals, options) { + const isoFields = roundIsoDateTimeFields(internals, validateRoundingOptions(options)) + + return createPlainDateTime({ + ...isoFields, + calendar: internals.calendar, + }) + }, + + equals(internals, other) { + const otherInternals = toPlainDateTimeInternals(other) + return !compareIsoFields(internals, otherInternals) && + isStringCastsEqual(internals.calendar, otherInternals.calendar) + }, + + toString(internals, options) { + // TODO: don't let options (smallestUnit/fractionalWhatever) be access twice!!! + return formatIsoDateTimeFields(roundIsoDateTimeFields(internals, options), options) + + formatCalendar(internals.calendar, options) + }, + + toLocaleString(internals, locales, options) { + return '' + }, + + valueOf: neverValueOf, + + toZonedDateTime( + internals, + timeZoneArg, + options, // { disambiguation } - optional + ) { + const { calendar } = internals + const timeZone = toTimeZoneSlot(timeZoneArg) + const epochNanoseconds = plainDateTimeToEpochNanoseconds(timeZone, this, options), + + return createZonedDateTime({ + epochNanoseconds, + timeZone, + calendar, + }) + }, + + toPlainDate(internals) { + return createPlainDate(pluckIsoDateSlots(internals)) + }, + + toPlainYearMonth() { + return dateToPlainYearMonth(this) + }, + + toPlainMonthDay() { + return dateToPlainMonthDay(this) + }, + + toPlainTime(internals) { + return createPlainTime(pluckIsoTimeFields(internals)) + }, + + getISOFields: pluckIsoDateTimeSlots, + }, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + compare(arg0, arg1) { + return compareIsoFields( + toPlainDateTimeInternals(arg0), + toPlainDateTimeInternals(arg1), + ) + }, + }, +) diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js new file mode 100644 index 00000000..d70c7d3c --- /dev/null +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -0,0 +1,81 @@ +import { isoCalendarId } from './calendarAdapter' +import { monthDayGetters } from './calendarFields' +import { + bagToPlainMonthDayInternals, + isStringCastsEqual, + mapRefiners, + plainMonthDayToPlainDate, + plainMonthDayWithBag, +} from './convert' +import { formatIsoMonthDayFields, formatPossibleDate } from './format' +import { + compareIsoFields, + isoDateSlotRefiners, + pluckIsoDateSlots, + regulateIsoDateFields, +} from './isoFields' +import { optionsToOverflow } from './options' +import { stringToMonthDayInternals } from './parse' +import { createTemporalClass, neverValueOf } from './temporalClass' + +export const [ + PlainMonthDay, + createPlainMonthDay, + toPlainMonthDayInternals, +] = createTemporalClass( + 'PlainMonthDay', + + // Creation + // ----------------------------------------------------------------------------------------------- + + (isoMonth, isoDay, calendarArg = isoCalendarId, referenceIsoYear = 1972) => { + return regulateIsoDateFields( + mapRefiners({ + isoYear: referenceIsoYear, + isoMonth, + isoDay, + calendar: calendarArg, + }, isoDateSlotRefiners), + ) + }, + {}, + bagToPlainMonthDayInternals, + stringToMonthDayInternals, + optionsToOverflow, + + // Getters + // ----------------------------------------------------------------------------------------------- + + monthDayGetters, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + with(internals, bag, options) { + return createPlainMonthDay(plainMonthDayWithBag(this, bag, options)) + }, + + equals(internals, otherArg) { + const otherInternals = toPlainMonthDayInternals(otherArg) + return !compareIsoFields(internals, otherInternals) && + isStringCastsEqual(internals.calendar, otherInternals.calendar) + }, + + toString(internals, options) { + return formatPossibleDate(internals, options, formatIsoMonthDayFields) + }, + + toLocaleString(internals, locales, options) { + return '' + }, + + valueOf: neverValueOf, + + toPlainDate(internals, bag) { + return plainMonthDayToPlainDate(this, bag) + }, + + getISOFields: pluckIsoDateSlots, + }, +) diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js new file mode 100644 index 00000000..436c362c --- /dev/null +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -0,0 +1,155 @@ +import { timeGetters } from './calendarFields' +import { + bagToPlainTimeInternals, + createZonedDateTimeConverter, + mapRefiners, + plainTimeWithBag, + zonedDateTimeInternalsToIso, +} from './convert' +import { diffTimes } from './diff' +import { createDuration, toDurationInternals } from './duration' +import { negateDurationFields } from './durationFields' +import { formatIsoTimeFields } from './format' +import { + compareIsoTimeFields, + isoTimeFieldRefiners, + pluckIsoTimeFields, + regulateIsoTimeFields, +} from './isoFields' +import { movePlainTime } from './move' +import { optionsToOverflow } from './options' +import { stringToPlainTimeInternals } from './parse' +import { toPlainDateInternals } from './plainDate' +import { createPlainDateTime } from './plainDateTime' +import { roundIsoTimeFields } from './round' +import { createTemporalClass, neverValueOf } from './temporalClass' + +export const [ + PlainTime, + createPlainTime, + toPlainTimeInternals, +] = createTemporalClass( + 'PlainTime', + + // Creation + // ----------------------------------------------------------------------------------------------- + + ( + isoHour = 0, + isoMinute = 0, + isoSecond = 0, + isoMillisecond = 0, + isoMicrosecond = 0, + isoNanosecond = 0, + ) => { + return regulateIsoTimeFields( + mapRefiners({ + isoHour, + isoMinute, + isoSecond, + isoMillisecond, + isoMicrosecond, + isoNanosecond, + }, isoTimeFieldRefiners), + ) + }, + { + PlainDateTime: pluckIsoTimeFields, + ZonedDateTime: (internals) => pluckIsoTimeFields(zonedDateTimeInternalsToIso(internals)), + }, + bagToPlainTimeInternals, + stringToPlainTimeInternals, + optionsToOverflow, + + // Getters + // ----------------------------------------------------------------------------------------------- + + timeGetters, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + with(internals, bag, options) { + return plainTimeWithBag(this, bag, options) + }, + + add(internals, durationArg) { + return movePlainTime(internals, toDurationInternals(durationArg)) + }, + + subtract(internals, durationArg) { + return movePlainTime( + internals, + negateDurationFields(toDurationInternals(durationArg)), + ) + }, + + until(internals, options) { + return createDuration( + diffTimes( + internals, + toPlainTimeInternals(internals), + options, + ), + ) + }, + + since(internals, options) { + return createDuration( + diffTimes( + toPlainTimeInternals(internals), + internals, + options, // TODO: reverse rounding + ), + ) + }, + + round(internals, options) { + return roundIsoTimeFields(internals, options) + }, + + equals(internals, other) { + const otherInternals = toPlainTimeInternals(other) + return compareIsoTimeFields(internals, otherInternals) + }, + + toString(internals, options) { + // TODO: don't let options (smallestUnit/fractionalWhatever) be access twice!!! + return formatIsoTimeFields(roundIsoTimeFields(internals, options), options) + }, + + toLocaleString(internals, locales, options) { + return '' + }, + + valueOf: neverValueOf, + + toZonedDateTime: createZonedDateTimeConverter((options) => { + return toPlainDateInternals(options.plainDate) + }), + + toPlainDateTime(internals, plainDateArg) { + return createPlainDateTime({ + ...internals, + ...toPlainDateInternals(plainDateArg), + }) + }, + + getISOFields(internals) { + return pluckIsoTimeFields(internals) + }, + }, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + compare(arg0, arg1) { + return compareIsoTimeFields( + toPlainTimeInternals(arg0), + toPlainTimeInternals(arg1), + ) + }, + }, +) diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js new file mode 100644 index 00000000..667c85b4 --- /dev/null +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -0,0 +1,138 @@ +import { isoCalendarId } from './calendarAdapter' +import { yearMonthGetters } from './calendarFields' +import { + bagToPlainYearMonthInternals, + isStringCastsEqual, + mapRefiners, + plainYearMonthToPlainDate, + plainYearMonthToPlainDateFirst, + plainYearMonthWithBag, +} from './convert' +import { diffDates } from './diff' +import { toDurationInternals } from './duration' +import { negateDurationFields } from './durationFields' +import { formatIsoYearMonthFields, formatPossibleDate } from './format' +import { + compareIsoFields, + isoDateSlotRefiners, + pluckIsoDateSlots, + regulateIsoDateFields, +} from './isoFields' +import { movePlainYearMonth } from './move' +import { optionsToOverflow } from './options' +import { stringToPlainYearMonthInternals } from './parse' +import { createTemporalClass, neverValueOf } from './temporalClass' + +export const [ + PlainYearMonth, + createPlainYearMonth, + toPlainYearMonthInternals, +] = createTemporalClass( + 'PlainYearMonth', + + // Creation + // ----------------------------------------------------------------------------------------------- + + (isoYear, isoMonth, calendarArg = isoCalendarId, referenceIsoDay = 1) => { + return regulateIsoDateFields( + mapRefiners({ + isoYear, + isoMonth, + isoDay: referenceIsoDay, + calendar: calendarArg, + }, isoDateSlotRefiners), + ) + }, + {}, + bagToPlainYearMonthInternals, + stringToPlainYearMonthInternals, + optionsToOverflow, + + // Getters + // ----------------------------------------------------------------------------------------------- + + yearMonthGetters, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + with(internals, bag, options) { + return createPlainYearMonth(plainYearMonthWithBag(internals, bag, options)) + }, + + add(internals, durationArg, options) { + return movePlainYearMonth( + internals, + toDurationInternals(durationArg), + options, + ) + }, + + subtract(internals, durationArg, options) { + return movePlainYearMonth( + internals, + negateDurationFields(toDurationInternals(durationArg)), + options, + ) + }, + + until(internals, otherArg, options) { + const { calendar } = internals + return createPlainYearMonth( + diffDates( + calendar, + plainYearMonthToPlainDateFirst(internals), + plainYearMonthToPlainDateFirst(toPlainYearMonthInternals(otherArg)), + options, + ), + ) + }, + + since(internals, otherArg, options) { + const { calendar } = internals + return createPlainYearMonth( + diffDates( + calendar, + plainYearMonthToPlainDateFirst(toPlainYearMonthInternals(otherArg)), + plainYearMonthToPlainDateFirst(internals), + options, // TODO: flip rounding args + ), + ) + }, + + equals(internals, otherArg) { + const otherInternals = toPlainYearMonthInternals(otherArg) + return !compareIsoFields(internals, otherInternals) && + isStringCastsEqual(internals.calendar, otherInternals.calendar) + }, + + toString(internals, options) { + return formatPossibleDate(internals, options, formatIsoYearMonthFields) + }, + + toLocaleString(internals, locales, options) { + return '' + }, + + valueOf: neverValueOf, + + toPlainDate(internals, bag) { + return plainYearMonthToPlainDate(this, bag) + }, + + getISOFields: pluckIsoDateSlots, + }, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + compare(arg0, arg1) { + return compareIsoFields( + toPlainYearMonthInternals(arg0), + toPlainYearMonthInternals(arg1), + ) + }, + }, +) diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js new file mode 100644 index 00000000..7ca124c2 --- /dev/null +++ b/packages/temporal-polyfill/src/new/round.js @@ -0,0 +1,63 @@ +import { isTimeUnit, toSmallestUnit } from './options' + +/* +(RoundDuration) +Only has smallestUnit +Options includes relativeTo +should work for ANY smallestUnit + +does NOT do balancing, because caller might want a specific type of balancing +*/ +export function roundDurationInternals(durationInternals, options) { + +} + +/* +NOTE: Duration should call this if relativeTo is a ZonedDateTime +*/ +export function adjustDurationFieldsForTimeZone( + durationInternals, + zonedDateTime, + options, // { roundingIncrement, smallestUnit, roundingMode } +) { + // AdjustRoundedDurationDays + + const smallestUnit = toSmallestUnit(options) + + // short-circuit if time-rounding won't happen + if ( + !isTimeUnit(smallestUnit) || + (smallestUnit === 'nanosecond' && options.roundingIncrement === 1) + ) { + return durationInternals + } +} + +function getNanosecondsInNormalDay() { + return 86400e9 +} + +export function roundIsoDateTimeFields( + isoFields, + options, + getNanosecondsInDay = getNanosecondsInNormalDay, +) { + const isoTimeFields = roundIsoTimeFields(isoFields, options, getNanosecondsInDay) + return combineThem(isoFields, isoTimeFields) +} + +export function roundIsoTimeFields( + isoTimeFields, + options, + getNanosecondsInDay = getNanosecondsInNormalDay, +) { + // returns isoTimeFields back +} + +function combineThem(isoDateFields, isoTimeFields) { + // uses 'day' field as delta. will rebalance date (using iso util) +} + +export function roundEpochNanoseconds(epochNanoseconds, options) { + +} diff --git a/packages/temporal-polyfill/src/new/temporal.js b/packages/temporal-polyfill/src/new/temporal.js new file mode 100644 index 00000000..f9b0beb4 --- /dev/null +++ b/packages/temporal-polyfill/src/new/temporal.js @@ -0,0 +1,26 @@ +import { Calendar } from './calendar' +import { Duration } from './duration' +import { Instant } from './instant' +import { Now } from './now' +import { defineProps } from './obj' +import { PlainDate } from './plainDate' +import { PlainDateTime } from './plainDateTime' +import { PlainMonthDay } from './plainMonthDay' +import { PlainTime } from './plainTime' +import { PlainYearMonth } from './plainYearMonth' +import { TimeZone } from './timeZone' +import { ZonedDateTime } from './zonedDateTime' + +export const Temporal = defineProps({}, { + PlainYearMonth, + PlainMonthDay, + PlainDate, + PlainTime, + PlainDateTime, + ZonedDateTime, + Instant, + Calendar, + TimeZone, + Duration, + Now, +}) diff --git a/packages/temporal-polyfill/src/new/temporalClass.js b/packages/temporal-polyfill/src/new/temporalClass.js new file mode 100644 index 00000000..61bbedc8 --- /dev/null +++ b/packages/temporal-polyfill/src/new/temporalClass.js @@ -0,0 +1,89 @@ +import { defineProps, isObjectLike, mapProps } from './obj' + +const internalsMap = new WeakMap() +export const getInternals = internalsMap.get.bind(internalsMap) + +const nameSymbol = Symbol() + +function noop() {} + +export function createTemporalClass( + name, // rename? + constructorToInternals, + nameToInternalsMap, + bagToInternals = noop, + stringToInternals, + parseOptions = noop, + getters, + methods, + staticMembers = {}, +) { + function TemporalObj(...args) { + internalsMap.set(this, constructorToInternals(...args)) + } + + const proto = TemporalObj.prototype + + function createInstance(internals) { + const instance = Object.create(proto) + internalsMap.set(instance, internals) + return instance + } + + function toInternals(arg, options) { + let argInternals = getInternals(arg) + + if (argInternals) { + const argName = arg[nameSymbol] // might raise red flags accessing this!!! + if (argName !== name) { + argInternals = (nameToInternalsMap[argName] || noop)(argInternals) + } + } + + return (!argInternals && isObjectLike(arg) && bagToInternals(arg, options)) || + (parseOptions(options), argInternals || stringToInternals(toString(arg))) + } + + function curryMethod(method) { + return /* Object.setPrototypeOf( */ function(...args) { + if (!(this instanceof TemporalObj)) { + throw new TypeError('Invalid receiver') + } + return method.call(this, getInternals(this), ...args) + } /* , null) */ + } + + Object.defineProperties(proto, { + ...mapProps(getters, (getter) => ({ + get: curryMethod(getter), + configurable: true, + })), + [Symbol.toStringTag]: { + value: 'Temporal.' + name, + configurable: true, + }, + [nameSymbol]: { // might raise red flags accessing this!!! + value: name, + }, + }) + + methods.toJSON = function() { + return String(this) + } + staticMembers.from = function(arg, options) { + return createInstance(toInternals(arg, options)) + } + + defineProps(proto, mapProps(methods, curryMethod)) + defineProps(TemporalObj, staticMembers) + + return [ + TemporalObj, + createInstance, + toInternals, + ] +} + +export function neverValueOf() { + throw new TypeError('Cannot convert object using valueOf') +} diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js new file mode 100644 index 00000000..5e9447f4 --- /dev/null +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -0,0 +1,76 @@ +import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' +import { Calendar } from './calendar' +import { createComplexBagRefiner } from './convert' +import { formatOffsetNanoseconds } from './format' +import { toInstantEpochNanoseconds } from './instant' +import { stringToTimeZoneId } from './parse' +import { createTemporalClass } from './temporalClass' +import { instantToOffsetNanoseconds } from './timeZoneProtocol' + +export const [TimeZone] = createTemporalClass( + 'TimeZone', + + // Creation + // ----------------------------------------------------------------------------------------------- + + // constructor to internals + (id) => { + return queryTimeZoneImpl(id) + }, + {}, + createComplexBagRefiner('timeZone', Calendar), + stringToTimeZoneId, + undefined, + + // Getters + // ----------------------------------------------------------------------------------------------- + + { + id(impl) { + return impl.id + }, + }, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + getOffsetStringFor(impl, instantArg) { + return formatOffsetNanoseconds( + // TODO: figure out timeZoneProtocol + instantToOffsetNanoseconds( + this, + toInstantEpochNanoseconds(instantArg), + ), + ) + }, + + getOffsetNanosecondsFor(impl, instantArg) { + // TODO + }, + + getPlainDateTimeFor(impl, instantArg, calendarArg) { + // TODO + }, + + getInstantFor(impl, dateTimeArg, options) { + // TODO + }, + + getPossibleInstantsFor(impl, dateTimeArg) { + // TODO + }, + + getPreviousTransition(impl, instantArg) { + // TODO + }, + + getNextTransition(impl, instantArg) { + // TODO + }, + + toString(impl) { + return impl.id + }, + }, +) diff --git a/packages/temporal-polyfill/src/new/timeZoneProtocol.js b/packages/temporal-polyfill/src/new/timeZoneProtocol.js new file mode 100644 index 00000000..d485e9b2 --- /dev/null +++ b/packages/temporal-polyfill/src/new/timeZoneProtocol.js @@ -0,0 +1,73 @@ +import { strictArrayOfType, toInteger } from './cast' +import { Instant, createInstant } from './instant' +import { nanosecondsInDay } from './nanoseconds' +import { getInternals } from './temporalClass' + +// High-level usage with Temporal objects +// ------------------------------------------------------------------------------------------------- + +export function zonedDateTimeInternalsToOffsetNanoseconds(internals) { + return instantToOffsetNanoseconds(internals.timeZone, createInstant(internals.epochNanoseconds)) +} + +export function computeIsoFieldEpochNanoseconds( + isoFields, // should accept PlainDateTime instead? + timeZoneProtocol, + offset, + z, + offsetHandling, // 'reject' + disambig, // 'compatible' + fuzzy, +) { + // relies on plainDateTimeToPossibleInstants +} + +export function computeNanosecondsInDay(isoFields, timeZoneProtocol) { + // relies on plainDateTimeToPossibleInstants +} + +// Utils for Calendar and users of CalendarProtocol +// ------------------------------------------------------------------------------------------------- + +export function instantToPlainDateTimeInternals(timeZoneProtocol, calendar, instant) { + return getInternals(instantToPlainDateTime(timeZoneProtocol, calendar, instant)) +} + +export function instantToPlainDateTime(timeZoneProtocol, calendar, instant) { + // relies on instantToOffsetNanoseconds +} + +export function plainDateTimeToEpochNanoseconds(timeZoneProtocol, plainDateTime, disambiguation) { + return getInternals(plainDateTimeToInstant(timeZoneProtocol, plainDateTime, disambiguation)) +} + +function plainDateTimeToInstant(timeZoneProtocol, plainDateTime, disambiguation) { + // relies on plainDateTimeToPossibleInstants +} + +// Only raw CalendarProtocol methods that can be relied upon +// ------------------------------------------------------------------------------------------------- + +export function instantToOffsetNanoseconds(timeZoneProtocol, instant) { + const nanoseconds = toInteger(timeZoneProtocol.getOffsetNanosecondsFor(instant)) + + if (Math.abs(nanoseconds) >= nanosecondsInDay) { + throw new RangeError('out of range') + } + + return nanoseconds +} + +export function plainDateTimeToPossibleInstants(timeZoneProtocol, plainDateTime) { + return strictArrayOfType(timeZoneProtocol.getPossibleInstantsFor(plainDateTime), Instant) +} + +// Utils +// ------------------------------------------------------------------------------------------------- + +export function getCommonTimeZone() { +} + +export function toTimeZoneSlot() { + +} diff --git a/packages/temporal-polyfill/src/new/timeZoneProtocol2.js b/packages/temporal-polyfill/src/new/timeZoneProtocol2.js new file mode 100644 index 00000000..0ade447e --- /dev/null +++ b/packages/temporal-polyfill/src/new/timeZoneProtocol2.js @@ -0,0 +1,2 @@ + +// TODO diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js new file mode 100644 index 00000000..39b678de --- /dev/null +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -0,0 +1,347 @@ +import { getCommonCalendar, toCalendarSlot } from './calendarAdapter' +import { dateTimeGetters } from './calendarFields' +import { + bagToZonedDateTimeInternals, + dateToPlainMonthDay, + dateToPlainYearMonth, + isStringCastsEqual, + zonedDateTimeInternalsToIso, + zonedDateTimeWithBag, +} from './convert' +import { diffZoneEpochNanoseconds } from './diff' +import { toDurationInternals } from './duration' +import { negateDurationFields } from './durationFields' +import { + formatCalendar, + formatIsoDateTimeFields, + formatOffsetNanoseconds, + formatTimeZone, +} from './format' +import { createInstant } from './instant' +import { + isoTimeFieldDefaults, + pluckIsoDateSlots, + pluckIsoDateTimeSlots, + pluckIsoTimeFields, +} from './isoFields' +import { compareLargeInts, toLargeInt } from './largeInt' +import { moveZonedDateTimeInternals } from './move' +import { epochGetters, nanosecondsInHour } from './nanoseconds' +import { mapProps } from './obj' +import { optionsToOverflow } from './options' +import { stringToZonedDateTimeInternals } from './parse' +import { createPlainDate, toPlainDateInternals } from './plainDate' +import { createPlainDateTime } from './plainDateTime' +import { createPlainTime, toPlainTimeInternals } from './plainTime' +import { roundIsoDateTimeFields } from './round' +import { createTemporalClass, neverValueOf } from './temporalClass' +import { + computeIsoFieldEpochNanoseconds, + computeNanosecondsInDay, + getCommonTimeZone, + instantToOffsetNanoseconds, + instantToPlainDateTimeInternals, + plainDateTimeToEpochNanoseconds, + toTimeZoneSlot, + zonedDateTimeInternalsToOffsetNanoseconds, +} from './timeZoneProtocol' + +export const [ + ZonedDateTime, + createZonedDateTime, + toZonedDateTimeInternals, +] = createTemporalClass( + 'ZonedDateTime', + + // Creation + // ----------------------------------------------------------------------------------------------- + + (epochNanoseconds, timeZoneArg, calendarArg) => { + return { + epochNanoseconds: toLargeInt(epochNanoseconds), // TODO: stricter + timeZone: toTimeZoneSlot(timeZoneArg), + calendar: toCalendarSlot(calendarArg), + } + }, + {}, + bagToZonedDateTimeInternals, + stringToZonedDateTimeInternals, + optionsToOverflow, + + // Getters + // ----------------------------------------------------------------------------------------------- + + { + ...mapProps(epochGetters, (getter) => { + return function(internals) { + return getter(internals.epochNanoseconds) + } + }), + + ...mapProps(dateTimeGetters, (getter) => { + return function(internals) { + return getter(zonedDateTimeInternalsToIso(internals)) + } + }), + + hoursInDay(internals) { + return computeNanosecondsInDay(internals.epochNanoseconds, internals.timeZone) / + nanosecondsInHour + }, + + offsetNanoseconds(internals) { + return zonedDateTimeInternalsToOffsetNanoseconds(internals) + }, + + offset(internals) { + return formatOffsetNanoseconds(zonedDateTimeInternalsToOffsetNanoseconds(internals)) + }, + }, + + // Methods + // ----------------------------------------------------------------------------------------------- + + { + with(internals, bag, options) { + return zonedDateTimeWithBag(this, bag, options) + }, + + withPlainTime(internals, plainTimeArg) { + const { timeZone } = internals + const epochNanoseconds = plainDateTimeToEpochNanoseconds( + timeZone, + createPlainDateTime({ + ...zonedDateTimeInternalsToIso(internals), + ...toPlainTimeInternals(plainTimeArg), + }), + ) + + return createZonedDateTime({ + epochNanoseconds, + timeZone, + calendar: internals.calendar, + }) + }, + + withPlainDate(internals, plainDateArg) { + const { timeZone } = internals + const epochNanoseconds = plainDateTimeToEpochNanoseconds( + timeZone, + createPlainDateTime({ + ...zonedDateTimeInternalsToIso(internals), + ...toPlainDateInternals(plainDateArg), + // calendar doesn't matter + }), + ) + + return createZonedDateTime({ + epochNanoseconds, + timeZone, + calendar: internals.calendar, + }) + }, + + withTimeZone(internals, timeZoneArg) { + return createZonedDateTime({ + ...internals, + timeZone: toTimeZoneSlot(timeZoneArg), + }) + }, + + withCalendar(internals, calendarArg) { + return createZonedDateTime({ + ...internals, + calendar: toCalendarSlot(calendarArg), + }) + }, + + add(internals, durationArg, options) { + return createZonedDateTime( + moveZonedDateTimeInternals( + internals, + toDurationInternals(durationArg), + options, + ), + ) + }, + + subtract(internals, durationArg, options) { + return createZonedDateTime( + moveZonedDateTimeInternals( + internals, + negateDurationFields(toDurationInternals(durationArg)), + options, + ), + ) + }, + + until(internals, otherArg, options) { + const otherInternals = toZonedDateTimeInternals(otherArg) + return diffZoneEpochNanoseconds( + internals.epochNanoseconds, + otherInternals.epochNanoseconds, + getCommonTimeZone(internals, otherInternals), + getCommonCalendar(internals, otherInternals), + options, // TODO: spread out lots of options!!! + ) + }, + + since(internals, otherArg, options) { + const otherInternals = toZonedDateTimeInternals(otherArg) + return diffZoneEpochNanoseconds( + otherInternals.epochNanoseconds, + internals.epochNanoseconds, + getCommonTimeZone(internals, otherInternals), + getCommonCalendar(internals, otherInternals), + options, // TODO: flip rounding options!!!!! + ) + }, + + round(internals, options) { + let { epochNanoseconds, timeZone, calendar } = internals + + const instant = createInstant(epochNanoseconds) + const offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) + let isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + isoFields = roundIsoDateTimeFields( + isoFields, + options, + () => computeNanosecondsInDay(isoFields, timeZone), + ) + epochNanoseconds = computeIsoFieldEpochNanoseconds( + isoFields, + timeZone, + offsetNanoseconds, + false, // z + 'prefer', // keep old offsetNanoseconds if possible + 'compatible', + true, // fuzzy + ) + + return createZonedDateTime({ + epochNanoseconds, + timeZone, + calendar, + }) + }, + + startOfDay(internals) { + let { epochNanoseconds, timeZone, calendar } = internals + + const isoFields = { + ...zonedDateTimeInternalsToIso(internals), + ...isoTimeFieldDefaults, + } + + epochNanoseconds = computeIsoFieldEpochNanoseconds( + isoFields, + timeZone, + undefined, // offsetNanoseconds + false, // z + 'reject', + 'compatible', + true, // fuzzy + ) + + return createZonedDateTime({ + epochNanoseconds, + timeZone, + calendar, + }) + }, + + equals(internals, otherZonedDateTimeArg) { + const otherInternals = toZonedDateTimeInternals(otherZonedDateTimeArg) + + return !compareLargeInts(internals.epochNanoseconds, otherInternals.epochNanoseconds) && + isStringCastsEqual(internals.calendar, otherInternals.calendar) && + isStringCastsEqual(internals.timeZone, otherInternals.timeZone) + }, + + toString(internals, options) { + let { epochNanoseconds, timeZone, calendar } = internals + + // TODO: don't let options be accessed twice! once by rounding, twice by formatting + + let instant = createInstant(epochNanoseconds) + let offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) + let isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + isoFields = roundIsoDateTimeFields( + isoFields, + options, + () => computeNanosecondsInDay(isoFields, timeZone), + ) + epochNanoseconds = computeIsoFieldEpochNanoseconds( + isoFields, + timeZone, + offsetNanoseconds, + false, // z + 'prefer', // keep old offsetNanoseconds if possible + 'compatible', + true, // fuzzy + ) + instant = createInstant(epochNanoseconds) + offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) + isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + + return formatIsoDateTimeFields(isoFields, options) + + formatOffsetNanoseconds(offsetNanoseconds) + + formatTimeZone(timeZone, options) + + formatCalendar(calendar, options) + }, + + toLocaleString(internals, locales, options) { + return '' + }, + + valueOf: neverValueOf, + + toInstant(internals) { + return createInstant(internals.epochNanoseconds) + }, + + toPlainDate(internals) { + return createPlainDate(pluckIsoDateSlots(zonedDateTimeInternalsToIso(internals))) + }, + + toPlainTime(internals) { + return createPlainTime(pluckIsoTimeFields(zonedDateTimeInternalsToIso(internals))) + }, + + toPlainDateTime(internals) { + return createPlainDateTime(zonedDateTimeInternalsToIso(internals)) + }, + + toPlainYearMonth() { + return dateToPlainYearMonth(this) + }, + + toPlainMonthDay() { + return dateToPlainMonthDay(this) + }, + + getISOFields(internals) { + const { timeZone, calendar } = internals + + return { + // maintain alphabetical order + calendar, + ...pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(internals)), + offset: formatOffsetNanoseconds(zonedDateTimeInternalsToOffsetNanoseconds(internals)), + timeZone: String(timeZone), + } + }, + }, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + compare(arg0, arg1) { + return compareLargeInts( + toZonedDateTimeInternals(arg0).epochNanoseconds, + toZonedDateTimeInternals(arg1).epochNanoseconds, + ) + }, + }, +) From 02d748aec166833adca254209e8868f5e76e4360 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 12 May 2023 15:12:39 -0400 Subject: [PATCH 074/805] scratch --- packages/temporal-polyfill/misc/NOTES.txt | 24 +- .../temporal-polyfill/src/new/calendar.js | 113 ++- .../src/new/calendarAdapter.js | 132 --- .../src/new/calendarConfig.js | 101 +++ .../src/new/calendarFields.js | 30 +- .../temporal-polyfill/src/new/calendarImpl.js | 836 +++++++++++++++++- .../temporal-polyfill/src/new/calendarOps.js | 94 ++ packages/temporal-polyfill/src/new/cast.js | 12 +- packages/temporal-polyfill/src/new/convert.js | 224 +++-- packages/temporal-polyfill/src/new/diff.js | 102 ++- .../temporal-polyfill/src/new/duration.js | 17 +- .../src/new/durationFields.js | 1 + packages/temporal-polyfill/src/new/format.js | 2 +- packages/temporal-polyfill/src/new/instant.js | 57 +- .../src/new/internalClass.js | 60 ++ .../temporal-polyfill/src/new/isoFields.js | 34 +- packages/temporal-polyfill/src/new/lang.js | 11 + packages/temporal-polyfill/src/new/move.js | 181 ++-- packages/temporal-polyfill/src/new/move2.js | 2 - packages/temporal-polyfill/src/new/now.js | 79 +- packages/temporal-polyfill/src/new/obj.js | 38 +- packages/temporal-polyfill/src/new/parse.js | 15 +- .../temporal-polyfill/src/new/plainDate.js | 58 +- .../src/new/plainDateTime.js | 75 +- .../src/new/plainMonthDay.js | 28 +- .../temporal-polyfill/src/new/plainTime.js | 50 +- .../src/new/plainYearMonth.js | 63 +- .../temporal-polyfill/src/new/temporal.js | 6 +- .../src/new/temporalClass.js | 87 +- .../temporal-polyfill/src/new/timeZone.js | 94 +- .../temporal-polyfill/src/new/timeZoneImpl.js | 14 + .../temporal-polyfill/src/new/timeZoneOps.js | 84 ++ .../src/new/timeZoneProtocol.js | 73 -- .../src/new/timeZoneProtocol2.js | 2 - .../src/new/zonedDateTime.js | 122 ++- .../temporal-polyfill/src/public/calendar.ts | 1 + 36 files changed, 2125 insertions(+), 797 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/calendarAdapter.js create mode 100644 packages/temporal-polyfill/src/new/calendarConfig.js create mode 100644 packages/temporal-polyfill/src/new/calendarOps.js create mode 100644 packages/temporal-polyfill/src/new/internalClass.js create mode 100644 packages/temporal-polyfill/src/new/lang.js delete mode 100644 packages/temporal-polyfill/src/new/move2.js create mode 100644 packages/temporal-polyfill/src/new/timeZoneImpl.js create mode 100644 packages/temporal-polyfill/src/new/timeZoneOps.js delete mode 100644 packages/temporal-polyfill/src/new/timeZoneProtocol.js delete mode 100644 packages/temporal-polyfill/src/new/timeZoneProtocol2.js diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/misc/NOTES.txt index 27a23b02..74168b31 100644 --- a/packages/temporal-polyfill/misc/NOTES.txt +++ b/packages/temporal-polyfill/misc/NOTES.txt @@ -9,14 +9,24 @@ https://github.com/js-temporal/temporal-polyfill/blob/main/lib/ecmascript.ts#L18 TODO: move to global builtin casts!!!! -now = Temporal.PlainDate.from('2022-01-01') -then = Temporal.PlainDate.from('2023-12-25') - -duration = now.until(then, { largestUnit: 'year', smallestUnit: 'month', roundingMode: 'ceil' }) -console.log(duration.toString()) -roundedDuration = duration.round({ relativeTo: now, largestUnit: 'year', smallestUnit: 'month', roundingMode: 'ceil' }) -console.log(roundedDuration.toString()) +const past = Temporal.PlainDate.from('2022-01-01') +const future = Temporal.PlainDate.from('2023-12-25') + +const durationViaUntil = past.until(future, { + largestUnit: 'year', + smallestUnit: 'month', + roundingMode: 'ceil' +}) +console.log(durationViaUntil.toString()) // P1Y12M (undesirable result IMO) + +const durationViaRound = past.until(future).round({ + relativeTo: past, + largestUnit: 'year', + smallestUnit: 'month', + roundingMode: 'ceil' +}) +console.log(durationViaRound.toString()) // P2Y (expected result) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index fada4408..fdb16957 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -1,7 +1,15 @@ -import { queryCalendarImpl } from '../calendarImpl/calendarImplQuery' // ah -import { dateCalendarRefiners } from './calendarFields' -import { createComplexBagRefiner } from './convert' +import { + getRequiredDateFields, + getRequiredMonthDayFields, + getRequiredYearMonthFields, +} from './calendarConfig' +import { dateCalendarRefiners, dateFieldNames, yearMonthFieldNames } from './calendarFields' +import { isoDaysInWeek, queryCalendarImpl } from './calendarImpl' +import { strictArrayOfStrings, toObject } from './cast' +import { createComplexBagRefiner, prepareFields } from './convert' import { createDuration, toDurationInternals } from './duration' +import { internalIdGetters, returnId } from './internalClass' +import { noop } from './lang' import { mapProps } from './obj' import { optionsToLargestUnit, optionsToOverflow } from './options' import { stringToCalendarId } from './parse' @@ -11,28 +19,34 @@ import { createPlainYearMonth } from './plainYearMonth' import { createTemporalClass } from './temporalClass' import { TimeZone } from './timeZone' -export const [Calendar] = createTemporalClass( +/* +Must do input validation +*/ +export const [Calendar, createCalendar] = createTemporalClass( 'Calendar', // Creation // ----------------------------------------------------------------------------------------------- - (id) => { - return queryCalendarImpl(id) - }, - {}, + // constructorToInternals + queryCalendarImpl, + + // massageOtherInternals + noop, + + // bagToInternals createComplexBagRefiner('calendar', TimeZone), - stringToCalendarId, - undefined, + + // stringToInternals + (str) => queryCalendarImpl(stringToCalendarId(str)), + + // handleUnusedOptions + noop, // Getters // ----------------------------------------------------------------------------------------------- - { - id(impl) { - return impl.id // TODO: more DRY with toString() - }, - }, + internalIdGetters, // Methods // ----------------------------------------------------------------------------------------------- @@ -44,10 +58,14 @@ export const [Calendar] = createTemporalClass( } }), + daysInWeek() { + return isoDaysInWeek + }, + dateAdd(impl, plainDateArg, durationArg, options) { return createPlainDate( impl.dateAdd( - toPlainDateInternals(plainDateArg), + toPlainDateInternals(plainDateArg), // round time parts??? toDurationInternals(durationArg), optionsToLargestUnit(options), ), @@ -57,34 +75,61 @@ export const [Calendar] = createTemporalClass( dateUntil(impl, startPlainDateArg, endPlainDateArg, options) { return createDuration( impl.dateUntil( - toPlainDateInternals(startPlainDateArg), - toPlainDateInternals(endPlainDateArg), + toPlainDateInternals(startPlainDateArg), // round time parts??? + toPlainDateInternals(endPlainDateArg), // round time parts??? optionsToOverflow(options), ), ) }, - ...mapProps({ - dateFromFields: createPlainDate, - yearMonthFromFields: createPlainYearMonth, - monthDayFromFields: createPlainMonthDay, - fields: identityFunc, - mergeFields: identityFunc, - }, transformInternalMethod), + dateFromFields(impl, fields, options) { + return createPlainDate({ + calendar: impl, + ...impl.dateFromFields( + prepareFields(fields, impl.fields(dateFieldNames), getRequiredDateFields(impl)), + optionsToOverflow(options), + ), + }) + }, - toString(impl) { - return impl.id // TODO: more DRY with toString() + yearMonthFromFields(impl, fields, options) { + return createPlainYearMonth({ + calendar: impl, + ...impl.yearMonthFromFields( + prepareFields(fields, impl.fields(yearMonthFieldNames), getRequiredYearMonthFields(impl)), + optionsToOverflow(options), + ), + }) + }, + + monthDayFromFields(impl, fields, options) { + return createPlainMonthDay({ + calendar: impl, + ...impl.monthDayFromFields( + // refine y/m/d fields + prepareFields(fields, impl.fields(dateFieldNames), getRequiredMonthDayFields(impl)), + optionsToOverflow(options), + ), + }) }, + + fields(impl, fieldNames) { + return impl.fields(strictArrayOfStrings(fieldNames)) + }, + + mergeFields(impl, fields0, fields1) { + return impl.mergeFields( + removeUndefines(toObject(fields0)), + removeUndefines(toObject(fields1)), + ) + }, + + toString: returnId, }, ) -// Misc -// ---- +// utils -function identityFunc(input) { return input } +function removeUndefines(obj) { // and copy -function transformInternalMethod(transformRes, methodName) { - return (impl, ...args) => { - return transformRes(impl[methodName](...args)) - } } diff --git a/packages/temporal-polyfill/src/new/calendarAdapter.js b/packages/temporal-polyfill/src/new/calendarAdapter.js deleted file mode 100644 index bcc239ba..00000000 --- a/packages/temporal-polyfill/src/new/calendarAdapter.js +++ /dev/null @@ -1,132 +0,0 @@ -import { strictArrayOfStrings, strictInstanceOf, toObject } from './cast' -import { createDuration } from './duration' -import { mapProps } from './obj' -import { PlainDate, createPlainDate } from './plainDate' -import { PlainMonthDay } from './plainMonthDay' -import { PlainYearMonth } from './plainYearMonth' -import { getInternals } from './temporalClass' - -// first attempt -// ------------- - -export const moveDate = createCalendarFallback( - 'dateAdd', - createInternalGetter(PlainDate), - (isoDateFields, durationFields, overflow) => [ - createPlainDate(isoDateFields), - createDuration(durationFields), - { overflow }, - ], -) - -export const diffExactDates = createCalendarFallback( - 'dateUntil', - createInternalGetter(PlainDate), - (startIsoDateFields, endIsoDateFields, largestUnit) => [ - createPlainDate(startIsoDateFields), - createPlainDate(endIsoDateFields), - { largestUnit }, - ], -) - -export const dateFieldsToIso = createCalendarFallback( - 'dateFromFields', - createInternalGetter(PlainDate), -) - -export const yearMonthFieldsToIso = createCalendarFallback( - 'yearMonthFromFields', - createInternalGetter(PlainYearMonth), -) - -export const monthDayFieldsToIso = createCalendarFallback( - 'monthDayFields', - createInternalGetter(PlainMonthDay), -) - -export const mergeFields = createCalendarFallback('mergeFields', toObject) - -export const transformFieldNames = createCalendarFallback('fields', strictArrayOfStrings) - -function createCalendarFallback( - methodName, - transformRes, - transformArgs = identityFunc, -) { - return (calendar, ...args) => { - if (typeof calendar === 'string') { - return queryCalendarImpl(calendar)[methodName](...args) - } - return transformRes(calendar[methodName](...transformArgs(...args))) - } -} - -// second attempt -// -------------- -// CHOOSE THIS APPROACH -// All methods will query this adapter once in the beginning -// Better than querying adapter-ness multiple times throughout a multi-step operation - -const getStrictPlainDateInternals = createInternalGetter(PlainDate) - -export const CalendarOpsAdapter = createInternalClass({ - dateAdd(calendar, isoDateFields, durationFields, overflow) { - return getStrictPlainDateInternals( - calendar.dateAdd( - createPlainDate(isoDateFields), // hopefully won't look at blank .calendar - createDuration(durationFields), - { overflow }, - ), - ) - }, - - dateUntil(calendar, startIsoDateFields, endIsoDateFields, largestUnit) { - return getStrictPlainDateInternals( - calendar.dateUntil( - createPlainDate(startIsoDateFields), // hopefully won't look at blank .calendar - createPlainDate(endIsoDateFields), // hopefully won't look at blank .calendar - { largestUnit }, - ), - ) - }, - - ...mapProps({ - dateFromFields: getStrictPlainDateInternals, - yearMonthFromFields: createInternalGetter(PlainYearMonth), - monthDayFields: createInternalGetter(PlainMonthDay), - mergeFields: toObject, - fields: strictArrayOfStrings, - }, transformInternalMethod), -}) - -// Misc -// ---- - -// same thing used in calendar.js -function transformInternalMethod(transformRes, methodName) { - return (impl, ...args) => { - return transformRes(impl[methodName](...args)) - } -} - -function createInternalClass() { - -} - -function createInternalGetter(Class) { - return (res) => getInternals(strictInstanceOf(Class), res) -} - -function queryCalendarImpl() { -} - -export const isoCalendarId = 'iso8601' - -export function getCommonCalendar(internals0, internals1) { -} - -export function toCalendarSlot() { - -} - -function identityFunc(input) { return input } diff --git a/packages/temporal-polyfill/src/new/calendarConfig.js b/packages/temporal-polyfill/src/new/calendarConfig.js new file mode 100644 index 00000000..391b6cd6 --- /dev/null +++ b/packages/temporal-polyfill/src/new/calendarConfig.js @@ -0,0 +1,101 @@ + +export const isoCalendarId = 'iso8601' +export const gregoryCalendarId = 'gregory' +export const japaneseCalendarId = 'japanese' + +// for converting from [era,eraYear] -> year +// if origin is >=0, +// year = origin + eraYear +// if origin is <0, consider the era to be 'reverse' direction +// year = -origin - eraYear +// year = -(origin + eraYear) +export const eraOriginsByCalendarId = { + [gregoryCalendarId]: { + bce: -1, + ce: 0, + }, + [japaneseCalendarId]: { + bce: -1, + ce: 0, + meiji: 1867, + taisho: 1911, + showa: 1925, + heisei: 1988, + reiwa: 2018, + }, + ethioaa: { + era0: 0, + }, + ethiopic: { + era0: 0, + era1: 5500, + }, + coptic: { + era0: -1, + era1: 0, + }, + roc: { + beforeroc: -1, + minguo: 0, + }, + buddhist: { + be: 0, + }, + islamic: { + ah: 0, + }, + indian: { + saka: 0, + }, + persian: { + ap: 0, + }, +} + +export const eraRemaps = { + bc: 'bce', + ad: 'ce', +} + +export function getAllowErasInFields(calendarOps) { + return calendarOps.id !== isoCalendarId +} + +export function getErasBeginMidYear(calendarOps) { + return calendarOps.id === japaneseCalendarId +} + +export const leapYearMetas = { + chinese: 11, // (positive) max possible leap month + dangi: 11, // " + hebrew: -6, // (negative) constant leap month +} + +// Required Fields +// ------------------------------------------------------------------------------------------------- + +const defaultRequiredDateFields = ['day'] +const defaultRequiredYearMonthFields = [] +const defaultRequiredMonthDayFields = ['day'] + +const isoRequiredDateFields = [...defaultRequiredDateFields, 'year'] +const isoRequiredYearMonthFields = [...defaultRequiredYearMonthFields, 'year'] +const isoRequiredMonthDayFields = defaultRequiredMonthDayFields + +export function getRequiredDateFields(calendarOps) { + return calendarOps.id === isoCalendarId + ? isoRequiredDateFields + : defaultRequiredDateFields +} + +export function getRequiredYearMonthFields(calendarOps) { + return calendarOps.id === isoCalendarId + ? isoRequiredYearMonthFields + : defaultRequiredYearMonthFields +} + +export function getRequiredMonthDayFields(calendarOps) { + return calendarOps.id === isoCalendarId + ? isoRequiredMonthDayFields + : defaultRequiredMonthDayFields +} diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index 854fe4b9..a578119a 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -2,6 +2,8 @@ import { toIntegerThrowOnInfinity, toPositiveInteger } from './cast' import { isoTimeFieldDefaults, isoTimeFieldNames } from './isoFields' import { mapProps, remapProps } from './obj' +// does NOT contain era/eraYear (considered special-case for certain calendars) + export const yearMonthFieldRefiners = { // sorted alphabetically month: toPositiveInteger, @@ -37,11 +39,17 @@ export const dateTimeFieldRefiners = { ...timeFieldRefiners, } -export const yearMonthStatRefiners = { - daysInMonth: toPositiveInteger, +export const yearStatRefiners = { + // sorted alphabetically, for predictable macros daysInYear: toPositiveInteger, - monthsInYear: toPositiveInteger, inLeapYear: toPositiveInteger, + monthsInYear: toPositiveInteger, +} +export const yearStatNames = Object.keys(yearStatRefiners) + +export const yearMonthStatRefiners = { + ...yearStatRefiners, + daysInMonth: toPositiveInteger, } export const dateStatRefiners = { @@ -53,14 +61,22 @@ export const dateStatRefiners = { daysInWeek: toPositiveInteger, } +// +// NOTE: "basic" names are for converting between Plain* objects. Don't need all numeric fields +// export const dateFieldNames = Object.keys(dateFieldRefiners) +export const dateFieldBasics = ['day', 'month', 'year'] export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) // month/monthCode/year export const yearMonthBasicNames = yearMonthFieldNames.slice(1) // monthCode/year export const monthDayFieldNames = dateFieldNames.slice(0, 3) // day/month/monthCode export const monthDayBasicNames = ['day', 'monthCode'] +export const monthFieldNames = monthDayFieldNames.slice(1) // month/monthCode export const dateTimeFieldNames = Object.keys(dateTimeFieldRefiners).sort() export const timeFieldNames = Object.keys(timeFieldRefiners) +export const eraYearFieldNames = ['era', 'eraYear'] +export const allYearFieldNames = [...eraYearFieldNames, 'year'] + export const yearMonthGetters = createCalendarGetters({ ...yearMonthFieldRefiners, ...yearMonthStatRefiners, @@ -90,12 +106,14 @@ export const dateTimeGetters = { function createCalendarGetters(refiners) { const getters = mapProps(refiners, (refiner, fieldName) => { return function(internals) { - return refiner(internals.calendar[fieldName][this]) + return refiner(internals.calendar[fieldName](this)) } }) - getters.calendar = function(internals) { - return internals.calendar + + getters.calendarId = function(internals) { + return internals.calendar.id } + return getters } diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 4869bae9..ad6f94b0 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -1,99 +1,837 @@ +import { + eraOriginsByCalendarId, + eraRemaps, + getAllowErasInFields, + getErasBeginMidYear, + gregoryCalendarId, + isoCalendarId, + japaneseCalendarId, + leapYearMetas, +} from './calendarConfig' +import { + allYearFieldNames, + dateFieldBasics, + eraYearFieldNames, + monthDayFieldNames, + monthFieldNames, + yearStatNames, +} from './calendarFields' +import { computeIntlMonthsInYearSpan, computeIsoMonthsInYearSpan, diffYearMonthDay } from './diff' +import { durationFieldDefaults } from './durationFields' +import { isoDateFieldNames, isoTimeFieldDefaults } from './isoFields' +import { addIntlMonths, addIsoMonths } from './move' -/* -If we don't use a class, we can pile-in iso util methods like: -- getIsoDayOfWeek -*/ +// Base ISO Calendar +// ------------------------------------------------------------------------------------------------- + +class IsoCalendarImpl { + constructor(id) { + this.id = id + } + + era(isoDateFields) { + // undefined + } + + eraYear(isoDateFields) { + // undefined + } + + monthCode(isoDateFields) { + return formatMonthCode(isoDateFields.isoMonth) + } + + daysInMonth(isoDateFields) { + return this.queryDaysInMonth(...this.queryYearMonthDay(isoDateFields)) + } + + dateFromFields(fields, overflow) { + const year = this.readYear(fields) + const month = this.refineMonth(fields, year, overflow) + const day = this.refineDay(fields, month, year, overflow) + return this.queryIsoFields(year, month, day) + } + + yearMonthFromFields(fields, overflow) { + const year = this.readYear(fields) + const month = this.refineMonth(fields, year, overflow) + return this.queryIsoFields(year, month) + } + + monthDayFromFields(fields, overflow) { + let { month, monthCode, day } = fields + let year + + if (monthCode !== undefined) { + // year is guessed + const [monthCodeNumber, isLeapMonth] = parseMonthCode(monthCode) + ;([year, month] = this.queryYearMonthForMonthDay(monthCodeNumber, isLeapMonth, day)) + } else { + // year is required + year = this.readYear(fields) + month = this.refineMonth(fields, year, overflow) + } + + return this.queryIsoFields(year, month, day) + } + + fields(fieldNames) { + if (getAllowErasInFields(this) && fieldNames.indexOf('year') !== -1) { + return fieldNames.concat(eraYearFieldNames) + } + + return fieldNames + } + + mergeFields(baseFields, additionalFields) { + const merged = Object.assign({}, baseFields) + + removePropSet(merged, additionalFields, monthFieldNames) + + if (getAllowErasInFields(this)) { + removePropSet(merged, additionalFields, allYearFieldNames) + } + + if (getErasBeginMidYear(this)) { + removePropSet( + merged, + additionalFields, + monthDayFieldNames, + eraYearFieldNames, + ) + } + + return Object.assign(merged, additionalFields) + } + + // Internal Querying + // ----------------- + + queryIsoFields(year, month, day) { + return { isoYear: year, isoMonth: month, isoDay: day } + } + + queryDateStart(year, month, day) { + return isoToEpochMilli(year, month, day) + } + + queryYearMonthDay(isoDateFields) { + return [isoDateFields.isoYear, isoDateFields.isoMonth, isoDateFields.isoDay] + } + + queryYearMonthForMonthDay(monthCodeNumber /*, isLeapMonth, day */) { + return [isoEpochFirstLeapYear, monthCodeNumber] + } + + queryLeapMonth(year) { + // undefined + } + + // Algorithmic Computations + // ------------------------ + + dayOfYear(isoDateFields) { + const dayEpochMilliseconds = isoFieldsToEpochMilli({ + ...isoDateFields, + ...isoTimeFieldDefaults, + }) + const yearStartEpochMilliseconds = this.queryDateStart(this.year(isoDateFields)) + return diffDaysMilli(yearStartEpochMilliseconds, dayEpochMilliseconds) + } + + dateAdd(isoDateFields, durationFields, overflow) { + const { years, months, weeks, days } = durationFields + let ms + + if (years || months) { + let [year, month, day] = this.queryYearMonthDay(isoDateFields) + + if (years) { + year += years + month = constrainInt(month, 1, this.queryMonthsInYear(year), overflow) + } + + if (months) { + ([year, month] = this.addMonths(year, month, months)) + day = constrainInt(day, 1, this.queryDaysInMonth(year, month), overflow) + } + + ms = this.queryDateStart(year, months, day) + } else if (weeks || days) { + ms = isoFieldsToEpochMilli(isoDateFields) + } else { + return isoDateFields + } + + ms = addDaysMilli(ms, weeks * isoDaysInWeek + days) + return epochMilliToIsoFields(ms) + } + + dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { + if (largestUnit <= 'week') { // TODO + let weeks = 0 + let days = diffDaysMilli( + isoFieldsToEpochMilli(startIsoDateFields), + isoFieldsToEpochMilli(endIsoDateFields), + ) + + if (largestUnit === 'day') { // TODO + weeks = Math.trunc(days / isoDaysInWeek) + days %= isoDaysInWeek + } + + return { ...durationFieldDefaults, weeks, days } + } + + const yearMonthDayStart = this.queryYearMonthDay(startIsoDateFields) + const yearMonthDayEnd = this.queryYearMonthDay(endIsoDateFields) + let [years, months, days] = diffYearMonthDay(...yearMonthDayStart, ...yearMonthDayEnd, this) + + if (largestUnit === 'month') { // TODO + months = this.queryMonthsInYearSpan(yearMonthDayStart[0], years) + years = 0 + } + + return { ...durationFieldDefaults, years, months, days } + } + + // Field "Refining" (Reading & Constraining) + // ----------------------------------------- + + refineMonth(fields, year, overflow) { + return constrainInt( + this.readMonth(fields, year, overflow), + 1, + this.queryMonthsInYear(year), + overflow, + ) + } + + refineDay(fields, month, year, overflow) { + return constrainInt( + fields.day, // day guaranteed to exist because of required*Fields + 1, + this.queryDaysInMonth(year, month), + overflow, + ) + } + + // Field Reading + // ------------- + + readYear(fields) { + let { era, eraYear, year } = fields + + if (getAllowErasInFields(this) && era !== undefined && eraYear !== undefined) { + const yearByEra = this.readYearByEra(era, eraYear) + + if (year !== undefined && year !== yearByEra) { + throw new RangeError('The year and era/eraYear must agree') + } + + year = yearByEra + } else if (year === undefined) { + // Will never reach this point for ISO calendar system b/c of required*Fields + // TODO: is this true for monthday parsing? + throw new RangeError('Must specify year or era/eraYear') + } + + return year + } + + readYearByEra(era, eraYear) { + const eraOrigins = getEraOrigins(this.id) + if (eraOrigins === undefined) { + throw new RangeError('Does not accept era/eraYear') + } + + const eraOrigin = eraOrigins[era] + if (eraOrigin === undefined) { + throw new RangeError('Unknown era') + } + + return eraYearToYear(eraYear, eraOrigin) + } + + readMonth( + fields, + year, // optional if known that calendar doesn't support leap months + overflowForLeap = 'reject', + ) { + let { month, monthCode } = fields + + if (monthCode !== undefined) { + const monthByCode = this.readMonthByCode(monthCode, year, overflowForLeap) + + if (month !== undefined && month !== monthByCode) { + throw new RangeError('The month and monthCode do not agree') + } + + month = monthByCode + } else if (month === undefined) { + throw new RangeError('Must specify either month or monthCode') + } + + return month + } + + readMonthByCode( + monthCode, + year, // optional if known that calendar doesn't support leap months + overflowForLeap = 'reject', + ) { + const leapMonth = this.queryLeapMonth(year) + const [monthCodeNumber, isLeapMonth] = parseMonthCode(monthCode) + const month = refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) + + if (isLeapMonth) { + const leapYearMeta = leapYearMetas[getCalendarIdBase(this.id)] + if (leapYearMeta === undefined) { + throw new RangeError('Calendar system doesnt support leap months') + } + + if ( + leapYearMeta > 0 + ? month > leapYearMeta // max possible leap month + : month !== -leapYearMeta // (negative) constant leap month + ) { + throw new RangeError('Invalid leap-month month code') + } + + if (overflowForLeap === 'reject' && month !== leapMonth) { + throw new RangeError('Invalid leap-month month code') + } + } + + return month + } +} + +// Prototype Trickery +// ------------------ + +const isoYearQueryMethods = { + // sorted alphabetically, for predictable macros + queryDaysInYear: computeIsoDaysInYear, + queryIsLeapYear: computeIsoIsLeapYear, + queryMonthsInYear: computeIsoMonthsInYear, + queryMonthsInYearSpan: computeIsoMonthsInYearSpan, +} + +Object.assign(IsoCalendarImpl.prototype, { + dayOfWeek: computeIsoDayOfWeek, + weekOfYear: computeIsoWeekOfYear, + yearOfWeek: computeIsoYearOfWeek, + addMonths: addIsoMonths, + queryDaysInMonth: computeIsoDaysInMonth, + ...isoYearQueryMethods, +}) + +// year/month/day +dateFieldBasics.forEach((dateFieldName, i) => { + IsoCalendarImpl.prototype[dateFieldName] = function(isoDateFields) { + return isoDateFields[isoDateFieldNames[i]] + } +}) + +// daysInYear/inLeapYear/monthsInYear +Object.keys(isoYearQueryMethods).forEach((queryMethodName, i) => { + IsoCalendarImpl.prototype[yearStatNames[i]] = function(isoDateFields) { + return this[queryMethodName](this.year(isoDateFields)) + } +}) + +// Gregory Calendar +// ------------------------------------------------------------------------------------------------- + +class GregoryCalendarImpl extends IsoCalendarImpl { + era(isoDateFields) { + return computeGregoryEra(isoDateFields.isoYear) + } + + eraYear(isoDateFields) { + return computeGregoryEraYear(isoDateFields.isoYear) + } +} + +function computeGregoryEra(isoYear) { + return isoYear < 1 ? 'bce' : 'ce' +} + +function computeGregoryEraYear(isoYear) { + return isoYear < 1 ? -(isoYear - 1) : isoYear +} + +// Japanese Calendar +// ------------------------------------------------------------------------------------------------- + +class JapaneseCalendarImpl extends GregoryCalendarImpl { + isoDateFieldsToIntl = createJapaneseFieldCache() -export class CalendarImpl { era(isoDateFields) { - // return string + return this.isoDateFieldsToIntl(isoDateFields).era } eraYear(isoDateFields) { - // return number + return this.isoDateFieldsToIntl(isoDateFields).eraYear } +} + +// Intl Calendar +// ------------------------------------------------------------------------------------------------- - year(isoDateFields) { - // return number +class IntlCalendarImpl extends IsoCalendarImpl { + constructor(id) { + super(id) + + const epochMillisecondsToIntlFields = createEpochMillisecondsToIntlFields(id) + const [queryYear, yearAtEpoch] = createIntlMonthCache(epochMillisecondsToIntlFields) + + this.isoDateFieldsToIntl = createIntlFieldCache(epochMillisecondsToIntlFields) + this.queryYear = queryYear + this.yearAtEpoch = yearAtEpoch } month(isoDateFields) { - // return number + return this.queryYearMonthDay(isoDateFields)[1] } monthCode(isoDateFields) { - // return string + const [year, month] = this.queryYearMonthDay(isoDateFields) + const leapMonth = this.queryLeapMonth(year) + return formatMonthCode(month, leapMonth) + } + + addMonths(year, month, monthDelta) { + return addIntlMonths(year, month, monthDelta, this) } - day(isoDateFields) { - // return number + // Internal Querying + // ----------------- + + queryIsoFields(year, month, day) { + return epochMilliToIsoFields(this.queryDateStart(year, month, day)) } - dayOfWeek(isoDateFields) { - // return number + queryDaysInYear(year) { + const milli = this.queryDateStart(year) + const milliNext = this.queryDateStart(year + 1) + return diffDaysMilli(milli, milliNext) } - dayOfYear(isoDateFields) { - // return number + queryIsLeapYear(year) { + const daysPrev = this.queryDaysInYear(year - 1) + const days = this.queryDaysInYear(year) + const daysNext = this.queryDaysInYear(year + 1) + return days > daysPrev && days > daysNext } - weekOfYear(isoDateFields) { - // return number + queryYearMonthDay(isoDateFields) { + const intlFields = this.isoDateFieldsToIntl(isoDateFields) + const { year } = intlFields + const { monthStrToNum } = this.queryYear(year) + const month = monthStrToNum[intlFields.month] + return [year, month, intlFields.day] } - yearOfWeek(isoDateFields) { - // return number + queryYearMonthForMonthDay(monthCodeNumber, isLeapMonth, day) { + let year = this.yearAtEpoch + const endYear = year + 100 + + for (; year < endYear; year++) { + const leapMonth = this.queryLeapMonth(year) + const month = refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) + + if ( + (!isLeapMonth || month === leapMonth) && + day <= this.queryDaysInMonth(year, month) + ) { + return [year, month] + } + } + + throw new RangeError('Could not guess year') } - daysInWeek(isoDateFields) { - // return number + queryLeapMonth(year) { + const currentMonthStrs = this.queryMonthStrs(year) + const prevMonthStrs = this.queryMonthStrs(year - 1) + const prevLength = currentMonthStrs.length + + if (currentMonthStrs.length > prevLength) { + for (let i = 0; i < prevLength; i++) { + if (prevMonthStrs[i] !== currentMonthStrs[i]) { + return i + 1 // convert to 1-based + } + } + } } - daysInMonth(isoDateFields) { - // return number + queryMonthsInYear(year) { + const { monthEpochMilliseconds } = this.queryYear(year) + return monthEpochMilliseconds.length } - daysInYear(isoDateFields) { - // return number + queryMonthsInYearSpan(yearStart, yearDelta) { + return computeIntlMonthsInYearSpan(yearStart, yearDelta, this) } - monthsInYear(isoDateFields) { - // return number + queryDaysInMonth(year, month) { + const { monthEpochMilliseconds } = this.queryYear(year) + let nextMonth = month + 1 + let nextMonthEpochMilliseconds = monthEpochMilliseconds + + if (nextMonth > monthEpochMilliseconds.length) { + nextMonth = 1 + nextMonthEpochMilliseconds = this.queryYear(year + 1).monthEpochMilliseconds + } + + return diffDaysMilli( + monthEpochMilliseconds[month - 1], + nextMonthEpochMilliseconds[nextMonth - 1], + ) } - inLeapYear(isoDateFields) { - // return boolean + queryDateStart(year, month = 1, day = 1) { + return addDaysMilli( + this.queryYear(year).monthEpochMilliseconds[month - 1], + day - 1, + ) } - // should return IsoFields+calendar props! - dateFromFields(fields, overflow) { - // return isoDateFields + queryMonthStrs(year) { + return Object.keys(this.queryYear(year).monthStrToNum) } +} - // should return IsoFields+calendar props! - yearMonthFromFields(fields, overflow) { - // return isoDateFields. should be very similar to what's already in calendar.ts +// Prototype Trickery +// ------------------ + +// era/eraYear/year/day +allYearFieldNames.concat('day').forEach((dateFieldName) => { + IntlCalendarImpl.prototype[dateFieldName] = function(isoDateFields) { + return this.isoDateFieldsToIntl(isoDateFields)[dateFieldName] } +}) - // should return IsoFields+calendar props! - monthDayFromFields(fields, overflow) { - // return isoDateFields. should be very similar to what's already in calendar.ts +// CalendarImpl Querying +// ------------------------------------------------------------------------------------------------- + +const calendarImplClasses = { + [isoCalendarId]: IsoCalendarImpl, + [gregoryCalendarId]: GregoryCalendarImpl, + [japaneseCalendarId]: JapaneseCalendarImpl, +} + +const calendarImplCache = {} + +export function queryCalendarImpl(calendarId) { + const calendarIdBase = getCalendarIdBase(calendarId) + const CalendarImplClass = calendarImplClasses[calendarIdBase] + + if (CalendarImplClass) { + calendarId = calendarIdBase } - // should return IsoFields+calendar props! - dateAdd(isoDateFields, durationFields, overflow) { - // return isoDateFields + return calendarImplCache[calendarId] || ( + calendarImplCache[calendarId] = new (CalendarImplClass || IntlCalendarImpl)(calendarId) + ) +} + +// IntlFields Querying +// ------------------------------------------------------------------------------------------------- + +function createIntlFieldCache(epochMillisecondsToIntlFields) { + return buildWeakMapCache((isoDateFields) => { + const epochMilliseconds = isoFieldsToEpochMilli(isoDateFields) + return epochMillisecondsToIntlFields(epochMilliseconds) + }) +} + +function createJapaneseFieldCache() { + const epochMillisecondsToIntlFields = createEpochMillisecondsToIntlFields(japaneseCalendarId) + const primaryEraMilli = isoToEpochMilli(1868, 9, 8) + + return buildWeakMapCache((isoDateFields) => { + const epochMilliseconds = isoFieldsToEpochMilli(isoDateFields) + const intlFields = epochMillisecondsToIntlFields(epochMilliseconds) + + if (epochMilliseconds < primaryEraMilli) { + intlFields.era = computeGregoryEra(isoDateFields.isoYear) + intlFields.eraYear = computeGregoryEraYear(isoDateFields.isoYear) + } + + return intlFields + }) +} + +function createEpochMillisecondsToIntlFields(calendarId) { + const intlFormat = buildIntlFormat(calendarId) + + if (!isCalendarIdsRelated(calendarId, intlFormat.resolvedOptions().calendar)) { + throw new RangeError('Invalid calendar: ' + calendarId) } - dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { - // return durationFields + return (epochMilliseconds) => { + const intlParts = hashIntlFormatParts(intlFormat, epochMilliseconds) + return parseIntlParts(intlParts, calendarId) } +} - fields(fieldNames) { - // return string[] +function parseIntlParts(intlParts, calendarId) { + let year = parseInt(intlParts.relatedYear || intlParts.year) + let era + let eraYear + + if (intlParts.era) { + const eraOrigins = getEraOrigins(calendarId) + if (eraOrigins !== undefined) { + era = normalizeShortEra(intlParts.era) + year = eraYearToYear(eraYear = year, eraOrigins[era] || 0) + } + } + + return { + era, + eraYear, + year, + month: intlParts.month, // a short month string! + day: parseInt(intlParts.day), + } +} + +// Intl.DateTimeFormat Utils +// ------------------------------------------------------------------------------------------------- + +function buildIntlFormat(calendarId) { + return new Intl.DateTimeFormat('en-US', { + calendar: calendarId, + era: 'short', // 'narrow' is too terse for japanese months + year: 'numeric', + month: 'short', // easier to identify monthCodes + day: 'numeric', + timeZone: 'UTC', + }) +} + +function hashIntlFormatParts(intlFormat, epochMilliseconds) { + const parts = intlFormat.formatToParts(epochMilliseconds) + const hash = {} + + for (const part of parts) { + hash[part.type] = part.value + } + + return hash +} + +// Intl Month Cache +// ------------------------------------------------------------------------------------------------- + +function createIntlMonthCache(epochMillisecondsToIntlFields) { + const yearAtEpoch = epochMillisecondsToIntlFields(0) + const yearCorrection = yearAtEpoch - isoEpochOriginYear + const yearCache = {} + + function queryYear(year) { + return yearCache[year] || ( // TODO: reusable pattern for this? + yearCache[year] = buildYear(year) + ) + } + + function buildYear(year) { + let ms = isoToEpochMilli(year - yearCorrection) + let intlFields + const msReversed = [] + const monthStrsReversed = [] + + // move beyond current year + do { + ms = addDaysMilli(ms, 400) + } while ((intlFields = epochMillisecondsToIntlFields(ms)).year <= year) + + do { + // move to start-of-month + ms = addDaysMilli(ms, 1 - intlFields.day) + + // only record the epochMilli if current year + if (intlFields.year === year) { + msReversed.push(ms) + monthStrsReversed.push(intlFields.month) + } + + // move to last day of previous month + ms = addDaysMilli(ms, -1) + } while ((intlFields = epochMillisecondsToIntlFields(ms)).year >= year) + + return { + monthEpochMilliseconds: msReversed.reverse(), + monthStrToNum: monthStrsReversed.reverse().reduce(accumMonthStrToNum, {}), + } + } + + return [queryYear, yearAtEpoch] +} + +function accumMonthStrToNum(accum, monthStr, index) { + accum[monthStr] = index + 1 + return accum +} + +// Era Utils +// ------------------------------------------------------------------------------------------------- + +function getEraOrigins(calendarId) { + return eraOriginsByCalendarId[getCalendarIdBase(calendarId)] +} + +function eraYearToYear(eraYear, eraOrigin) { + // see the origin format in calendarConfig + return (eraOrigin + eraYear) * (numSign(eraOrigin) || 1) +} + +function normalizeShortEra(formattedEra) { + formattedEra = formattedEra + .normalize('NFD') // 'Shōwa' -> 'Showa' + .replace(/[^a-z0-9]/g, '') // 'Before R.O.C.' -> 'BeforeROC' + .toLowerCase() // 'BeforeROC' -> 'beforeroc' + + return eraRemaps[formattedEra] || formattedEra +} + +// Month Utils +// ------------------------------------------------------------------------------------------------- + +function parseMonthCode(monthCode) { + const m = monthCode.match(/^M(\d{2})(L?)$/) + if (!m) { + throw new RangeError('Invalid monthCode format') } - mergeFields(baseFieldNames, additionalFieldNames) { - // return object + return [ + parseInt(m[1]), // monthCodeNumber + Boolean(m[2]), + ] +} + +function refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) { + return monthCodeNumber + ( + (isLeapMonth || (leapMonth && monthCodeNumber >= leapMonth)) // TODO: double check this + ? 1 + : 0 + ) +} + +function formatMonthCode(month, leapMonth) { + return 'M' + twoDigit( + month - ( + (leapMonth && month >= leapMonth) // TODO: double check this + ? 1 + : 0 + ), + ) + ((month === leapMonth) ? 'L' : '') +} + +// Calendar ID Utils +// ------------------------------------------------------------------------------------------------- + +function isCalendarIdsRelated(calendarId0, calendarId1) { + return getCalendarIdBase(calendarId0) === getCalendarIdBase(calendarId1) +} + +function getCalendarIdBase(calendarId) { + return calendarId.split('-')[0] +} + +// ISO & Time +// ------------------------------------------------------------------------------------------------- + +export const isoMonthsInYear = 12 +export const isoDaysInWeek = 7 +const isoEpochOriginYear = 1970 +const isoEpochFirstLeapYear = 1972 + +export function computeIsoMonthsInYear(isoYear) { + return isoMonthsInYear +} + +function computeIsoDaysInMonth(isoYear, isoMonth) { + switch (isoMonth) { + case 2: + return computeIsoIsLeapYear(isoYear) ? 29 : 28 + case 4: + case 6: + case 9: + case 11: + return 30 } + return 31 +} + +function computeIsoDaysInYear(isoYear) { + return computeIsoIsLeapYear(isoYear) ? 365 : 366 +} + +function computeIsoIsLeapYear(isoYear) { + return isoYear % 4 === 0 && (isoYear % 100 !== 0 || isoYear % 400 === 0) +} + +function computeIsoDayOfWeek(isoDateFields) { + return generateLegacyDate(isoDateFields).getDay() + 1 +} + +function computeIsoWeekOfYear(isoDateFields) { +} + +function computeIsoYearOfWeek(isoDateFields) { +} + +function isoFieldsToEpochMilli(isoFields) { +} + +function isoToEpochMilli(isoYear, isoMonth, isoDate) { +} + +function diffDaysMilli(milli0, milli1) { +} + +function addDaysMilli() { +} + +function generateLegacyDate(isoDateTimeFields) { +} + +function epochMilliToIsoFields() { +} + +// General Utils +// ------------------------------------------------------------------------------------------------- + +function removePropSet( + targetObj, + testObj, + testPropNames, + deletablePropNames = testPropNames, +) { + for (const testPropName of testPropNames) { + if (testObj[testPropName] !== undefined) { + for (const deletablePropName of deletablePropNames) { + delete targetObj[deletablePropName] + } + break + } + } +} + +function twoDigit(num) { +} + +function buildWeakMapCache() { +} + +function constrainInt(subject, minIncl, maxIncl, overflow = 'reject') { + // maybe don't accept min? already vetted to be positive (or non-negative) integer +} + +function numSign() { } diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js new file mode 100644 index 00000000..679150d4 --- /dev/null +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -0,0 +1,94 @@ +import { createCalendar } from './calendar' +import { queryCalendarImpl } from './calendarImpl' +import { strictArrayOfStrings, toObject } from './cast' +import { createDuration } from './duration' +import { + createInternalClass, + createInternalGetter, + getInternals, + internalIdGetters, +} from './internalClass' +import { PlainDate, createPlainDate } from './plainDate' +import { PlainMonthDay } from './plainMonthDay' +import { PlainYearMonth } from './plainYearMonth' + +export function queryCalendarOps(calendarSlot) { + if (typeof calendarSlot === 'object') { + return new CalendarOpsAdapter(calendarSlot) + } + return queryCalendarImpl(calendarSlot) // string +} + +export function getCommonCalendarOps(internals0, internals1) { +} + +export function getPublicCalendar(internals) { + const { calendar } = internals + return getInternals(calendar) || // if CalendarOpsAdapter + createCalendar(calendar) // if CalendarImpl +} + +// Adapter +// ------------------------------------------------------------------------------------------------- + +const getStrictPlainDateInternals = createInternalGetter(PlainDate) + +/* +Must do output-validation on whatever internal Calendar returns +*/ +const CalendarOpsAdapter = createInternalClass(internalIdGetters, { + dateAdd(calendar, isoDateFields, durationFields, overflow) { + return getStrictPlainDateInternals( + calendar.dateAdd( + createPlainDate(isoDateFields), // hopefully won't look at blank .calendar + createDuration(durationFields), + { overflow }, + ), + ) + }, + + dateUntil(calendar, startIsoDateFields, endIsoDateFields, largestUnit) { + return getStrictPlainDateInternals( + calendar.dateUntil( + createPlainDate(startIsoDateFields), // hopefully won't look at blank .calendar + createPlainDate(endIsoDateFields), // hopefully won't look at blank .calendar + { largestUnit }, + ), + ) + }, + + /* + Fields should have already been plucked and refined from raw input + */ + dateFromFields(calendar, fields, overflow) { + return getStrictPlainDateInternals( // TODO: pluck away `calendar`Op + calendar.dateFromFields(fields, { overflow }), + ) + }, + + /* + Fields should have already been plucked and refined from raw input + */ + yearMonthFromFields(calendar, fields, overflow) { + return createInternalGetter(PlainYearMonth)( + calendar.yearMonthFromFields(fields, { overflow }), + ) + }, + + /* + Fields should have already been plucked and refined from raw input + */ + monthDayFromFields(calendar, fields, overflow) { + return createInternalGetter(PlainMonthDay)( + calendar.monthDayFields(calendar, fields, { overflow }), + ) + }, + + fields(calendar, fieldNames) { + return strictArrayOfStrings(calendar.fields(calendar, fieldNames)) + }, + + mergeFields(calendar, fields0, fields1) { + return toObject(calendar.mergeFields(fields0, fields1)) + }, +}) diff --git a/packages/temporal-polyfill/src/new/cast.js b/packages/temporal-polyfill/src/new/cast.js index 42d14a16..99dcfd1a 100644 --- a/packages/temporal-polyfill/src/new/cast.js +++ b/packages/temporal-polyfill/src/new/cast.js @@ -1,11 +1,19 @@ +export function strictNumber(input) { + +} + export function strictInstanceOf(obj, Class) { } -export function strictArrayOfStrings(obj) { +export function strictArrayOfStrings(obj) { // rethink } -export function strictArrayOfType(obj) { +export function strictArrayOfType(obj) { // used? +} + +export function strictArray() { + } export function toObject() { diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index d37583aa..45f98910 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -1,12 +1,9 @@ import { - dateFieldsToIso, + getRequiredDateFields, + getRequiredMonthDayFields, + getRequiredYearMonthFields, isoCalendarId, - mergeFields, - monthDayFieldsToIso, - toCalendarSlot, - transformFieldNames, - yearMonthFieldsToIso, -} from './calendarAdapter' +} from './calendarConfig' import { dateFieldNames, dateTimeFieldNames, @@ -18,30 +15,26 @@ import { yearMonthBasicNames, yearMonthFieldNames, } from './calendarFields' +import { queryCalendarOps } from './calendarOps' import { toInteger, toObject } from './cast' import { durationFieldDefaults, durationFieldRefiners, refineDurationFields, } from './durationFields' +import { getInternals } from './internalClass' import { - regulateIsoDateTimeFields, - regulateIsoTimeFields, + constrainIsoDateTimeFields, + constrainIsoTimeFields, } from './isoFields' import { isObjectLike, pluckProps, removeDuplicateStrings } from './obj' -import { toDisambiguation, toOffsetHandling, toOverflowOptions } from './options' +import { optionsToOverflow, toDisambiguation, toOffsetHandling, toOverflowOptions } from './options' import { parseOffsetNanoseconds } from './parse' import { createPlainDate } from './plainDate' -import { createPlainDateTime } from './plainDateTime' import { createPlainMonthDay } from './plainMonthDay' import { createPlainTime } from './plainTime' import { createPlainYearMonth } from './plainYearMonth' -import { getInternals } from './temporalClass' -import { - computeIsoFieldEpochNanoseconds, - plainDateTimeToEpochNanoseconds, - toTimeZoneSlot, -} from './timeZoneProtocol' +import { computeIsoFieldEpochNanoseconds, getBestInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' // Duration @@ -55,19 +48,21 @@ export function bagToDurationFields(bag) { // ------------------------------------------------------------------------------------------------- export function bagToZonedDateTimeInternals(bag, options) { - const [calendar, fields] = refineBag( + const calendarOps = extractCalendarOpsFromBag(bag) + const fields = refineBag( + calendarOps, bag, dateTimeFieldNames, - ['offset'], + getRequiredDateFields(calendarOps).concat(['offset']), ['timeZone'], ) - const timeZone = toTimeZoneSlot(fields.timeZone) - const isoFields = dateFieldsToIso(calendar, fields, options) // overflow options + const timeZone = queryTimeZoneOps(fields.timeZone) + const isoFields = calendarOps.dateFromFields(fields, optionsToOverflow(options)) const epochNanoseconds = computeIsoFieldEpochNanoseconds( - { ...isoFields, ...timeFieldsToIso(fields) }, timeZone, + { ...isoFields, ...timeFieldsToIso(fields) }, fields.offset !== undefined ? parseOffsetNanoseconds(fields.offset) : undefined, false, // z? toOffsetHandling(options), @@ -78,18 +73,18 @@ export function bagToZonedDateTimeInternals(bag, options) { return { epochNanoseconds, timeZone, - calendar, + calendar: calendarOps, } } export function zonedDateTimeWithBag(zonedDateTime, bag, options) { - const { timeZone } = getInternals(zonedDateTime) - const [calendar, fields] = mergeBag(zonedDateTime, bag, dateTimeFieldNames, ['offset']) - const isoFields = dateFieldsToIso(calendar, fields, options) + const { calendar, timeZone } = getInternals(zonedDateTime) + const fields = mergeBag(calendar, zonedDateTime, bag, dateTimeFieldNames, ['offset']) + const isoFields = calendar.dateFromFields(fields, optionsToOverflow(options)) const epochNanoseconds = computeIsoFieldEpochNanoseconds( - { ...isoFields, ...timeFieldsToIso(fields) }, timeZone, + { ...isoFields, ...timeFieldsToIso(fields) }, parseOffsetNanoseconds(fields.offset), false, // z? toOffsetHandling(options), @@ -105,21 +100,16 @@ export function zonedDateTimeWithBag(zonedDateTime, bag, options) { } export function bagToPlainMonthDayInternals(bag, options) { - let calendar = extractCalendar(bag) + let calendar = extractCalendarFieldFromBag(bag) let calendarAbsent = !calendar if (calendarAbsent) { calendar = bag.calendar calendarAbsent = calendar === undefined - - if (calendarAbsent) { - calendar = isoCalendarId - } else { - calendar = toCalendarSlot(calendar) - } + calendar = queryCalendarOps(calendarAbsent ? isoCalendarId : calendar) } - const fieldNames = transformFieldNames(calendar, ['day', 'month', 'monthCode', 'year']) + const fieldNames = calendar.fields(dateFieldNames) const fields = prepareFields(bag, fieldNames, []) // Callers who omit the calendar are not writing calendar-independent @@ -134,31 +124,36 @@ export function bagToPlainMonthDayInternals(bag, options) { fields.year = 1972 } - return monthDayFieldsToIso(calendar, fields, options) + return calendar.monthDayFromFields(calendar, fields, optionsToOverflow(options)) } export function plainMonthDayWithBag(plainMonthDay, bag, options) { - return monthDayFieldsToIso( - ...mergeBag(plainMonthDay, bag, ['month', 'monthCode', 'year']), - options, - ) + const { calendar } = getInternals(plainMonthDay) + const fields = mergeBag(calendar, plainMonthDay, bag, dateFieldNames) + return calendar.monthDayFromFields(fields, optionsToOverflow(options)) } export function bagToPlainYearMonthInternals(bag, options) { - return yearMonthFieldsToIso(...refineBag(bag, yearMonthFieldNames), options) + const calendarOps = extractCalendarOpsFromBag(bag) + const fields = refineBag( + calendarOps, + bag, + yearMonthFieldNames, + getRequiredYearMonthFields(calendarOps), + ) + return calendarOps.yearMonthFromFields(fields, optionsToOverflow(options)) } export function plainYearMonthWithBag(plainYearMonth, bag, options) { - return yearMonthFieldsToIso( - ...mergeBag(plainYearMonth, bag, yearMonthFieldNames), - options, - ) + const { calendar } = getInternals(plainYearMonth) + const fields = mergeBag(calendar, plainYearMonth, bag, yearMonthFieldNames) + return calendar.yearMonthFromFields(fields, optionsToOverflow(options)) } export function bagToPlainTimeInternals(bag, options) { const overflowOpt = toOverflowOptions(options) // TODO: single opt! - return regulateIsoTimeFields( + return constrainIsoTimeFields( timeFieldsToIso( prepareFields(bag, timeFieldNames, []), ), @@ -175,33 +170,57 @@ export function plainTimeWithBag(plainTime, bag, options) { ...additionalFields, }) return createPlainTime( - regulateIsoTimeFields(newInternals, overflowOpt), + constrainIsoTimeFields(newInternals, overflowOpt), ) } export function bagToPlainDateSlots(bag, options) { - return dateFieldsToIso(...refineBag(bag, dateFieldNames), options) + const calendarOps = extractCalendarOpsFromBag(bag) + const fields = refineBag( + calendarOps, + bag, + dateFieldNames, + getRequiredDateFields(calendarOps), + ) + + return { + calendar: calendarOps, + ...calendarOps.dateFromFields(fields, optionsToOverflow(options)), + } } export function plainDateWithBag(plainDate, bag, options) { - return dateFieldsToIso(...mergeBag(plainDate, bag, dateFieldNames), options) + const { calendar } = getInternals(plainDate) + const fields = mergeBag(calendar, plainDate, bag, dateFieldNames) + + return { + calendar, + ...calendar.dateFromFields(fields, optionsToOverflow(options)), + } } export function bagToPlainDateTimeInternals(bag, options) { - const [calendar, fields] = refineBag(bag, dateTimeFieldNames) - const plainDateTimeInternals = dateFieldsToIso(calendar, fields, options) + const calendarOps = extractCalendarOpsFromBag(bag) + const fields = refineBag( + calendarOps, + bag, + dateTimeFieldNames, + getRequiredDateFields(calendarOps), + ) + const plainDateTimeInternals = calendarOps.dateFromFields(fields, optionsToOverflow(options)) - return regulateIsoDateTimeFields({ + return constrainIsoDateTimeFields({ ...plainDateTimeInternals, ...timeFieldsToIso(fields), }) } export function plainDateTimeWithBag(plainDate, bag, options) { - const [calendar, fields] = mergeBag(plainDate, bag, dateTimeFieldNames) - const plainDateTimeInternals = dateFieldsToIso(calendar, fields, options) + const { calendar } = getInternals(plainDate) + const fields = mergeBag(calendar, plainDate, bag, dateTimeFieldNames) + const plainDateTimeInternals = calendar.dateFromFields(fields, optionsToOverflow(options)) - return regulateIsoDateTimeFields({ + return constrainIsoDateTimeFields({ ...plainDateTimeInternals, ...timeFieldsToIso(fields), }) @@ -213,13 +232,27 @@ export function plainDateTimeWithBag(plainDate, bag, options) { export function dateToPlainYearMonth( dateObj, // PlainDate/PlainDateTime/ZonedDateTime ) { - return createPlainYearMonth(yearMonthFieldsToIso(...pluckFields(dateObj, yearMonthBasicNames))) + const calendarOps = getInternals(dateObj).calendar + const fields = refineBag( + calendarOps, + dateObj, + yearMonthBasicNames, + getRequiredYearMonthFields(calendarOps), + ) + return createPlainYearMonth(calendarOps.yearMonthFromFields(fields, 'constrain')) } export function dateToPlainMonthDay( dateObj, // PlainDate/PlainDateTime/ZonedDateTime ) { - return createPlainMonthDay(monthDayFieldsToIso(...pluckFields(dateObj, monthDayBasicNames))) + const calendarOps = getInternals(dateObj).calendar + const fields = refineBag( + calendarOps, + dateObj, + monthDayBasicNames, + getRequiredMonthDayFields(calendarOps), + ) + return createPlainMonthDay(calendarOps.monthDayFromFields(fields, 'constrain')) } // to PlainDate @@ -230,21 +263,32 @@ export function plainYearMonthToPlainDateFirst(plainYearMonth) { } export function plainYearMonthToPlainDate(plainYearMonth, bag) { - return mergeToPlainDate(plainYearMonth, yearMonthBasicNames, bag, ['day']) + return mergeToPlainDate( + plainYearMonth, + yearMonthBasicNames, // what to extract from plainYearMonth + bag, + ['day'], // what to extract from bag + ) } export function plainMonthDayToPlainDate(plainMonthDay, bag) { - return mergeToPlainDate(plainMonthDay, monthDayBasicNames, bag, ['year']) + return mergeToPlainDate( + plainMonthDay, + monthDayBasicNames, // what to extract from plainMonthDay + bag, + ['year'], // what to extract from bag + ) } // to PlainDateTime // ------------------------------------------------------------------------------------------------- // bad name now. should have something with 'slots' +// should return calendar/timezone??? needed in many places export function zonedDateTimeInternalsToIso(internals) { // use timeZone2.js /* - return instantToPlainDateTime( + return instantToPlainDateTime222( internals.timeZone, internals.calendar, createInstant(internals.epochNanoseconds), @@ -255,15 +299,15 @@ export function zonedDateTimeInternalsToIso(internals) { // to ZonedDateTime // ------------------------------------------------------------------------------------------------- -export function createZonedDateTimeConverter(getRequiredInternals) { +export function createZonedDateTimeConverter(getAdditionalIsoFields) { return (internals, options) => { const refinedOptions = toObject(options) // required!!! - const epochNanoseconds = plainDateTimeToEpochNanoseconds( - refinedOptions.timeZone, - createPlainDateTime({ + const epochNanoseconds = getBestInstantFor( + internals.timeZone, + { ...internals, - ...getRequiredInternals(refinedOptions), - }), + ...getAdditionalIsoFields(refinedOptions), + }, ) return createZonedDateTime({ @@ -277,34 +321,34 @@ export function createZonedDateTimeConverter(getRequiredInternals) { // Calendar-field processing // ------------------------------------------------------------------------------------------------- -export function refineBag( +function refineBag( + calendarOps, bag, validFieldNames, requiredFieldNames = [], forcedValidFieldNames = [], ) { - const calendar = extractCalendar(bag) || isoCalendarId - const fieldNames = transformFieldNames(calendar, validFieldNames) + const fieldNames = calendarOps.fields(validFieldNames) .concat(requiredFieldNames, forcedValidFieldNames) const fields = prepareFields(bag, fieldNames, requiredFieldNames) - return [calendar, fields] + return fields } -export function mergeBag( +function mergeBag( + calendarOps, obj, bag, validFieldNames, requiredFieldNames = [], ) { // TODO: check bag doesn't have timezone/calendar - const { calendar } = getInternals(obj) - const fieldNames = transformFieldNames(calendar, validFieldNames) + const fieldNames = calendarOps.fields(validFieldNames) fieldNames.push(...requiredFieldNames) let fields = prepareFields(obj, fieldNames, requiredFieldNames) const additionalFields = prepareFields(bag, fieldNames) // partial - fields = mergeFields(calendar, fields, additionalFields) + fields = calendarOps.mergeFields(fields, additionalFields) fields = prepareFields(fields, fieldNames, requiredFieldNames) - return [calendar, fields] + return [fields] } function mergeToPlainDate( @@ -314,20 +358,17 @@ function mergeToPlainDate( otherFieldNames, ) { const { calendar } = getInternals(obj) - const receiverFieldNames = transformFieldNames(calendar, objFieldNames) + const receiverFieldNames = calendar.fields(objFieldNames) const receiverFields = pluckProps(obj, receiverFieldNames) - const inputFieldNames = transformFieldNames(calendar, otherFieldNames) - const inputFields = prepareFields(other, inputFieldNames, []) + const inputFieldNames = calendar.fields(otherFieldNames) + const inputFields = prepareFields(other, inputFieldNames, getRequiredDateFields(calendar)) const mergedFieldNames = removeDuplicateStrings(receiverFieldNames.concat(inputFieldNames)) - let mergedFields = mergeFields(calendar, receiverFields, inputFields) + let mergedFields = calendar.mergeFields(receiverFields, inputFields) mergedFields = prepareFields(mergedFields, mergedFieldNames, []) - return createPlainDate(mergedFields, { overflow: 'reject' }) -} - -function pluckFields(obj, validFieldNames) { - const { calendar } = getInternals(obj) - const fieldNames = transformFieldNames(calendar, validFieldNames) - return [calendar, pluckProps(obj, fieldNames)] + return createPlainDate({ + ...calendar.dateFromFields(mergedFields, 'reject'), + calendar, + }) } // ahhh @@ -386,10 +427,11 @@ export function isStringCastsEqual(obj0, obj1) { String(obj0) === String(obj1) } -/* -Won't default to iso -*/ -function extractCalendar(bag) { +function extractCalendarOpsFromBag(bag) { + return queryCalendarOps(extractCalendarFieldFromBag(bag) || isoCalendarId) +} + +function extractCalendarFieldFromBag(bag) { const internals = getInternals(bag) const { calendar } = internals || {} if (calendar) { @@ -397,7 +439,7 @@ function extractCalendar(bag) { } ({ calendar }) = bag if (calendar) { - return toCalendarSlot(calendar) + return queryCalendarOps(calendar) } } diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index bdb09ce6..2893c521 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -1,3 +1,4 @@ +import { isoMonthsInYear } from './calendarImpl' import { addDaysToIsoFields, pluckIsoTimeFields } from './isoFields' import { compareLargeInts } from './largeInt' import { nanosecondsInDay } from './nanoseconds' @@ -24,7 +25,7 @@ export function diffEpochNanoseconds( ) } -export function diffZoneEpochNanoseconds( +export function diffZonedEpochNanoseconds( startEpochNanoseconds, endEpochNanoseconds, timeZone, @@ -65,12 +66,7 @@ export function diffZoneEpochNanoseconds( midEpochNanoseconds = isoToZoneEpochNanoseconds(midIsoFields) } - const dateDiff = diffExactDates( - startIsoFields, - midIsoFields, - calendar, - largestUnit, - ) + const dateDiff = calendar.dateUntil(startIsoFields, midIsoFields, largestUnit) const timeDiff = diffExactLargeNanoseconds( endEpochNanoseconds.subtract(midEpochNanoseconds), 'hours', // largestUnit (default?) @@ -129,12 +125,7 @@ export function diffDateTimes( timeNanosecondDiff += nanosecondsInDay } - const dateDiff = diffExactDates( - midIsoFields, - endIsoFields, - calendar, - largestUnit, - ) + const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnit) const timeDiff = nanosecondsToTimeDuration( timeNanosecondDiff, 'hours', // largestUnit (default?) @@ -178,12 +169,7 @@ export function diffDates( ) } - const dateDiff = diffExactDates( - startIsoDateFields, - endIsoDateFields, - calendar, - largestUnit, - ) + const dateDiff = calendar.dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) return roundRelativeDuration( dateDiff, @@ -204,6 +190,75 @@ export function diffTimes() { } +// CalendarImpl Utils +// ------------------------------------------------------------------------------------------------- + +export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calendarImpl) { + let yearDiff + let monthsInYear1 + let monthDiff + let daysInMonth1 + let dayDiff + + function updateYearMonth() { + yearDiff = year1 - year0 + monthsInYear1 = calendarImpl.monthsInYear(year1) + monthDiff = month1 - Math.min(month0, monthsInYear1) + } + + function updateYearMonthDay() { + updateYearMonth() + daysInMonth1 = calendarImpl.daysInMonth(year1, month1) + dayDiff = day1 - Math.min(day0, daysInMonth1) + } + + updateYearMonthDay() + const daySign = numberSign(dayDiff) + const sign = numberSign(yearDiff) || numberSign(monthDiff) || daySign + + if (sign) { + // overshooting day? - correct by moving to penultimate month + if (daySign && daySign !== sign) { + const oldDaysInMonth1 = daysInMonth1 + ;([year1, month1] = calendarImpl.addMonths(year1, month1, -sign)) + updateYearMonthDay() + dayDiff += sign < 0 // correct with days-in-month further in past + ? oldDaysInMonth1 // correcting from past -> future + : daysInMonth1 // correcting from future -> past + } + + // overshooting month? - correct by moving to penultimate year + const monthSign = numberSign(monthDiff) + if (monthSign && monthSign !== sign) { + const oldMonthsInYear1 = monthsInYear1 + year1 -= sign + updateYearMonth() + monthDiff += sign < 0 // correct with months-in-year further in past + ? oldMonthsInYear1 // correcting from past -> future + : monthsInYear1 // correcting from future -> past + } + } + + return [yearDiff, monthDiff, dayDiff] +} + +export function computeIsoMonthsInYearSpan(isoYearStart, yearDelta) { + return yearDelta * isoMonthsInYear +} + +export function computeIntlMonthsInYearSpan(yearStart, yearDelta, calendarImpl) { + const yearEnd = yearStart + yearDelta + const yearSign = numberSign(yearDelta) + const yearCorrection = yearSign < 0 ? -1 : 0 + let months = 0 + + for (let year = 0; year !== yearEnd; year += yearSign) { + months += calendarImpl.queryMonthsInYear(year + yearCorrection) + } + + return months +} + // Public Duration Stuff // ------------------------------------------------------------------------------------------------- @@ -229,15 +284,6 @@ export function computeDurationTotal( // Exact Diffing // ------------------------------------------------------------------------------------------------- -function diffExactDates( - startIsoDateFields, - endIsoDateFields, - calendar, - largestUnit, -) { - // defers to CalendarProtocol -} - function diffExactLargeNanoseconds( nanoseconds, largestUnit, diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index c24b9272..b9606159 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -5,8 +5,10 @@ import { negateDurationFields, refineDurationFields, } from './durationFields' +import { neverValueOf } from './internalClass' +import { noop } from './lang' import { stringToDurationFields } from './parse' -import { createTemporalClass, neverValueOf } from './temporalClass' +import { createTemporalClass } from './temporalClass' export const [ Duration, @@ -18,6 +20,7 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals ( years = 0, months = 0, @@ -43,10 +46,18 @@ export const [ nanoseconds, }) }, - {}, + + // massageOtherInternals + noop, + + // bagToInternals bagToDurationFields, + + // stringToInternals stringToDurationFields, - undefined, + + // handleUnusedOptions + noop, // Getters // ----------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 33742f97..e2d5e2b9 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -41,6 +41,7 @@ export const durationTimeFieldDefaults = remapProps( export const durationFieldDefaults = { // does not include 'sign' years: 0, months: 0, + // TODO: weeks!!! days: 0, ...durationTimeFieldDefaults, } diff --git a/packages/temporal-polyfill/src/new/format.js b/packages/temporal-polyfill/src/new/format.js index 4a48fc70..eafc5b9f 100644 --- a/packages/temporal-polyfill/src/new/format.js +++ b/packages/temporal-polyfill/src/new/format.js @@ -1,4 +1,4 @@ -import { isoCalendarId } from './calendarAdapter' +import { isoCalendarId } from './calendarConfig' import { toCalendarNameOption } from './options' export function formatPossibleDate(internals, options, formatSimple) { diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 736b3225..18b4b15a 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -1,4 +1,5 @@ -import { isoCalendarId, toCalendarSlot } from './calendarAdapter' +import { isoCalendarId } from './calendarConfig' +import { queryCalendarOps } from './calendarOps' import { toObject } from './cast' import { diffEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' @@ -9,6 +10,8 @@ import { formatOffsetNanoseconds, formatTimeZone, } from './format' +import { neverValueOf } from './internalClass' +import { noop } from './lang' import { compareLargeInts, createLargeInt, toLargeInt } from './largeInt' import { moveEpochNanoseconds } from './move' import { @@ -19,13 +22,9 @@ import { regulateEpochNanoseconds, } from './nanoseconds' import { roundEpochNanoseconds } from './round' -import { createTemporalClass, neverValueOf } from './temporalClass' -import { - instantToOffsetNanoseconds, - instantToPlainDateTimeInternals, - toTimeZoneSlot, -} from './timeZoneProtocol' -import { createZonedDateTime } from './zonedDateTime' +import { createTemporalClass } from './temporalClass' +import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' +import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' export const [ Instant, @@ -37,15 +36,26 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals (epochNanoseconds) => { return regulateEpochNanoseconds(toLargeInt(epochNanoseconds)) }, - { - ZonedDateTime: (internals) => internals.epochNanoseconds, + + // massageOtherInternals + (arg, argInternals) => { + if (arg instanceof ZonedDateTime) { + return argInternals.epochNanoseconds + } }, - undefined, // bagToInternals + + // bagToInternals + noop, + + // stringToInternals stringToEpochNanoseconds, - undefined, // parseOptions + + // handleUnusedOptions + noop, // Getters // ----------------------------------------------------------------------------------------------- @@ -59,7 +69,7 @@ export const [ toZonedDateTimeISO(epochNanoseconds, timeZoneArg) { createZonedDateTime({ epochNanoseconds, - timeZone: toTimeZoneSlot(timeZoneArg), + timeZone: queryTimeZoneOps(timeZoneArg), calendar: isoCalendarId, }) }, @@ -69,8 +79,8 @@ export const [ return createZonedDateTime({ epochNanoseconds, - timeZone: toTimeZoneSlot(refinedObj.timeZone), - calendar: toCalendarSlot(refinedObj.calendar), + timeZone: queryTimeZoneOps(refinedObj.timeZone), + calendar: queryCalendarOps(refinedObj.calendar), }) }, @@ -123,18 +133,12 @@ export const [ const refinedOptions = toObject(options) // TODO: make optional // ^important for destructuring options because used once for rounding, second for formatting - const calendar = refinedOptions.calendar !== undefined - ? toCalendarSlot(refinedOptions.calendar) - : isoCalendarId - - const timeZone = refinedOptions.timeZone !== undefined - ? toTimeZoneSlot(refinedOptions.timeZone) - : 'UTC' + const calendar = queryCalendarOps(refinedOptions.calendar || isoCalendarId) + const timeZone = queryTimeZoneOps(refinedOptions.timeZone || utcTimeZoneId) epochNanoseconds = roundEpochNanoseconds(epochNanoseconds, refinedOptions) - const instant = createInstant(epochNanoseconds) - const offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) - const isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) + const isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) return formatIsoDateTimeFields(isoFields, refinedOptions) + formatOffsetNanoseconds(offsetNanoseconds) + @@ -174,3 +178,6 @@ export const [ function stringToEpochNanoseconds(str) { // TODO } + +function epochNanosecondsToIso() { +} diff --git a/packages/temporal-polyfill/src/new/internalClass.js b/packages/temporal-polyfill/src/new/internalClass.js new file mode 100644 index 00000000..86ec4f58 --- /dev/null +++ b/packages/temporal-polyfill/src/new/internalClass.js @@ -0,0 +1,60 @@ +import { mapHash } from '../utils/obj' +import { strictInstanceOf } from './cast' +import { identityFunc } from './lang' +import { createGetterDescriptors, createPropDescriptors } from './obj' + +export const internalsMap = new WeakMap() +export const getInternals = internalsMap.get.bind(internalsMap) + +// TODO: rename to 'wrapper' class? + +export function createInternalClass( + getters, + methods, + constructorToInternals = identityFunc, + extraPrototypeDescriptors = {}, + staticMembers = {}, +) { + function InternalObj(...args) { + internalsMap.set(this, constructorToInternals(...args)) + } + + function curryMethod(method) { + return /* Object.setPrototypeOf( */ function(...args) { + if (!(this instanceof InternalObj)) { + throw new TypeError('Invalid receiver') + } + return method.call(this, getInternals(this), ...args) + } /* , null) */ + } + + Object.defineProperties(InternalObj.prototype, { + ...createGetterDescriptors(mapHash(getters, curryMethod)), + ...createPropDescriptors(mapHash(methods, curryMethod)), + ...extraPrototypeDescriptors, + }) + + Object.defineProperties(InternalObj, createPropDescriptors(staticMembers)) + + return InternalObj +} + +export function neverValueOf() { + throw new TypeError('Cannot convert object using valueOf') +} + +export function transformInternalMethod(transformRes, methodName) { + return (impl, ...args) => { + return transformRes(impl[methodName](...args)) + } +} + +export function returnId(internals) { + return internals.id +} + +export const internalIdGetters = { id: returnId } + +export function createInternalGetter(Class) { + return (res) => getInternals(strictInstanceOf(Class), res) +} diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index ae39fe86..ef00493c 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -1,10 +1,10 @@ -import { toCalendarSlot } from './calendarAdapter' +import { queryCalendarOps } from './calendarOps' import { toIntegerThrowOnInfinity, toIntegerWithoutRounding, toPositiveInteger } from './cast' import { pluckProps } from './obj' export const isoDateSlotRefiners = { // sorted alphabetically - calendar: toCalendarSlot, + calendar: queryCalendarOps, // prolly kill this!!! isoDay: toPositiveInteger, isoMonth: toPositiveInteger, isoYear: toIntegerWithoutRounding, @@ -27,6 +27,7 @@ export const isoDateTimeSlotRefiners = { } export const isoDateSlotNames = Object.keys(isoDateSlotRefiners) +export const isoDateFieldNames = isoDateSlotNames.slice(1) export const isoTimeFieldNames = Object.keys(isoTimeFieldRefiners) // no calendar export const isoDateTimeSlotNames = Object.keys(isoDateTimeSlotRefiners).sort() @@ -39,6 +40,18 @@ export const isoTimeFieldDefaults = { isoSecond: 0, } +export function generatePublicIsoDateFields(internals) { + const publicFields = pluckIsoDateSlots(internals) + publicFields.calendar = publicFields.calendar.id // correct? + return publicFields +} + +export function generatePublicIsoDateTimeFields(internals) { + const publicFields = pluckIsoDateTimeSlots(internals) + publicFields.calendar = publicFields.calendar.id // correct? + return publicFields +} + export function pluckIsoDateTimeSlots(isoFields) { return pluckProps(isoFields, isoDateTimeSlotNames) } @@ -47,6 +60,10 @@ export function pluckIsoDateSlots(isoFields) { return pluckProps(isoFields, isoDateSlotNames) } +export function pluckIsoDateFields(isoFields) { + return pluckProps(isoFields, isoDateFieldNames) +} + export function pluckIsoTimeFields(isoFields) { return pluckProps(isoFields, isoTimeFieldNames) } @@ -59,18 +76,15 @@ export function compareIsoTimeFields() { // uses conversion to milliseconds } -// TODO: make distinction between "regulate" (which considers overflow) and "reject" (throws error) - -export function regulateIsoDateTimeFields() { - +export function constrainIsoDateTimeFields(isoDateTimeFields, overflow = 'reject') { + // ahhhh! calendar gets passed in here!!! } -export function regulateIsoDateFields() { - +export function constrainIsoDateFields(isoDateFields, overflow = 'reject') { + // ahhhh! calendar gets passed in here!!! } -export function regulateIsoTimeFields() { - +export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { } export function addDaysToIsoFields() { diff --git a/packages/temporal-polyfill/src/new/lang.js b/packages/temporal-polyfill/src/new/lang.js new file mode 100644 index 00000000..712cd027 --- /dev/null +++ b/packages/temporal-polyfill/src/new/lang.js @@ -0,0 +1,11 @@ + +export function identityFunc(thing) { + return thing +} + +export function noop() { +} + +export function positiveModulo(n, max) { + return (n % max + max) % max +} diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 1f46249d..3faf70ac 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -1,32 +1,22 @@ -import { moveDate } from './calendarAdapter' -import { - dateToPlainYearMonth, - plainYearMonthToPlainDate, -} from './convert' +import { isoMonthsInYear } from './calendarImpl' import { durationHasDateParts, durationTimeFieldDefaults, durationTimeFieldsToIso, } from './durationFields' -import { createInstant } from './instant' import { isoTimeFieldsToNanoseconds, nanosecondsToIsoTimeFields } from './nanoseconds' -import { createPlainDateTime } from './plainDateTime' -import { createPlainTime } from './plainTime' -import { getInternals } from './temporalClass' -import { - instantToPlainDateTimeInternals, - plainDateTimeToEpochNanoseconds, -} from './timeZoneProtocol' -/* -!!! all sorts of confusion in this file about internals/plain -*/ - -// High-level objects -// ------------------------------------------------------------------------------------------------- +export function moveEpochNanoseconds(epochNanoseconds, durationFields) { + return epochNanoseconds.add(onlyDurationTimeFieldsToIso(durationFields)) +} -export function moveZonedDateTimeInternals(internals, durationFields, options) { - let { epochNanoseconds, calendar, timeZone } = internals +export function moveZonedEpochNanoseconds( + epochNanoseconds, + durationFields, + calendar, + timeZone, + overflowHandling, +) { const durationTimeNanoseconds = isoTimeFieldsToNanoseconds( durationTimeFieldsToIso(durationFields), ) @@ -34,103 +24,128 @@ export function moveZonedDateTimeInternals(internals, durationFields, options) { if (!durationHasDateParts(durationFields)) { epochNanoseconds = epochNanoseconds.add(durationTimeNanoseconds) } else { - const plainDateTimeInternals = instantToPlainDateTimeInternals( - timeZone, - calendar, - createInstant(epochNanoseconds), - ) - const movedPlainDateInternals = moveDate( - calendar, - plainDateTimeInternals, + const isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds, timeZone) + const movedIsoDateFields = calendar.dateAdd( + isoDateTimeFields, { ...durationFields, // date parts ...durationTimeFieldDefaults, // time parts }, - options, + overflowHandling, ) - const movedPlainDateTime = createPlainDateTime({ - ...plainDateTimeInternals, // time parts - ...movedPlainDateInternals, // date parts - }) - epochNanoseconds = plainDateTimeToEpochNanoseconds(timeZone, movedPlainDateTime, 'compatible') + const movedIsoDateTimeFields = { + ...isoDateTimeFields, // time parts + ...movedIsoDateFields, // date parts + } + epochNanoseconds = isoToEpochNanoseconds(movedIsoDateTimeFields, timeZone) .add(durationTimeNanoseconds) } - return { - epochNanoseconds, - timeZone, - calendar, - } -} - -export function movePlainYearMonth(plainYearMonth, durationFields, options) { - const { calendar } = getInternals(plainYearMonth) - let plainDate = plainYearMonthToPlainDate(plainYearMonth, { - day: durationFields.sign < 0 - ? calendar.daysInMonth(plainYearMonth) - : 1, - }) - plainDate = moveDate(calendar, plainDate, durationFields, options) - return dateToPlainYearMonth(plainDate) + return epochNanoseconds } -export function movePlainDateTime(plainDateTime, durationFields, options) { - const internals = getInternals(plainDateTime) +export function moveDateTime( + isoDateTimeFields, + durationFields, + calendar, + overflowHandling, +) { const [movedIsoTimeFields, dayDelta] = addIsoTimeFields( - internals, + isoDateTimeFields, durationTimeFieldsToIso(durationFields), ) - const movedPlainDate = moveDate( - internals.calendar, - internals, // only date parts will be used + const movedIsoDateFields = calendar.dateAdd( + isoDateTimeFields, // only date parts will be used { ...durationFields, // date parts - ...durationTimeFieldDefaults, // time parts (must be zero so calendar doesn't round) + ...durationTimeFieldDefaults, // time parts (must be zero so calendar doesn't round)??? days: durationFields.days + dayDelta, }, - options, + overflowHandling, ) - return createPlainDateTime({ - ...getInternals(movedPlainDate), + return { + ...movedIsoDateFields, ...movedIsoTimeFields, - }) + } } -// Used internally by Calendar::dateAdd (aka movePlainDate) -// ------------------------------------------------------------------------------------------------- +export function moveTime(isoTimeFields, durationFields) { + const [movedIsoTimeFields] = addIsoTimeFields( + isoTimeFields, + onlyDurationTimeFieldsToIso(durationFields), + ) + return movedIsoTimeFields +} -// TODO +export function addIsoMonths(year, month, monthDelta) { + year += Math.trunc(monthDelta / isoMonthsInYear) + month += monthDelta % isoMonthsInYear -// Epoch/Time -// ------------------------------------------------------------------------------------------------- + if (month < 1) { + year-- + month += isoMonthsInYear + } else if (month > isoMonthsInYear) { + year++ + month -= isoMonthsInYear + } -export function moveEpochNanoseconds(epochNanoseconds, durationFields) { - return epochNanoseconds.add(onlyDurationTimeFieldsToIso(durationFields)) + return [year, month] } -/* -Accepts internals but returns PlainTime -*/ -export function movePlainTime(internals, durationFields) { - const [movedIsoTimeFields] = addIsoTimeFields( - internals, - onlyDurationTimeFieldsToIso(durationFields), - ) - return createPlainTime(movedIsoTimeFields) -} +export function addIntlMonths(year, month, monthDelta, calendarImpl) { + month += monthDelta -function onlyDurationTimeFieldsToIso(durationFields) { - if (durationHasDateParts(durationFields)) { - throw new RangeError('Cant have date parts') + if (monthDelta < 0) { + if (month < Number.MIN_SAFE_INTEGER) { + throw new RangeError('Months out of range') + } + while (month < 1) { + month += calendarImpl.monthsInYear(--year) + } + } else { + if (month > Number.MAX_SAFE_INTEGER) { + throw new RangeError('Months out of range') + } + let monthsInYear + while (month > (monthsInYear = calendarImpl.monthsInYear(year))) { + month -= monthsInYear + year++ + } } - return durationTimeFieldsToIso(durationFields) + + return [year, month] } +// Epoch/Time Utils +// ------------------------------------------------------------------------------------------------- + function addIsoTimeFields(isoTimeFields0, isoTimeFields1) { return nanosecondsToIsoTimeFields( // returns [movedIsoTimeFields, dayDelta] isoTimeFieldsToNanoseconds(isoTimeFields0) + isoTimeFieldsToNanoseconds(isoTimeFields1), ) } + +// Utils +// ------------------------------------------------------------------------------------------------- + +function epochNanosecondsToIso(epochNanoseconds, timeZone) { + +} + +function isoToEpochNanoseconds(isoFields, timeZone, disambig) { + return isoToPossibleEpochNanoseconds(isoFields, timeZone)[0] // example +} + +function isoToPossibleEpochNanoseconds(isoFields, timeZone) { + +} + +function onlyDurationTimeFieldsToIso(durationFields) { + if (durationHasDateParts(durationFields)) { + throw new RangeError('Cant have date parts') + } + return durationTimeFieldsToIso(durationFields) +} diff --git a/packages/temporal-polyfill/src/new/move2.js b/packages/temporal-polyfill/src/new/move2.js deleted file mode 100644 index 0ade447e..00000000 --- a/packages/temporal-polyfill/src/new/move2.js +++ /dev/null @@ -1,2 +0,0 @@ - -// TODO diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index 084087ff..90cd66fc 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -1,2 +1,79 @@ +import { nanoInMilli } from '../dateUtils/units' +import { isoCalendarId } from './calendarConfig' +import { queryCalendarOps } from './calendarOps' +import { zonedDateTimeInternalsToIso } from './convert' +import { createInstant } from './instant' +import { pluckIsoDateSlots, pluckIsoTimeFields } from './isoFields' +import { createLargeInt } from './largeInt' +import { createPropDescriptors, createTemporalNameDescriptors } from './obj' +import { createPlainDate } from './plainDate' +import { createPlainDateTime } from './plainDateTime' +import { createPlainTime } from './plainTime' +import { queryTimeZoneOps } from './timeZoneOps' +import { createZonedDateTime } from './zonedDateTime' -export const Now = null +export const Now = Object.defineProperties({}, { + ...createTemporalNameDescriptors('Now'), + ...createPropDescriptors({ + zonedDateTime: getCurrentZonedDateTime, + zonedDateTimeISO: (timeZoneArg) => getCurrentZonedDateTime(isoCalendarId, timeZoneArg), + plainDateTime: getCurrentPlainDateTime, + plainDateTimeISO: (timeZoneArg) => getCurrentPlainDateTime(isoCalendarId, timeZoneArg), + plainDate: getCurrentPlainDate, + plainDateISO: (timeZoneArg) => getCurrentPlainDate(isoCalendarId, timeZoneArg), + plainTimeISO: getCurrentPlainTime, + instant: getCurrentInstant, + timeZoneId: getCurrentTimeZoneId, + }), +}) + +function getCurrentZonedDateTime(calendarArg, timeZoneArg) { + return createZonedDateTime( + getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg), + ) +} + +function getCurrentPlainDateTime(calendarArg, timeZoneArg) { + return createPlainDateTime( + getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg), + ) +} + +function getCurrentPlainDate(calendarArg, timeZoneArg) { + return createPlainDate( + pluckIsoDateSlots(getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg)), + ) +} + +function getCurrentPlainTime(timeZoneArg) { + return createPlainTime( + pluckIsoTimeFields(getCurrentPlainDateTimeSlots(isoCalendarId, timeZoneArg)), + ) +} + +function getCurrentInstant() { + return createInstant(getCurrentEpochNanoseconds()) +} + +function getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg) { + return zonedDateTimeInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)) +} + +function getCurrentZonedDateTimeSlots( + calendarArg, + timeZoneArg = getCurrentTimeZoneId(), +) { + return { + epochNanoseconds: getCurrentEpochNanoseconds(), + calendar: queryCalendarOps(calendarArg), + timeZone: queryTimeZoneOps(timeZoneArg), + } +} + +function getCurrentEpochNanoseconds() { + return createLargeInt(Date.now()).mult(nanoInMilli) +} + +function getCurrentTimeZoneId() { + return new Intl.DateTimeFormat().resolvedOptions().timeZone +} diff --git a/packages/temporal-polyfill/src/new/obj.js b/packages/temporal-polyfill/src/new/obj.js index 464dcf1f..cc5f1272 100644 --- a/packages/temporal-polyfill/src/new/obj.js +++ b/packages/temporal-polyfill/src/new/obj.js @@ -11,20 +11,36 @@ export function remapProps(obj, oldKeys, newKeys) { } -export function defineProps(obj, props) { - return Object.defineProperties( - obj, - mapProps(props, (value) => ({ - value, - writable: true, - configurable: true, - })), - ) -} - export function pluckProps(obj, props) { } export function removeDuplicateStrings(a0, a1) { } + +// descriptor stuff +// ---------------- + +export function createPropDescriptors(props) { + return mapProps(props, (value) => ({ + value, + configurable: true, + writable: true, + })) +} + +export function createGetterDescriptors(getters) { + return mapProps(getters, (getter) => ({ + get: getter, + configurable: true, + })) +} + +export function createTemporalNameDescriptors(temporalName) { + return { + [Symbol.toStringTag]: { + value: 'Temporal.' + temporalName, + configurable: true, + }, + } +} diff --git a/packages/temporal-polyfill/src/new/parse.js b/packages/temporal-polyfill/src/new/parse.js index 70b57cd6..ee576fd6 100644 --- a/packages/temporal-polyfill/src/new/parse.js +++ b/packages/temporal-polyfill/src/new/parse.js @@ -1,29 +1,30 @@ -import { isoCalendarId, toCalendarSlot } from './calendarAdapter' +import { isoCalendarId } from './calendarConfig' +import { queryCalendarOps } from './calendarOps' import { isValidIsoFields, pluckIsoDateSlots, pluckIsoDateTimeSlots, pluckIsoTimeFields, } from './isoFields' -import { computeIsoFieldEpochNanoseconds, toTimeZoneSlot } from './timeZoneProtocol' +import { computeIsoFieldEpochNanoseconds, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' // High-level // ------------------------------------------------------------------------------------------------- export function stringToZonedDateTimeInternals(s) { - const parsed = parseDateTime(s) + const parsed = parseDateTime(s) // TODO: use just 'calendar' and 'timeZone' ? if (parsed) { if (!parsed.timeZoneId) { throw new Error() } - const calendar = toCalendarSlot(parsed.calendarId || isoCalendarId) - const timeZone = toTimeZoneSlot(parsed.timeZoneId) + const calendar = queryCalendarOps(parsed.calendarId || isoCalendarId) + const timeZone = queryTimeZoneOps(parsed.timeZoneId) const epochNanoseconds = computeIsoFieldEpochNanoseconds( - parsed, timeZone, + parsed, parsed.offset !== undefined ? parseOffsetNanoseconds(parsed.offset) : undefined, parsed.z, 'reject', @@ -142,7 +143,7 @@ export function stringToTimeZoneId(s) { return parsed.timeZonedId // TODO: need to canonicalize (run through DateTimeFormat) } if (parsed.hasZ) { - return 'UTC' + return utcTimeZoneId } if (parsed.offset) { return parsed.offset diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 4b5ed65b..5c31097b 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -1,10 +1,10 @@ -import { - getCommonCalendar, - isoCalendarId, - moveDate, - toCalendarSlot, -} from './calendarAdapter' +import { isoCalendarId } from './calendarConfig' import { dateGetters } from './calendarFields' +import { + getCommonCalendarOps, + getPublicCalendar, + queryCalendarOps, +} from './calendarOps' import { bagToPlainDateSlots, createZonedDateTimeConverter, @@ -19,18 +19,21 @@ import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { formatCalendar, formatIsoDateFields } from './format' +import { neverValueOf } from './internalClass' import { compareIsoFields, + constrainIsoDateFields, + generatePublicIsoDateFields, isoDateSlotRefiners, isoTimeFieldDefaults, pluckIsoDateSlots, - regulateIsoDateFields, } from './isoFields' import { optionsToOverflow } from './options' import { stringToPlainDateInternals } from './parse' -import { createPlainDateTime } from './plainDateTime' +import { PlainDateTime, createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' -import { createTemporalClass, neverValueOf } from './temporalClass' +import { createTemporalClass } from './temporalClass' +import { ZonedDateTime } from './zonedDateTime' export const [ PlainDate, @@ -42,8 +45,9 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals (isoYear, isoMonth, isoDay, calendarArg = isoCalendarId) => { - return regulateIsoDateFields( + return constrainIsoDateFields( mapRefiners({ isoYear, isoMonth, @@ -52,12 +56,24 @@ export const [ }, isoDateSlotRefiners), ) }, - { - PlainDateTime: pluckIsoDateSlots, - ZonedDateTime: zonedDateTimeInternalsToIso, + + // massageOtherInternals + (arg, argInternals) => { + if (arg instanceof PlainDateTime) { + return pluckIsoDateSlots(argInternals) + } + if (arg instanceof ZonedDateTime) { + return zonedDateTimeInternalsToIso(argInternals) + } }, + + // bagToInternals bagToPlainDateSlots, + + // stringToInternals stringToPlainDateInternals, + + // handleUnusedOptions optionsToOverflow, // Getters @@ -76,13 +92,12 @@ export const [ withCalendar(internals, calendarArg) { return createPlainDate({ ...internals, - calendar: toCalendarSlot(calendarArg), + calendar: queryCalendarOps(calendarArg), }) }, add(internals, durationArg, options) { - return moveDate( - internals.calendar, + return internals.calendar.dateAdd( internals, toDurationInternals(durationArg), options, @@ -90,8 +105,7 @@ export const [ }, subtract(internals, durationArg, options) { - return moveDate( - internals.calendar, + return internals.calendar.dateAdd( internals, negateDurationFields(toDurationInternals(durationArg)), options, @@ -100,13 +114,13 @@ export const [ until(internals, otherArg, options) { const otherInternals = toPlainDateInternals(otherArg) - const calendar = getCommonCalendar(internals, otherInternals) + const calendar = getCommonCalendarOps(internals, otherInternals) return diffDates(calendar, internals, otherInternals, options, 1) }, since(internals, otherArg, options) { const otherInternals = toPlainDateInternals(otherArg) - const calendar = getCommonCalendar(internals, otherInternals) + const calendar = getCommonCalendarOps(internals, otherInternals) return diffDates(calendar, internals, otherInternals, options, -1) }, @@ -146,7 +160,9 @@ export const [ return dateToPlainMonthDay(this) }, - getISOFields: pluckIsoDateSlots, + getISOFields: generatePublicIsoDateFields, + + getCalendar: getPublicCalendar, }, // Static diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index dc109f2f..14c8f194 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -1,5 +1,6 @@ -import { isoCalendarId, toCalendarSlot } from './calendarAdapter' +import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' +import { getPublicCalendar, queryCalendarOps } from './calendarOps' import { bagToPlainDateTimeInternals, dateToPlainMonthDay, @@ -13,24 +14,25 @@ import { diffDateTimes } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { formatCalendar, formatIsoDateTimeFields } from './format' +import { neverValueOf } from './internalClass' import { compareIsoFields, + generatePublicIsoDateTimeFields, isoDateTimeSlotRefiners, isoTimeFieldDefaults, pluckIsoDateSlots, - pluckIsoDateTimeSlots, pluckIsoTimeFields, - regulateIsoDateTimeFields, + constrainIsoDateTimeFields, } from './isoFields' -import { movePlainDateTime } from './move' -import { optionsToOverflow, validateRoundingOptions } from './options' +import { moveDateTime } from './move' +import { optionsToOverflow, toDisambiguation, validateRoundingOptions } from './options' import { stringToPlainDateTimeInternals } from './parse' -import { createPlainDate, toPlainDateInternals } from './plainDate' +import { PlainDate, createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' -import { createTemporalClass, neverValueOf } from './temporalClass' -import { plainDateTimeToEpochNanoseconds, toTimeZoneSlot } from './timeZoneProtocol' -import { createZonedDateTime } from './zonedDateTime' +import { createTemporalClass } from './temporalClass' +import { getBestInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' export const [ PlainDateTime, @@ -42,6 +44,7 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals ( isoYear, isoMonth, @@ -54,7 +57,7 @@ export const [ isoNanosecond = 0, calendarArg = isoCalendarId, ) => { - return regulateIsoDateTimeFields( + return constrainIsoDateTimeFields( mapRefiners({ isoYear, isoMonth, @@ -65,16 +68,28 @@ export const [ isoMillisecond, isoMicrosecond, isoNanosecond, - calendar: toCalendarSlot(calendarArg), + calendar: queryCalendarOps(calendarArg), }, isoDateTimeSlotRefiners), ) }, - { - PlainDate: (internals) => ({ ...internals, ...isoTimeFieldDefaults }), - ZonedDateTime: zonedDateTimeInternalsToIso, + + // massageOtherInternals + (arg, argInternals) => { + if (arg instanceof PlainDate) { + return { ...argInternals, ...isoTimeFieldDefaults } + } + if (arg instanceof ZonedDateTime) { + return zonedDateTimeInternalsToIso(argInternals) + } }, + + // bagToInternals bagToPlainDateTimeInternals, + + // stringToInternals stringToPlainDateTimeInternals, + + // handleUnusedOptions optionsToOverflow, // Getters @@ -107,23 +122,29 @@ export const [ withCalendar(internals, calendarArg) { return createPlainDateTime({ ...internals, - calendar: toCalendarSlot(calendarArg), + calendar: queryCalendarOps(calendarArg), }) }, add(internals, durationArg, options) { - return movePlainDateTime( - internals, - toDurationInternals(durationArg), - options, + return createPlainDateTime( + moveDateTime( + internals, + toDurationInternals(durationArg), + internals.calendar, + optionsToOverflow(options), + ), ) }, subtract(internals, durationArg, options) { - return movePlainDateTime( - internals, - negateDurationFields(toDurationInternals(durationArg)), - options, + return createPlainDateTime( + moveDateTime( + internals, + negateDurationFields(toDurationInternals(durationArg)), + internals.calendar, + optionsToOverflow(options), + ), ) }, @@ -176,8 +197,8 @@ export const [ options, // { disambiguation } - optional ) { const { calendar } = internals - const timeZone = toTimeZoneSlot(timeZoneArg) - const epochNanoseconds = plainDateTimeToEpochNanoseconds(timeZone, this, options), + const timeZone = queryTimeZoneOps(timeZoneArg) + const epochNanoseconds = getBestInstantFor(timeZone, internals, toDisambiguation(options)) return createZonedDateTime({ epochNanoseconds, @@ -202,7 +223,9 @@ export const [ return createPlainTime(pluckIsoTimeFields(internals)) }, - getISOFields: pluckIsoDateTimeSlots, + getISOFields: generatePublicIsoDateTimeFields, + + getCalendar: getPublicCalendar, }, // Static diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index d70c7d3c..eaabd7d0 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -1,5 +1,6 @@ -import { isoCalendarId } from './calendarAdapter' +import { isoCalendarId } from './calendarConfig' import { monthDayGetters } from './calendarFields' +import { getPublicCalendar } from './calendarOps' import { bagToPlainMonthDayInternals, isStringCastsEqual, @@ -8,15 +9,17 @@ import { plainMonthDayWithBag, } from './convert' import { formatIsoMonthDayFields, formatPossibleDate } from './format' +import { neverValueOf } from './internalClass' import { compareIsoFields, + constrainIsoDateFields, + generatePublicIsoDateFields, isoDateSlotRefiners, - pluckIsoDateSlots, - regulateIsoDateFields, } from './isoFields' +import { noop } from './lang' import { optionsToOverflow } from './options' import { stringToMonthDayInternals } from './parse' -import { createTemporalClass, neverValueOf } from './temporalClass' +import { createTemporalClass } from './temporalClass' export const [ PlainMonthDay, @@ -28,8 +31,9 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals (isoMonth, isoDay, calendarArg = isoCalendarId, referenceIsoYear = 1972) => { - return regulateIsoDateFields( + return constrainIsoDateFields( mapRefiners({ isoYear: referenceIsoYear, isoMonth, @@ -38,9 +42,17 @@ export const [ }, isoDateSlotRefiners), ) }, - {}, + + // massageOtherInternals + noop, + + // bagToInternals bagToPlainMonthDayInternals, + + // stringToInternals stringToMonthDayInternals, + + // handleUnusedOptions optionsToOverflow, // Getters @@ -76,6 +88,8 @@ export const [ return plainMonthDayToPlainDate(this, bag) }, - getISOFields: pluckIsoDateSlots, + getISOFields: generatePublicIsoDateFields, + + getCalendar: getPublicCalendar, }, ) diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 436c362c..148b62b1 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -10,19 +10,21 @@ import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { formatIsoTimeFields } from './format' +import { neverValueOf } from './internalClass' import { compareIsoTimeFields, isoTimeFieldRefiners, pluckIsoTimeFields, - regulateIsoTimeFields, + constrainIsoTimeFields, } from './isoFields' -import { movePlainTime } from './move' +import { moveTime } from './move' import { optionsToOverflow } from './options' import { stringToPlainTimeInternals } from './parse' import { toPlainDateInternals } from './plainDate' -import { createPlainDateTime } from './plainDateTime' +import { PlainDateTime, createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' -import { createTemporalClass, neverValueOf } from './temporalClass' +import { createTemporalClass } from './temporalClass' +import { ZonedDateTime } from './zonedDateTime' export const [ PlainTime, @@ -34,6 +36,7 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals ( isoHour = 0, isoMinute = 0, @@ -42,7 +45,7 @@ export const [ isoMicrosecond = 0, isoNanosecond = 0, ) => { - return regulateIsoTimeFields( + return constrainIsoTimeFields( mapRefiners({ isoHour, isoMinute, @@ -53,12 +56,24 @@ export const [ }, isoTimeFieldRefiners), ) }, - { - PlainDateTime: pluckIsoTimeFields, - ZonedDateTime: (internals) => pluckIsoTimeFields(zonedDateTimeInternalsToIso(internals)), + + // massageOtherInternals + (arg, argInternals) => { + if (arg instanceof PlainDateTime) { + return pluckIsoTimeFields(argInternals) + } + if (arg instanceof ZonedDateTime) { + return pluckIsoTimeFields(zonedDateTimeInternalsToIso(argInternals)) + } }, + + // bagToInternals bagToPlainTimeInternals, + + // stringToInternals stringToPlainTimeInternals, + + // handleUnusedOptions optionsToOverflow, // Getters @@ -75,13 +90,20 @@ export const [ }, add(internals, durationArg) { - return movePlainTime(internals, toDurationInternals(durationArg)) + return createPlainTime( + moveTime( + internals, + toDurationInternals(durationArg), + ), + ) }, subtract(internals, durationArg) { - return movePlainTime( - internals, - negateDurationFields(toDurationInternals(durationArg)), + return createPlainTime( + moveTime( + internals, + negateDurationFields(toDurationInternals(durationArg)), + ), ) }, @@ -136,9 +158,7 @@ export const [ }) }, - getISOFields(internals) { - return pluckIsoTimeFields(internals) - }, + getISOFields: pluckIsoTimeFields, }, // Static diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 667c85b4..412399ea 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -1,5 +1,6 @@ -import { isoCalendarId } from './calendarAdapter' +import { isoCalendarId } from './calendarConfig' import { yearMonthGetters } from './calendarFields' +import { getPublicCalendar } from './calendarOps' import { bagToPlainYearMonthInternals, isStringCastsEqual, @@ -12,16 +13,17 @@ import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { formatIsoYearMonthFields, formatPossibleDate } from './format' +import { getInternals, neverValueOf } from './internalClass' import { compareIsoFields, + constrainIsoDateFields, + generatePublicIsoDateFields, isoDateSlotRefiners, - pluckIsoDateSlots, - regulateIsoDateFields, } from './isoFields' -import { movePlainYearMonth } from './move' +import { noop } from './lang' import { optionsToOverflow } from './options' import { stringToPlainYearMonthInternals } from './parse' -import { createTemporalClass, neverValueOf } from './temporalClass' +import { createTemporalClass } from './temporalClass' export const [ PlainYearMonth, @@ -33,8 +35,9 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals (isoYear, isoMonth, calendarArg = isoCalendarId, referenceIsoDay = 1) => { - return regulateIsoDateFields( + return constrainIsoDateFields( mapRefiners({ isoYear, isoMonth, @@ -43,9 +46,17 @@ export const [ }, isoDateSlotRefiners), ) }, - {}, + + // massageOtherInternals + noop, + + // bagToInternals bagToPlainYearMonthInternals, + + // stringToInternals stringToPlainYearMonthInternals, + + // handleUnusedOptions optionsToOverflow, // Getters @@ -63,17 +74,19 @@ export const [ add(internals, durationArg, options) { return movePlainYearMonth( - internals, + this, + internals.calendar, toDurationInternals(durationArg), - options, + optionsToOverflow(options), ) }, subtract(internals, durationArg, options) { return movePlainYearMonth( - internals, + this, + internals.calendar, negateDurationFields(toDurationInternals(durationArg)), - options, + optionsToOverflow(options), ) }, @@ -121,7 +134,9 @@ export const [ return plainYearMonthToPlainDate(this, bag) }, - getISOFields: pluckIsoDateSlots, + getISOFields: generatePublicIsoDateFields, + + getCalendar: getPublicCalendar, }, // Static @@ -136,3 +151,27 @@ export const [ }, }, ) + +// Utils +// ------------------------------------------------------------------------------------------------- + +function movePlainYearMonth( + plainYearMonth, + calendar, + durationFields, + overflowHandling, +) { + const plainDate = plainYearMonthToPlainDate(plainYearMonth, { + day: durationFields.sign < 0 + ? calendar.daysInMonth(plainYearMonth) + : 1, + }) + + let isoDateFields = getInternals(plainDate) + isoDateFields = calendar.dateAdd(isoDateFields, durationFields, overflowHandling) + + return createPlainYearMonth({ + ...isoDateFields, + calendar, + }) +} diff --git a/packages/temporal-polyfill/src/new/temporal.js b/packages/temporal-polyfill/src/new/temporal.js index f9b0beb4..21935bf5 100644 --- a/packages/temporal-polyfill/src/new/temporal.js +++ b/packages/temporal-polyfill/src/new/temporal.js @@ -2,7 +2,7 @@ import { Calendar } from './calendar' import { Duration } from './duration' import { Instant } from './instant' import { Now } from './now' -import { defineProps } from './obj' +import { createPropDescriptors } from './obj' import { PlainDate } from './plainDate' import { PlainDateTime } from './plainDateTime' import { PlainMonthDay } from './plainMonthDay' @@ -11,7 +11,7 @@ import { PlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' import { ZonedDateTime } from './zonedDateTime' -export const Temporal = defineProps({}, { +export const Temporal = Object.defineProperties({}, createPropDescriptors({ PlainYearMonth, PlainMonthDay, PlainDate, @@ -23,4 +23,4 @@ export const Temporal = defineProps({}, { TimeZone, Duration, Now, -}) +})) diff --git a/packages/temporal-polyfill/src/new/temporalClass.js b/packages/temporal-polyfill/src/new/temporalClass.js index 61bbedc8..43a0f3a1 100644 --- a/packages/temporal-polyfill/src/new/temporalClass.js +++ b/packages/temporal-polyfill/src/new/temporalClass.js @@ -1,31 +1,34 @@ -import { defineProps, isObjectLike, mapProps } from './obj' - -const internalsMap = new WeakMap() -export const getInternals = internalsMap.get.bind(internalsMap) - -const nameSymbol = Symbol() - -function noop() {} +import { createInternalClass, getInternals, internalsMap } from './internalClass' +import { createTemporalNameDescriptors, isObjectLike } from './obj' export function createTemporalClass( - name, // rename? + temporalName, constructorToInternals, - nameToInternalsMap, - bagToInternals = noop, + massageOtherInternals, + bagToInternals, stringToInternals, - parseOptions = noop, + handleUnusedOptions, getters, methods, staticMembers = {}, ) { - function TemporalObj(...args) { - internalsMap.set(this, constructorToInternals(...args)) + methods.toJSON = function() { + return String(this) + } + staticMembers.from = function(arg, options) { + return createInstance(toInternals(arg, options)) } - const proto = TemporalObj.prototype + const TemporalObj = createInternalClass( + getters, + methods, + constructorToInternals, + createTemporalNameDescriptors(temporalName), // extraPrototypeDescriptors + staticMembers, + ) function createInstance(internals) { - const instance = Object.create(proto) + const instance = Object.create(TemporalObj.prototype) internalsMap.set(instance, internals) return instance } @@ -33,57 +36,13 @@ export function createTemporalClass( function toInternals(arg, options) { let argInternals = getInternals(arg) - if (argInternals) { - const argName = arg[nameSymbol] // might raise red flags accessing this!!! - if (argName !== name) { - argInternals = (nameToInternalsMap[argName] || noop)(argInternals) - } + if (argInternals && !(arg instanceof TemporalObj)) { + argInternals = massageOtherInternals(arg, argInternals) } return (!argInternals && isObjectLike(arg) && bagToInternals(arg, options)) || - (parseOptions(options), argInternals || stringToInternals(toString(arg))) + (handleUnusedOptions(options), argInternals || stringToInternals(toString(arg))) } - function curryMethod(method) { - return /* Object.setPrototypeOf( */ function(...args) { - if (!(this instanceof TemporalObj)) { - throw new TypeError('Invalid receiver') - } - return method.call(this, getInternals(this), ...args) - } /* , null) */ - } - - Object.defineProperties(proto, { - ...mapProps(getters, (getter) => ({ - get: curryMethod(getter), - configurable: true, - })), - [Symbol.toStringTag]: { - value: 'Temporal.' + name, - configurable: true, - }, - [nameSymbol]: { // might raise red flags accessing this!!! - value: name, - }, - }) - - methods.toJSON = function() { - return String(this) - } - staticMembers.from = function(arg, options) { - return createInstance(toInternals(arg, options)) - } - - defineProps(proto, mapProps(methods, curryMethod)) - defineProps(TemporalObj, staticMembers) - - return [ - TemporalObj, - createInstance, - toInternals, - ] -} - -export function neverValueOf() { - throw new TypeError('Cannot convert object using valueOf') + return [TemporalObj, createInstance, toInternals] } diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 5e9447f4..4a89176a 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -1,35 +1,43 @@ import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' import { Calendar } from './calendar' +import { queryCalendarOps } from './calendarOps' import { createComplexBagRefiner } from './convert' import { formatOffsetNanoseconds } from './format' -import { toInstantEpochNanoseconds } from './instant' +import { createInstant, toInstantEpochNanoseconds } from './instant' +import { internalIdGetters, returnId } from './internalClass' +import { identityFunc, noop } from './lang' +import { mapProps } from './obj' +import { toDisambiguation } from './options' import { stringToTimeZoneId } from './parse' +import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { createTemporalClass } from './temporalClass' -import { instantToOffsetNanoseconds } from './timeZoneProtocol' +import { getBestInstantFor } from './timeZoneOps' -export const [TimeZone] = createTemporalClass( +export const [TimeZone, createTimeZone] = createTemporalClass( 'TimeZone', // Creation // ----------------------------------------------------------------------------------------------- - // constructor to internals - (id) => { - return queryTimeZoneImpl(id) - }, - {}, + // constructorToInternals + queryTimeZoneImpl, + + // massageOtherInternals + noop, + + // bagToInternals createComplexBagRefiner('timeZone', Calendar), - stringToTimeZoneId, - undefined, + + // stringToInternals + (str) => queryTimeZoneImpl(stringToTimeZoneId(str)), + + // handleUnusedOptions + noop, // Getters // ----------------------------------------------------------------------------------------------- - { - id(impl) { - return impl.id - }, - }, + internalIdGetters, // Methods // ----------------------------------------------------------------------------------------------- @@ -37,40 +45,50 @@ export const [TimeZone] = createTemporalClass( { getOffsetStringFor(impl, instantArg) { return formatOffsetNanoseconds( - // TODO: figure out timeZoneProtocol - instantToOffsetNanoseconds( - this, - toInstantEpochNanoseconds(instantArg), - ), + impl.getOffsetNanosecondsFor(toInstantEpochNanoseconds(instantArg)), ) }, - getOffsetNanosecondsFor(impl, instantArg) { - // TODO - }, - getPlainDateTimeFor(impl, instantArg, calendarArg) { - // TODO - }, + const epochNanoseconds = toInstantEpochNanoseconds(instantArg) + const offsetNanoseconds = impl.getOffsetNanosecondsFor(impl, epochNanoseconds) - getInstantFor(impl, dateTimeArg, options) { - // TODO + return createPlainDateTime({ + ...epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)), + calendar: queryCalendarOps(calendarArg), + }) }, - getPossibleInstantsFor(impl, dateTimeArg) { - // TODO + getInstantFor(impl, plainDateTimeArg, options) { + return getBestInstantFor( + impl, + toPlainDateTimeInternals(plainDateTimeArg), + toDisambiguation(options), + ) }, - getPreviousTransition(impl, instantArg) { - // TODO + getPossibleInstantsFor(impl, plainDateTimeArg) { + return impl.getPossibleInstantsFor(toPlainDateTimeInternals(plainDateTimeArg)) + .map(createInstant) }, - getNextTransition(impl, instantArg) { - // TODO - }, + ...mapProps({ + getPreviousTransition: createInstant, + getNextTransition: createInstant, + getOffsetNanosecondsFor: identityFunc, + }, (transformRes, methodName) => { + return (impl, instantArg) => { + return transformRes(impl[methodName](toInstantEpochNanoseconds(instantArg))) + } + }), - toString(impl) { - return impl.id - }, + toString: returnId, }, ) + +// TimeZone Conversions +// ------------------------------------------------------------------------------------------------- + +function epochNanosecondsToIso(epochNanoseconds, timeZone) { + +} diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js new file mode 100644 index 00000000..28368bae --- /dev/null +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -0,0 +1,14 @@ + +export function queryTimeZoneImpl() { + +} + +export class TimeZoneImpl { + getOffsetNanosecondsFor(epochNanoseconds) { + // TODO + } + + getPossibleInstantsFor(isoDateTimeFields) { + // TODO + } +} diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js new file mode 100644 index 00000000..fb0645d5 --- /dev/null +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -0,0 +1,84 @@ +import { strictArray, strictNumber } from './cast' +import { Instant, createInstant } from './instant' +import { + createInternalClass, + createInternalGetter, + getInternals, + internalIdGetters, +} from './internalClass' +import { nanosecondsInDay } from './nanoseconds' +import { createPlainDateTime } from './plainDateTime' +import { createTimeZone } from './timeZone' +import { queryTimeZoneImpl } from './timeZoneImpl' + +export const utcTimeZoneId = 'UTC' + +export function queryTimeZoneOps(timeZoneSlot) { + if (typeof timeZoneSlot === 'object') { + return new TimeZoneOpsAdapter(timeZoneSlot) + } + return queryTimeZoneImpl(timeZoneSlot) // string +} + +export function getCommonTimeZoneOps(internals0, internals1) { +} + +export function getPublicTimeZone(internals) { + const { timeZone } = internals + return getInternals(timeZone) || // if TimeZoneOpsAdapter + createTimeZone(timeZone) // if TimeZoneImpl +} + +// Public Utils +// ------------ + +export function getBestInstantFor( + timeZoneOps, + isoDateTimeFields, + disambig = 'compatible', +) { +} + +export function computeIsoFieldEpochNanoseconds( + timeZoneOps, + isoDateTimeFields, + offset, + z, + offsetHandling, // 'reject' + disambig, // 'compatible' + fuzzy, +) { +} + +export function computeNanosecondsInDay( + timeZoneOps, + isoFields, +) { +} + +// Adapter +// ------- + +const getStrictInstantEpochNanoseconds = createInternalGetter(Instant) + +const TimeZoneOpsAdapter = createInternalClass(internalIdGetters, { + getOffsetNanosecondsFor(timeZone, epochNanoseconds) { + const nanoseconds = strictNumber( // TODO: integer? + timeZone.getOffsetNanosecondsFor(createInstant(epochNanoseconds)), + ) + + if (Math.abs(nanoseconds) >= nanosecondsInDay) { + throw new RangeError('out of range') + } + + return nanoseconds + }, + + getPossibleInstantsFor(timeZone, isoDateTimeFields) { + return strictArray( + timeZone.getPossibleInstantsFor( + createPlainDateTime(isoDateTimeFields), // hopefully won't look at blank .calendar + ), + ).map(getStrictInstantEpochNanoseconds) + }, +}) diff --git a/packages/temporal-polyfill/src/new/timeZoneProtocol.js b/packages/temporal-polyfill/src/new/timeZoneProtocol.js deleted file mode 100644 index d485e9b2..00000000 --- a/packages/temporal-polyfill/src/new/timeZoneProtocol.js +++ /dev/null @@ -1,73 +0,0 @@ -import { strictArrayOfType, toInteger } from './cast' -import { Instant, createInstant } from './instant' -import { nanosecondsInDay } from './nanoseconds' -import { getInternals } from './temporalClass' - -// High-level usage with Temporal objects -// ------------------------------------------------------------------------------------------------- - -export function zonedDateTimeInternalsToOffsetNanoseconds(internals) { - return instantToOffsetNanoseconds(internals.timeZone, createInstant(internals.epochNanoseconds)) -} - -export function computeIsoFieldEpochNanoseconds( - isoFields, // should accept PlainDateTime instead? - timeZoneProtocol, - offset, - z, - offsetHandling, // 'reject' - disambig, // 'compatible' - fuzzy, -) { - // relies on plainDateTimeToPossibleInstants -} - -export function computeNanosecondsInDay(isoFields, timeZoneProtocol) { - // relies on plainDateTimeToPossibleInstants -} - -// Utils for Calendar and users of CalendarProtocol -// ------------------------------------------------------------------------------------------------- - -export function instantToPlainDateTimeInternals(timeZoneProtocol, calendar, instant) { - return getInternals(instantToPlainDateTime(timeZoneProtocol, calendar, instant)) -} - -export function instantToPlainDateTime(timeZoneProtocol, calendar, instant) { - // relies on instantToOffsetNanoseconds -} - -export function plainDateTimeToEpochNanoseconds(timeZoneProtocol, plainDateTime, disambiguation) { - return getInternals(plainDateTimeToInstant(timeZoneProtocol, plainDateTime, disambiguation)) -} - -function plainDateTimeToInstant(timeZoneProtocol, plainDateTime, disambiguation) { - // relies on plainDateTimeToPossibleInstants -} - -// Only raw CalendarProtocol methods that can be relied upon -// ------------------------------------------------------------------------------------------------- - -export function instantToOffsetNanoseconds(timeZoneProtocol, instant) { - const nanoseconds = toInteger(timeZoneProtocol.getOffsetNanosecondsFor(instant)) - - if (Math.abs(nanoseconds) >= nanosecondsInDay) { - throw new RangeError('out of range') - } - - return nanoseconds -} - -export function plainDateTimeToPossibleInstants(timeZoneProtocol, plainDateTime) { - return strictArrayOfType(timeZoneProtocol.getPossibleInstantsFor(plainDateTime), Instant) -} - -// Utils -// ------------------------------------------------------------------------------------------------- - -export function getCommonTimeZone() { -} - -export function toTimeZoneSlot() { - -} diff --git a/packages/temporal-polyfill/src/new/timeZoneProtocol2.js b/packages/temporal-polyfill/src/new/timeZoneProtocol2.js deleted file mode 100644 index 0ade447e..00000000 --- a/packages/temporal-polyfill/src/new/timeZoneProtocol2.js +++ /dev/null @@ -1,2 +0,0 @@ - -// TODO diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 39b678de..c64c1d82 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -1,5 +1,5 @@ -import { getCommonCalendar, toCalendarSlot } from './calendarAdapter' import { dateTimeGetters } from './calendarFields' +import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' import { bagToZonedDateTimeInternals, dateToPlainMonthDay, @@ -8,7 +8,7 @@ import { zonedDateTimeInternalsToIso, zonedDateTimeWithBag, } from './convert' -import { diffZoneEpochNanoseconds } from './diff' +import { diffZonedEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { @@ -18,14 +18,16 @@ import { formatTimeZone, } from './format' import { createInstant } from './instant' +import { neverValueOf } from './internalClass' import { isoTimeFieldDefaults, pluckIsoDateSlots, pluckIsoDateTimeSlots, pluckIsoTimeFields, } from './isoFields' +import { noop } from './lang' import { compareLargeInts, toLargeInt } from './largeInt' -import { moveZonedDateTimeInternals } from './move' +import { moveZonedEpochNanoseconds } from './move' import { epochGetters, nanosecondsInHour } from './nanoseconds' import { mapProps } from './obj' import { optionsToOverflow } from './options' @@ -34,17 +36,15 @@ import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' -import { createTemporalClass, neverValueOf } from './temporalClass' +import { createTemporalClass } from './temporalClass' import { computeIsoFieldEpochNanoseconds, computeNanosecondsInDay, - getCommonTimeZone, - instantToOffsetNanoseconds, - instantToPlainDateTimeInternals, - plainDateTimeToEpochNanoseconds, - toTimeZoneSlot, - zonedDateTimeInternalsToOffsetNanoseconds, -} from './timeZoneProtocol' + getBestInstantFor, + getCommonTimeZoneOps, + getPublicTimeZone, + queryTimeZoneOps, +} from './timeZoneOps' export const [ ZonedDateTime, @@ -56,16 +56,25 @@ export const [ // Creation // ----------------------------------------------------------------------------------------------- + // constructorToInternals (epochNanoseconds, timeZoneArg, calendarArg) => { return { epochNanoseconds: toLargeInt(epochNanoseconds), // TODO: stricter - timeZone: toTimeZoneSlot(timeZoneArg), - calendar: toCalendarSlot(calendarArg), + timeZone: queryTimeZoneOps(timeZoneArg), + calendar: queryCalendarOps(calendarArg), } }, - {}, + + // massageOtherInternals + noop, + + // bagToInternals bagToZonedDateTimeInternals, + + // stringToInternals stringToZonedDateTimeInternals, + + // handleUnusedOptions optionsToOverflow, // Getters @@ -85,8 +94,10 @@ export const [ }), hoursInDay(internals) { - return computeNanosecondsInDay(internals.epochNanoseconds, internals.timeZone) / - nanosecondsInHour + return computeNanosecondsInDay( + internals.timeZone, + zonedDateTimeInternalsToIso(internals), + ) / nanosecondsInHour }, offsetNanoseconds(internals) { @@ -108,12 +119,12 @@ export const [ withPlainTime(internals, plainTimeArg) { const { timeZone } = internals - const epochNanoseconds = plainDateTimeToEpochNanoseconds( + const epochNanoseconds = getBestInstantFor( timeZone, - createPlainDateTime({ + { ...zonedDateTimeInternalsToIso(internals), ...toPlainTimeInternals(plainTimeArg), - }), + }, ) return createZonedDateTime({ @@ -125,13 +136,12 @@ export const [ withPlainDate(internals, plainDateArg) { const { timeZone } = internals - const epochNanoseconds = plainDateTimeToEpochNanoseconds( + const epochNanoseconds = getBestInstantFor( timeZone, - createPlainDateTime({ + { ...zonedDateTimeInternalsToIso(internals), ...toPlainDateInternals(plainDateArg), - // calendar doesn't matter - }), + }, ) return createZonedDateTime({ @@ -144,14 +154,14 @@ export const [ withTimeZone(internals, timeZoneArg) { return createZonedDateTime({ ...internals, - timeZone: toTimeZoneSlot(timeZoneArg), + timeZone: queryTimeZoneOps(timeZoneArg), }) }, withCalendar(internals, calendarArg) { return createZonedDateTime({ ...internals, - calendar: toCalendarSlot(calendarArg), + calendar: queryCalendarOps(calendarArg), }) }, @@ -177,22 +187,22 @@ export const [ until(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) - return diffZoneEpochNanoseconds( + return diffZonedEpochNanoseconds( internals.epochNanoseconds, otherInternals.epochNanoseconds, - getCommonTimeZone(internals, otherInternals), - getCommonCalendar(internals, otherInternals), + getCommonTimeZoneOps(internals, otherInternals), + getCommonCalendarOps(internals, otherInternals), options, // TODO: spread out lots of options!!! ) }, since(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) - return diffZoneEpochNanoseconds( + return diffZonedEpochNanoseconds( otherInternals.epochNanoseconds, internals.epochNanoseconds, - getCommonTimeZone(internals, otherInternals), - getCommonCalendar(internals, otherInternals), + getCommonTimeZoneOps(internals, otherInternals), + getCommonCalendarOps(internals, otherInternals), options, // TODO: flip rounding options!!!!! ) }, @@ -200,13 +210,13 @@ export const [ round(internals, options) { let { epochNanoseconds, timeZone, calendar } = internals - const instant = createInstant(epochNanoseconds) - const offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) - let isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) + let isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + isoFields = roundIsoDateTimeFields( isoFields, options, - () => computeNanosecondsInDay(isoFields, timeZone), + () => computeNanosecondsInDay(timeZone, isoFields), ) epochNanoseconds = computeIsoFieldEpochNanoseconds( isoFields, @@ -263,13 +273,13 @@ export const [ // TODO: don't let options be accessed twice! once by rounding, twice by formatting - let instant = createInstant(epochNanoseconds) - let offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) - let isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + let offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) + let isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + isoFields = roundIsoDateTimeFields( isoFields, options, - () => computeNanosecondsInDay(isoFields, timeZone), + () => computeNanosecondsInDay(timeZone, isoFields), ) epochNanoseconds = computeIsoFieldEpochNanoseconds( isoFields, @@ -280,9 +290,9 @@ export const [ 'compatible', true, // fuzzy ) - instant = createInstant(epochNanoseconds) - offsetNanoseconds = instantToOffsetNanoseconds(timeZone, instant) - isoFields = instantToPlainDateTimeInternals(timeZone, calendar, instant) + + offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) + isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) return formatIsoDateTimeFields(isoFields, options) + formatOffsetNanoseconds(offsetNanoseconds) + @@ -325,12 +335,15 @@ export const [ return { // maintain alphabetical order - calendar, + calendar: calendar.id, // correct? ...pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(internals)), offset: formatOffsetNanoseconds(zonedDateTimeInternalsToOffsetNanoseconds(internals)), - timeZone: String(timeZone), + timeZone: timeZone.id, // correct? } }, + + getCalendar: getPublicCalendar, + getTimeZone: getPublicTimeZone, }, // Static @@ -345,3 +358,24 @@ export const [ }, }, ) + +// Utils +// ------------------------------------------------------------------------------------------------- + +function moveZonedDateTimeInternals(internals, durationFields, overflowHandling) { + return moveZonedEpochNanoseconds( + internals.epochNanoseconds, + durationFields, + internals.calendar, + internals.timeZone, + overflowHandling, + ) +} + +function zonedDateTimeInternalsToOffsetNanoseconds(internals) { + return internals.timeZone // TimeZoneOps + .getOffsetNanosecondsFor(internals.epochNanoseconds) +} + +function epochNanosecondsToIso() { +} diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/public/calendar.ts index 5de5296b..3a371676 100644 --- a/packages/temporal-polyfill/src/public/calendar.ts +++ b/packages/temporal-polyfill/src/public/calendar.ts @@ -578,6 +578,7 @@ export function mergeCalFields(baseFields: any, newFields: any, calendarID: stri // utils +// BAD NAME // TODO: can we eliminate this now that it's checked in public date classes? function isoToEpochNanoSafe( calendarImpl: CalendarImpl, From ef2a679915104cad18400b9235e5e8caff05e1b1 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 31 May 2023 15:34:53 -0400 Subject: [PATCH 075/805] lots of stuff --- .../temporal-polyfill/src/new/calendar.js | 4 +- .../src/new/calendarFields.js | 2 +- .../temporal-polyfill/src/new/calendarImpl.js | 50 +- .../temporal-polyfill/src/new/calendarOps.js | 7 +- packages/temporal-polyfill/src/new/convert.js | 50 +- .../src/new/dateTimeFormat.js | 268 +++++++++++ packages/temporal-polyfill/src/new/diff.js | 147 ++---- .../temporal-polyfill/src/new/duration.js | 196 +++++++- .../src/new/durationFields.js | 4 + packages/temporal-polyfill/src/new/instant.js | 24 +- .../src/new/internalClass.js | 4 +- .../temporal-polyfill/src/new/isoFields.js | 7 +- packages/temporal-polyfill/src/new/move.js | 6 +- .../temporal-polyfill/src/new/nanoseconds.js | 18 +- packages/temporal-polyfill/src/new/now.js | 9 +- packages/temporal-polyfill/src/new/parse.js | 4 +- .../temporal-polyfill/src/new/plainDate.js | 21 +- .../src/new/plainDateTime.js | 37 +- .../src/new/plainMonthDay.js | 11 +- .../temporal-polyfill/src/new/plainTime.js | 23 +- .../src/new/plainYearMonth.js | 11 +- packages/temporal-polyfill/src/new/round.js | 433 ++++++++++++++++-- .../src/new/temporalClass.js | 23 +- .../temporal-polyfill/src/new/timeZone.js | 31 +- .../temporal-polyfill/src/new/timeZoneImpl.js | 294 +++++++++++- .../temporal-polyfill/src/new/timeZoneOps.js | 147 +++++- .../src/new/zonedDateTime.js | 98 ++-- 27 files changed, 1564 insertions(+), 365 deletions(-) create mode 100644 packages/temporal-polyfill/src/new/dateTimeFormat.js diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index fdb16957..7e916673 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -31,8 +31,8 @@ export const [Calendar, createCalendar] = createTemporalClass( // constructorToInternals queryCalendarImpl, - // massageOtherInternals - noop, + // internalsConversionMap + {}, // bagToInternals createComplexBagRefiner('calendar', TimeZone), diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index a578119a..486866ba 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -65,7 +65,7 @@ export const dateStatRefiners = { // NOTE: "basic" names are for converting between Plain* objects. Don't need all numeric fields // export const dateFieldNames = Object.keys(dateFieldRefiners) -export const dateFieldBasics = ['day', 'month', 'year'] +export const dateBasicNames = ['day', 'month', 'year'] export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) // month/monthCode/year export const yearMonthBasicNames = yearMonthFieldNames.slice(1) // monthCode/year export const monthDayFieldNames = dateFieldNames.slice(0, 3) // day/month/monthCode diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index ad6f94b0..2505274e 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -10,12 +10,13 @@ import { } from './calendarConfig' import { allYearFieldNames, - dateFieldBasics, + dateBasicNames, eraYearFieldNames, monthDayFieldNames, monthFieldNames, yearStatNames, } from './calendarFields' +import { IntlDateTimeFormat } from './dateTimeFormat' import { computeIntlMonthsInYearSpan, computeIsoMonthsInYearSpan, diffYearMonthDay } from './diff' import { durationFieldDefaults } from './durationFields' import { isoDateFieldNames, isoTimeFieldDefaults } from './isoFields' @@ -140,6 +141,8 @@ class IsoCalendarImpl { } dateAdd(isoDateFields, durationFields, overflow) { + // TODO: move all of this into move.js file? + const { years, months, weeks, days } = durationFields let ms @@ -168,31 +171,40 @@ class IsoCalendarImpl { } dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { + // TODO: move all of this into diff.js file? + if (largestUnit <= 'week') { // TODO let weeks = 0 let days = diffDaysMilli( isoFieldsToEpochMilli(startIsoDateFields), isoFieldsToEpochMilli(endIsoDateFields), ) + const sign = numSign(days) if (largestUnit === 'day') { // TODO weeks = Math.trunc(days / isoDaysInWeek) days %= isoDaysInWeek } - return { ...durationFieldDefaults, weeks, days } + return { ...durationFieldDefaults, weeks, days, sign } } const yearMonthDayStart = this.queryYearMonthDay(startIsoDateFields) const yearMonthDayEnd = this.queryYearMonthDay(endIsoDateFields) - let [years, months, days] = diffYearMonthDay(...yearMonthDayStart, ...yearMonthDayEnd, this) + let [years, months, days, sign] = diffYearMonthDay( + ...yearMonthDayStart, + ...yearMonthDayEnd, + this, + ) if (largestUnit === 'month') { // TODO months = this.queryMonthsInYearSpan(yearMonthDayStart[0], years) years = 0 } - return { ...durationFieldDefaults, years, months, days } + return { ...durationFieldDefaults, years, months, days, sign } + + // TODO: only return DateDurationFields } // Field "Refining" (Reading & Constraining) @@ -328,7 +340,7 @@ Object.assign(IsoCalendarImpl.prototype, { }) // year/month/day -dateFieldBasics.forEach((dateFieldName, i) => { +dateBasicNames.forEach((dateFieldName, i) => { IsoCalendarImpl.prototype[dateFieldName] = function(isoDateFields) { return isoDateFields[isoDateFieldNames[i]] } @@ -579,6 +591,15 @@ function createEpochMillisecondsToIntlFields(calendarId) { } function parseIntlParts(intlParts, calendarId) { + return { + ...parseIntlYear(intlParts, calendarId), + month: intlParts.month, // a short month string! + day: parseInt(intlParts.day), + } +} + +// best place for this? +export function parseIntlYear(intlParts, calendarId) { let year = parseInt(intlParts.relatedYear || intlParts.year) let era let eraYear @@ -591,29 +612,26 @@ function parseIntlParts(intlParts, calendarId) { } } - return { - era, - eraYear, - year, - month: intlParts.month, // a short month string! - day: parseInt(intlParts.day), - } + return { era, eraYear, year } } -// Intl.DateTimeFormat Utils +// DateTimeFormat Utils // ------------------------------------------------------------------------------------------------- +const standardCalendarId = 'en-GB' // gives 24-hour clock + function buildIntlFormat(calendarId) { - return new Intl.DateTimeFormat('en-US', { + return new IntlDateTimeFormat(standardCalendarId, { calendar: calendarId, + timeZone: 'UTC', era: 'short', // 'narrow' is too terse for japanese months year: 'numeric', month: 'short', // easier to identify monthCodes day: 'numeric', - timeZone: 'UTC', }) } +// best place for this? function hashIntlFormatParts(intlFormat, epochMilliseconds) { const parts = intlFormat.formatToParts(epochMilliseconds) const hash = {} @@ -748,7 +766,7 @@ function getCalendarIdBase(calendarId) { export const isoMonthsInYear = 12 export const isoDaysInWeek = 7 -const isoEpochOriginYear = 1970 +export const isoEpochOriginYear = 1970 // best place? const isoEpochFirstLeapYear = 1972 export function computeIsoMonthsInYear(isoYear) { diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index 679150d4..4338d5c3 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -19,15 +19,16 @@ export function queryCalendarOps(calendarSlot) { return queryCalendarImpl(calendarSlot) // string } -export function getCommonCalendarOps(internals0, internals1) { -} - export function getPublicCalendar(internals) { const { calendar } = internals return getInternals(calendar) || // if CalendarOpsAdapter createCalendar(calendar) // if CalendarImpl } +export function getCommonCalendarOps(internals0, internals1) { + // TODO +} + // Adapter // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index 45f98910..cad2b3f7 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -19,6 +19,7 @@ import { queryCalendarOps } from './calendarOps' import { toInteger, toObject } from './cast' import { durationFieldDefaults, + durationFieldNames, durationFieldRefiners, refineDurationFields, } from './durationFields' @@ -34,9 +35,11 @@ import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainTime } from './plainTime' import { createPlainYearMonth } from './plainYearMonth' -import { computeIsoFieldEpochNanoseconds, getBestInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' +// TODO: rename bag? + // Duration // ------------------------------------------------------------------------------------------------- @@ -44,6 +47,12 @@ export function bagToDurationFields(bag) { return refineDurationFields({ ...durationFieldDefaults, ...bag }) } +export function durationWithBag(durationFields, bag) { + const partialDurationFields = prepareFields(bag, durationFieldNames) + return refineDurationFields({ ...durationFields, ...partialDurationFields }) + // TODO: inefficient b/c refineDurationFields will re-parse +} + // high level yo // ------------------------------------------------------------------------------------------------- @@ -60,7 +69,7 @@ export function bagToZonedDateTimeInternals(bag, options) { const timeZone = queryTimeZoneOps(fields.timeZone) const isoFields = calendarOps.dateFromFields(fields, optionsToOverflow(options)) - const epochNanoseconds = computeIsoFieldEpochNanoseconds( + const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoFields, ...timeFieldsToIso(fields) }, fields.offset !== undefined ? parseOffsetNanoseconds(fields.offset) : undefined, @@ -82,7 +91,7 @@ export function zonedDateTimeWithBag(zonedDateTime, bag, options) { const fields = mergeBag(calendar, zonedDateTime, bag, dateTimeFieldNames, ['offset']) const isoFields = calendar.dateFromFields(fields, optionsToOverflow(options)) - const epochNanoseconds = computeIsoFieldEpochNanoseconds( + const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoFields, ...timeFieldsToIso(fields) }, parseOffsetNanoseconds(fields.offset), @@ -283,18 +292,19 @@ export function plainMonthDayToPlainDate(plainMonthDay, bag) { // to PlainDateTime // ------------------------------------------------------------------------------------------------- -// bad name now. should have something with 'slots' -// should return calendar/timezone??? needed in many places -export function zonedDateTimeInternalsToIso(internals) { - // use timeZone2.js - /* - return instantToPlainDateTime222( - internals.timeZone, - internals.calendar, - createInstant(internals.epochNanoseconds), +export const zonedDateTimeInternalsToIso = createLazyMap(( + internals, // { epochNanoseconds, timeZone } +) => { // { isoYear..., offsetNanoseconds } + const offsetNanoseconds = internals.timeZone.getOffsetNanosecondsFor(internals.epochNanoseconds) + const isoDateTimeFields = epochNanoToIsoFields( + internals.epochNanoseconds.sub(offsetNanoseconds), // subtraction correct? ) - */ -} + + return { + ...isoDateTimeFields, + offsetNanoseconds, + } +}) // to ZonedDateTime // ------------------------------------------------------------------------------------------------- @@ -302,7 +312,7 @@ export function zonedDateTimeInternalsToIso(internals) { export function createZonedDateTimeConverter(getAdditionalIsoFields) { return (internals, options) => { const refinedOptions = toObject(options) // required!!! - const epochNanoseconds = getBestInstantFor( + const epochNanoseconds = getSingleInstantFor( internals.timeZone, { ...internals, @@ -446,3 +456,13 @@ function extractCalendarFieldFromBag(bag) { export function mapRefiners(input, refinerMap) { // loops get driven props of input } + +// util +// ---- + +function createLazyMap() { +} + +function epochNanoToIsoFields() { + +} diff --git a/packages/temporal-polyfill/src/new/dateTimeFormat.js b/packages/temporal-polyfill/src/new/dateTimeFormat.js new file mode 100644 index 00000000..7cef0a87 --- /dev/null +++ b/packages/temporal-polyfill/src/new/dateTimeFormat.js @@ -0,0 +1,268 @@ +import { isoCalendarId } from './calendarConfig' +import { dateBasicNames, timeFieldDefaults } from './calendarFields' +import { isoEpochOriginYear } from './calendarImpl' +import { getInternals } from './internalClass' +import { identityFunc } from './lang' +import { epochNanoToMilli } from './nanoseconds' +import { getTemporalName } from './temporalClass' +import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' + +// DateTimeFormat +// ------------------------------------------------------------------------------------------------- + +export const IntlDateTimeFormat = Intl.DateTimeFormat + +export class DateTimeFormat extends IntlDateTimeFormat { + format(arg) { + const [formattable, format] = resolveSingleFormattable(this, arg) + return format + ? format.format(formattable) + : super.format(formattable) + // must use super because .format is always bound: + // https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype.format + } + + formatToParts(arg) { + const [formattable, format] = resolveSingleFormattable(this, arg) + return format + ? format.formatToParts(formattable) + : super.formatToParts(formattable) + } +} + +['formatRange', 'formatRangeToParts'].forEach((methodName) => { + const origMethod = IntlDateTimeFormat.prototype[methodName] + if (origMethod) { + DateTimeFormat.prototype[methodName] = function(arg0, arg1) { + const [formattable0, formattable1, format] = resolveRangeFormattables(this, arg0, arg1) + return origMethod.call(format || this, formattable0, formattable1) + } + } +}) + +function resolveSingleFormattable(origFormat, arg) { + const getSpecificFormat = getGetSpecificFormat(origFormat) + const resolvedOptions = origFormat.resolvedOptions() + + return resolveFormattable(arg, getSpecificFormat, resolvedOptions) +} + +function resolveRangeFormattables(origFormat, arg0, arg1) { + const getSpecificFormat = getGetSpecificFormat(origFormat) + const resolvedOptions = origFormat.resolvedOptions() + + let [formattable0, format0] = resolveFormattable(arg0, getSpecificFormat, resolvedOptions) + const [formattable1, format1] = resolveFormattable(arg1, getSpecificFormat, resolvedOptions) + + if (format0 && format1) { + if (format0 !== format1) { + throw new TypeError('Accepts two Temporal values of same type') + } + } else { + format0 = undefined + } + + return [formattable0, formattable1, format0] +} + +// Internal Nested DateTimeFormat Cache +// ------------------------------------------------------------------------------------------------- + +const getGetSpecificFormat = createLazyMap(() => createLazyMap(createSpecificFormat), WeakMap) + +function createSpecificFormat(massageOptions, resolvedOptions) { + return new IntlDateTimeFormat(resolvedOptions.locale, massageOptions(resolvedOptions)) +} + +// Resolving Formattable Objects (and Format) +// ------------------------------------------------------------------------------------------------- + +export function resolveZonedFormattable( + internals, // for ZonedDateTime + locales, + options, // NOT resolved yet (does not include locale) +) { + options = { ...options } + + if (options.timeZone !== undefined) { + throw new TypeError('ZonedDateTime toLocaleString does not accept a timeZone option') + } + options.timeZone = internals.timeZone.id + + if ( + options.timeZoneName === undefined && + !hasAnyMatchingProps(options, dateTimeOptionNames) + ) { + // The rest of the defaults will be filled in by formatting the Instant + options.timeZoneName = 'short' + } + + const format = new IntlDateTimeFormat(locales, options) + + checkCalendarsCompatible( + internals.calendar.id, + format.resolvedOptions().calendar, + ) + + return [ + epochNanoToMilli(internals.epochNanoseconds), + format, + ] +} + +function resolveFormattable( + arg, + getSpecificFormat, + resolvedOptions, +) { + const temporalName = getTemporalName(arg) + const massageOptions = optionMassagers[temporalName] + + if (massageOptions) { + const internalsToEpochNano = epochNanoConverters[temporalName] || dateTimeInternalsToEpochNano + const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) + + return [ + epochNanoToMilli(epochNano), + getSpecificFormat(massageOptions, resolvedOptions), + ] + } + + return [arg] +} + +// Format Option Massagers +// ------------------------------------------------------------------------------------------------- + +const timeBasicNames = ['hour', 'minute', 'second'] +const dateTimeBasicNames = [...dateBasicNames, ...timeBasicNames] +const yearMonthBasicNames = ['year', 'month'] +const monthDayBasicNames = ['month', 'day'] + +const dateOptionNames = [ + ...dateBasicNames, + 'weekday', + 'dateStyle', +] +const timeOptionNames = [ + ...timeBasicNames, + 'dayPeriod', // am/pm + 'timeStyle', +] +const dateTimeOptionNames = [ + ...dateOptionNames, + ...timeOptionNames, +] + +const dateTimeExclusions = ['timeZoneName'] +const dateExclusions = [...dateTimeExclusions, ...timeOptionNames] +const timeExclusions = [...dateTimeExclusions, ...dateOptionNames] +const yearMonthExclusions = [ + ...dateTimeExclusions, + 'day', + 'weekday', + 'dateStyle', + ...timeOptionNames, +] +const monthDayExclusions = [ + ...dateTimeExclusions, + 'year', + 'weekday', + 'dateStyle', + ...timeOptionNames, +] + +function createMassager(optionNames, basicNames, exclusionNames) { + const defaults = propsWithSameValue(basicNames, 'numeric') + + return (options) => { + options = excludeProps(options, exclusionNames) + + if (!hasAnyMatchingProps(options, optionNames)) { + Object.assign(options, defaults) + } + + return options + } +} + +const optionMassagers = { + PlainTime: createMassager(timeOptionNames, timeBasicNames, timeExclusions), + PlainDateTime: createMassager(dateTimeOptionNames, dateTimeBasicNames, dateTimeExclusions), + PlainDate: createMassager(dateOptionNames, dateBasicNames, dateExclusions), + PlainYearMonth: createMassager(yearMonthBasicNames, yearMonthBasicNames, yearMonthExclusions), + PlainMonthDay: createMassager(monthDayBasicNames, monthDayBasicNames, monthDayExclusions), + Instant: createMassager(dateTimeOptionNames, dateTimeBasicNames, []), + ZonedDateTime: () => { + throw new TypeError('Cant do on ZonedDateTime') + }, +} + +// Epoch Conversions +// ------------------------------------------------------------------------------------------------- + +const epochNanoConverters = { + Instant: identityFunc, + PlainTime: timeInternalsToEpochNano, + // otherwise, use dateTimeInternalsToEpochNano +} + +function timeInternalsToEpochNano(internals, options) { + return getSingleInstantFor({ + isoYear: isoEpochOriginYear, + isoMonth: 1, + isoDay: 1, + ...internals, + timeZone: queryTimeZoneOps(options.timeZone), + }) +} + +function dateTimeInternalsToEpochNano(internals, options, temporalName) { + checkCalendarsCompatible( + internals.calendar.id, + options.calendarId, + strictCalendarCheck[temporalName], + ) + + return getSingleInstantFor({ + ...timeFieldDefaults, + isoHour: 12, + ...internals, + timeZone: queryTimeZoneOps(options.timeZone), + }) +} + +// Calendar Check +// ------------------------------------------------------------------------------------------------- + +const strictCalendarCheck = { + PlainYearMonth: true, + PlainMonthDay: true, +} + +function checkCalendarsCompatible(calendarId, resolveCalendarId, strict) { + if (!( + calendarId === resolveCalendarId || + (!strict && ( + calendarId === isoCalendarId || + resolveCalendarId === isoCalendarId + )) + )) { + throw new RangeError('Mismatching calendars') + } +} + +// Utils +// ------------------------------------------------------------------------------------------------- + +function excludeProps(options, propNames) { +} + +function hasAnyMatchingProps(props, propNames) { +} + +function createLazyMap() { +} + +function propsWithSameValue() { +} diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 2893c521..9247c5d3 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -1,9 +1,12 @@ import { isoMonthsInYear } from './calendarImpl' import { addDaysToIsoFields, pluckIsoTimeFields } from './isoFields' +import { identityFunc } from './lang' import { compareLargeInts } from './largeInt' -import { nanosecondsInDay } from './nanoseconds' +import { moveDateTime, moveZonedEpochNanoseconds } from './move' +import { nanosecondsInIsoDay } from './nanoseconds' +import { roundLargeNanoseconds, roundRelativeDuration } from './round' -// Diffing & Rounding +// Diffing // ------------------------------------------------------------------------------------------------- export function diffEpochNanoseconds( @@ -14,8 +17,8 @@ export function diffEpochNanoseconds( roundingMode, roundingIncrement, ) { - return diffExactLargeNanoseconds( - roundLargeNanoseconds( + return roundLargeNanoseconds( + diffExactLargeNanoseconds( endEpochNanoseconds.subtract(startEpochNanoseconds), smallestUnit, roundingMode, @@ -26,16 +29,19 @@ export function diffEpochNanoseconds( } export function diffZonedEpochNanoseconds( + calendar, + timeZone, startEpochNanoseconds, endEpochNanoseconds, - timeZone, - calendar, largestUnit, - smallestUnit, - roundingMode, - roundingIncrement, + // for createMarkerSystem's convenience + // TODO: eventually make these universal variables defaultSmallestUnit/defaultRoundingMode + // for input-validation + smallestUnit = 'nanoseconds', + roundingMode = 'halfExpand', + roundingIncrement = 1, ) { - if (smallestUnit < 'day') { // TODO + if (largestUnit < 'day') { // TODO return diffEpochNanoseconds( startEpochNanoseconds, endEpochNanoseconds, @@ -74,23 +80,21 @@ export function diffZonedEpochNanoseconds( return roundRelativeDuration( { ...dateDiff, ...timeDiff, sign }, - startIsoFields, - startEpochNanoseconds, - endIsoFields, endEpochNanoseconds, - isoToZoneEpochNanoseconds, - calendar, - largestUnit, + startEpochNanoseconds, // marker + identityFunc, // markerToEpochNanoseconds + moveZonedEpochNanoseconds.bind(undefined, calendar, timeZone), // moveMarker smallestUnit, roundingMode, roundingIncrement, + largestUnit, ) } export function diffDateTimes( + calendar, startIsoFields, endIsoFields, - calendar, largestUnit, smallestUnit, roundingMode, @@ -99,7 +103,7 @@ export function diffDateTimes( const startEpochNanoseconds = isoToUtcEpochNanoseconds(startIsoFields) const endEpochNanoseconds = isoToUtcEpochNanoseconds(endIsoFields) - if (smallestUnit < 'day') { // TODO + if (largestUnit < 'day') { // TODO return diffEpochNanoseconds( startEpochNanoseconds, endEpochNanoseconds, @@ -109,12 +113,13 @@ export function diffDateTimes( roundingIncrement, ) } + // TODO: what about day optimization? const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) const startTimeNanoseconds = isoTimeToNanoseconds(startIsoFields) // number const endTimeNanoseconds = isoTimeToNanoseconds(endIsoFields) // number let timeNanosecondDiff = endTimeNanoseconds - startTimeNanoseconds - const timeSign = numberSign(timeNanosecondDiff) + const timeSign = Math.sign(timeNanosecondDiff) let midIsoFields = startIsoFields if (timeSign === -sign) { @@ -122,7 +127,7 @@ export function diffDateTimes( ...addDaysToIsoFields(startIsoFields, sign), ...pluckIsoTimeFields(startIsoFields), } - timeNanosecondDiff += nanosecondsInDay + timeNanosecondDiff += nanosecondsInIsoDay } const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnit) @@ -133,35 +138,30 @@ export function diffDateTimes( return roundRelativeDuration( { ...dateDiff, ...timeDiff, sign }, - startIsoFields, - startEpochNanoseconds, - endIsoFields, endEpochNanoseconds, - isoToUtcEpochNanoseconds, - calendar, - largestUnit, + startIsoFields, // marker + isoToUtcEpochNanoseconds, // markerToEpochNanoseconds + moveDateTime.bind(undefined, calendar), // moveMarker smallestUnit, roundingMode, roundingIncrement, + largestUnit, ) } export function diffDates( + calendar, startIsoDateFields, endIsoDateFields, - calendar, largestUnit, smallestUnit, roundingMode, roundingIncrement, ) { - const startEpochNanoseconds = isoToUtcEpochNanoseconds(startIsoDateFields) - const endEpochNanoseconds = isoToUtcEpochNanoseconds(endIsoDateFields) - - if (smallestUnit < 'day') { // TODO + if (largestUnit < 'day') { // TODO return diffEpochNanoseconds( - startEpochNanoseconds, - endEpochNanoseconds, + isoToUtcEpochNanoseconds(startIsoDateFields), + isoToUtcEpochNanoseconds(endIsoDateFields), largestUnit, smallestUnit, roundingMode, @@ -173,16 +173,14 @@ export function diffDates( return roundRelativeDuration( dateDiff, - startIsoDateFields, - startEpochNanoseconds, - endIsoDateFields, - endEpochNanoseconds, - isoToUtcEpochNanoseconds, - calendar, - largestUnit, + isoToUtcEpochNanoseconds(endIsoDateFields), + startIsoDateFields, // marker + isoToUtcEpochNanoseconds, // markerToEpochNanoseconds + calendar.dateAdd.bind(calendar), // moveMarker smallestUnit, roundingMode, roundingIncrement, + largestUnit, ) } @@ -213,8 +211,8 @@ export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calen } updateYearMonthDay() - const daySign = numberSign(dayDiff) - const sign = numberSign(yearDiff) || numberSign(monthDiff) || daySign + const daySign = Math.sign(dayDiff) + const sign = Math.sign(yearDiff) || Math.sign(monthDiff) || daySign if (sign) { // overshooting day? - correct by moving to penultimate month @@ -228,7 +226,7 @@ export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calen } // overshooting month? - correct by moving to penultimate year - const monthSign = numberSign(monthDiff) + const monthSign = Math.sign(monthDiff) if (monthSign && monthSign !== sign) { const oldMonthsInYear1 = monthsInYear1 year1 -= sign @@ -239,7 +237,7 @@ export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calen } } - return [yearDiff, monthDiff, dayDiff] + return [yearDiff, monthDiff, dayDiff, sign] } export function computeIsoMonthsInYearSpan(isoYearStart, yearDelta) { @@ -248,7 +246,7 @@ export function computeIsoMonthsInYearSpan(isoYearStart, yearDelta) { export function computeIntlMonthsInYearSpan(yearStart, yearDelta, calendarImpl) { const yearEnd = yearStart + yearDelta - const yearSign = numberSign(yearDelta) + const yearSign = Math.sign(yearDelta) const yearCorrection = yearSign < 0 ? -1 : 0 let months = 0 @@ -259,28 +257,6 @@ export function computeIntlMonthsInYearSpan(yearStart, yearDelta, calendarImpl) return months } -// Public Duration Stuff -// ------------------------------------------------------------------------------------------------- - -export function roundDuration( - durationFields, - largestUnit, - smallestUnit, - roundingMode, - roundingIncrement, - relativeTo, -) { - -} - -export function computeDurationTotal( - durationFields, - unit, - relativeTo, -) { - -} - // Exact Diffing // ------------------------------------------------------------------------------------------------- @@ -288,36 +264,6 @@ function diffExactLargeNanoseconds( nanoseconds, largestUnit, ) { - -} - -// Rounding -// ------------------------------------------------------------------------------------------------- - -function roundRelativeDuration( - durationFields, - startIsoFields, - startEpochNanoseconds, - endIsoFields, - endEpochNanoseconds, - isoToZoneEpochNanoseconds, - calendar, - largestUnit, - smallestUnit, - roundingMode, - roundingIncrement, -) { - // TOOO: figure out edge case where time fields round up past end of zoned day, - // and then must be rerounded with the next day's reference frame -} - -function roundLargeNanoseconds( - nanoseconds, - smallestUnit, - roundingMode, - roundingIncrement, -) { - } // Epoch/Time @@ -349,10 +295,3 @@ function isoToEpochNanoseconds(isoFields, timeZone, disambig) { function isoToPossibleEpochNanoseconds(isoFields, timeZone) { } - -// Random Utils -// ------------------------------------------------------------------------------------------------- - -function numberSign(number) { - -} diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index b9606159..c7cfc2f8 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -1,13 +1,24 @@ -import { bagToDurationFields } from './convert' +import { bagToDurationFields, durationWithBag } from './convert' +import { diffZonedEpochNanoseconds } from './diff' import { absolutizeDurationFields, + addDurationFields, durationFieldGetters, negateDurationFields, refineDurationFields, } from './durationFields' import { neverValueOf } from './internalClass' -import { noop } from './lang' +import { identityFunc, noop } from './lang' +import { compareLargeInts } from './largeInt' +import { moveZonedEpochNanoseconds } from './move' +import { optionsToLargestUnit } from './options' import { stringToDurationFields } from './parse' +import { + roundDayTimeDuration, + roundRelativeDuration, + totalDayTimeDuration, + totalRelativeDuration, +} from './round' import { createTemporalClass } from './temporalClass' export const [ @@ -47,8 +58,8 @@ export const [ }) }, - // massageOtherInternals - noop, + // internalsConversionMap + {}, // bagToInternals bagToDurationFields, @@ -74,18 +85,11 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(someDurationFields) { - // TODO - // TODO: will need to recompute sign!!! - }, + with: durationWithBag, - add(internals, options) { - // TODO - }, + add: addToDuration.bind(undefined, 1), - subtract(internals, options) { - // TODO - }, + subtract: addToDuration.bind(undefined, -1), negated(internals) { return createDuration(negateDurationFields(internals)) @@ -96,11 +100,53 @@ export const [ }, round(internals, options) { - // TODO + const largestUnit = optionsToLargestUnit(options) // accepts auto? + const smallestUnit = optionsToSmallestUnit(options) + const roundingIncrement = optionsToRoundingIncrement(options) + const roundingMode = optionsToRoundingMode(options) + const markerInternals = optionsToRelativeTo(options) // optional + + if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { + // TODO: check internals doesn't have large fields + return roundDayTimeDuration(internals, smallestUnit, roundingMode, roundingIncrement) + } + + if (!markerInternals) { + throw new RangeError('need relativeTo') + } + + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + + return roundRelativeDuration( + ...spanDuration(internals, largestUnit, ...markerSystem), + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ...markerSystem, + ) }, - total(internals, unit) { - // TODO + total(internals, options) { + const totalUnit = optionsToTotalUnit(options) + const markerInternals = optionsToRelativeTo(options) // optional + const largestUnit = getLargestDurationUnit(internals) + + if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { + return totalDayTimeDuration(internals, totalUnit) + } + + if (!markerInternals) { + throw new RangeError('need relativeTo') + } + + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + + return totalRelativeDuration( + ...spanDuration(internals, largestUnit, ...markerSystem), + totalUnit, + ...markerSystem, + ) }, valueOf: neverValueOf, @@ -110,8 +156,120 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(durationArg0, durationArg1) { - // TODO + compare(durationArg0, durationArg1, options) { + const durationFields0 = toDurationInternals(durationArg0) + const durationFields1 = toDurationInternals(durationArg1) + const markerInternals = optionsToRelativeTo(options) // optional + const largestUnit = Math.max( + getLargestDurationUnit(durationFields0), + getLargestDurationUnit(durationFields1), + ) + + if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { + return compareLargeInts( + durationDayTimeToNanoseconds(durationFields0), + durationDayTimeToNanoseconds(durationFields1), + ) + } + + if (!markerInternals) { + throw new RangeError('need relativeTo') + } + + const [marker, markerToEpochNanoseconds, moveMarker] = createMarkerSystem(markerInternals) + + return compareLargeInts( + markerToEpochNanoseconds(moveMarker(marker, durationFields0)), + markerToEpochNanoseconds(moveMarker(marker, durationFields1)), + ) }, }, ) + +// Utils +// ------------------------------------------------------------------------------------------------- + +function addToDuration(direction, internals, otherArg, options) { + const otherFields = toDurationInternals(otherArg) + const markerInternals = optionsToRelativeTo(options) // optional + const largestUnit = Math.max( + getLargestDurationUnit(internals), + getLargestDurationUnit(otherFields), + ) + + const addedDurationFields = addDurationFields(internals, otherFields, direction) + + if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { + return balanceDurationDayTime(addedDurationFields) + } + + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + return spanDuration(internals, largestUnit, ...markerSystem)[0] +} + +function createMarkerSystem(markerInternals) { + const { calendar, timeZone, epochNanoseconds } = markerInternals + + if (epochNanoseconds) { + return [ + epochNanoseconds, // marker + identityFunc, // markerToEpochNanoseconds + moveZonedEpochNanoseconds.bind(undefined, calendar, timeZone), // moveMarker + diffZonedEpochNanoseconds.bind(undefined, calendar, timeZone), // diffMarkers + ] + } else { + return [ + markerInternals, // marker (IsoDateFields) + isoToUtcEpochNanoseconds, // markerToEpochNanoseconds + calendar.dateAdd.bind(calendar), // moveMarker + calendar.dateUntil.bind(calendar), // diffMarkers + ] + } +} + +function spanDuration( + durationFields, + largestUnit, + // marker system... + marker, + markerToEpochNanoseconds, + moveMarker, + diffMarkers, +) { + const endMarker = markerToEpochNanoseconds(moveMarker(marker, durationFields)) + const balancedDuration = diffMarkers(marker, endMarker, largestUnit) + return [balancedDuration, endMarker] +} + +function balanceDurationDayTime( + durationFields, + largestUnit, // day/time +) { +} + +function getLargestDurationUnit(durationFields) { +} + +function durationDayTimeToNanoseconds( + durationFields, // NOT BALANCED +) { +} + +function optionsToTotalUnit() { +} + +function optionsToRelativeTo() { + // should return ZoneDateTimeINTERNALS or PlainDateINTERNALS +} + +function isoToUtcEpochNanoseconds(isoFields) { +} + +function optionsToSmallestUnit(options) { +} + +function optionsToRoundingIncrement(options) { +} + +function optionsToRoundingMode(options) { +} diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index e2d5e2b9..9e79ecc1 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -81,3 +81,7 @@ function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { // should throw error if mismatch // TODO: audit repeat uses of this } + +export function addDurationFields(durationFields0, durationFields1, sign) { + +} diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 18b4b15a..4401b9f3 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -21,10 +21,10 @@ import { nanosecondsInSecond, regulateEpochNanoseconds, } from './nanoseconds' -import { roundEpochNanoseconds } from './round' +import { roundLargeNanoseconds } from './round' import { createTemporalClass } from './temporalClass' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' -import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' +import { createZonedDateTime } from './zonedDateTime' export const [ Instant, @@ -41,11 +41,9 @@ export const [ return regulateEpochNanoseconds(toLargeInt(epochNanoseconds)) }, - // massageOtherInternals - (arg, argInternals) => { - if (arg instanceof ZonedDateTime) { - return argInternals.epochNanoseconds - } + // internalsConversionMap + { + ZonedDateTime: (argInternals) => argInternals.epochNanoseconds, }, // bagToInternals @@ -119,7 +117,12 @@ export const [ }, round(epochNanoseconds, options) { - return createInstant(roundEpochNanoseconds(epochNanoseconds, options)) + return createInstant( + roundLargeNanoseconds( + epochNanoseconds, + options, // TODO: break apart options + ), + ) }, equals(epochNanoseconds, otherArg) { @@ -136,7 +139,10 @@ export const [ const calendar = queryCalendarOps(refinedOptions.calendar || isoCalendarId) const timeZone = queryTimeZoneOps(refinedOptions.timeZone || utcTimeZoneId) - epochNanoseconds = roundEpochNanoseconds(epochNanoseconds, refinedOptions) + epochNanoseconds = roundLargeNanoseconds( + epochNanoseconds, + refinedOptions, // TODO: break apart options + ) const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) const isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) diff --git a/packages/temporal-polyfill/src/new/internalClass.js b/packages/temporal-polyfill/src/new/internalClass.js index 86ec4f58..9a4cd323 100644 --- a/packages/temporal-polyfill/src/new/internalClass.js +++ b/packages/temporal-polyfill/src/new/internalClass.js @@ -1,6 +1,6 @@ import { mapHash } from '../utils/obj' import { strictInstanceOf } from './cast' -import { identityFunc } from './lang' +import { identityFunc, noop } from './lang' import { createGetterDescriptors, createPropDescriptors } from './obj' export const internalsMap = new WeakMap() @@ -14,9 +14,11 @@ export function createInternalClass( constructorToInternals = identityFunc, extraPrototypeDescriptors = {}, staticMembers = {}, + handleInstance = noop, ) { function InternalObj(...args) { internalsMap.set(this, constructorToInternals(...args)) + handleInstance(this) } function curryMethod(method) { diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index ef00493c..514ea7ec 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -88,9 +88,14 @@ export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { } export function addDaysToIsoFields() { - + // short-circuit if nothing to add } export function isValidIsoFields() { } + +/* +TODO: move AWAY from just 'isofields' because might get confused with getISOFields() +name it 'isodatetimefields' +*/ diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 3faf70ac..a4b37120 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -11,10 +11,10 @@ export function moveEpochNanoseconds(epochNanoseconds, durationFields) { } export function moveZonedEpochNanoseconds( - epochNanoseconds, - durationFields, calendar, timeZone, + epochNanoseconds, + durationFields, overflowHandling, ) { const durationTimeNanoseconds = isoTimeFieldsToNanoseconds( @@ -45,9 +45,9 @@ export function moveZonedEpochNanoseconds( } export function moveDateTime( + calendar, isoDateTimeFields, durationFields, - calendar, overflowHandling, ) { const [movedIsoTimeFields, dayDelta] = addIsoTimeFields( diff --git a/packages/temporal-polyfill/src/new/nanoseconds.js b/packages/temporal-polyfill/src/new/nanoseconds.js index 9ac4b7da..aed4d913 100644 --- a/packages/temporal-polyfill/src/new/nanoseconds.js +++ b/packages/temporal-polyfill/src/new/nanoseconds.js @@ -3,7 +3,13 @@ export const nanosecondsInMillisecond = 1000000 export const nanosecondsInSecond = 1000000000 export const nanosecondsInMinute = 60000000000 // used? export const nanosecondsInHour = 3600000000000 -export const nanosecondsInDay = 86400000000000 // used? +export const nanosecondsInIsoDay = 86400000000000 + +export const nanosecondsInUnit = {} // include iso-day as well + +export function epochNanoToMilli(epochNano) { + return epochNano.div(nanosecondsInMillisecond).toNumber() +} export const epochGetters = { epochNanoseconds(epochNanoseconds) { @@ -14,12 +20,10 @@ export const epochGetters = { return epochNanoseconds.div(nanosecondsInMicrosecond).toBigInt() }, - epochMilliseconds(epochNanoseconds) { - return epochNanoseconds.div(nanosecondsInMillisecond).toBigInt() - }, + epochMilliseconds: epochNanoToMilli, epochSeconds(epochNanoseconds) { - return epochNanoseconds.div(nanosecondsInSecond).toBigInt() + return epochNanoseconds.div(nanosecondsInSecond).toNumber() }, } @@ -32,5 +36,9 @@ export function isoTimeFieldsToNanoseconds() { } export function nanosecondsToIsoTimeFields() { + /* + const dayDelta = Math.floor(nanoseconds / nanosecondsInIsoDay) + nanoseconds %= nanosecondsInIsoDay + */ // return [isoTimeFields, dayDelta] } diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index 90cd66fc..8b3af1c4 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -2,8 +2,9 @@ import { nanoInMilli } from '../dateUtils/units' import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { zonedDateTimeInternalsToIso } from './convert' +import { IntlDateTimeFormat } from './dateTimeFormat' import { createInstant } from './instant' -import { pluckIsoDateSlots, pluckIsoTimeFields } from './isoFields' +import { pluckIsoDateSlots, pluckIsoDateTimeSlots, pluckIsoTimeFields } from './isoFields' import { createLargeInt } from './largeInt' import { createPropDescriptors, createTemporalNameDescriptors } from './obj' import { createPlainDate } from './plainDate' @@ -56,7 +57,9 @@ function getCurrentInstant() { } function getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg) { - return zonedDateTimeInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)) + return pluckIsoDateTimeSlots( + zonedDateTimeInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)), + ) } function getCurrentZonedDateTimeSlots( @@ -75,5 +78,5 @@ function getCurrentEpochNanoseconds() { } function getCurrentTimeZoneId() { - return new Intl.DateTimeFormat().resolvedOptions().timeZone + return new IntlDateTimeFormat().resolvedOptions().timeZone } diff --git a/packages/temporal-polyfill/src/new/parse.js b/packages/temporal-polyfill/src/new/parse.js index ee576fd6..a03dc14a 100644 --- a/packages/temporal-polyfill/src/new/parse.js +++ b/packages/temporal-polyfill/src/new/parse.js @@ -6,7 +6,7 @@ import { pluckIsoDateTimeSlots, pluckIsoTimeFields, } from './isoFields' -import { computeIsoFieldEpochNanoseconds, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' +import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' // High-level @@ -22,7 +22,7 @@ export function stringToZonedDateTimeInternals(s) { const calendar = queryCalendarOps(parsed.calendarId || isoCalendarId) const timeZone = queryTimeZoneOps(parsed.timeZoneId) - const epochNanoseconds = computeIsoFieldEpochNanoseconds( + const epochNanoseconds = getMatchingInstantFor( timeZone, parsed, parsed.offset !== undefined ? parseOffsetNanoseconds(parsed.offset) : undefined, diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 5c31097b..5c909c62 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -30,10 +30,9 @@ import { } from './isoFields' import { optionsToOverflow } from './options' import { stringToPlainDateInternals } from './parse' -import { PlainDateTime, createPlainDateTime } from './plainDateTime' +import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' -import { createTemporalClass } from './temporalClass' -import { ZonedDateTime } from './zonedDateTime' +import { createTemporalClass, toLocaleStringMethod } from './temporalClass' export const [ PlainDate, @@ -57,14 +56,10 @@ export const [ ) }, - // massageOtherInternals - (arg, argInternals) => { - if (arg instanceof PlainDateTime) { - return pluckIsoDateSlots(argInternals) - } - if (arg instanceof ZonedDateTime) { - return zonedDateTimeInternalsToIso(argInternals) - } + // internalsConversionMap + { + PlainDateTime: pluckIsoDateSlots, + ZonedDateTime: (argInternals) => pluckIsoDateSlots(zonedDateTimeInternalsToIso(argInternals)), }, // bagToInternals @@ -135,9 +130,7 @@ export const [ formatCalendar(internals.calendar, options) }, - toLocaleString(internals, locales, options) { - return '' - }, + toLocaleString: toLocaleStringMethod, valueOf: neverValueOf, diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 14c8f194..7635c0ec 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -17,22 +17,23 @@ import { formatCalendar, formatIsoDateTimeFields } from './format' import { neverValueOf } from './internalClass' import { compareIsoFields, + constrainIsoDateTimeFields, generatePublicIsoDateTimeFields, isoDateTimeSlotRefiners, isoTimeFieldDefaults, pluckIsoDateSlots, + pluckIsoDateTimeSlots, pluckIsoTimeFields, - constrainIsoDateTimeFields, } from './isoFields' import { moveDateTime } from './move' import { optionsToOverflow, toDisambiguation, validateRoundingOptions } from './options' import { stringToPlainDateTimeInternals } from './parse' -import { PlainDate, createPlainDate, toPlainDateInternals } from './plainDate' +import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' -import { createTemporalClass } from './temporalClass' -import { getBestInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' +import { createTemporalClass, toLocaleStringMethod } from './temporalClass' +import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { createZonedDateTime } from './zonedDateTime' export const [ PlainDateTime, @@ -73,14 +74,12 @@ export const [ ) }, - // massageOtherInternals - (arg, argInternals) => { - if (arg instanceof PlainDate) { - return { ...argInternals, ...isoTimeFieldDefaults } - } - if (arg instanceof ZonedDateTime) { - return zonedDateTimeInternalsToIso(argInternals) - } + // internalsConversionMap + { + PlainDate: (argInternals) => ({ ...argInternals, ...isoTimeFieldDefaults }), + ZonedDateTime: (argInternals) => { + return pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(argInternals)) + }, }, // bagToInternals @@ -129,9 +128,9 @@ export const [ add(internals, durationArg, options) { return createPlainDateTime( moveDateTime( + internals.calendar, internals, toDurationInternals(durationArg), - internals.calendar, optionsToOverflow(options), ), ) @@ -140,9 +139,9 @@ export const [ subtract(internals, durationArg, options) { return createPlainDateTime( moveDateTime( + internals.calendar, internals, negateDurationFields(toDurationInternals(durationArg)), - internals.calendar, optionsToOverflow(options), ), ) @@ -150,6 +149,7 @@ export const [ until(internals, otherArg, options) { return diffDateTimes( + // TODO: give calendar arg internals, toPlainDateTimeInternals(otherArg), options, // TODO: spread out lots of options!!! @@ -158,6 +158,7 @@ export const [ since(internals, otherArg, options) { return diffDateTimes( + // TODO: give calendar arg toPlainDateTimeInternals(otherArg), internals, options, // TODO: flip rounding options @@ -185,9 +186,7 @@ export const [ formatCalendar(internals.calendar, options) }, - toLocaleString(internals, locales, options) { - return '' - }, + toLocaleString: toLocaleStringMethod, valueOf: neverValueOf, @@ -198,7 +197,7 @@ export const [ ) { const { calendar } = internals const timeZone = queryTimeZoneOps(timeZoneArg) - const epochNanoseconds = getBestInstantFor(timeZone, internals, toDisambiguation(options)) + const epochNanoseconds = getSingleInstantFor(timeZone, internals, toDisambiguation(options)) return createZonedDateTime({ epochNanoseconds, diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index eaabd7d0..a208b643 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -16,10 +16,9 @@ import { generatePublicIsoDateFields, isoDateSlotRefiners, } from './isoFields' -import { noop } from './lang' import { optionsToOverflow } from './options' import { stringToMonthDayInternals } from './parse' -import { createTemporalClass } from './temporalClass' +import { createTemporalClass, toLocaleStringMethod } from './temporalClass' export const [ PlainMonthDay, @@ -43,8 +42,8 @@ export const [ ) }, - // massageOtherInternals - noop, + // internalsConversionMap + {}, // bagToInternals bagToPlainMonthDayInternals, @@ -78,9 +77,7 @@ export const [ return formatPossibleDate(internals, options, formatIsoMonthDayFields) }, - toLocaleString(internals, locales, options) { - return '' - }, + toLocaleString: toLocaleStringMethod, valueOf: neverValueOf, diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 148b62b1..e7f9483d 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -13,18 +13,17 @@ import { formatIsoTimeFields } from './format' import { neverValueOf } from './internalClass' import { compareIsoTimeFields, + constrainIsoTimeFields, isoTimeFieldRefiners, pluckIsoTimeFields, - constrainIsoTimeFields, } from './isoFields' import { moveTime } from './move' import { optionsToOverflow } from './options' import { stringToPlainTimeInternals } from './parse' import { toPlainDateInternals } from './plainDate' -import { PlainDateTime, createPlainDateTime } from './plainDateTime' +import { createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' -import { createTemporalClass } from './temporalClass' -import { ZonedDateTime } from './zonedDateTime' +import { createTemporalClass, toLocaleStringMethod } from './temporalClass' export const [ PlainTime, @@ -57,14 +56,10 @@ export const [ ) }, - // massageOtherInternals - (arg, argInternals) => { - if (arg instanceof PlainDateTime) { - return pluckIsoTimeFields(argInternals) - } - if (arg instanceof ZonedDateTime) { - return pluckIsoTimeFields(zonedDateTimeInternalsToIso(argInternals)) - } + // internalsConversionMap + { + PlainDateTime: pluckIsoTimeFields, + ZonedDateTime: (argInternals) => pluckIsoTimeFields(zonedDateTimeInternalsToIso(argInternals)), }, // bagToInternals @@ -141,9 +136,7 @@ export const [ return formatIsoTimeFields(roundIsoTimeFields(internals, options), options) }, - toLocaleString(internals, locales, options) { - return '' - }, + toLocaleString: toLocaleStringMethod, valueOf: neverValueOf, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 412399ea..ea7cb842 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -20,10 +20,9 @@ import { generatePublicIsoDateFields, isoDateSlotRefiners, } from './isoFields' -import { noop } from './lang' import { optionsToOverflow } from './options' import { stringToPlainYearMonthInternals } from './parse' -import { createTemporalClass } from './temporalClass' +import { createTemporalClass, toLocaleStringMethod } from './temporalClass' export const [ PlainYearMonth, @@ -47,8 +46,8 @@ export const [ ) }, - // massageOtherInternals - noop, + // internalsConversionMap + {}, // bagToInternals bagToPlainYearMonthInternals, @@ -124,9 +123,7 @@ export const [ return formatPossibleDate(internals, options, formatIsoYearMonthFields) }, - toLocaleString(internals, locales, options) { - return '' - }, + toLocaleString: toLocaleStringMethod, valueOf: neverValueOf, diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 7ca124c2..010aadba 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -1,63 +1,416 @@ -import { isTimeUnit, toSmallestUnit } from './options' +import { durationFieldDefaults, durationTimeFieldDefaults } from './durationFields' +import { addDaysToIsoFields, isoTimeFieldDefaults } from './isoFields' +import { identityFunc } from './lang' +import { createLargeInt } from './largeInt' +import { + isoTimeFieldsToNanoseconds, + nanosecondsInIsoDay, + nanosecondsInUnit, + nanosecondsToIsoTimeFields, +} from './nanoseconds' +import { computeNanosecondsInDay } from './timeZoneOps' -/* -(RoundDuration) -Only has smallestUnit -Options includes relativeTo -should work for ANY smallestUnit +export function roundToMinute(nanoseconds) { // can be positive or negative -does NOT do balancing, because caller might want a specific type of balancing -*/ -export function roundDurationInternals(durationInternals, options) { +} + +// Rounding Dates +// ------------------------------------------------------------------------------------------------- + +export function roundIsoDateTimeFields( + isoDateTimeFields, + smallestUnit, // day/time + roundingMode, + roundingIncrement, + timeZoneOps = undefined, +) { + let isoTimeFields + let dayDelta + + if (smallestUnit === 'day') { + const nanosecondsInDay = timeZoneOps + ? computeNanosecondsInDay(timeZoneOps, isoDateTimeFields) + : nanosecondsInIsoDay + dayDelta = roundNanoseconds( + isoTimeFieldsToNanoseconds(isoDateTimeFields), + nanosecondsInDay, + roundingMode, + ) + + isoTimeFields = isoTimeFieldDefaults + } else { + ([isoTimeFields, dayDelta] = roundIsoTimeFields( + isoDateTimeFields, + smallestUnit, + roundingMode, + roundingIncrement, + )) + } + + return { + ...addDaysToIsoFields(isoDateTimeFields, dayDelta), + ...isoTimeFields, + } } -/* -NOTE: Duration should call this if relativeTo is a ZonedDateTime -*/ -export function adjustDurationFieldsForTimeZone( - durationInternals, - zonedDateTime, - options, // { roundingIncrement, smallestUnit, roundingMode } +export function roundIsoTimeFields( + isoTimeFields, + smallestUnit, // time + roundingMode, + roundingIncrement, ) { - // AdjustRoundedDurationDays + const nanoseconds = roundNanoseconds( + isoTimeFieldsToNanoseconds(isoTimeFields), + nanosecondsInUnit[smallestUnit] * roundingIncrement, + roundingMode, + ) + return nanosecondsToIsoTimeFields(nanoseconds) +} + +// Rounding Duration +// ------------------------------------------------------------------------------------------------- - const smallestUnit = toSmallestUnit(options) +export function roundDayTimeDuration( + durationFields, + smallestUnit, + roundingMode, + roundingIncrement, +) { + const largeNanoseconds = durationDayTimeToNanoseconds(durationFields) + const r = roundLargeNanoseconds(largeNanoseconds, smallestUnit, roundingMode, roundingIncrement) + return nanosecondsToDurationDayTime(r) +} - // short-circuit if time-rounding won't happen - if ( - !isTimeUnit(smallestUnit) || - (smallestUnit === 'nanosecond' && options.roundingIncrement === 1) - ) { - return durationInternals +export function roundRelativeDuration( + durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNanoseconds, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, +) { + if (smallestUnit === 'nanoseconds' && roundingIncrement === 1) { + return durationFields } + + let [roundedDurationFields, roundedEpochNanoseconds, grew] = ( + smallestUnit >= 'day' + ? nudgeRelativeDuration + : markerToEpochMilliseconds === identityFunc // marker is ZonedDateTime's epochNanoseconds? + ? nudgeRelativeDurationTime + : nudgeDurationTime + )( + durationFields, + endEpochNanoseconds, + smallestUnit, + roundingMode, + roundingIncrement, + // marker system only needed for nudgeRelativeDuration... + marker, + moveMarker, + markerToEpochMilliseconds, + ) + + // grew a day/week/month/year? + if (grew) { + roundedDurationFields = bubbleRelativeDuration( + roundedDurationFields, + roundedEpochNanoseconds, + largestUnit, + smallestUnit, + // marker system... + marker, + moveMarker, + markerToEpochMilliseconds, + ) + } + + return roundedDurationFields } -function getNanosecondsInNormalDay() { - return 86400e9 +// Rounding Numbers +// ------------------------------------------------------------------------------------------------- + +export function roundLargeNanoseconds( + largeNanoseconds, + smallestUnit, + roundingMode, + roundingIncrement, +) { + let [timeNanoseconds, days] = splitDayTimeNanoseconds(largeNanoseconds) + + timeNanoseconds = roundNanoseconds( + timeNanoseconds, + nanosecondsInUnit[smallestUnit] * roundingIncrement, + roundingMode, + ) + + const dayDelta = Math.trunc(timeNanoseconds / nanosecondsInIsoDay) + timeNanoseconds %= nanosecondsInIsoDay + + return createLargeInt(nanosecondsInIsoDay).mult(days + dayDelta).add(timeNanoseconds) } -export function roundIsoDateTimeFields( - isoFields, - options, - getNanosecondsInDay = getNanosecondsInNormalDay, +function splitDayTimeNanoseconds(largeNanoseconds) { + const days = largeNanoseconds.div(nanosecondsInIsoDay) + const dayNanoseconds = createLargeInt(nanosecondsInIsoDay).mult(days) + const timeNanoseconds = largeNanoseconds.sub(dayNanoseconds) + return [timeNanoseconds, days] +} + +function roundNanoseconds(num, nanoIncrement, roundingMode) { + return roundWithMode(num / nanoIncrement, roundingMode) * nanoIncrement +} + +function roundWithMode(num, roundingMode) { +} + +// Total Duration +// ------------------------------------------------------------------------------------------------- + +export function totalDayTimeDuration( // assumes iso-length days + durationFields, + unit, ) { - const isoTimeFields = roundIsoTimeFields(isoFields, options, getNanosecondsInDay) - return combineThem(isoFields, isoTimeFields) + const largeNanoseconds = durationDayTimeToNanoseconds(durationFields) + return largeNanoseconds.divide(nanosecondsInUnit[unit]).toNumber() } -export function roundIsoTimeFields( - isoTimeFields, - options, - getNanosecondsInDay = getNanosecondsInNormalDay, +export function totalRelativeDuration( + durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNanoseconds, + totalUnit, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, ) { - // returns isoTimeFields back + const { sign } = durationFields + + const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( + clearDurationFields(durationFields, 'nanoseconds', totalUnit - 1), + totalUnit, + sign, + // marker system... + marker, + moveMarker, + markerToEpochMilliseconds, + ) + + const portion = + endEpochNanoseconds.subtract(epochNanoseconds0).toNumber() / + epochNanoseconds1.subtract(epochNanoseconds0).toNumber() + + return durationFields[totalUnit] + portion } -function combineThem(isoDateFields, isoTimeFields) { - // uses 'day' field as delta. will rebalance date (using iso util) +// Nudge +// ------------------------------------------------------------------------------------------------- + +function nudgeDurationTime( + durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNanoseconds, // NOT NEEDED, just for adding result to + smallestUnit, + roundingMode, + roundingIncrement, +) { + const nano = durationTimeToNanoseconds(durationFields) + const roundedNano = roundNanoseconds( + nano, + nanosecondsInUnit[smallestUnit] * roundingIncrement, + roundingMode, + ) + + const [durationTimeFields, dayDelta] = nanosecondsToDurationTime(roundedNano) + const nudgedDurationFields = { + ...durationFields, + days: durationFields.days + dayDelta, + ...durationTimeFields, + } + + return [ + nudgedDurationFields, + endEpochNanoseconds.add(roundedNano - nano), + dayDelta, + ] } -export function roundEpochNanoseconds(epochNanoseconds, options) { +function nudgeRelativeDurationTime( + durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNanoseconds, // NOT NEEDED, just for conformance + smallestUnit, + roundingMode, + roundingIncrement, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, +) { + const { sign } = durationFields + const divisor = nanosecondsInUnit[smallestUnit] * roundingIncrement + const nano = durationTimeToNanoseconds(durationFields) + let roundedNano = roundNanoseconds(nano, divisor, roundingMode) + + const [dayEpochNanoseconds0, dayEpochNanoseconds1] = clampRelativeDuration( + { ...durationFields, ...durationTimeFieldDefaults }, + 'days', + sign, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, + ) + + const daySpanEpochNanoseconds = dayEpochNanoseconds1.subtract(dayEpochNanoseconds0).toNumber() + const beyondDay = roundedNano - daySpanEpochNanoseconds + let dayDelta = 0 + + if (!beyondDay || Math.sign(beyondDay) === sign) { + dayDelta++ + roundedNano = roundNanoseconds(beyondDay, divisor, roundingMode) + endEpochNanoseconds = dayEpochNanoseconds1.add(roundedNano) + } else { + endEpochNanoseconds = dayEpochNanoseconds0.add(roundedNano) + } + + const [durationTimeFields] = nanosecondsToDurationTime(roundedNano) + const nudgedDurationFields = { + ...durationFields, + days: durationFields.days + dayDelta, + ...durationTimeFields, + } + + return [nudgedDurationFields, endEpochNanoseconds, dayDelta] +} + +function nudgeRelativeDuration( + durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNanoseconds, + smallestUnit, + roundingMode, + roundingIncrement, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, +) { + const { sign } = durationFields + + const baseDurationFields = clearDurationFields(durationFields, 'nanoseconds', smallestUnit - 1) + baseDurationFields[smallestUnit] = Math.trunc(durationFields[smallestUnit] / roundingIncrement) + + const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( + baseDurationFields, + smallestUnit, + roundingIncrement * sign, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, + ) + + const portion = + endEpochNanoseconds.subtract(epochNanoseconds0).toNumber() / + epochNanoseconds1.subtract(epochNanoseconds0).toNumber() + + const roundedPortion = roundWithMode(portion * sign, roundingMode) // -1/0/1 + + if (roundedPortion) { // enlarged? + baseDurationFields[smallestUnit] += roundingIncrement * sign + + return [baseDurationFields, epochNanoseconds1, roundedPortion] + } else { + return [baseDurationFields, epochNanoseconds0, roundedPortion] + } +} + +// Utils +// ------------------------------------------------------------------------------------------------- + +function bubbleRelativeDuration( + durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNanoseconds, + largestUnit, + smallestUnit, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, +) { + const { sign } = durationFields + + for (let currentUnit = smallestUnit + 1; currentUnit < largestUnit; currentUnit++) { // TODO + if (currentUnit === 'week') { // correct? + continue + } + + const baseDurationFields = clearDurationFields(durationFields, 'nanoseconds', currentUnit - 1) + baseDurationFields[currentUnit] += sign + + const thresholdEpochNanoseconds = markerToEpochMilliseconds( + moveMarker(marker, baseDurationFields), + ) + + const beyondThreshold = endEpochNanoseconds.subtract(thresholdEpochNanoseconds).toNumber() + if (!beyondThreshold || Math.sign(beyondThreshold) === sign) { + durationFields = baseDurationFields + } else { + break + } + } + + return durationFields +} + +function clampRelativeDuration( + durationFields, + clampUnit, + clampDistance, + // marker system... + marker, + markerToEpochMilliseconds, + moveMarker, +) { + const clampDurationFields = { ...durationFieldDefaults, [clampUnit]: clampDistance } + const marker0 = moveMarker(marker, durationFields) + const marker1 = moveMarker(marker0, clampDurationFields) + const epochNanoseconds0 = markerToEpochMilliseconds(marker0) + const epochNanoseconds1 = markerToEpochMilliseconds(marker1) + return [epochNanoseconds0, epochNanoseconds1] +} + +function clearDurationFields(durationFields, firstUnit, lastUnit) { +} + +// Duration Time +// ------------- + +function durationTimeToNanoseconds( + durationTimeFields, // time-fields must be cumulatively less than a day +) { + // returns Number +} + +function nanosecondsToDurationTime( + nanoseconds, // can be signed +) { + // returns [durationTimeFields, dayDelta] +} + +// Duration Day-Time +// ----------------- + +function durationDayTimeToNanoseconds( + durationFields, // NOT BALANCED +) { + // returns LargeInt +} +function nanosecondsToDurationDayTime(largeNano) { + // returns DurationFields (even tho year/week/month will be 0) } diff --git a/packages/temporal-polyfill/src/new/temporalClass.js b/packages/temporal-polyfill/src/new/temporalClass.js index 43a0f3a1..e14a0f92 100644 --- a/packages/temporal-polyfill/src/new/temporalClass.js +++ b/packages/temporal-polyfill/src/new/temporalClass.js @@ -1,10 +1,15 @@ +import { DateTimeFormat } from './dateTimeFormat' import { createInternalClass, getInternals, internalsMap } from './internalClass' +import { noop } from './lang' import { createTemporalNameDescriptors, isObjectLike } from './obj' +const temporaNameMap = WeakMap() +export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) + export function createTemporalClass( temporalName, constructorToInternals, - massageOtherInternals, + internalsConversionMap, bagToInternals, stringToInternals, handleUnusedOptions, @@ -25,24 +30,36 @@ export function createTemporalClass( constructorToInternals, createTemporalNameDescriptors(temporalName), // extraPrototypeDescriptors staticMembers, + setTemporalName, // handleInstance ) function createInstance(internals) { const instance = Object.create(TemporalObj.prototype) internalsMap.set(instance, internals) + setTemporalName(instance) return instance } function toInternals(arg, options) { let argInternals = getInternals(arg) + const argTemporalName = getTemporalName(arg) - if (argInternals && !(arg instanceof TemporalObj)) { - argInternals = massageOtherInternals(arg, argInternals) + if (argInternals && argTemporalName !== temporalName) { + argInternals = (internalsConversionMap[argTemporalName] || noop)(argInternals) } return (!argInternals && isObjectLike(arg) && bagToInternals(arg, options)) || (handleUnusedOptions(options), argInternals || stringToInternals(toString(arg))) } + function setTemporalName(instance) { + temporaNameMap.set(instance, temporalName) + } + return [TemporalObj, createInstance, toInternals] } + +export function toLocaleStringMethod(internals, locales, options) { + const format = new DateTimeFormat(locales, options) + return format.format(this) +} diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 4a89176a..447c7c8a 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -5,13 +5,12 @@ import { createComplexBagRefiner } from './convert' import { formatOffsetNanoseconds } from './format' import { createInstant, toInstantEpochNanoseconds } from './instant' import { internalIdGetters, returnId } from './internalClass' -import { identityFunc, noop } from './lang' -import { mapProps } from './obj' +import { noop } from './lang' import { toDisambiguation } from './options' import { stringToTimeZoneId } from './parse' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { createTemporalClass } from './temporalClass' -import { getBestInstantFor } from './timeZoneOps' +import { getSingleInstantFor } from './timeZoneOps' export const [TimeZone, createTimeZone] = createTemporalClass( 'TimeZone', @@ -22,8 +21,8 @@ export const [TimeZone, createTimeZone] = createTemporalClass( // constructorToInternals queryTimeZoneImpl, - // massageOtherInternals - noop, + // internalsConversionMap + {}, // bagToInternals createComplexBagRefiner('timeZone', Calendar), @@ -60,7 +59,7 @@ export const [TimeZone, createTimeZone] = createTemporalClass( }, getInstantFor(impl, plainDateTimeArg, options) { - return getBestInstantFor( + return getSingleInstantFor( impl, toPlainDateTimeInternals(plainDateTimeArg), toDisambiguation(options), @@ -72,15 +71,17 @@ export const [TimeZone, createTimeZone] = createTemporalClass( .map(createInstant) }, - ...mapProps({ - getPreviousTransition: createInstant, - getNextTransition: createInstant, - getOffsetNanosecondsFor: identityFunc, - }, (transformRes, methodName) => { - return (impl, instantArg) => { - return transformRes(impl[methodName](toInstantEpochNanoseconds(instantArg))) - } - }), + getOffsetNanosecondsFor(impl, instantArg) { + return impl.getOffsetNanosecondsFor(toInstantEpochNanoseconds(instantArg)) + }, + + getNextTransition(impl, instantArg) { + return impl.getTransition(toInstantEpochNanoseconds(instantArg), 1) + }, + + getPreviousTransition(impl, instantArg) { + return impl.getTransition(toInstantEpochNanoseconds(instantArg), -1) + }, toString: returnId, }, diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index 28368bae..bef2c564 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -1,14 +1,298 @@ +/* eslint-disable no-return-assign */ +/* eslint-disable no-unmodified-loop-condition */ +import { parseIntlYear } from './calendarImpl' +import { IntlDateTimeFormat } from './dateTimeFormat' +import { createLargeInt } from './largeInt' +import { nanosecondsInSecond } from './nanoseconds' +import { parseOffsetNanoseconds } from './parse' -export function queryTimeZoneImpl() { +const nanoInMilli = 1000 +const nanoInMicro = 1000 +const milliInSec = 1000 +const secInDay = 86400 +const periodDur = secInDay * 60 +const minPossibleTransition = isoToEpochSec(1847) +const maxPossibleTransition = isoToEpochSec(new Date().getUTCFullYear() + 10) +const intlTimeZoneImplCache = {} + +export function queryTimeZoneImpl(timeZoneId) { + const offsetNano = parseOffsetNanoseconds(timeZoneId) + + if (offsetNano !== undefined) { + return new FixedTimeZoneImpl(timeZoneId, offsetNano) + } + + return intlTimeZoneImplCache[timeZoneId] || ( + intlTimeZoneImplCache[timeZoneId] = new IntlTimeZoneImpl(timeZoneId) + ) } -export class TimeZoneImpl { - getOffsetNanosecondsFor(epochNanoseconds) { - // TODO +// Fixed +// ------------------------------------------------------------------------------------------------- + +export class FixedTimeZoneImpl { + constructor(id, offetNano) { + this.id = id + this.offsetNano = offetNano + } + + getOffsetNanosecondsFor(epochNano) { + return [this.offsetNano] } getPossibleInstantsFor(isoDateTimeFields) { - // TODO + return [isoFieldsToEpochNano(isoDateTimeFields).add(this.offsetNano)] + } + + getTransition(epochNano, direction) { + return null } } + +// Intl +// ------------------------------------------------------------------------------------------------- + +export class IntlTimeZoneImpl { + constructor(id) { + this.id = id + this.store = createIntlTimeZoneStore(createComputeOffsetSec(id)) + } + + getOffsetNanosecondsFor(epochNano) { + const [epochSec] = epochNanoToSec(epochNano) + return this.store.getOffsetSec(epochSec) * nanosecondsInSecond + } + + getPossibleInstantsFor(isoDateTimeFields) { + const [zonedEpochSec, subsecNano] = isoFieldsToEpochSec(isoDateTimeFields) + return this.store.getPossibleEpochSec(zonedEpochSec) + .map((epochSec) => epochSecToNano(epochSec).add(subsecNano)) + } + + /* + exclusive for both directions + */ + getTransition(epochNano, direction) { + const [epochSec, subsecNano] = epochNanoToSec(epochNano) + const resEpochSec = this.store.getTransition( + epochSec + ((direction > 0 || subsecNano) ? 1 : 0), + direction, + ) + if (resEpochSec === undefined) { + return null + } + return epochSecToNano(resEpochSec) + } +} + +function createIntlTimeZoneStore(computeOffsetSec) { + const getSample = createLazyMap(computeOffsetSec) // always given startEpochSec/endEpochSec + const getSplit = createLazyMap((startEpochSec) => [startEpochSec, startEpochSec + periodDur]) + let minTransition = minPossibleTransition + let maxTransition = maxPossibleTransition + + function getPossibleEpochSec(zonedEpochSec) { + let startOffsetSec = getOffsetSec(zonedEpochSec - secInDay) + let endOffsetSec = getOffsetSec(zonedEpochSec + secInDay) + const startUtcEpochSec = zonedEpochSec - startOffsetSec + + if (startOffsetSec === endOffsetSec) { + return [startUtcEpochSec] + } + + const endUtcEpochSec = zonedEpochSec - endOffsetSec + startOffsetSec = getOffsetSec(startUtcEpochSec) + endOffsetSec = getOffsetSec(endUtcEpochSec) + + if (startOffsetSec === endOffsetSec) { + return [startUtcEpochSec] + } + + if (startUtcEpochSec < endUtcEpochSec) { + return [startUtcEpochSec, endUtcEpochSec] + } + + return [] + } + + function getOffsetSec(epochSec) { + const clampedEpochSec = clamp(epochSec, minTransition, maxTransition) + const [startEpochSec, endEpochSec] = computePeriod(clampedEpochSec) + const startOffsetSec = getSample(startEpochSec) + const endOffsetSec = getSample(endEpochSec) + + if (startOffsetSec === endOffsetSec) { + return startOffsetSec + } + + const split = getSplit(startEpochSec) + return pinch(split, startOffsetSec, endOffsetSec, epochSec) + } + + /* + inclusive for positive direction, exclusive for negative + */ + function getTransition(epochSec, direction) { + const clampedEpochSec = clamp(epochSec, minTransition, maxTransition) + let [startEpochSec, endEpochSec] = computePeriod(clampedEpochSec) + + const inc = periodDur * direction + const inBounds = direction < 0 + ? () => endEpochSec > minTransition || (minTransition = clampedEpochSec, false) + : () => startEpochSec < maxTransition || (maxTransition = clampedEpochSec, false) + + while (inBounds()) { + const startOffsetSec = getSample(startEpochSec) + const endOffsetSec = getSample(endEpochSec) + + if (startOffsetSec !== endOffsetSec) { + const split = getSplit(startEpochSec) + pinch(split, startOffsetSec, endOffsetSec) + const transitionEpochSec = split[0] + + if ((compareNumbers(epochSec, transitionEpochSec) || 1) === direction) { + return transitionEpochSec + } + } + + startEpochSec += inc + endEpochSec += inc + } + } + + /* + everything outside of 'split' is know that transition doesn't happen + transition is the first reading of a new offset period + just one isolated sample doesn't make it known + */ + function pinch(split, startOffsetSec, endOffsetSec, forEpochSec) { + let offsetSec + let splitDurSec + + while ( + (forEpochSec === undefined || + (forEpochSec < split[0] + ? startOffsetSec + : forEpochSec >= split[1] + ? endOffsetSec + : undefined + ) === undefined + ) && + (splitDurSec = split[1] - split[0]) + ) { + const middleEpochSec = split[0] + Math.floor(splitDurSec / 2) + const middleOffsetSec = computeOffsetSec(middleEpochSec) + + if (middleOffsetSec === endOffsetSec) { + split[1] = middleEpochSec + } else { // middleOffsetSec === startOffsetSec + split[0] = middleEpochSec + 1 + } + } + + return offsetSec + } + + return { getPossibleEpochSec, getOffsetSec, getTransition } +} + +function computePeriod(epochSec) { + const startEpochSec = Math.floor(epochSec / periodDur) + const endEpochSec = startEpochSec + periodDur + return [startEpochSec, endEpochSec] +} + +function createComputeOffsetSec(timeZoneId) { + const format = buildIntlFormat(timeZoneId) + + return (epochSec) => { + const intlParts = hashIntlFormatParts(format, epochSec * milliInSec) + const zonedEpochSec = isoToEpochSec( + parseIntlYear(intlParts).year, + parseInt(intlParts.month), + parseInt(intlParts.day), + parseInt(intlParts.hour), + parseInt(intlParts.minute), + parseInt(intlParts.second), + ) + return zonedEpochSec - epochSec + } +} + +const standardCalendarId = 'en-GB' // gives 24-hour clock + +function buildIntlFormat(timeZoneId) { + // format will ALWAYS do gregorian. need to parse year + return new IntlDateTimeFormat(standardCalendarId, { + timeZone: timeZoneId, + era: 'short', + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + }) +} + +// Utils +// ------------------------------------------------------------------------------------------------- + +// does floor +function epochNanoToSec(epochNano) { + let epochSec = epochNano.div(nanosecondsInSecond).toNumber() // does truncation + let subsecNano = epochNano.sub(createLargeInt(epochSec).mult(nanosecondsInSecond)).toNumber() + + if (subsecNano < 0) { + epochSec-- + subsecNano += nanosecondsInSecond + } + + return [epochSec, subsecNano] +} + +function epochSecToNano(epochSec) { + return createLargeInt(epochSec).mult(nanosecondsInSecond) +} + +function createLazyMap(computeFunc) { +} + +function isoFieldsToEpochNano(isoFields) { +} + +function compareNumbers() { +} + +function clamp() { +} + +function hashIntlFormatParts() { +} + +// TODO: rename these to UTC-something? + +function isoToEpochSec(...args) { // doesn't accept beyond sec + return isoToEpochMilli(...args) / milliInSec // no need for rounding +} + +function isoToEpochMilli() { +} + +function isoFieldsToEpochSec(isoDateTimeFields) { + const epochSec = isoToEpochSec( + isoDateTimeFields.year, + isoDateTimeFields.month, + isoDateTimeFields.day, + isoDateTimeFields.hour, + isoDateTimeFields.minute, + isoDateTimeFields.second, + ) + const subsecNano = + isoDateTimeFields.millisecond * nanoInMilli + + isoDateTimeFields.microsecond * nanoInMicro + + isoDateTimeFields.nanosecond + + return [epochSec, subsecNano] +} diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index fb0645d5..08db7d2d 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -6,8 +6,10 @@ import { getInternals, internalIdGetters, } from './internalClass' -import { nanosecondsInDay } from './nanoseconds' +import { addDaysToIsoFields, isoTimeFieldDefaults } from './isoFields' +import { nanosecondsInIsoDay } from './nanoseconds' import { createPlainDateTime } from './plainDateTime' +import { roundToMinute } from './round' import { createTimeZone } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' @@ -20,40 +22,142 @@ export function queryTimeZoneOps(timeZoneSlot) { return queryTimeZoneImpl(timeZoneSlot) // string } -export function getCommonTimeZoneOps(internals0, internals1) { -} - export function getPublicTimeZone(internals) { const { timeZone } = internals return getInternals(timeZone) || // if TimeZoneOpsAdapter createTimeZone(timeZone) // if TimeZoneImpl } +export function getCommonTimeZoneOps(internals0, internals1) { + // TODO +} + // Public Utils // ------------ -export function getBestInstantFor( +export function computeNanosecondsInDay( timeZoneOps, - isoDateTimeFields, - disambig = 'compatible', + isoDateFields, // could contain time fields though ) { + isoDateFields = { ...isoDateFields, ...isoTimeFieldDefaults } + const epochNano0 = getSingleInstantFor(timeZoneOps, isoDateFields) + const epochNano1 = getSingleInstantFor(timeZoneOps, addDaysToIsoFields(isoDateFields, 1)) + return epochNano1.sub(epochNano0).toNumber() } -export function computeIsoFieldEpochNanoseconds( +export function getMatchingInstantFor( timeZoneOps, isoDateTimeFields, - offset, - z, - offsetHandling, // 'reject' - disambig, // 'compatible' - fuzzy, + offsetNano, // optional + hasZ, + // need these defaults? + offsetHandling = 'reject', + disambig = 'compatible', + fuzzy = false, ) { + if (offsetNano !== undefined && offsetHandling !== 'ignore') { + // we ALWAYS use Z as a zero offset + if (offsetHandling === 'use' || hasZ) { + return isoFieldsToEpochNano(isoDateTimeFields).sub(offsetNano) + } + + const matchingEpochNano = findMatchingEpochNano( + timeZoneOps, + isoDateTimeFields, + offsetNano, + fuzzy, + ) + + if (matchingEpochNano !== undefined) { + return matchingEpochNano + } + + if (offsetHandling === 'reject') { + throw new RangeError('Mismatching offset/timezone') + } + // else (offsetHandling === 'prefer') ... + } + + return getSingleInstantFor(timeZoneOps, isoDateTimeFields, disambig) } -export function computeNanosecondsInDay( +function findMatchingEpochNano(timeZoneOps, isoDateTimeFields, offsetNano, fuzzy) { + const possibleEpochNanos = timeZoneOps.getPossibleInstantsFor(isoDateTimeFields) + const zonedEpochNano = isoFieldsToEpochNano(isoDateTimeFields) + + if (fuzzy) { + offsetNano = roundToMinute(offsetNano) + } + + for (const possibleEpochNano of possibleEpochNanos) { + let possibleOffsetNano = zonedEpochNano.sub(possibleEpochNano).toNumber() + + if (fuzzy) { + possibleOffsetNano = roundToMinute(possibleOffsetNano) + } + + if (possibleOffsetNano === offsetNano) { + return possibleEpochNano + } + } +} + +export function getSingleInstantFor( timeZoneOps, - isoFields, + isoDateTimeFields, + disambig = 'compatible', ) { + let epochNanos = timeZoneOps.getPossibleInstantsFor(isoDateTimeFields) + + if (epochNanos.length === 1) { + return epochNanos[0] + } + + if (disambig === 'reject') { + throw new RangeError('Ambiguous offset') + } + + // within a transition that jumps back + // ('compatible' means 'earlier') + if (epochNanos.length) { + return epochNanos[ + disambig === 'later' + ? 1 + : 0 // 'earlier' and 'compatible' + ] + } + + // within a transition that jumps forward... + // ('compatible' means 'later') + + const zonedEpochNano = isoFieldsToEpochNano(isoDateTimeFields) + const gapNano = computeGapNear(timeZoneOps, zonedEpochNano) + + epochNanos = timeZoneOps.getPossibleInstantsFor( + epochNanoToIsoFields( + zonedEpochNano.add(gapNano * ( + disambig === 'earlier' + ? -1 + : 1 // 'later' or 'compatible' + )), + ), + ) + + return epochNanos[ + disambig === 'earlier' + ? 0 + : epochNanos.length - 1 // 'later' or 'compatible' + ] +} + +function computeGapNear(timeZoneOps, zonedEpochNano) { + const startOffsetNano = timeZoneOps.getOffsetNanosecondsFor( + zonedEpochNano.add(-nanosecondsInIsoDay), + ) + const endOffsetNano = timeZoneOps.getOffsetNanosecondsFor( + zonedEpochNano.add(nanosecondsInIsoDay), + ) + return endOffsetNano - startOffsetNano } // Adapter @@ -67,7 +171,7 @@ const TimeZoneOpsAdapter = createInternalClass(internalIdGetters, { timeZone.getOffsetNanosecondsFor(createInstant(epochNanoseconds)), ) - if (Math.abs(nanoseconds) >= nanosecondsInDay) { + if (Math.abs(nanoseconds) >= nanosecondsInIsoDay) { throw new RangeError('out of range') } @@ -82,3 +186,14 @@ const TimeZoneOpsAdapter = createInternalClass(internalIdGetters, { ).map(getStrictInstantEpochNanoseconds) }, }) + +// Utils +// ----- + +function isoFieldsToEpochNano() { + +} + +function epochNanoToIsoFields() { + +} diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index c64c1d82..b80e33fe 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -8,6 +8,7 @@ import { zonedDateTimeInternalsToIso, zonedDateTimeWithBag, } from './convert' +import { resolveZonedFormattable } from './dateTimeFormat' import { diffZonedEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -25,7 +26,6 @@ import { pluckIsoDateTimeSlots, pluckIsoTimeFields, } from './isoFields' -import { noop } from './lang' import { compareLargeInts, toLargeInt } from './largeInt' import { moveZonedEpochNanoseconds } from './move' import { epochGetters, nanosecondsInHour } from './nanoseconds' @@ -38,10 +38,9 @@ import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' import { createTemporalClass } from './temporalClass' import { - computeIsoFieldEpochNanoseconds, computeNanosecondsInDay, - getBestInstantFor, getCommonTimeZoneOps, + getMatchingInstantFor, getPublicTimeZone, queryTimeZoneOps, } from './timeZoneOps' @@ -65,8 +64,8 @@ export const [ } }, - // massageOtherInternals - noop, + // internalsConversionMap + {}, // bagToInternals bagToZonedDateTimeInternals, @@ -100,12 +99,17 @@ export const [ ) / nanosecondsInHour }, + // TODO: make this a getter? offsetNanoseconds(internals) { - return zonedDateTimeInternalsToOffsetNanoseconds(internals) + // TODO: more DRY + return zonedDateTimeInternalsToIso(internals).offsetNanoseconds }, offset(internals) { - return formatOffsetNanoseconds(zonedDateTimeInternalsToOffsetNanoseconds(internals)) + return formatOffsetNanoseconds( + // TODO: more DRY + zonedDateTimeInternalsToIso(internals).offsetNanoseconds, + ) }, }, @@ -118,36 +122,51 @@ export const [ }, withPlainTime(internals, plainTimeArg) { - const { timeZone } = internals - const epochNanoseconds = getBestInstantFor( + const { calendar, timeZone } = internals + const isoFields = { + ...zonedDateTimeInternalsToIso(internals), + ...toPlainTimeInternals(plainTimeArg), + } + + const epochNano = getMatchingInstantFor( timeZone, - { - ...zonedDateTimeInternalsToIso(internals), - ...toPlainTimeInternals(plainTimeArg), - }, + isoFields, + isoFields.offsetNano, + false, // hasZ + undefined, // offsetHandling + undefined, // disambig + false, // fuzzy ) return createZonedDateTime({ - epochNanoseconds, + epochNanoseconds: epochNano, timeZone, - calendar: internals.calendar, + calendar, }) }, + // TODO: more DRY with withPlainTime and zonedDateTimeWithBag? withPlainDate(internals, plainDateArg) { - const { timeZone } = internals - const epochNanoseconds = getBestInstantFor( + const { calendar, timeZone } = internals + const isoFields = { + ...zonedDateTimeInternalsToIso(internals), + ...toPlainDateInternals(plainDateArg), + } + + const epochNano = getMatchingInstantFor( timeZone, - { - ...zonedDateTimeInternalsToIso(internals), - ...toPlainDateInternals(plainDateArg), - }, + isoFields, + isoFields.offsetNano, + false, // hasZ + undefined, // offsetHandling + undefined, // disambig + false, // fuzzy ) return createZonedDateTime({ - epochNanoseconds, + epochNanoseconds: epochNano, timeZone, - calendar: internals.calendar, + calendar, }) }, @@ -188,10 +207,10 @@ export const [ until(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) return diffZonedEpochNanoseconds( + getCommonCalendarOps(internals, otherInternals), + getCommonTimeZoneOps(internals, otherInternals), internals.epochNanoseconds, otherInternals.epochNanoseconds, - getCommonTimeZoneOps(internals, otherInternals), - getCommonCalendarOps(internals, otherInternals), options, // TODO: spread out lots of options!!! ) }, @@ -199,10 +218,10 @@ export const [ since(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) return diffZonedEpochNanoseconds( + getCommonCalendarOps(internals, otherInternals), + getCommonTimeZoneOps(internals, otherInternals), otherInternals.epochNanoseconds, internals.epochNanoseconds, - getCommonTimeZoneOps(internals, otherInternals), - getCommonCalendarOps(internals, otherInternals), options, // TODO: flip rounding options!!!!! ) }, @@ -218,7 +237,7 @@ export const [ options, () => computeNanosecondsInDay(timeZone, isoFields), ) - epochNanoseconds = computeIsoFieldEpochNanoseconds( + epochNanoseconds = getMatchingInstantFor( isoFields, timeZone, offsetNanoseconds, @@ -243,7 +262,7 @@ export const [ ...isoTimeFieldDefaults, } - epochNanoseconds = computeIsoFieldEpochNanoseconds( + epochNanoseconds = getMatchingInstantFor( isoFields, timeZone, undefined, // offsetNanoseconds @@ -281,7 +300,7 @@ export const [ options, () => computeNanosecondsInDay(timeZone, isoFields), ) - epochNanoseconds = computeIsoFieldEpochNanoseconds( + epochNanoseconds = getMatchingInstantFor( isoFields, timeZone, offsetNanoseconds, @@ -301,7 +320,8 @@ export const [ }, toLocaleString(internals, locales, options) { - return '' + const [epochMilli, format] = resolveZonedFormattable(internals, locales, options) + return format.format(epochMilli) }, valueOf: neverValueOf, @@ -319,7 +339,7 @@ export const [ }, toPlainDateTime(internals) { - return createPlainDateTime(zonedDateTimeInternalsToIso(internals)) + return createPlainDateTime(pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(internals))) }, toPlainYearMonth() { @@ -337,7 +357,10 @@ export const [ // maintain alphabetical order calendar: calendar.id, // correct? ...pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(internals)), - offset: formatOffsetNanoseconds(zonedDateTimeInternalsToOffsetNanoseconds(internals)), + offset: formatOffsetNanoseconds( + // TODO: more DRY + zonedDateTimeInternalsToIso(internals).offsetNanoseconds, + ), timeZone: timeZone.id, // correct? } }, @@ -364,18 +387,13 @@ export const [ function moveZonedDateTimeInternals(internals, durationFields, overflowHandling) { return moveZonedEpochNanoseconds( - internals.epochNanoseconds, - durationFields, internals.calendar, internals.timeZone, + internals.epochNanoseconds, + durationFields, overflowHandling, ) } -function zonedDateTimeInternalsToOffsetNanoseconds(internals) { - return internals.timeZone // TimeZoneOps - .getOffsetNanosecondsFor(internals.epochNanoseconds) -} - function epochNanosecondsToIso() { } From 7cdab127074b2786ff49a63c108949252bcb4d61 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 31 May 2023 15:45:18 -0400 Subject: [PATCH 076/805] readability improvements --- .../src/new/dateTimeFormat.js | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/packages/temporal-polyfill/src/new/dateTimeFormat.js b/packages/temporal-polyfill/src/new/dateTimeFormat.js index 7cef0a87..5598acd8 100644 --- a/packages/temporal-polyfill/src/new/dateTimeFormat.js +++ b/packages/temporal-polyfill/src/new/dateTimeFormat.js @@ -7,11 +7,17 @@ import { epochNanoToMilli } from './nanoseconds' import { getTemporalName } from './temporalClass' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' +export const IntlDateTimeFormat = Intl.DateTimeFormat + +const getGetSpecificFormat = createLazyMap(() => createLazyMap(createSpecificFormat), WeakMap) + +function createSpecificFormat(massageOptions, resolvedOptions) { + return new IntlDateTimeFormat(resolvedOptions.locale, massageOptions(resolvedOptions)) +} + // DateTimeFormat // ------------------------------------------------------------------------------------------------- -export const IntlDateTimeFormat = Intl.DateTimeFormat - export class DateTimeFormat extends IntlDateTimeFormat { format(arg) { const [formattable, format] = resolveSingleFormattable(this, arg) @@ -32,46 +38,39 @@ export class DateTimeFormat extends IntlDateTimeFormat { ['formatRange', 'formatRangeToParts'].forEach((methodName) => { const origMethod = IntlDateTimeFormat.prototype[methodName] + if (origMethod) { DateTimeFormat.prototype[methodName] = function(arg0, arg1) { const [formattable0, formattable1, format] = resolveRangeFormattables(this, arg0, arg1) - return origMethod.call(format || this, formattable0, formattable1) + return origMethod.call(format, formattable0, formattable1) } } }) -function resolveSingleFormattable(origFormat, arg) { - const getSpecificFormat = getGetSpecificFormat(origFormat) - const resolvedOptions = origFormat.resolvedOptions() +function resolveSingleFormattable(format, arg) { + const getSpecificFormat = getGetSpecificFormat(format) + const resolvedOptions = format.resolvedOptions() + // returned format might be undefined return resolveFormattable(arg, getSpecificFormat, resolvedOptions) } -function resolveRangeFormattables(origFormat, arg0, arg1) { - const getSpecificFormat = getGetSpecificFormat(origFormat) - const resolvedOptions = origFormat.resolvedOptions() +function resolveRangeFormattables(format, arg0, arg1) { + const getSpecificFormat = getGetSpecificFormat(format) + const resolvedOptions = format.resolvedOptions() - let [formattable0, format0] = resolveFormattable(arg0, getSpecificFormat, resolvedOptions) + const [formattable0, format0] = resolveFormattable(arg0, getSpecificFormat, resolvedOptions) const [formattable1, format1] = resolveFormattable(arg1, getSpecificFormat, resolvedOptions) if (format0 && format1) { if (format0 !== format1) { throw new TypeError('Accepts two Temporal values of same type') } - } else { - format0 = undefined + format = format0 } - return [formattable0, formattable1, format0] -} - -// Internal Nested DateTimeFormat Cache -// ------------------------------------------------------------------------------------------------- - -const getGetSpecificFormat = createLazyMap(() => createLazyMap(createSpecificFormat), WeakMap) - -function createSpecificFormat(massageOptions, resolvedOptions) { - return new IntlDateTimeFormat(resolvedOptions.locale, massageOptions(resolvedOptions)) + // always returns a format + return [formattable0, formattable1, format] } // Resolving Formattable Objects (and Format) @@ -207,20 +206,20 @@ const epochNanoConverters = { // otherwise, use dateTimeInternalsToEpochNano } -function timeInternalsToEpochNano(internals, options) { +function timeInternalsToEpochNano(internals, resolvedOptions) { return getSingleInstantFor({ isoYear: isoEpochOriginYear, isoMonth: 1, isoDay: 1, ...internals, - timeZone: queryTimeZoneOps(options.timeZone), + timeZone: queryTimeZoneOps(resolvedOptions.timeZone), }) } -function dateTimeInternalsToEpochNano(internals, options, temporalName) { +function dateTimeInternalsToEpochNano(internals, resolvedOptions, temporalName) { checkCalendarsCompatible( internals.calendar.id, - options.calendarId, + resolvedOptions.calendarId, strictCalendarCheck[temporalName], ) @@ -228,7 +227,7 @@ function dateTimeInternalsToEpochNano(internals, options, temporalName) { ...timeFieldDefaults, isoHour: 12, ...internals, - timeZone: queryTimeZoneOps(options.timeZone), + timeZone: queryTimeZoneOps(resolvedOptions.timeZone), }) } From 43a1307e472f72c4c10dd25953fa4eabb40d6d1d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 31 May 2023 15:53:19 -0400 Subject: [PATCH 077/805] even more readable --- .../src/new/dateTimeFormat.js | 54 ++++++++++--------- packages/temporal-polyfill/src/new/format.js | 2 + 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/packages/temporal-polyfill/src/new/dateTimeFormat.js b/packages/temporal-polyfill/src/new/dateTimeFormat.js index 5598acd8..37d5e85c 100644 --- a/packages/temporal-polyfill/src/new/dateTimeFormat.js +++ b/packages/temporal-polyfill/src/new/dateTimeFormat.js @@ -7,16 +7,9 @@ import { epochNanoToMilli } from './nanoseconds' import { getTemporalName } from './temporalClass' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -export const IntlDateTimeFormat = Intl.DateTimeFormat - -const getGetSpecificFormat = createLazyMap(() => createLazyMap(createSpecificFormat), WeakMap) +// TODO: rename to intlFormat? -function createSpecificFormat(massageOptions, resolvedOptions) { - return new IntlDateTimeFormat(resolvedOptions.locale, massageOptions(resolvedOptions)) -} - -// DateTimeFormat -// ------------------------------------------------------------------------------------------------- +export const IntlDateTimeFormat = Intl.DateTimeFormat export class DateTimeFormat extends IntlDateTimeFormat { format(arg) { @@ -47,6 +40,15 @@ export class DateTimeFormat extends IntlDateTimeFormat { } }) +// DateTimeFormat Helpers +// ------------------------------------------------------------------------------------------------- + +const getGetSpecificFormat = createLazyMap(() => createLazyMap(createSpecificFormat), WeakMap) + +function createSpecificFormat(transformOptions, resolvedOptions) { + return new IntlDateTimeFormat(resolvedOptions.locale, transformOptions(resolvedOptions)) +} + function resolveSingleFormattable(format, arg) { const getSpecificFormat = getGetSpecificFormat(format) const resolvedOptions = format.resolvedOptions() @@ -115,15 +117,15 @@ function resolveFormattable( resolvedOptions, ) { const temporalName = getTemporalName(arg) - const massageOptions = optionMassagers[temporalName] + const transformOptions = optionTransformers[temporalName] - if (massageOptions) { + if (transformOptions) { const internalsToEpochNano = epochNanoConverters[temporalName] || dateTimeInternalsToEpochNano const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) return [ epochNanoToMilli(epochNano), - getSpecificFormat(massageOptions, resolvedOptions), + getSpecificFormat(transformOptions, resolvedOptions), ] } @@ -171,7 +173,19 @@ const monthDayExclusions = [ ...timeOptionNames, ] -function createMassager(optionNames, basicNames, exclusionNames) { +const optionTransformers = { + PlainTime: createTransformer(timeOptionNames, timeBasicNames, timeExclusions), + PlainDateTime: createTransformer(dateTimeOptionNames, dateTimeBasicNames, dateTimeExclusions), + PlainDate: createTransformer(dateOptionNames, dateBasicNames, dateExclusions), + PlainYearMonth: createTransformer(yearMonthBasicNames, yearMonthBasicNames, yearMonthExclusions), + PlainMonthDay: createTransformer(monthDayBasicNames, monthDayBasicNames, monthDayExclusions), + Instant: createTransformer(dateTimeOptionNames, dateTimeBasicNames, []), + ZonedDateTime: () => { + throw new TypeError('Cant do on ZonedDateTime') + }, +} + +function createTransformer(optionNames, basicNames, exclusionNames) { const defaults = propsWithSameValue(basicNames, 'numeric') return (options) => { @@ -185,18 +199,6 @@ function createMassager(optionNames, basicNames, exclusionNames) { } } -const optionMassagers = { - PlainTime: createMassager(timeOptionNames, timeBasicNames, timeExclusions), - PlainDateTime: createMassager(dateTimeOptionNames, dateTimeBasicNames, dateTimeExclusions), - PlainDate: createMassager(dateOptionNames, dateBasicNames, dateExclusions), - PlainYearMonth: createMassager(yearMonthBasicNames, yearMonthBasicNames, yearMonthExclusions), - PlainMonthDay: createMassager(monthDayBasicNames, monthDayBasicNames, monthDayExclusions), - Instant: createMassager(dateTimeOptionNames, dateTimeBasicNames, []), - ZonedDateTime: () => { - throw new TypeError('Cant do on ZonedDateTime') - }, -} - // Epoch Conversions // ------------------------------------------------------------------------------------------------- @@ -225,7 +227,7 @@ function dateTimeInternalsToEpochNano(internals, resolvedOptions, temporalName) return getSingleInstantFor({ ...timeFieldDefaults, - isoHour: 12, + isoHour: 12, // will not dst-shift into prev/next day ...internals, timeZone: queryTimeZoneOps(resolvedOptions.timeZone), }) diff --git a/packages/temporal-polyfill/src/new/format.js b/packages/temporal-polyfill/src/new/format.js index eafc5b9f..1e40accd 100644 --- a/packages/temporal-polyfill/src/new/format.js +++ b/packages/temporal-polyfill/src/new/format.js @@ -1,6 +1,8 @@ import { isoCalendarId } from './calendarConfig' import { toCalendarNameOption } from './options' +// rename file to 'isoFormat'? + export function formatPossibleDate(internals, options, formatSimple) { const calendarNameOpt = toCalendarNameOption(options) const showCalendar = From be48257c0c01fe2ec204c66f07340572612f6b14 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 1 Jun 2023 11:58:05 -0400 Subject: [PATCH 078/805] move files/imports around --- .../src/new/{convert.js => bag.js} | 40 ++-- .../temporal-polyfill/src/new/calendar.js | 29 ++- .../src/new/calendarFields.js | 4 +- .../temporal-polyfill/src/new/calendarImpl.js | 113 +++-------- .../temporal-polyfill/src/new/calendarOps.js | 14 +- packages/temporal-polyfill/src/new/cast.js | 76 -------- packages/temporal-polyfill/src/new/diff.js | 48 ++--- .../temporal-polyfill/src/new/duration.js | 37 ++-- .../src/new/durationFields.js | 5 +- packages/temporal-polyfill/src/new/instant.js | 18 +- .../new/{dateTimeFormat.js => intlFormat.js} | 48 +++-- .../temporal-polyfill/src/new/isoFields.js | 17 +- .../src/new/{format.js => isoFormat.js} | 2 - packages/temporal-polyfill/src/new/isoMath.js | 183 ++++++++++++++++++ .../src/new/{parse.js => isoParse.js} | 0 packages/temporal-polyfill/src/new/lang.js | 11 -- packages/temporal-polyfill/src/new/move.js | 23 +-- .../temporal-polyfill/src/new/nanoseconds.js | 44 ----- packages/temporal-polyfill/src/new/now.js | 6 +- packages/temporal-polyfill/src/new/obj.js | 46 ----- packages/temporal-polyfill/src/new/options.js | 97 ++++++++++ .../temporal-polyfill/src/new/plainDate.js | 30 +-- .../src/new/plainDateTime.js | 21 +- .../src/new/plainMonthDay.js | 23 ++- .../temporal-polyfill/src/new/plainTime.js | 14 +- .../src/new/plainYearMonth.js | 21 +- packages/temporal-polyfill/src/new/round.js | 9 +- .../temporal-polyfill/src/new/temporal.js | 2 +- .../src/new/temporalClass.js | 13 +- .../temporal-polyfill/src/new/timeZone.js | 18 +- .../temporal-polyfill/src/new/timeZoneImpl.js | 84 ++------ .../temporal-polyfill/src/new/timeZoneOps.js | 34 ++-- packages/temporal-polyfill/src/new/util.js | 91 +++++++++ .../new/{internalClass.js => wrapperClass.js} | 15 +- .../src/new/zonedDateTime.js | 36 ++-- 35 files changed, 624 insertions(+), 648 deletions(-) rename packages/temporal-polyfill/src/new/{convert.js => bag.js} (95%) delete mode 100644 packages/temporal-polyfill/src/new/cast.js rename packages/temporal-polyfill/src/new/{dateTimeFormat.js => intlFormat.js} (91%) rename packages/temporal-polyfill/src/new/{format.js => isoFormat.js} (97%) create mode 100644 packages/temporal-polyfill/src/new/isoMath.js rename packages/temporal-polyfill/src/new/{parse.js => isoParse.js} (100%) delete mode 100644 packages/temporal-polyfill/src/new/lang.js delete mode 100644 packages/temporal-polyfill/src/new/nanoseconds.js delete mode 100644 packages/temporal-polyfill/src/new/obj.js create mode 100644 packages/temporal-polyfill/src/new/util.js rename packages/temporal-polyfill/src/new/{internalClass.js => wrapperClass.js} (77%) diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/bag.js similarity index 95% rename from packages/temporal-polyfill/src/new/convert.js rename to packages/temporal-polyfill/src/new/bag.js index cad2b3f7..c7e001b3 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/bag.js @@ -16,30 +16,35 @@ import { yearMonthFieldNames, } from './calendarFields' import { queryCalendarOps } from './calendarOps' -import { toInteger, toObject } from './cast' import { durationFieldDefaults, durationFieldNames, durationFieldRefiners, refineDurationFields, } from './durationFields' -import { getInternals } from './internalClass' import { constrainIsoDateTimeFields, constrainIsoTimeFields, } from './isoFields' -import { isObjectLike, pluckProps, removeDuplicateStrings } from './obj' -import { optionsToOverflow, toDisambiguation, toOffsetHandling, toOverflowOptions } from './options' -import { parseOffsetNanoseconds } from './parse' +import { epochNanoToIsoFields, isoEpochFirstLeapYear } from './isoMath' +import { parseOffsetNanoseconds } from './isoParse' +import { + optionsToOverflow, + toDisambiguation, + toInteger, + toObject, + toOffsetHandling, + toOverflowOptions, +} from './options' import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainTime } from './plainTime' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { createLazyMap, isObjectLike, pluckProps, removeDuplicateStrings } from './util' +import { getInternals } from './wrapperClass' import { createZonedDateTime } from './zonedDateTime' -// TODO: rename bag? - // Duration // ------------------------------------------------------------------------------------------------- @@ -130,7 +135,7 @@ export function bagToPlainMonthDayInternals(bag, options) { fields.monthCode === undefined && fields.year === undefined ) { - fields.year = 1972 + fields.year = isoEpochFirstLeapYear } return calendar.monthDayFromFields(calendar, fields, optionsToOverflow(options)) @@ -432,11 +437,6 @@ export function prepareFields(bag, fieldNames, requiredFields) { // TODO: error-out if no valid vields } -export function isStringCastsEqual(obj0, obj1) { - return obj0 === obj1 || // optimization - String(obj0) === String(obj1) -} - function extractCalendarOpsFromBag(bag) { return queryCalendarOps(extractCalendarFieldFromBag(bag) || isoCalendarId) } @@ -452,17 +452,3 @@ function extractCalendarFieldFromBag(bag) { return queryCalendarOps(calendar) } } - -export function mapRefiners(input, refinerMap) { - // loops get driven props of input -} - -// util -// ---- - -function createLazyMap() { -} - -function epochNanoToIsoFields() { - -} diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 7e916673..9cf8f75e 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -1,23 +1,22 @@ +import { createComplexBagRefiner, prepareFields } from './bag' import { getRequiredDateFields, getRequiredMonthDayFields, getRequiredYearMonthFields, } from './calendarConfig' import { dateCalendarRefiners, dateFieldNames, yearMonthFieldNames } from './calendarFields' -import { isoDaysInWeek, queryCalendarImpl } from './calendarImpl' -import { strictArrayOfStrings, toObject } from './cast' -import { createComplexBagRefiner, prepareFields } from './convert' +import { queryCalendarImpl } from './calendarImpl' import { createDuration, toDurationInternals } from './duration' -import { internalIdGetters, returnId } from './internalClass' -import { noop } from './lang' -import { mapProps } from './obj' -import { optionsToLargestUnit, optionsToOverflow } from './options' -import { stringToCalendarId } from './parse' +import { isoDaysInWeek } from './isoMath' +import { stringToCalendarId } from './isoParse' +import { optionsToLargestUnit, optionsToOverflow, strictArrayOfStrings, toObject } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { createTemporalClass } from './temporalClass' import { TimeZone } from './timeZone' +import { mapProps, noop, removeUndefines } from './util' +import { internalIdGetters, returnId } from './wrapperClass' /* Must do input validation @@ -65,8 +64,8 @@ export const [Calendar, createCalendar] = createTemporalClass( dateAdd(impl, plainDateArg, durationArg, options) { return createPlainDate( impl.dateAdd( - toPlainDateInternals(plainDateArg), // round time parts??? - toDurationInternals(durationArg), + toPlainDateInternals(plainDateArg), + toDurationInternals(durationArg), // TODO: balance-up time parts to days optionsToLargestUnit(options), ), ) @@ -75,8 +74,8 @@ export const [Calendar, createCalendar] = createTemporalClass( dateUntil(impl, startPlainDateArg, endPlainDateArg, options) { return createDuration( impl.dateUntil( - toPlainDateInternals(startPlainDateArg), // round time parts??? - toPlainDateInternals(endPlainDateArg), // round time parts??? + toPlainDateInternals(startPlainDateArg), + toPlainDateInternals(endPlainDateArg), optionsToOverflow(options), ), ) @@ -127,9 +126,3 @@ export const [Calendar, createCalendar] = createTemporalClass( toString: returnId, }, ) - -// utils - -function removeUndefines(obj) { // and copy - -} diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index 486866ba..fc161b7e 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -1,6 +1,6 @@ -import { toIntegerThrowOnInfinity, toPositiveInteger } from './cast' import { isoTimeFieldDefaults, isoTimeFieldNames } from './isoFields' -import { mapProps, remapProps } from './obj' +import { toIntegerThrowOnInfinity, toPositiveInteger } from './options' +import { mapProps, remapProps } from './util' // does NOT contain era/eraYear (considered special-case for certain calendars) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 2505274e..b10d90ba 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -16,11 +16,30 @@ import { monthFieldNames, yearStatNames, } from './calendarFields' -import { IntlDateTimeFormat } from './dateTimeFormat' import { computeIntlMonthsInYearSpan, computeIsoMonthsInYearSpan, diffYearMonthDay } from './diff' import { durationFieldDefaults } from './durationFields' +import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' import { isoDateFieldNames, isoTimeFieldDefaults } from './isoFields' +import { + addDaysMilli, + computeIsoDayOfWeek, + computeIsoDaysInMonth, + computeIsoDaysInYear, + computeIsoIsLeapYear, + computeIsoMonthsInYear, + computeIsoWeekOfYear, + computeIsoYearOfWeek, + diffDaysMilli, + epochMilliToIsoFields, + isoDaysInWeek, + isoEpochFirstLeapYear, + isoEpochOriginYear, + isoFieldsToEpochMilli, + isoToEpochMilli, +} from './isoMath' import { addIntlMonths, addIsoMonths } from './move' +import { constrainInt } from './options' +import { buildWeakMapCache, twoDigit } from './util' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -179,7 +198,7 @@ class IsoCalendarImpl { isoFieldsToEpochMilli(startIsoDateFields), isoFieldsToEpochMilli(endIsoDateFields), ) - const sign = numSign(days) + const sign = Math.sign(days) if (largestUnit === 'day') { // TODO weeks = Math.trunc(days / isoDaysInWeek) @@ -618,8 +637,6 @@ export function parseIntlYear(intlParts, calendarId) { // DateTimeFormat Utils // ------------------------------------------------------------------------------------------------- -const standardCalendarId = 'en-GB' // gives 24-hour clock - function buildIntlFormat(calendarId) { return new IntlDateTimeFormat(standardCalendarId, { calendar: calendarId, @@ -631,18 +648,6 @@ function buildIntlFormat(calendarId) { }) } -// best place for this? -function hashIntlFormatParts(intlFormat, epochMilliseconds) { - const parts = intlFormat.formatToParts(epochMilliseconds) - const hash = {} - - for (const part of parts) { - hash[part.type] = part.value - } - - return hash -} - // Intl Month Cache // ------------------------------------------------------------------------------------------------- @@ -705,7 +710,7 @@ function getEraOrigins(calendarId) { function eraYearToYear(eraYear, eraOrigin) { // see the origin format in calendarConfig - return (eraOrigin + eraYear) * (numSign(eraOrigin) || 1) + return (eraOrigin + eraYear) * (Math.sign(eraOrigin) || 1) } function normalizeShortEra(formattedEra) { @@ -761,67 +766,6 @@ function getCalendarIdBase(calendarId) { return calendarId.split('-')[0] } -// ISO & Time -// ------------------------------------------------------------------------------------------------- - -export const isoMonthsInYear = 12 -export const isoDaysInWeek = 7 -export const isoEpochOriginYear = 1970 // best place? -const isoEpochFirstLeapYear = 1972 - -export function computeIsoMonthsInYear(isoYear) { - return isoMonthsInYear -} - -function computeIsoDaysInMonth(isoYear, isoMonth) { - switch (isoMonth) { - case 2: - return computeIsoIsLeapYear(isoYear) ? 29 : 28 - case 4: - case 6: - case 9: - case 11: - return 30 - } - return 31 -} - -function computeIsoDaysInYear(isoYear) { - return computeIsoIsLeapYear(isoYear) ? 365 : 366 -} - -function computeIsoIsLeapYear(isoYear) { - return isoYear % 4 === 0 && (isoYear % 100 !== 0 || isoYear % 400 === 0) -} - -function computeIsoDayOfWeek(isoDateFields) { - return generateLegacyDate(isoDateFields).getDay() + 1 -} - -function computeIsoWeekOfYear(isoDateFields) { -} - -function computeIsoYearOfWeek(isoDateFields) { -} - -function isoFieldsToEpochMilli(isoFields) { -} - -function isoToEpochMilli(isoYear, isoMonth, isoDate) { -} - -function diffDaysMilli(milli0, milli1) { -} - -function addDaysMilli() { -} - -function generateLegacyDate(isoDateTimeFields) { -} - -function epochMilliToIsoFields() { -} - // General Utils // ------------------------------------------------------------------------------------------------- @@ -840,16 +784,3 @@ function removePropSet( } } } - -function twoDigit(num) { -} - -function buildWeakMapCache() { -} - -function constrainInt(subject, minIncl, maxIncl, overflow = 'reject') { - // maybe don't accept min? already vetted to be positive (or non-negative) integer -} - -function numSign() { -} diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index 4338d5c3..237f877a 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -1,16 +1,16 @@ import { createCalendar } from './calendar' import { queryCalendarImpl } from './calendarImpl' -import { strictArrayOfStrings, toObject } from './cast' import { createDuration } from './duration' +import { strictArrayOfStrings, toObject } from './options' +import { PlainDate, createPlainDate } from './plainDate' +import { PlainMonthDay } from './plainMonthDay' +import { PlainYearMonth } from './plainYearMonth' import { - createInternalClass, createInternalGetter, + createWrapperClass, getInternals, internalIdGetters, -} from './internalClass' -import { PlainDate, createPlainDate } from './plainDate' -import { PlainMonthDay } from './plainMonthDay' -import { PlainYearMonth } from './plainYearMonth' +} from './wrapperClass' export function queryCalendarOps(calendarSlot) { if (typeof calendarSlot === 'object') { @@ -37,7 +37,7 @@ const getStrictPlainDateInternals = createInternalGetter(PlainDate) /* Must do output-validation on whatever internal Calendar returns */ -const CalendarOpsAdapter = createInternalClass(internalIdGetters, { +const CalendarOpsAdapter = createWrapperClass(internalIdGetters, { dateAdd(calendar, isoDateFields, durationFields, overflow) { return getStrictPlainDateInternals( calendar.dateAdd( diff --git a/packages/temporal-polyfill/src/new/cast.js b/packages/temporal-polyfill/src/new/cast.js deleted file mode 100644 index 99dcfd1a..00000000 --- a/packages/temporal-polyfill/src/new/cast.js +++ /dev/null @@ -1,76 +0,0 @@ - -export function strictNumber(input) { - -} - -export function strictInstanceOf(obj, Class) { -} - -export function strictArrayOfStrings(obj) { // rethink -} - -export function strictArrayOfType(obj) { // used? -} - -export function strictArray() { - -} - -export function toObject() { -} - -export function toNumber(value) { - if (typeof value === 'bigint') { - throw new TypeError('Cannot convert BigInt to number') - } - return Number(value) -} - -export function toInteger(value) { - const num = toNumber(value) - if (isNaN(num)) return 0 - const integer = Math.trunc(num) - if (num === 0) return 0 - return integer -} - -export function toString(value) { - if (typeof value === 'symbol') { - throw new TypeError('Cannot convert a Symbol value to a String') - } - return String(value) -} - -export function toIntegerThrowOnInfinity(value) { - const integer = toInteger(value) - if (!Number.isFinite(integer)) { - throw new RangeError('infinity is out of range') - } - return integer -} - -export function toPositiveInteger(valueParam, property) { - const value = toInteger(valueParam) - if (!Number.isFinite(value)) { - throw new RangeError('infinity is out of range') - } - if (value < 1) { - if (property !== undefined) { - throw new RangeError(`property '${property}' cannot be a a number less than one`) - } - throw new RangeError('Cannot convert a number less than one to a positive integer') - } - return value -} - -export function toIntegerWithoutRounding(valueParam) { - const value = toNumber(valueParam) - if (isNaN(value)) return 0 - if (!Number.isFinite(value)) { - throw new RangeError('infinity is out of range') - } - if (!Number.isInteger(value)) { - throw new RangeError(`unsupported fractional value ${value}`) - } - return toInteger(value) // ℝ(value) in spec text; converts -0 to 0 -} diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 9247c5d3..d9cb9bb8 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -1,10 +1,18 @@ -import { isoMonthsInYear } from './calendarImpl' -import { addDaysToIsoFields, pluckIsoTimeFields } from './isoFields' -import { identityFunc } from './lang' +import { pluckIsoTimeFields } from './isoFields' +import { + addDaysToIsoFields, + epochNanosecondsToIso, + isoMonthsInYear, + isoTimeToNanoseconds, + isoToUtcEpochNanoseconds, + nanosecondsInIsoDay, + nanosecondsToTimeDuration, +} from './isoMath' import { compareLargeInts } from './largeInt' import { moveDateTime, moveZonedEpochNanoseconds } from './move' -import { nanosecondsInIsoDay } from './nanoseconds' import { roundLargeNanoseconds, roundRelativeDuration } from './round' +import { getSingleInstantFor } from './timeZoneOps' +import { identityFunc } from './util' // Diffing // ------------------------------------------------------------------------------------------------- @@ -53,7 +61,7 @@ export function diffZonedEpochNanoseconds( } function isoToZoneEpochNanoseconds(isoFields) { - return isoToEpochNanoseconds(isoFields, timeZone) + return getSingleInstantFor(timeZone, isoFields) } const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) @@ -265,33 +273,3 @@ function diffExactLargeNanoseconds( largestUnit, ) { } - -// Epoch/Time -// ------------------------------------------------------------------------------------------------- - -function isoToUtcEpochNanoseconds(isoFields) { - -} - -function isoTimeToNanoseconds(isoTimeFields) { - -} - -function nanosecondsToTimeDuration(nanoseconds) { // nanoseconds is a number - -} - -// TimeZone Conversions -// ------------------------------------------------------------------------------------------------- - -function epochNanosecondsToIso(epochNanoseconds, timeZone) { - -} - -function isoToEpochNanoseconds(isoFields, timeZone, disambig) { - return isoToPossibleEpochNanoseconds(isoFields, timeZone)[0] // example -} - -function isoToPossibleEpochNanoseconds(isoFields, timeZone) { - -} diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index c7cfc2f8..a47d222f 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -1,4 +1,4 @@ -import { bagToDurationFields, durationWithBag } from './convert' +import { bagToDurationFields, durationWithBag } from './bag' import { diffZonedEpochNanoseconds } from './diff' import { absolutizeDurationFields, @@ -7,12 +7,18 @@ import { negateDurationFields, refineDurationFields, } from './durationFields' -import { neverValueOf } from './internalClass' -import { identityFunc, noop } from './lang' +import { isoToUtcEpochNanoseconds } from './isoMath' +import { stringToDurationFields } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNanoseconds } from './move' -import { optionsToLargestUnit } from './options' -import { stringToDurationFields } from './parse' +import { + optionsToLargestUnit, + optionsToRelativeTo, + optionsToRoundingIncrement, + optionsToRoundingMode, + optionsToSmallestUnit, + optionsToTotalUnit, +} from './options' import { roundDayTimeDuration, roundRelativeDuration, @@ -20,6 +26,8 @@ import { totalRelativeDuration, } from './round' import { createTemporalClass } from './temporalClass' +import { identityFunc, noop } from './util' +import { neverValueOf } from './wrapperClass' export const [ Duration, @@ -254,22 +262,3 @@ function durationDayTimeToNanoseconds( durationFields, // NOT BALANCED ) { } - -function optionsToTotalUnit() { -} - -function optionsToRelativeTo() { - // should return ZoneDateTimeINTERNALS or PlainDateINTERNALS -} - -function isoToUtcEpochNanoseconds(isoFields) { -} - -function optionsToSmallestUnit(options) { -} - -function optionsToRoundingIncrement(options) { -} - -function optionsToRoundingMode(options) { -} diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 9e79ecc1..1ecec399 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -1,7 +1,6 @@ -import { toIntegerWithoutRounding } from './cast' -import { mapRefiners } from './convert' import { isoTimeFieldDefaults, isoTimeFieldNames } from './isoFields' -import { remapProps } from './obj' +import { toIntegerWithoutRounding } from './options' +import { mapRefiners, remapProps } from './util' const durationDateFieldRefiners = { // sorted alphabetically diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 4401b9f3..e5c80892 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -1,6 +1,5 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' -import { toObject } from './cast' import { diffEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -9,21 +8,23 @@ import { formatIsoDateTimeFields, formatOffsetNanoseconds, formatTimeZone, -} from './format' -import { neverValueOf } from './internalClass' -import { noop } from './lang' -import { compareLargeInts, createLargeInt, toLargeInt } from './largeInt' -import { moveEpochNanoseconds } from './move' +} from './isoFormat' import { epochGetters, + epochNanosecondsToIso, nanosecondsInMicrosecond, nanosecondsInMillisecond, nanosecondsInSecond, regulateEpochNanoseconds, -} from './nanoseconds' +} from './isoMath' +import { compareLargeInts, createLargeInt, toLargeInt } from './largeInt' +import { moveEpochNanoseconds } from './move' +import { toObject } from './options' import { roundLargeNanoseconds } from './round' import { createTemporalClass } from './temporalClass' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' +import { noop } from './util' +import { neverValueOf } from './wrapperClass' import { createZonedDateTime } from './zonedDateTime' export const [ @@ -184,6 +185,3 @@ export const [ function stringToEpochNanoseconds(str) { // TODO } - -function epochNanosecondsToIso() { -} diff --git a/packages/temporal-polyfill/src/new/dateTimeFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js similarity index 91% rename from packages/temporal-polyfill/src/new/dateTimeFormat.js rename to packages/temporal-polyfill/src/new/intlFormat.js index 37d5e85c..f4b49cb5 100644 --- a/packages/temporal-polyfill/src/new/dateTimeFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -1,11 +1,34 @@ import { isoCalendarId } from './calendarConfig' import { dateBasicNames, timeFieldDefaults } from './calendarFields' -import { isoEpochOriginYear } from './calendarImpl' -import { getInternals } from './internalClass' -import { identityFunc } from './lang' -import { epochNanoToMilli } from './nanoseconds' +import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' import { getTemporalName } from './temporalClass' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { + createLazyMap, + excludeProps, + hasAnyMatchingProps, + identityFunc, + zipSingleValue, +} from './util' +import { getInternals } from './wrapperClass' + +export const standardCalendarId = 'en-GB' // gives 24-hour clock + +export function hashIntlFormatParts(intlFormat, epochMilliseconds) { + const parts = intlFormat.formatToParts(epochMilliseconds) + const hash = {} + + for (const part of parts) { + hash[part.type] = part.value + } + + return hash +} + +// Stuff +// ------------------------------------------------------------------------------------------------- + +// AHHH... problem with resolvedOptions... need to whitelist original // TODO: rename to intlFormat? @@ -186,7 +209,7 @@ const optionTransformers = { } function createTransformer(optionNames, basicNames, exclusionNames) { - const defaults = propsWithSameValue(basicNames, 'numeric') + const defaults = zipSingleValue(basicNames, 'numeric') return (options) => { options = excludeProps(options, exclusionNames) @@ -252,18 +275,3 @@ function checkCalendarsCompatible(calendarId, resolveCalendarId, strict) { throw new RangeError('Mismatching calendars') } } - -// Utils -// ------------------------------------------------------------------------------------------------- - -function excludeProps(options, propNames) { -} - -function hasAnyMatchingProps(props, propNames) { -} - -function createLazyMap() { -} - -function propsWithSameValue() { -} diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 514ea7ec..73f3c688 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -1,6 +1,6 @@ import { queryCalendarOps } from './calendarOps' -import { toIntegerThrowOnInfinity, toIntegerWithoutRounding, toPositiveInteger } from './cast' -import { pluckProps } from './obj' +import { toIntegerThrowOnInfinity, toIntegerWithoutRounding, toPositiveInteger } from './options' +import { pluckProps } from './util' export const isoDateSlotRefiners = { // sorted alphabetically @@ -68,14 +68,6 @@ export function pluckIsoTimeFields(isoFields) { return pluckProps(isoFields, isoTimeFieldNames) } -export function compareIsoFields() { - // uses Date.UTC -} - -export function compareIsoTimeFields() { - // uses conversion to milliseconds -} - export function constrainIsoDateTimeFields(isoDateTimeFields, overflow = 'reject') { // ahhhh! calendar gets passed in here!!! } @@ -87,12 +79,7 @@ export function constrainIsoDateFields(isoDateFields, overflow = 'reject') { export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { } -export function addDaysToIsoFields() { - // short-circuit if nothing to add -} - export function isValidIsoFields() { - } /* diff --git a/packages/temporal-polyfill/src/new/format.js b/packages/temporal-polyfill/src/new/isoFormat.js similarity index 97% rename from packages/temporal-polyfill/src/new/format.js rename to packages/temporal-polyfill/src/new/isoFormat.js index 1e40accd..eafc5b9f 100644 --- a/packages/temporal-polyfill/src/new/format.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -1,8 +1,6 @@ import { isoCalendarId } from './calendarConfig' import { toCalendarNameOption } from './options' -// rename file to 'isoFormat'? - export function formatPossibleDate(internals, options, formatSimple) { const calendarNameOpt = toCalendarNameOption(options) const showCalendar = diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js new file mode 100644 index 00000000..70685261 --- /dev/null +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -0,0 +1,183 @@ +import { createLargeInt } from './largeInt' + +export const nanosecondsInMicrosecond = 1000 +export const nanosecondsInMillisecond = 1000000 +export const nanosecondsInSecond = 1000000000 +export const nanosecondsInMinute = 60000000000 // used? +export const nanosecondsInHour = 3600000000000 +export const nanosecondsInIsoDay = 86400000000000 + +export const nanosecondsInUnit = {} // include iso-day as well + +export function epochNanoToMilli(epochNano) { + return epochNano.div(nanosecondsInMillisecond).toNumber() +} + +export const epochGetters = { + epochNanoseconds(epochNanoseconds) { + return epochNanoseconds.toBigInt() + }, + + epochMicroseconds(epochNanoseconds) { + return epochNanoseconds.div(nanosecondsInMicrosecond).toBigInt() + }, + + epochMilliseconds: epochNanoToMilli, + + epochSeconds(epochNanoseconds) { + return epochNanoseconds.div(nanosecondsInSecond).toNumber() + }, +} + +export function regulateEpochNanoseconds(epochNanoseconds) { + // ensure the browser allows it +} + +// Stuff + +export const isoMonthsInYear = 12 +export const isoDaysInWeek = 7 +export const isoEpochOriginYear = 1970 +export const isoEpochFirstLeapYear = 1972 + +export function computeIsoMonthsInYear(isoYear) { + return isoMonthsInYear +} + +export function computeIsoDaysInMonth(isoYear, isoMonth) { + switch (isoMonth) { + case 2: + return computeIsoIsLeapYear(isoYear) ? 29 : 28 + case 4: + case 6: + case 9: + case 11: + return 30 + } + return 31 +} + +export function computeIsoDaysInYear(isoYear) { + return computeIsoIsLeapYear(isoYear) ? 365 : 366 +} + +export function computeIsoIsLeapYear(isoYear) { + return isoYear % 4 === 0 && (isoYear % 100 !== 0 || isoYear % 400 === 0) +} + +export function computeIsoDayOfWeek(isoDateFields) { + return generateLegacyDate(isoDateFields).getDay() + 1 +} + +export function computeIsoWeekOfYear(isoDateFields) { +} + +export function computeIsoYearOfWeek(isoDateFields) { +} + +export function isoFieldsToEpochMilli(isoFields) { +} + +export function isoToEpochMilli(isoYear, isoMonth, isoDate) { +} + +export function diffDaysMilli(milli0, milli1) { +} + +export function addDaysMilli(epochMilli, milli) { +} + +export function generateLegacyDate(isoDateTimeFields) { +} + +export function epochMilliToIsoFields() { +} + +// TIME math... + +export function isoTimeFieldsToNanoseconds() { + +} + +export function nanosecondsToIsoTimeFields() { + /* + const dayDelta = Math.floor(nanoseconds / nanosecondsInIsoDay) + nanoseconds %= nanosecondsInIsoDay + */ + // return [isoTimeFields, dayDelta] +} + +// does floor +export function epochNanoToSec(epochNano) { + let epochSec = epochNano.div(nanosecondsInSecond).toNumber() // does truncation + let subsecNano = epochNano.sub(createLargeInt(epochSec).mult(nanosecondsInSecond)).toNumber() + + if (subsecNano < 0) { + epochSec-- + subsecNano += nanosecondsInSecond + } + + return [epochSec, subsecNano] +} + +export function epochSecToNano(epochSec) { + return createLargeInt(epochSec).mult(nanosecondsInSecond) +} + +export function epochNanoToIsoFields() { +} + +export function isoToUtcEpochNanoseconds(isoFields) { +} + +export function isoFieldsToEpochNano(isoFields) { +} + +export function isoTimeToNanoseconds(isoTimeFields) { +} + +export function nanosecondsToTimeDuration(nanoseconds) { // nanoseconds is a number + // returns an (incomplete?) Duration? + // good idea to put here? +} + +export function epochNanosecondsToIso(epochNanoseconds, timeZone) { +} + +export function compareIsoFields() { + // uses Date.UTC +} + +export function compareIsoTimeFields() { + // uses conversion to milliseconds +} + +export function addDaysToIsoFields() { + // short-circuit if nothing to add +} + +export const milliInSec = 1000 +export const nanoInMicro = 1000 +export const nanoInMilli = 1000 +export const secInDay = 86400 + +export function isoToEpochSec(...args) { // doesn't accept beyond sec + return isoToEpochMilli(...args) / milliInSec // no need for rounding +} + +export function isoFieldsToEpochSec(isoDateTimeFields) { + const epochSec = isoToEpochSec( + isoDateTimeFields.year, + isoDateTimeFields.month, + isoDateTimeFields.day, + isoDateTimeFields.hour, + isoDateTimeFields.minute, + isoDateTimeFields.second, + ) + const subsecNano = + isoDateTimeFields.millisecond * nanoInMilli + + isoDateTimeFields.microsecond * nanoInMicro + + isoDateTimeFields.nanosecond + + return [epochSec, subsecNano] +} diff --git a/packages/temporal-polyfill/src/new/parse.js b/packages/temporal-polyfill/src/new/isoParse.js similarity index 100% rename from packages/temporal-polyfill/src/new/parse.js rename to packages/temporal-polyfill/src/new/isoParse.js diff --git a/packages/temporal-polyfill/src/new/lang.js b/packages/temporal-polyfill/src/new/lang.js deleted file mode 100644 index 712cd027..00000000 --- a/packages/temporal-polyfill/src/new/lang.js +++ /dev/null @@ -1,11 +0,0 @@ - -export function identityFunc(thing) { - return thing -} - -export function noop() { -} - -export function positiveModulo(n, max) { - return (n % max + max) % max -} diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index a4b37120..88e23085 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -1,10 +1,15 @@ -import { isoMonthsInYear } from './calendarImpl' import { durationHasDateParts, durationTimeFieldDefaults, durationTimeFieldsToIso, } from './durationFields' -import { isoTimeFieldsToNanoseconds, nanosecondsToIsoTimeFields } from './nanoseconds' +import { + epochNanosecondsToIso, + isoMonthsInYear, + isoTimeFieldsToNanoseconds, + nanosecondsToIsoTimeFields, +} from './isoMath' +import { getSingleInstantFor } from './timeZoneOps' export function moveEpochNanoseconds(epochNanoseconds, durationFields) { return epochNanoseconds.add(onlyDurationTimeFieldsToIso(durationFields)) @@ -37,7 +42,7 @@ export function moveZonedEpochNanoseconds( ...isoDateTimeFields, // time parts ...movedIsoDateFields, // date parts } - epochNanoseconds = isoToEpochNanoseconds(movedIsoDateTimeFields, timeZone) + epochNanoseconds = getSingleInstantFor(timeZone, movedIsoDateTimeFields) .add(durationTimeNanoseconds) } @@ -131,18 +136,6 @@ function addIsoTimeFields(isoTimeFields0, isoTimeFields1) { // Utils // ------------------------------------------------------------------------------------------------- -function epochNanosecondsToIso(epochNanoseconds, timeZone) { - -} - -function isoToEpochNanoseconds(isoFields, timeZone, disambig) { - return isoToPossibleEpochNanoseconds(isoFields, timeZone)[0] // example -} - -function isoToPossibleEpochNanoseconds(isoFields, timeZone) { - -} - function onlyDurationTimeFieldsToIso(durationFields) { if (durationHasDateParts(durationFields)) { throw new RangeError('Cant have date parts') diff --git a/packages/temporal-polyfill/src/new/nanoseconds.js b/packages/temporal-polyfill/src/new/nanoseconds.js deleted file mode 100644 index aed4d913..00000000 --- a/packages/temporal-polyfill/src/new/nanoseconds.js +++ /dev/null @@ -1,44 +0,0 @@ -export const nanosecondsInMicrosecond = 1000 -export const nanosecondsInMillisecond = 1000000 -export const nanosecondsInSecond = 1000000000 -export const nanosecondsInMinute = 60000000000 // used? -export const nanosecondsInHour = 3600000000000 -export const nanosecondsInIsoDay = 86400000000000 - -export const nanosecondsInUnit = {} // include iso-day as well - -export function epochNanoToMilli(epochNano) { - return epochNano.div(nanosecondsInMillisecond).toNumber() -} - -export const epochGetters = { - epochNanoseconds(epochNanoseconds) { - return epochNanoseconds.toBigInt() - }, - - epochMicroseconds(epochNanoseconds) { - return epochNanoseconds.div(nanosecondsInMicrosecond).toBigInt() - }, - - epochMilliseconds: epochNanoToMilli, - - epochSeconds(epochNanoseconds) { - return epochNanoseconds.div(nanosecondsInSecond).toNumber() - }, -} - -export function regulateEpochNanoseconds(epochNanoseconds) { - -} - -export function isoTimeFieldsToNanoseconds() { - -} - -export function nanosecondsToIsoTimeFields() { - /* - const dayDelta = Math.floor(nanoseconds / nanosecondsInIsoDay) - nanoseconds %= nanosecondsInIsoDay - */ - // return [isoTimeFields, dayDelta] -} diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index 8b3af1c4..d434d545 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -1,16 +1,16 @@ import { nanoInMilli } from '../dateUtils/units' +import { zonedDateTimeInternalsToIso } from './bag' import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' -import { zonedDateTimeInternalsToIso } from './convert' -import { IntlDateTimeFormat } from './dateTimeFormat' import { createInstant } from './instant' +import { IntlDateTimeFormat } from './intlFormat' import { pluckIsoDateSlots, pluckIsoDateTimeSlots, pluckIsoTimeFields } from './isoFields' import { createLargeInt } from './largeInt' -import { createPropDescriptors, createTemporalNameDescriptors } from './obj' import { createPlainDate } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime } from './plainTime' import { queryTimeZoneOps } from './timeZoneOps' +import { createPropDescriptors, createTemporalNameDescriptors } from './util' import { createZonedDateTime } from './zonedDateTime' export const Now = Object.defineProperties({}, { diff --git a/packages/temporal-polyfill/src/new/obj.js b/packages/temporal-polyfill/src/new/obj.js deleted file mode 100644 index cc5f1272..00000000 --- a/packages/temporal-polyfill/src/new/obj.js +++ /dev/null @@ -1,46 +0,0 @@ - -export function isObjectLike() { - -} - -export function mapProps() { - -} - -export function remapProps(obj, oldKeys, newKeys) { - -} - -export function pluckProps(obj, props) { -} - -export function removeDuplicateStrings(a0, a1) { - -} - -// descriptor stuff -// ---------------- - -export function createPropDescriptors(props) { - return mapProps(props, (value) => ({ - value, - configurable: true, - writable: true, - })) -} - -export function createGetterDescriptors(getters) { - return mapProps(getters, (getter) => ({ - get: getter, - configurable: true, - })) -} - -export function createTemporalNameDescriptors(temporalName) { - return { - [Symbol.toStringTag]: { - value: 'Temporal.' + temporalName, - configurable: true, - }, - } -} diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 35af1906..a83145dc 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,4 +1,85 @@ +export function strictNumber(input) { + +} + +export function strictInstanceOf(obj, Class) { +} + +export function strictArrayOfStrings(obj) { // rethink +} + +export function strictArrayOfType(obj) { // used? +} + +export function strictArray() { + +} + +export function toObject() { +} + +export function toNumber(value) { + if (typeof value === 'bigint') { + throw new TypeError('Cannot convert BigInt to number') + } + return Number(value) +} + +export function toInteger(value) { + const num = toNumber(value) + if (isNaN(num)) return 0 + const integer = Math.trunc(num) + if (num === 0) return 0 + return integer +} + +export function toString(value) { + if (typeof value === 'symbol') { + throw new TypeError('Cannot convert a Symbol value to a String') + } + return String(value) +} + +export function toIntegerThrowOnInfinity(value) { + const integer = toInteger(value) + if (!Number.isFinite(integer)) { + throw new RangeError('infinity is out of range') + } + return integer +} + +export function toPositiveInteger(valueParam, property) { + const value = toInteger(valueParam) + if (!Number.isFinite(value)) { + throw new RangeError('infinity is out of range') + } + if (value < 1) { + if (property !== undefined) { + throw new RangeError(`property '${property}' cannot be a a number less than one`) + } + throw new RangeError('Cannot convert a number less than one to a positive integer') + } + return value +} + +export function toIntegerWithoutRounding(valueParam) { + const value = toNumber(valueParam) + if (isNaN(value)) return 0 + if (!Number.isFinite(value)) { + throw new RangeError('infinity is out of range') + } + if (!Number.isInteger(value)) { + throw new RangeError(`unsupported fractional value ${value}`) + } + return toInteger(value) // ℝ(value) in spec text; converts -0 to 0 +} + +// best place for this? (has 'overflow') +export function constrainInt(subject, minIncl, maxIncl, overflow = 'reject') { + // maybe don't accept min? already vetted to be positive (or non-negative) integer +} + export function largestOfTwoUnits() { } @@ -70,3 +151,19 @@ export function optionsToLargestUnit() { export function optionsToOverflow() { } + +export function optionsToTotalUnit() { +} + +export function optionsToRelativeTo() { + // should return ZoneDateTimeINTERNALS or PlainDateINTERNALS +} + +export function optionsToSmallestUnit(options) { +} + +export function optionsToRoundingIncrement(options) { +} + +export function optionsToRoundingMode(options) { +} diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 5c909c62..357d8446 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -1,38 +1,37 @@ -import { isoCalendarId } from './calendarConfig' -import { dateGetters } from './calendarFields' -import { - getCommonCalendarOps, - getPublicCalendar, - queryCalendarOps, -} from './calendarOps' import { bagToPlainDateSlots, createZonedDateTimeConverter, dateToPlainMonthDay, dateToPlainYearMonth, - isStringCastsEqual, - mapRefiners, plainDateWithBag, zonedDateTimeInternalsToIso, -} from './convert' +} from './bag' +import { isoCalendarId } from './calendarConfig' +import { dateGetters } from './calendarFields' +import { + getCommonCalendarOps, + getPublicCalendar, + queryCalendarOps, +} from './calendarOps' import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { formatCalendar, formatIsoDateFields } from './format' -import { neverValueOf } from './internalClass' import { - compareIsoFields, constrainIsoDateFields, generatePublicIsoDateFields, isoDateSlotRefiners, isoTimeFieldDefaults, pluckIsoDateSlots, } from './isoFields' +import { formatCalendar, formatIsoDateFields } from './isoFormat' +import { compareIsoFields } from './isoMath' +import { stringToPlainDateInternals } from './isoParse' import { optionsToOverflow } from './options' -import { stringToPlainDateInternals } from './parse' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' import { createTemporalClass, toLocaleStringMethod } from './temporalClass' +import { isIdPropsEqual, mapRefiners } from './util' +import { neverValueOf } from './wrapperClass' export const [ PlainDate, @@ -122,7 +121,7 @@ export const [ equals(internals, other) { const otherInternals = toPlainDateInternals(other) return !compareIsoFields(internals, otherInternals) && - isStringCastsEqual(internals.calendar, otherInternals.calendar) + isIdPropsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { @@ -174,6 +173,7 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- +// move to options file? function optionalToPlainTimeInternals(timeArg) { return timeArg === undefined ? isoTimeFieldDefaults : toPlainTimeInternals(timeArg) } diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 7635c0ec..b9fd0d81 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -1,22 +1,17 @@ -import { isoCalendarId } from './calendarConfig' -import { dateTimeGetters } from './calendarFields' -import { getPublicCalendar, queryCalendarOps } from './calendarOps' import { bagToPlainDateTimeInternals, dateToPlainMonthDay, dateToPlainYearMonth, - isStringCastsEqual, - mapRefiners, plainDateTimeWithBag, zonedDateTimeInternalsToIso, -} from './convert' +} from './bag' +import { isoCalendarId } from './calendarConfig' +import { dateTimeGetters } from './calendarFields' +import { getPublicCalendar, queryCalendarOps } from './calendarOps' import { diffDateTimes } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { formatCalendar, formatIsoDateTimeFields } from './format' -import { neverValueOf } from './internalClass' import { - compareIsoFields, constrainIsoDateTimeFields, generatePublicIsoDateTimeFields, isoDateTimeSlotRefiners, @@ -25,14 +20,18 @@ import { pluckIsoDateTimeSlots, pluckIsoTimeFields, } from './isoFields' +import { formatCalendar, formatIsoDateTimeFields } from './isoFormat' +import { compareIsoFields } from './isoMath' +import { stringToPlainDateTimeInternals } from './isoParse' import { moveDateTime } from './move' import { optionsToOverflow, toDisambiguation, validateRoundingOptions } from './options' -import { stringToPlainDateTimeInternals } from './parse' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' import { createTemporalClass, toLocaleStringMethod } from './temporalClass' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { isIdPropsEqual, mapRefiners } from './util' +import { neverValueOf } from './wrapperClass' import { createZonedDateTime } from './zonedDateTime' export const [ @@ -177,7 +176,7 @@ export const [ equals(internals, other) { const otherInternals = toPlainDateTimeInternals(other) return !compareIsoFields(internals, otherInternals) && - isStringCastsEqual(internals.calendar, otherInternals.calendar) + isIdPropsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index a208b643..95d5ec7c 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -1,24 +1,23 @@ -import { isoCalendarId } from './calendarConfig' -import { monthDayGetters } from './calendarFields' -import { getPublicCalendar } from './calendarOps' import { bagToPlainMonthDayInternals, - isStringCastsEqual, - mapRefiners, plainMonthDayToPlainDate, plainMonthDayWithBag, -} from './convert' -import { formatIsoMonthDayFields, formatPossibleDate } from './format' -import { neverValueOf } from './internalClass' +} from './bag' +import { isoCalendarId } from './calendarConfig' +import { monthDayGetters } from './calendarFields' +import { getPublicCalendar } from './calendarOps' import { - compareIsoFields, constrainIsoDateFields, generatePublicIsoDateFields, isoDateSlotRefiners, } from './isoFields' +import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' +import { compareIsoFields, isoEpochFirstLeapYear } from './isoMath' +import { stringToMonthDayInternals } from './isoParse' import { optionsToOverflow } from './options' -import { stringToMonthDayInternals } from './parse' import { createTemporalClass, toLocaleStringMethod } from './temporalClass' +import { isIdPropsEqual, mapRefiners } from './util' +import { neverValueOf } from './wrapperClass' export const [ PlainMonthDay, @@ -31,7 +30,7 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (isoMonth, isoDay, calendarArg = isoCalendarId, referenceIsoYear = 1972) => { + (isoMonth, isoDay, calendarArg = isoCalendarId, referenceIsoYear = isoEpochFirstLeapYear) => { return constrainIsoDateFields( mapRefiners({ isoYear: referenceIsoYear, @@ -70,7 +69,7 @@ export const [ equals(internals, otherArg) { const otherInternals = toPlainMonthDayInternals(otherArg) return !compareIsoFields(internals, otherInternals) && - isStringCastsEqual(internals.calendar, otherInternals.calendar) + isIdPropsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index e7f9483d..31906c98 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -1,29 +1,29 @@ -import { timeGetters } from './calendarFields' import { bagToPlainTimeInternals, createZonedDateTimeConverter, - mapRefiners, plainTimeWithBag, zonedDateTimeInternalsToIso, -} from './convert' +} from './bag' +import { timeGetters } from './calendarFields' import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { formatIsoTimeFields } from './format' -import { neverValueOf } from './internalClass' import { - compareIsoTimeFields, constrainIsoTimeFields, isoTimeFieldRefiners, pluckIsoTimeFields, } from './isoFields' +import { formatIsoTimeFields } from './isoFormat' +import { compareIsoTimeFields } from './isoMath' +import { stringToPlainTimeInternals } from './isoParse' import { moveTime } from './move' import { optionsToOverflow } from './options' -import { stringToPlainTimeInternals } from './parse' import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' import { createTemporalClass, toLocaleStringMethod } from './temporalClass' +import { mapRefiners } from './util' +import { neverValueOf } from './wrapperClass' export const [ PlainTime, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index ea7cb842..33806771 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -1,28 +1,27 @@ -import { isoCalendarId } from './calendarConfig' -import { yearMonthGetters } from './calendarFields' -import { getPublicCalendar } from './calendarOps' import { bagToPlainYearMonthInternals, - isStringCastsEqual, - mapRefiners, plainYearMonthToPlainDate, plainYearMonthToPlainDateFirst, plainYearMonthWithBag, -} from './convert' +} from './bag' +import { isoCalendarId } from './calendarConfig' +import { yearMonthGetters } from './calendarFields' +import { getPublicCalendar } from './calendarOps' import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { formatIsoYearMonthFields, formatPossibleDate } from './format' -import { getInternals, neverValueOf } from './internalClass' import { - compareIsoFields, constrainIsoDateFields, generatePublicIsoDateFields, isoDateSlotRefiners, } from './isoFields' +import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' +import { compareIsoFields } from './isoMath' +import { stringToPlainYearMonthInternals } from './isoParse' import { optionsToOverflow } from './options' -import { stringToPlainYearMonthInternals } from './parse' import { createTemporalClass, toLocaleStringMethod } from './temporalClass' +import { isIdPropsEqual, mapRefiners } from './util' +import { getInternals, neverValueOf } from './wrapperClass' export const [ PlainYearMonth, @@ -116,7 +115,7 @@ export const [ equals(internals, otherArg) { const otherInternals = toPlainYearMonthInternals(otherArg) return !compareIsoFields(internals, otherInternals) && - isStringCastsEqual(internals.calendar, otherInternals.calendar) + isIdPropsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 010aadba..59ce1e4e 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -1,14 +1,15 @@ import { durationFieldDefaults, durationTimeFieldDefaults } from './durationFields' -import { addDaysToIsoFields, isoTimeFieldDefaults } from './isoFields' -import { identityFunc } from './lang' -import { createLargeInt } from './largeInt' +import { isoTimeFieldDefaults } from './isoFields' import { + addDaysToIsoFields, isoTimeFieldsToNanoseconds, nanosecondsInIsoDay, nanosecondsInUnit, nanosecondsToIsoTimeFields, -} from './nanoseconds' +} from './isoMath' +import { createLargeInt } from './largeInt' import { computeNanosecondsInDay } from './timeZoneOps' +import { identityFunc } from './util' export function roundToMinute(nanoseconds) { // can be positive or negative diff --git a/packages/temporal-polyfill/src/new/temporal.js b/packages/temporal-polyfill/src/new/temporal.js index 21935bf5..c62096c8 100644 --- a/packages/temporal-polyfill/src/new/temporal.js +++ b/packages/temporal-polyfill/src/new/temporal.js @@ -2,13 +2,13 @@ import { Calendar } from './calendar' import { Duration } from './duration' import { Instant } from './instant' import { Now } from './now' -import { createPropDescriptors } from './obj' import { PlainDate } from './plainDate' import { PlainDateTime } from './plainDateTime' import { PlainMonthDay } from './plainMonthDay' import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' +import { createPropDescriptors } from './util' import { ZonedDateTime } from './zonedDateTime' export const Temporal = Object.defineProperties({}, createPropDescriptors({ diff --git a/packages/temporal-polyfill/src/new/temporalClass.js b/packages/temporal-polyfill/src/new/temporalClass.js index e14a0f92..e7d64e15 100644 --- a/packages/temporal-polyfill/src/new/temporalClass.js +++ b/packages/temporal-polyfill/src/new/temporalClass.js @@ -1,7 +1,6 @@ -import { DateTimeFormat } from './dateTimeFormat' -import { createInternalClass, getInternals, internalsMap } from './internalClass' -import { noop } from './lang' -import { createTemporalNameDescriptors, isObjectLike } from './obj' +import { DateTimeFormat } from './intlFormat' +import { createTemporalNameDescriptors, isObjectLike, noop } from './util' +import { createWrapperClass, getInternals, internalsMap } from './wrapperClass' const temporaNameMap = WeakMap() export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) @@ -24,7 +23,7 @@ export function createTemporalClass( return createInstance(toInternals(arg, options)) } - const TemporalObj = createInternalClass( + const TemporalObj = createWrapperClass( getters, methods, constructorToInternals, @@ -60,6 +59,10 @@ export function createTemporalClass( } export function toLocaleStringMethod(internals, locales, options) { + /* + Will create two internal Intl.DateTimeFormats :( + Create just one instead + */ const format = new DateTimeFormat(locales, options) return format.format(this) } diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 447c7c8a..ace09928 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -1,16 +1,17 @@ import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' +import { createComplexBagRefiner } from './bag' import { Calendar } from './calendar' import { queryCalendarOps } from './calendarOps' -import { createComplexBagRefiner } from './convert' -import { formatOffsetNanoseconds } from './format' import { createInstant, toInstantEpochNanoseconds } from './instant' -import { internalIdGetters, returnId } from './internalClass' -import { noop } from './lang' +import { formatOffsetNanoseconds } from './isoFormat' +import { epochNanosecondsToIso } from './isoMath' +import { stringToTimeZoneId } from './isoParse' import { toDisambiguation } from './options' -import { stringToTimeZoneId } from './parse' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { createTemporalClass } from './temporalClass' import { getSingleInstantFor } from './timeZoneOps' +import { noop } from './util' +import { internalIdGetters, returnId } from './wrapperClass' export const [TimeZone, createTimeZone] = createTemporalClass( 'TimeZone', @@ -86,10 +87,3 @@ export const [TimeZone, createTimeZone] = createTemporalClass( toString: returnId, }, ) - -// TimeZone Conversions -// ------------------------------------------------------------------------------------------------- - -function epochNanosecondsToIso(epochNanoseconds, timeZone) { - -} diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index bef2c564..624ac012 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -1,15 +1,18 @@ /* eslint-disable no-return-assign */ /* eslint-disable no-unmodified-loop-condition */ import { parseIntlYear } from './calendarImpl' -import { IntlDateTimeFormat } from './dateTimeFormat' -import { createLargeInt } from './largeInt' -import { nanosecondsInSecond } from './nanoseconds' -import { parseOffsetNanoseconds } from './parse' - -const nanoInMilli = 1000 -const nanoInMicro = 1000 -const milliInSec = 1000 -const secInDay = 86400 +import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' +import { + epochNanoToSec, + epochSecToNano, + isoFieldsToEpochNano, + isoFieldsToEpochSec, + isoToEpochSec, + milliInSec, nanosecondsInSecond, secInDay, +} from './isoMath' +import { parseOffsetNanoseconds } from './isoParse' +import { clamp, compareNumbers, createLazyMap } from './util' + const periodDur = secInDay * 60 const minPossibleTransition = isoToEpochSec(1847) const maxPossibleTransition = isoToEpochSec(new Date().getUTCFullYear() + 10) @@ -220,8 +223,6 @@ function createComputeOffsetSec(timeZoneId) { } } -const standardCalendarId = 'en-GB' // gives 24-hour clock - function buildIntlFormat(timeZoneId) { // format will ALWAYS do gregorian. need to parse year return new IntlDateTimeFormat(standardCalendarId, { @@ -235,64 +236,3 @@ function buildIntlFormat(timeZoneId) { second: 'numeric', }) } - -// Utils -// ------------------------------------------------------------------------------------------------- - -// does floor -function epochNanoToSec(epochNano) { - let epochSec = epochNano.div(nanosecondsInSecond).toNumber() // does truncation - let subsecNano = epochNano.sub(createLargeInt(epochSec).mult(nanosecondsInSecond)).toNumber() - - if (subsecNano < 0) { - epochSec-- - subsecNano += nanosecondsInSecond - } - - return [epochSec, subsecNano] -} - -function epochSecToNano(epochSec) { - return createLargeInt(epochSec).mult(nanosecondsInSecond) -} - -function createLazyMap(computeFunc) { -} - -function isoFieldsToEpochNano(isoFields) { -} - -function compareNumbers() { -} - -function clamp() { -} - -function hashIntlFormatParts() { -} - -// TODO: rename these to UTC-something? - -function isoToEpochSec(...args) { // doesn't accept beyond sec - return isoToEpochMilli(...args) / milliInSec // no need for rounding -} - -function isoToEpochMilli() { -} - -function isoFieldsToEpochSec(isoDateTimeFields) { - const epochSec = isoToEpochSec( - isoDateTimeFields.year, - isoDateTimeFields.month, - isoDateTimeFields.day, - isoDateTimeFields.hour, - isoDateTimeFields.minute, - isoDateTimeFields.second, - ) - const subsecNano = - isoDateTimeFields.millisecond * nanoInMilli + - isoDateTimeFields.microsecond * nanoInMicro + - isoDateTimeFields.nanosecond - - return [epochSec, subsecNano] -} diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index 08db7d2d..143e5cae 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -1,17 +1,22 @@ -import { strictArray, strictNumber } from './cast' import { Instant, createInstant } from './instant' +import { isoTimeFieldDefaults } from './isoFields' import { - createInternalClass, - createInternalGetter, - getInternals, - internalIdGetters, -} from './internalClass' -import { addDaysToIsoFields, isoTimeFieldDefaults } from './isoFields' -import { nanosecondsInIsoDay } from './nanoseconds' + addDaysToIsoFields, + epochNanoToIsoFields, + isoFieldsToEpochNano, + nanosecondsInIsoDay, +} from './isoMath' +import { strictArray, strictNumber } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' import { createTimeZone } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' +import { + createInternalGetter, + createWrapperClass, + getInternals, + internalIdGetters, +} from './wrapperClass' export const utcTimeZoneId = 'UTC' @@ -165,7 +170,7 @@ function computeGapNear(timeZoneOps, zonedEpochNano) { const getStrictInstantEpochNanoseconds = createInternalGetter(Instant) -const TimeZoneOpsAdapter = createInternalClass(internalIdGetters, { +const TimeZoneOpsAdapter = createWrapperClass(internalIdGetters, { getOffsetNanosecondsFor(timeZone, epochNanoseconds) { const nanoseconds = strictNumber( // TODO: integer? timeZone.getOffsetNanosecondsFor(createInstant(epochNanoseconds)), @@ -186,14 +191,3 @@ const TimeZoneOpsAdapter = createInternalClass(internalIdGetters, { ).map(getStrictInstantEpochNanoseconds) }, }) - -// Utils -// ----- - -function isoFieldsToEpochNano() { - -} - -function epochNanoToIsoFields() { - -} diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js new file mode 100644 index 00000000..e11b70b4 --- /dev/null +++ b/packages/temporal-polyfill/src/new/util.js @@ -0,0 +1,91 @@ + +export function isObjectLike() { +} + +export function mapRefiners(input, refinerMap) { + // loops get driven props of input +} + +export function mapProps(input, refinerMap) { + // loops get driven my refinerMap +} + +export function remapProps(obj, oldKeys, newKeys) { +} + +export function pluckProps(obj, props) { +} + +export function removeDuplicateStrings(a0, a1) { +} + +export function removeUndefines(obj) { // and copy +} + +export function buildWeakMapCache() { +} + +export function createLazyMap() { +} + +export function excludeProps(options, propNames) { +} + +export function hasAnyMatchingProps(props, propNames) { +} + +export function zipSingleValue() { +} + +// descriptor stuff +// ---------------- + +export function createPropDescriptors(props) { + return mapProps(props, (value) => ({ + value, + configurable: true, + writable: true, + })) +} + +export function createGetterDescriptors(getters) { + return mapProps(getters, (getter) => ({ + get: getter, + configurable: true, + })) +} + +export function createTemporalNameDescriptors(temporalName) { + return { + [Symbol.toStringTag]: { + value: 'Temporal.' + temporalName, + configurable: true, + }, + } +} + +// former lang +// ----------- + +export function identityFunc(thing) { + return thing +} + +export function noop() { +} + +export function positiveModulo(n, max) { + return (n % max + max) % max +} + +export function twoDigit(num) { // as a string +} + +export function compareNumbers() { +} + +export function clamp() { +} + +export function isIdPropsEqual(obj0, obj1) { +} diff --git a/packages/temporal-polyfill/src/new/internalClass.js b/packages/temporal-polyfill/src/new/wrapperClass.js similarity index 77% rename from packages/temporal-polyfill/src/new/internalClass.js rename to packages/temporal-polyfill/src/new/wrapperClass.js index 9a4cd323..87df762d 100644 --- a/packages/temporal-polyfill/src/new/internalClass.js +++ b/packages/temporal-polyfill/src/new/wrapperClass.js @@ -1,14 +1,10 @@ -import { mapHash } from '../utils/obj' -import { strictInstanceOf } from './cast' -import { identityFunc, noop } from './lang' -import { createGetterDescriptors, createPropDescriptors } from './obj' +import { strictInstanceOf } from './options' +import { createGetterDescriptors, createPropDescriptors, identityFunc, mapProps, noop } from './util' export const internalsMap = new WeakMap() export const getInternals = internalsMap.get.bind(internalsMap) -// TODO: rename to 'wrapper' class? - -export function createInternalClass( +export function createWrapperClass( getters, methods, constructorToInternals = identityFunc, @@ -31,8 +27,8 @@ export function createInternalClass( } Object.defineProperties(InternalObj.prototype, { - ...createGetterDescriptors(mapHash(getters, curryMethod)), - ...createPropDescriptors(mapHash(methods, curryMethod)), + ...createGetterDescriptors(mapProps(getters, curryMethod)), + ...createPropDescriptors(mapProps(methods, curryMethod)), ...extraPrototypeDescriptors, }) @@ -55,6 +51,7 @@ export function returnId(internals) { return internals.id } +// TODO: make a versoin that casts the id to string? For adapters export const internalIdGetters = { id: returnId } export function createInternalGetter(Class) { diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index b80e33fe..484e71db 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -1,37 +1,34 @@ -import { dateTimeGetters } from './calendarFields' -import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' import { bagToZonedDateTimeInternals, dateToPlainMonthDay, dateToPlainYearMonth, - isStringCastsEqual, zonedDateTimeInternalsToIso, zonedDateTimeWithBag, -} from './convert' -import { resolveZonedFormattable } from './dateTimeFormat' +} from './bag' +import { dateTimeGetters } from './calendarFields' +import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' import { diffZonedEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { - formatCalendar, - formatIsoDateTimeFields, - formatOffsetNanoseconds, - formatTimeZone, -} from './format' import { createInstant } from './instant' -import { neverValueOf } from './internalClass' +import { resolveZonedFormattable } from './intlFormat' import { isoTimeFieldDefaults, pluckIsoDateSlots, pluckIsoDateTimeSlots, pluckIsoTimeFields, } from './isoFields' +import { + formatCalendar, + formatIsoDateTimeFields, + formatOffsetNanoseconds, + formatTimeZone, +} from './isoFormat' +import { epochGetters, epochNanosecondsToIso, nanosecondsInHour } from './isoMath' +import { stringToZonedDateTimeInternals } from './isoParse' import { compareLargeInts, toLargeInt } from './largeInt' import { moveZonedEpochNanoseconds } from './move' -import { epochGetters, nanosecondsInHour } from './nanoseconds' -import { mapProps } from './obj' import { optionsToOverflow } from './options' -import { stringToZonedDateTimeInternals } from './parse' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime, toPlainTimeInternals } from './plainTime' @@ -44,6 +41,8 @@ import { getPublicTimeZone, queryTimeZoneOps, } from './timeZoneOps' +import { isIdPropsEqual, mapProps } from './util' +import { neverValueOf } from './wrapperClass' export const [ ZonedDateTime, @@ -283,8 +282,8 @@ export const [ const otherInternals = toZonedDateTimeInternals(otherZonedDateTimeArg) return !compareLargeInts(internals.epochNanoseconds, otherInternals.epochNanoseconds) && - isStringCastsEqual(internals.calendar, otherInternals.calendar) && - isStringCastsEqual(internals.timeZone, otherInternals.timeZone) + isIdPropsEqual(internals.calendar, otherInternals.calendar) && + isIdPropsEqual(internals.timeZone, otherInternals.timeZone) }, toString(internals, options) { @@ -394,6 +393,3 @@ function moveZonedDateTimeInternals(internals, durationFields, overflowHandling) overflowHandling, ) } - -function epochNanosecondsToIso() { -} From bb98b7ba957d738875de1eae118b27a7dfad6eaf Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 1 Jun 2023 12:27:12 -0400 Subject: [PATCH 079/805] top-level objects --- packages/temporal-polyfill/src/new/global.js | 6 ++++++ packages/temporal-polyfill/src/new/index.js | 3 +++ packages/temporal-polyfill/src/new/instant.js | 13 ++++++++++--- packages/temporal-polyfill/src/new/util.js | 4 ++++ packages/temporal-polyfill/src/new/wrapperClass.js | 11 +++++++++-- 5 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 packages/temporal-polyfill/src/new/global.js create mode 100644 packages/temporal-polyfill/src/new/index.js diff --git a/packages/temporal-polyfill/src/new/global.js b/packages/temporal-polyfill/src/new/global.js new file mode 100644 index 00000000..9c253123 --- /dev/null +++ b/packages/temporal-polyfill/src/new/global.js @@ -0,0 +1,6 @@ +import { DateTimeFormat, Temporal, toTemporalInstant } from './index' +import { defineProps } from './util' + +defineProps(globalThis, { Temporal }) +defineProps(Intl, { DateTimeFormat }) +defineProps(Date.prototype, { toTemporalInstant }) diff --git a/packages/temporal-polyfill/src/new/index.js b/packages/temporal-polyfill/src/new/index.js new file mode 100644 index 00000000..d6c918b2 --- /dev/null +++ b/packages/temporal-polyfill/src/new/index.js @@ -0,0 +1,3 @@ +export { Temporal } from './temporal' +export { DateTimeFormat } from './intlFormat' +export { toTemporalInstant } from './instant' diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index e5c80892..8d205fa9 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -168,9 +168,7 @@ export const [ return createInstant(createLargeInt(epochSeconds).mult(nanosecondsInSecond)) }, - fromEpochMilliseconds(epochMilliseconds) { - return createInstant(createLargeInt(epochMilliseconds).mult(nanosecondsInMillisecond)) - }, + fromEpochMilliseconds: epochMilliToInstant, fromEpochMicroseconds(epochMicroseconds) { return createInstant(toLargeInt(epochMicroseconds).mult(nanosecondsInMicrosecond)) @@ -185,3 +183,12 @@ export const [ function stringToEpochNanoseconds(str) { // TODO } + +function epochMilliToInstant(epochMilli) { + return createInstant(createLargeInt(epochMilli).mult(nanosecondsInMillisecond)) +} + +// a method for Date +export function toTemporalInstant() { + return epochMilliToInstant(this.valueOf()) +} diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index e11b70b4..eb0beb4d 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -37,6 +37,10 @@ export function hasAnyMatchingProps(props, propNames) { export function zipSingleValue() { } +export function defineProps(target, propVals) { + Object.defineProperties(target, createPropDescriptors(propVals)) +} + // descriptor stuff // ---------------- diff --git a/packages/temporal-polyfill/src/new/wrapperClass.js b/packages/temporal-polyfill/src/new/wrapperClass.js index 87df762d..1c593c4c 100644 --- a/packages/temporal-polyfill/src/new/wrapperClass.js +++ b/packages/temporal-polyfill/src/new/wrapperClass.js @@ -1,5 +1,12 @@ import { strictInstanceOf } from './options' -import { createGetterDescriptors, createPropDescriptors, identityFunc, mapProps, noop } from './util' +import { + createGetterDescriptors, + createPropDescriptors, + defineProps, + identityFunc, + mapProps, + noop, +} from './util' export const internalsMap = new WeakMap() export const getInternals = internalsMap.get.bind(internalsMap) @@ -32,7 +39,7 @@ export function createWrapperClass( ...extraPrototypeDescriptors, }) - Object.defineProperties(InternalObj, createPropDescriptors(staticMembers)) + defineProps(InternalObj, staticMembers) return InternalObj } From fc869e4df5f980f3b08fe86aa237a70db5d7141f Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 1 Jun 2023 19:24:27 -0400 Subject: [PATCH 080/805] mods --- packages/temporal-polyfill/src/new/bag.js | 15 +- .../temporal-polyfill/src/new/calendar.js | 55 +++---- .../src/new/calendarFields.js | 117 ++++++++------ .../temporal-polyfill/src/new/calendarImpl.js | 20 +++ .../temporal-polyfill/src/new/calendarOps.js | 95 ++++-------- packages/temporal-polyfill/src/new/class.js | 146 ++++++++++++++++++ .../temporal-polyfill/src/new/duration.js | 3 +- .../src/new/durationFields.js | 9 +- packages/temporal-polyfill/src/new/instant.js | 3 +- .../temporal-polyfill/src/new/intlFormat.js | 3 +- packages/temporal-polyfill/src/new/isoMath.js | 1 - packages/temporal-polyfill/src/new/now.js | 9 ++ packages/temporal-polyfill/src/new/options.js | 19 +++ .../temporal-polyfill/src/new/plainDate.js | 3 +- .../src/new/plainDateTime.js | 3 +- .../src/new/plainMonthDay.js | 3 +- .../temporal-polyfill/src/new/plainTime.js | 3 +- .../src/new/plainYearMonth.js | 3 +- .../temporal-polyfill/src/new/temporal.js | 6 +- .../src/new/temporalClass.js | 68 -------- .../temporal-polyfill/src/new/timeZone.js | 3 +- .../temporal-polyfill/src/new/timeZoneOps.js | 59 +++---- packages/temporal-polyfill/src/new/util.js | 6 +- .../temporal-polyfill/src/new/wrapperClass.js | 66 -------- .../src/new/zonedDateTime.js | 3 +- 25 files changed, 370 insertions(+), 351 deletions(-) create mode 100644 packages/temporal-polyfill/src/new/class.js delete mode 100644 packages/temporal-polyfill/src/new/temporalClass.js delete mode 100644 packages/temporal-polyfill/src/new/wrapperClass.js diff --git a/packages/temporal-polyfill/src/new/bag.js b/packages/temporal-polyfill/src/new/bag.js index c7e001b3..147377cc 100644 --- a/packages/temporal-polyfill/src/new/bag.js +++ b/packages/temporal-polyfill/src/new/bag.js @@ -8,6 +8,7 @@ import { dateFieldNames, dateTimeFieldNames, dateTimeFieldRefiners, + eraYearFieldRefiners, monthDayBasicNames, timeFieldDefaults, timeFieldNames, @@ -16,11 +17,11 @@ import { yearMonthFieldNames, } from './calendarFields' import { queryCalendarOps } from './calendarOps' +import { getInternals } from './class' import { - durationFieldDefaults, + addSignToDurationFields, durationFieldNames, durationFieldRefiners, - refineDurationFields, } from './durationFields' import { constrainIsoDateTimeFields, @@ -31,7 +32,6 @@ import { parseOffsetNanoseconds } from './isoParse' import { optionsToOverflow, toDisambiguation, - toInteger, toObject, toOffsetHandling, toOverflowOptions, @@ -42,20 +42,18 @@ import { createPlainTime } from './plainTime' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createLazyMap, isObjectLike, pluckProps, removeDuplicateStrings } from './util' -import { getInternals } from './wrapperClass' import { createZonedDateTime } from './zonedDateTime' // Duration // ------------------------------------------------------------------------------------------------- export function bagToDurationFields(bag) { - return refineDurationFields({ ...durationFieldDefaults, ...bag }) + return prepareFields(bag, durationFieldNames, []) } export function durationWithBag(durationFields, bag) { const partialDurationFields = prepareFields(bag, durationFieldNames) - return refineDurationFields({ ...durationFields, ...partialDurationFields }) - // TODO: inefficient b/c refineDurationFields will re-parse + return addSignToDurationFields({ ...durationFields, ...partialDurationFields }) } // high level yo @@ -390,10 +388,9 @@ function mergeToPlainDate( // ------------------------------------------------------------------------------------------------- const builtinRefiners = { + ...eraYearFieldRefiners, ...dateTimeFieldRefiners, ...durationFieldRefiners, - era: toString, - eraYear: toInteger, offset: toString, } diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 9cf8f75e..154d0e7c 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -4,8 +4,13 @@ import { getRequiredMonthDayFields, getRequiredYearMonthFields, } from './calendarConfig' -import { dateCalendarRefiners, dateFieldNames, yearMonthFieldNames } from './calendarFields' +import { + dateFieldNames, + dateGetterNames, + yearMonthFieldNames, +} from './calendarFields' import { queryCalendarImpl } from './calendarImpl' +import { createAdapterMethods, createTemporalClass, internalIdGetters, returnId } from './class' import { createDuration, toDurationInternals } from './duration' import { isoDaysInWeek } from './isoMath' import { stringToCalendarId } from './isoParse' @@ -13,10 +18,8 @@ import { optionsToLargestUnit, optionsToOverflow, strictArrayOfStrings, toObject import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' -import { createTemporalClass } from './temporalClass' import { TimeZone } from './timeZone' -import { mapProps, noop, removeUndefines } from './util' -import { internalIdGetters, returnId } from './wrapperClass' +import { identityFunc, mapArrayToProps, noop, removeUndefines } from './util' /* Must do input validation @@ -51,9 +54,9 @@ export const [Calendar, createCalendar] = createTemporalClass( // ----------------------------------------------------------------------------------------------- { - ...mapProps(dateCalendarRefiners, (refiner, methodName) => { + ...mapArrayToProps(dateGetterNames, (propName) => { return (impl, plainDateArg) => { - return impl[methodName](toPlainDateInternals(plainDateArg)) + return impl[propName](toPlainDateInternals(plainDateArg)) } }), @@ -61,25 +64,12 @@ export const [Calendar, createCalendar] = createTemporalClass( return isoDaysInWeek }, - dateAdd(impl, plainDateArg, durationArg, options) { - return createPlainDate( - impl.dateAdd( - toPlainDateInternals(plainDateArg), - toDurationInternals(durationArg), // TODO: balance-up time parts to days - optionsToLargestUnit(options), - ), - ) - }, - - dateUntil(impl, startPlainDateArg, endPlainDateArg, options) { - return createDuration( - impl.dateUntil( - toPlainDateInternals(startPlainDateArg), - toPlainDateInternals(endPlainDateArg), - optionsToOverflow(options), - ), - ) - }, + ...createAdapterMethods({ + dateAdd: [createPlainDate, toPlainDateInternals, toDurationInternals, optionsToLargestUnit], + dateUntil: [createDuration, toPlainDateInternals, toPlainDateInternals, optionsToOverflow], + fields: [identityFunc, strictArrayOfStrings], + mergeFields: [identityFunc, removeUndefinesStrict, removeUndefinesStrict], + }), dateFromFields(impl, fields, options) { return createPlainDate({ @@ -112,17 +102,10 @@ export const [Calendar, createCalendar] = createTemporalClass( }) }, - fields(impl, fieldNames) { - return impl.fields(strictArrayOfStrings(fieldNames)) - }, - - mergeFields(impl, fields0, fields1) { - return impl.mergeFields( - removeUndefines(toObject(fields0)), - removeUndefines(toObject(fields1)), - ) - }, - toString: returnId, }, ) + +function removeUndefinesStrict(obj) { + return removeUndefines(toObject(obj)) +} diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index fc161b7e..4b39671a 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -1,30 +1,36 @@ -import { isoTimeFieldDefaults, isoTimeFieldNames } from './isoFields' -import { toIntegerThrowOnInfinity, toPositiveInteger } from './options' -import { mapProps, remapProps } from './util' +import { isoTimeFieldNames } from './isoFields' +import { toBoolean, toInteger, toIntegerThrowOnInfinity, toPositiveInteger } from './options' +import { mapArrayToProps, remapProps, zipSingleValue } from './util' -// does NOT contain era/eraYear (considered special-case for certain calendars) +// Refiners +// ------------------------------------------------------------------------------------------------- -export const yearMonthFieldRefiners = { - // sorted alphabetically +const dayFieldRefiners = { day: toPositiveInteger } +const monthCodeFieldRefiners = { monthCode: toString } + +// Ordered alphabetically +export const eraYearFieldRefiners = { + era: toString, + eraYear: toInteger, +} + +// Ordered alphabetically +// Does not include era/eraYear +const yearMonthFieldRefiners = { month: toPositiveInteger, - monthCode: toString, + ...monthCodeFieldRefiners, year: toIntegerThrowOnInfinity, } +// Ordered alphabetically +// Does not include era/eraYear export const dateFieldRefiners = { - // sorted alphabetically - day: toPositiveInteger, + ...dayFieldRefiners, ...yearMonthFieldRefiners, } -export const monthDayFieldRefiners = { - // sorted alphabetically - day: toPositiveInteger, // not DRY - monthCode: toString, // not DRY -} - -export const timeFieldRefiners = { - // sorted alphabetically +// Ordered alphabetically +const timeFieldRefiners = { hour: toIntegerThrowOnInfinity, microsecond: toIntegerThrowOnInfinity, millisecond: toIntegerThrowOnInfinity, @@ -33,25 +39,27 @@ export const timeFieldRefiners = { second: toIntegerThrowOnInfinity, } +// Unordered +// Does not include era/eraYear export const dateTimeFieldRefiners = { - // keys must be resorted ...dateFieldRefiners, ...timeFieldRefiners, } -export const yearStatRefiners = { - // sorted alphabetically, for predictable macros +// Ordered alphabetically, for predictable macros +const yearStatRefiners = { daysInYear: toPositiveInteger, - inLeapYear: toPositiveInteger, + inLeapYear: toBoolean, monthsInYear: toPositiveInteger, } -export const yearStatNames = Object.keys(yearStatRefiners) +// Unordered export const yearMonthStatRefiners = { ...yearStatRefiners, daysInMonth: toPositiveInteger, } +// Unordered export const dateStatRefiners = { ...yearMonthStatRefiners, dayOfWeek: toPositiveInteger, @@ -61,52 +69,53 @@ export const dateStatRefiners = { daysInWeek: toPositiveInteger, } -// -// NOTE: "basic" names are for converting between Plain* objects. Don't need all numeric fields -// +// Property Names +// ------------------------------------------------------------------------------------------------- + +export const eraYearFieldNames = Object.keys(eraYearFieldRefiners) +export const allYearFieldNames = [...eraYearFieldNames, 'year'] + export const dateFieldNames = Object.keys(dateFieldRefiners) -export const dateBasicNames = ['day', 'month', 'year'] export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) // month/monthCode/year -export const yearMonthBasicNames = yearMonthFieldNames.slice(1) // monthCode/year export const monthDayFieldNames = dateFieldNames.slice(0, 3) // day/month/monthCode -export const monthDayBasicNames = ['day', 'monthCode'] export const monthFieldNames = monthDayFieldNames.slice(1) // month/monthCode export const dateTimeFieldNames = Object.keys(dateTimeFieldRefiners).sort() export const timeFieldNames = Object.keys(timeFieldRefiners) -export const eraYearFieldNames = ['era', 'eraYear'] -export const allYearFieldNames = [...eraYearFieldNames, 'year'] +export const dateBasicNames = ['day', 'month', 'year'] +export const yearMonthBasicNames = yearMonthFieldNames.slice(1) // monthCode/year +export const monthDayBasicNames = ['day', 'monthCode'] -export const yearMonthGetters = createCalendarGetters({ - ...yearMonthFieldRefiners, - ...yearMonthStatRefiners, -}) +export const yearStatNames = Object.keys(yearStatRefiners) // ordered, for predictable macros +export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) // unordered +export const dateStatNames = Object.keys(dateStatRefiners) // unordered -export const monthDayGetters = createCalendarGetters(monthDayFieldRefiners) +export const dateGetterNames = [...dateFieldNames, ...dateStatNames] // unordered +export const yearMonthGetterNames = [...yearMonthFieldNames, ...yearMonthStatNames] // unordered +export const monthDayGetterNames = monthDayFieldNames // unordered -export const dateCalendarRefiners = { - ...dateFieldRefiners, - ...dateStatRefiners, -} +// Getters +// ------------------------------------------------------------------------------------------------- -export const dateGetters = createCalendarGetters(dateCalendarRefiners) +export const dateGetters = createGetters(dateGetterNames) +export const yearMonthGetters = createGetters(yearMonthGetterNames) +export const monthDayGetters = createGetters(monthDayGetterNames) -export const timeGetters = isoTimeFieldNames.reduce((accum, isoTimeField, i) => { - accum[timeFieldNames[i]] = function(internals) { - return internals[isoTimeField] +export const timeGetters = mapArrayToProps(timeFieldNames, (timeFieldName, i) => { + return (isoTimeFieldsInternals) => { + return isoTimeFieldsInternals[isoTimeFieldNames[i]] } - return accum -}, {}) // TODO: somehow leverage remapProps instead? +}) export const dateTimeGetters = { ...dateGetters, ...timeGetters, } -function createCalendarGetters(refiners) { - const getters = mapProps(refiners, (refiner, fieldName) => { - return function(internals) { - return refiner(internals.calendar[fieldName](this)) +function createGetters(getterNames) { + const getters = mapArrayToProps(getterNames, (fieldName) => { + return (internals) => { + return internals.calendar[fieldName](internals) } }) @@ -117,8 +126,14 @@ function createCalendarGetters(refiners) { return getters } +// Defaults +// ------------------------------------------------------------------------------------------------- + +export const timeFieldDefaults = zipSingleValue(timeFieldNames, 0) + +// Conversion +// ------------------------------------------------------------------------------------------------- + export function timeFieldsToIso(timeFields) { return remapProps(timeFields, timeFieldNames, isoTimeFieldNames) } - -export const timeFieldDefaults = remapProps(isoTimeFieldDefaults, isoTimeFieldNames, timeFieldNames) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index b10d90ba..5341a74d 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -49,6 +49,18 @@ class IsoCalendarImpl { this.id = id } + year(isoDateFields) { + return isoDateFields.isoYear + } + + month(isoDateFields) { + return isoDateFields.isoMonth + } + + day(isoDateFields) { + return isoDateFields.isoDay + } + era(isoDateFields) { // undefined } @@ -423,10 +435,18 @@ class IntlCalendarImpl extends IsoCalendarImpl { this.yearAtEpoch = yearAtEpoch } + year(isoDateFields) { + return this.queryYearMonthDay(isoDateFields)[0] + } + month(isoDateFields) { return this.queryYearMonthDay(isoDateFields)[1] } + day(isoDateFields) { + return this.queryYearMonthDay(isoDateFields)[2] + } + monthCode(isoDateFields) { const [year, month] = this.queryYearMonthDay(isoDateFields) const leapMonth = this.queryLeapMonth(year) diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index 237f877a..344fc411 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -1,16 +1,19 @@ import { createCalendar } from './calendar' +import { dateFieldRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' -import { createDuration } from './duration' -import { strictArrayOfStrings, toObject } from './options' -import { PlainDate, createPlainDate } from './plainDate' -import { PlainMonthDay } from './plainMonthDay' -import { PlainYearMonth } from './plainYearMonth' import { - createInternalGetter, + createAdapterMethods, createWrapperClass, getInternals, + getStrictInternals, internalIdGetters, -} from './wrapperClass' +} from './class' +import { createDuration } from './duration' +import { largestUnitToOptions, overflowToOptions, strictArrayOfStrings, toObject } from './options' +import { PlainDate, createPlainDate } from './plainDate' +import { PlainMonthDay } from './plainMonthDay' +import { PlainYearMonth } from './plainYearMonth' +import { identityFunc, mapProps } from './util' export function queryCalendarOps(calendarSlot) { if (typeof calendarSlot === 'object') { @@ -32,64 +35,22 @@ export function getCommonCalendarOps(internals0, internals1) { // Adapter // ------------------------------------------------------------------------------------------------- -const getStrictPlainDateInternals = createInternalGetter(PlainDate) +const getPlainDateInternals = getStrictInternals(PlainDate) -/* -Must do output-validation on whatever internal Calendar returns -*/ -const CalendarOpsAdapter = createWrapperClass(internalIdGetters, { - dateAdd(calendar, isoDateFields, durationFields, overflow) { - return getStrictPlainDateInternals( - calendar.dateAdd( - createPlainDate(isoDateFields), // hopefully won't look at blank .calendar - createDuration(durationFields), - { overflow }, - ), - ) - }, - - dateUntil(calendar, startIsoDateFields, endIsoDateFields, largestUnit) { - return getStrictPlainDateInternals( - calendar.dateUntil( - createPlainDate(startIsoDateFields), // hopefully won't look at blank .calendar - createPlainDate(endIsoDateFields), // hopefully won't look at blank .calendar - { largestUnit }, - ), - ) - }, - - /* - Fields should have already been plucked and refined from raw input - */ - dateFromFields(calendar, fields, overflow) { - return getStrictPlainDateInternals( // TODO: pluck away `calendar`Op - calendar.dateFromFields(fields, { overflow }), - ) - }, - - /* - Fields should have already been plucked and refined from raw input - */ - yearMonthFromFields(calendar, fields, overflow) { - return createInternalGetter(PlainYearMonth)( - calendar.yearMonthFromFields(fields, { overflow }), - ) - }, - - /* - Fields should have already been plucked and refined from raw input - */ - monthDayFromFields(calendar, fields, overflow) { - return createInternalGetter(PlainMonthDay)( - calendar.monthDayFields(calendar, fields, { overflow }), - ) - }, - - fields(calendar, fieldNames) { - return strictArrayOfStrings(calendar.fields(calendar, fieldNames)) - }, - - mergeFields(calendar, fields0, fields1) { - return toObject(calendar.mergeFields(fields0, fields1)) - }, -}) +const CalendarOpsAdapter = createWrapperClass( + internalIdGetters, + createAdapterMethods({ + ...mapProps({ + ...eraYearFieldRefiners, + ...dateFieldRefiners, + ...dateStatRefiners, + }, (refiner) => [refiner, createPlainDate]), + dateAdd: [getPlainDateInternals, createPlainDate, createDuration, overflowToOptions], + dateUntil: [getPlainDateInternals, createPlainDate, createPlainDate, largestUnitToOptions], + dateFromFields: [getPlainDateInternals, identityFunc, overflowToOptions], + yearMonthFromFields: [getStrictInternals(PlainYearMonth), identityFunc, overflowToOptions], + monthDayFromFields: [getStrictInternals(PlainMonthDay), identityFunc, overflowToOptions], + fields: [strictArrayOfStrings, identityFunc], + mergeFields: [toObject, identityFunc, identityFunc], + }), +) diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js new file mode 100644 index 00000000..040c4753 --- /dev/null +++ b/packages/temporal-polyfill/src/new/class.js @@ -0,0 +1,146 @@ +import { DateTimeFormat } from './intlFormat' +import { strictInstanceOf } from './options' +import { + createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, + defineProps, + identityFunc, + isObjectLike, + mapProps, + noop, +} from './util' + +// Wrapper Class +// ------------------------------------------------------------------------------------------------- + +const internalsMap = new WeakMap() +export const getInternals = internalsMap.get.bind(internalsMap) + +export function createWrapperClass( + getters, + methods, + constructorToInternals = identityFunc, + extraPrototypeDescriptors = {}, + staticMembers = {}, + handleInstance = noop, +) { + function InternalObj(...args) { + internalsMap.set(this, constructorToInternals(...args)) + handleInstance(this) + } + + function curryMethod(method) { + return /* Object.setPrototypeOf( */ function(...args) { + if (!(this instanceof InternalObj)) { + throw new TypeError('Invalid receiver') + } + return method.call(this, getInternals(this), ...args) + } /* , null) */ + } + + Object.defineProperties(InternalObj.prototype, { + ...createGetterDescriptors(mapProps(getters, curryMethod)), + ...createPropDescriptors(mapProps(methods, curryMethod)), + ...extraPrototypeDescriptors, + }) + + defineProps(InternalObj, staticMembers) + + return InternalObj +} + +export function neverValueOf() { + throw new TypeError('Cannot convert object using valueOf') +} + +export function transformInternalMethod(transformRes, methodName) { + return (impl, ...args) => { + return transformRes(impl[methodName](...args)) + } +} + +export function returnId(internals) { + return internals.id +} + +// TODO: make a versoin that casts the id to string? For adapters +export const internalIdGetters = { id: returnId } + +// TODO: createStrictInternalGetter +export function getStrictInternals(Class) { + return (res) => getInternals(strictInstanceOf(Class), res) +} + +// Temporal Class +// ------------------------------------------------------------------------------------------------- + +const temporaNameMap = WeakMap() +export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) + +export function createTemporalClass( + temporalName, + constructorToInternals, + internalsConversionMap, + bagToInternals, + stringToInternals, + handleUnusedOptions, + getters, + methods, + staticMembers = {}, +) { + methods.toJSON = function() { + return String(this) + } + staticMembers.from = function(arg, options) { + return createInstance(toInternals(arg, options)) + } + + const TemporalObj = createWrapperClass( + getters, + methods, + constructorToInternals, + createTemporalNameDescriptors(temporalName), // extraPrototypeDescriptors + staticMembers, + setTemporalName, // handleInstance + ) + + function createInstance(internals) { + const instance = Object.create(TemporalObj.prototype) + internalsMap.set(instance, internals) + setTemporalName(instance) + return instance + } + + function toInternals(arg, options) { + let argInternals = getInternals(arg) + const argTemporalName = getTemporalName(arg) + + if (argInternals && argTemporalName !== temporalName) { + argInternals = (internalsConversionMap[argTemporalName] || noop)(argInternals) + } + + return (!argInternals && isObjectLike(arg) && bagToInternals(arg, options)) || + (handleUnusedOptions(options), argInternals || stringToInternals(toString(arg))) + } + + function setTemporalName(instance) { + temporaNameMap.set(instance, temporalName) + } + + return [TemporalObj, createInstance, toInternals] +} + +export function toLocaleStringMethod(internals, locales, options) { + /* + Will create two internal Intl.DateTimeFormats :( + Create just one instead + */ + const format = new DateTimeFormat(locales, options) + return format.format(this) +} + +// Adapter Utils +// ------------------------------------------------------------------------------------------------- + +export function createAdapterMethods() { + +} diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index a47d222f..a5085294 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -1,4 +1,5 @@ import { bagToDurationFields, durationWithBag } from './bag' +import { createTemporalClass, neverValueOf } from './class' import { diffZonedEpochNanoseconds } from './diff' import { absolutizeDurationFields, @@ -25,9 +26,7 @@ import { totalDayTimeDuration, totalRelativeDuration, } from './round' -import { createTemporalClass } from './temporalClass' import { identityFunc, noop } from './util' -import { neverValueOf } from './wrapperClass' export const [ Duration, diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 1ecec399..1486264b 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -71,9 +71,12 @@ export function durationTimeFieldsToIso(durationFields0) { } export function refineDurationFields(input) { - const obj = mapRefiners(input, durationFieldRefiners) - obj.sign = computeDurationFieldsSign(obj) - return obj + return addSignToDurationFields(mapRefiners(input, durationFieldRefiners)) +} + +export function addSignToDurationFields(fields) { + fields.sign = computeDurationFieldsSign(fields) + return fields } function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 8d205fa9..bd59710b 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -1,5 +1,6 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' +import { createTemporalClass, neverValueOf } from './class' import { diffEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -21,10 +22,8 @@ import { compareLargeInts, createLargeInt, toLargeInt } from './largeInt' import { moveEpochNanoseconds } from './move' import { toObject } from './options' import { roundLargeNanoseconds } from './round' -import { createTemporalClass } from './temporalClass' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { noop } from './util' -import { neverValueOf } from './wrapperClass' import { createZonedDateTime } from './zonedDateTime' export const [ diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index f4b49cb5..8709095e 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' import { dateBasicNames, timeFieldDefaults } from './calendarFields' +import { getInternals, getTemporalName } from './class' import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' -import { getTemporalName } from './temporalClass' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createLazyMap, @@ -10,7 +10,6 @@ import { identityFunc, zipSingleValue, } from './util' -import { getInternals } from './wrapperClass' export const standardCalendarId = 'en-GB' // gives 24-hour clock diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 70685261..8a9a778c 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -3,7 +3,6 @@ import { createLargeInt } from './largeInt' export const nanosecondsInMicrosecond = 1000 export const nanosecondsInMillisecond = 1000000 export const nanosecondsInSecond = 1000000000 -export const nanosecondsInMinute = 60000000000 // used? export const nanosecondsInHour = 3600000000000 export const nanosecondsInIsoDay = 86400000000000 diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index d434d545..9d90625d 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -77,6 +77,15 @@ function getCurrentEpochNanoseconds() { return createLargeInt(Date.now()).mult(nanoInMilli) } +// TimeZone +// -------- + +let queriedCurrentTimeZoneId + function getCurrentTimeZoneId() { + return queriedCurrentTimeZoneId ?? (queriedCurrentTimeZoneId = queryCurrentTimeZoneId()) +} + +function queryCurrentTimeZoneId() { return new IntlDateTimeFormat().resolvedOptions().timeZone } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index a83145dc..6c5714e0 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -34,6 +34,13 @@ export function toInteger(value) { return integer } +export function toStringOrUndefined() { +} + +export function toNumberOrUndefined() { + +} + export function toString(value) { if (typeof value === 'symbol') { throw new TypeError('Cannot convert a Symbol value to a String') @@ -49,6 +56,10 @@ export function toIntegerThrowOnInfinity(value) { return integer } +export function toBoolean() { + +} + export function toPositiveInteger(valueParam, property) { const value = toInteger(valueParam) if (!Number.isFinite(value)) { @@ -167,3 +178,11 @@ export function optionsToRoundingIncrement(options) { export function optionsToRoundingMode(options) { } + +export function overflowToOptions(overflow) { + return { overflow } +} + +export function largestUnitToOptions(largestUnit) { + return { largestUnit } +} diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 357d8446..53713266 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -13,6 +13,7 @@ import { getPublicCalendar, queryCalendarOps, } from './calendarOps' +import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -29,9 +30,7 @@ import { stringToPlainDateInternals } from './isoParse' import { optionsToOverflow } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' -import { createTemporalClass, toLocaleStringMethod } from './temporalClass' import { isIdPropsEqual, mapRefiners } from './util' -import { neverValueOf } from './wrapperClass' export const [ PlainDate, diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index b9fd0d81..122fb2d8 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -8,6 +8,7 @@ import { import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' import { getPublicCalendar, queryCalendarOps } from './calendarOps' +import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { diffDateTimes } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -28,10 +29,8 @@ import { optionsToOverflow, toDisambiguation, validateRoundingOptions } from './ import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' -import { createTemporalClass, toLocaleStringMethod } from './temporalClass' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { isIdPropsEqual, mapRefiners } from './util' -import { neverValueOf } from './wrapperClass' import { createZonedDateTime } from './zonedDateTime' export const [ diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 95d5ec7c..56ed292d 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -6,6 +6,7 @@ import { import { isoCalendarId } from './calendarConfig' import { monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' +import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { constrainIsoDateFields, generatePublicIsoDateFields, @@ -15,9 +16,7 @@ import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoFields, isoEpochFirstLeapYear } from './isoMath' import { stringToMonthDayInternals } from './isoParse' import { optionsToOverflow } from './options' -import { createTemporalClass, toLocaleStringMethod } from './temporalClass' import { isIdPropsEqual, mapRefiners } from './util' -import { neverValueOf } from './wrapperClass' export const [ PlainMonthDay, diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 31906c98..0914d803 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -5,6 +5,7 @@ import { zonedDateTimeInternalsToIso, } from './bag' import { timeGetters } from './calendarFields' +import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -21,9 +22,7 @@ import { optionsToOverflow } from './options' import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' -import { createTemporalClass, toLocaleStringMethod } from './temporalClass' import { mapRefiners } from './util' -import { neverValueOf } from './wrapperClass' export const [ PlainTime, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 33806771..76b986e8 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -7,6 +7,7 @@ import { import { isoCalendarId } from './calendarConfig' import { yearMonthGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' +import { createTemporalClass, getInternals, neverValueOf, toLocaleStringMethod } from './class' import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -19,9 +20,7 @@ import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoFields } from './isoMath' import { stringToPlainYearMonthInternals } from './isoParse' import { optionsToOverflow } from './options' -import { createTemporalClass, toLocaleStringMethod } from './temporalClass' import { isIdPropsEqual, mapRefiners } from './util' -import { getInternals, neverValueOf } from './wrapperClass' export const [ PlainYearMonth, diff --git a/packages/temporal-polyfill/src/new/temporal.js b/packages/temporal-polyfill/src/new/temporal.js index c62096c8..39dc9ce4 100644 --- a/packages/temporal-polyfill/src/new/temporal.js +++ b/packages/temporal-polyfill/src/new/temporal.js @@ -8,10 +8,10 @@ import { PlainMonthDay } from './plainMonthDay' import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' -import { createPropDescriptors } from './util' +import { defineProps } from './util' import { ZonedDateTime } from './zonedDateTime' -export const Temporal = Object.defineProperties({}, createPropDescriptors({ +export const Temporal = defineProps({}, { PlainYearMonth, PlainMonthDay, PlainDate, @@ -23,4 +23,4 @@ export const Temporal = Object.defineProperties({}, createPropDescriptors({ TimeZone, Duration, Now, -})) +}) diff --git a/packages/temporal-polyfill/src/new/temporalClass.js b/packages/temporal-polyfill/src/new/temporalClass.js deleted file mode 100644 index e7d64e15..00000000 --- a/packages/temporal-polyfill/src/new/temporalClass.js +++ /dev/null @@ -1,68 +0,0 @@ -import { DateTimeFormat } from './intlFormat' -import { createTemporalNameDescriptors, isObjectLike, noop } from './util' -import { createWrapperClass, getInternals, internalsMap } from './wrapperClass' - -const temporaNameMap = WeakMap() -export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) - -export function createTemporalClass( - temporalName, - constructorToInternals, - internalsConversionMap, - bagToInternals, - stringToInternals, - handleUnusedOptions, - getters, - methods, - staticMembers = {}, -) { - methods.toJSON = function() { - return String(this) - } - staticMembers.from = function(arg, options) { - return createInstance(toInternals(arg, options)) - } - - const TemporalObj = createWrapperClass( - getters, - methods, - constructorToInternals, - createTemporalNameDescriptors(temporalName), // extraPrototypeDescriptors - staticMembers, - setTemporalName, // handleInstance - ) - - function createInstance(internals) { - const instance = Object.create(TemporalObj.prototype) - internalsMap.set(instance, internals) - setTemporalName(instance) - return instance - } - - function toInternals(arg, options) { - let argInternals = getInternals(arg) - const argTemporalName = getTemporalName(arg) - - if (argInternals && argTemporalName !== temporalName) { - argInternals = (internalsConversionMap[argTemporalName] || noop)(argInternals) - } - - return (!argInternals && isObjectLike(arg) && bagToInternals(arg, options)) || - (handleUnusedOptions(options), argInternals || stringToInternals(toString(arg))) - } - - function setTemporalName(instance) { - temporaNameMap.set(instance, temporalName) - } - - return [TemporalObj, createInstance, toInternals] -} - -export function toLocaleStringMethod(internals, locales, options) { - /* - Will create two internal Intl.DateTimeFormats :( - Create just one instead - */ - const format = new DateTimeFormat(locales, options) - return format.format(this) -} diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index ace09928..7a75a296 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -2,16 +2,15 @@ import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' import { createComplexBagRefiner } from './bag' import { Calendar } from './calendar' import { queryCalendarOps } from './calendarOps' +import { createTemporalClass, internalIdGetters, returnId } from './class' import { createInstant, toInstantEpochNanoseconds } from './instant' import { formatOffsetNanoseconds } from './isoFormat' import { epochNanosecondsToIso } from './isoMath' import { stringToTimeZoneId } from './isoParse' import { toDisambiguation } from './options' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' -import { createTemporalClass } from './temporalClass' import { getSingleInstantFor } from './timeZoneOps' import { noop } from './util' -import { internalIdGetters, returnId } from './wrapperClass' export const [TimeZone, createTimeZone] = createTemporalClass( 'TimeZone', diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index 143e5cae..4a3eb34a 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -1,3 +1,10 @@ +import { + createAdapterMethods, + createWrapperClass, + getInternals, + getStrictInternals, + internalIdGetters, +} from './class' import { Instant, createInstant } from './instant' import { isoTimeFieldDefaults } from './isoFields' import { @@ -11,12 +18,6 @@ import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' import { createTimeZone } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' -import { - createInternalGetter, - createWrapperClass, - getInternals, - internalIdGetters, -} from './wrapperClass' export const utcTimeZoneId = 'UTC' @@ -168,26 +169,32 @@ function computeGapNear(timeZoneOps, zonedEpochNano) { // Adapter // ------- -const getStrictInstantEpochNanoseconds = createInternalGetter(Instant) +const getStrictInstantEpochNanoseconds = getStrictInternals(Instant) -const TimeZoneOpsAdapter = createWrapperClass(internalIdGetters, { - getOffsetNanosecondsFor(timeZone, epochNanoseconds) { - const nanoseconds = strictNumber( // TODO: integer? - timeZone.getOffsetNanosecondsFor(createInstant(epochNanoseconds)), - ) +export const TimeZoneOpsAdapter = createWrapperClass( + internalIdGetters, + createAdapterMethods({ + getOffsetNanosecondsFor: [ + validateOffsetNano, + createInstant, + ], + getPossibleInstantsFor: [ + extractEpochNanos, + createPlainDateTime, + ], + }), +) + +function validateOffsetNano(offsetNano) { + offsetNano = strictNumber(offsetNano) + + if (Math.abs(offsetNano) >= nanosecondsInIsoDay) { + throw new RangeError('out of range') + } - if (Math.abs(nanoseconds) >= nanosecondsInIsoDay) { - throw new RangeError('out of range') - } + return offsetNano +} - return nanoseconds - }, - - getPossibleInstantsFor(timeZone, isoDateTimeFields) { - return strictArray( - timeZone.getPossibleInstantsFor( - createPlainDateTime(isoDateTimeFields), // hopefully won't look at blank .calendar - ), - ).map(getStrictInstantEpochNanoseconds) - }, -}) +function extractEpochNanos(instants) { + return strictArray(instants).map(getStrictInstantEpochNanoseconds) +} diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index eb0beb4d..1516448b 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -10,6 +10,10 @@ export function mapProps(input, refinerMap) { // loops get driven my refinerMap } +export function mapArrayToProps() { + +} + export function remapProps(obj, oldKeys, newKeys) { } @@ -38,7 +42,7 @@ export function zipSingleValue() { } export function defineProps(target, propVals) { - Object.defineProperties(target, createPropDescriptors(propVals)) + return Object.defineProperties(target, createPropDescriptors(propVals)) } // descriptor stuff diff --git a/packages/temporal-polyfill/src/new/wrapperClass.js b/packages/temporal-polyfill/src/new/wrapperClass.js deleted file mode 100644 index 1c593c4c..00000000 --- a/packages/temporal-polyfill/src/new/wrapperClass.js +++ /dev/null @@ -1,66 +0,0 @@ -import { strictInstanceOf } from './options' -import { - createGetterDescriptors, - createPropDescriptors, - defineProps, - identityFunc, - mapProps, - noop, -} from './util' - -export const internalsMap = new WeakMap() -export const getInternals = internalsMap.get.bind(internalsMap) - -export function createWrapperClass( - getters, - methods, - constructorToInternals = identityFunc, - extraPrototypeDescriptors = {}, - staticMembers = {}, - handleInstance = noop, -) { - function InternalObj(...args) { - internalsMap.set(this, constructorToInternals(...args)) - handleInstance(this) - } - - function curryMethod(method) { - return /* Object.setPrototypeOf( */ function(...args) { - if (!(this instanceof InternalObj)) { - throw new TypeError('Invalid receiver') - } - return method.call(this, getInternals(this), ...args) - } /* , null) */ - } - - Object.defineProperties(InternalObj.prototype, { - ...createGetterDescriptors(mapProps(getters, curryMethod)), - ...createPropDescriptors(mapProps(methods, curryMethod)), - ...extraPrototypeDescriptors, - }) - - defineProps(InternalObj, staticMembers) - - return InternalObj -} - -export function neverValueOf() { - throw new TypeError('Cannot convert object using valueOf') -} - -export function transformInternalMethod(transformRes, methodName) { - return (impl, ...args) => { - return transformRes(impl[methodName](...args)) - } -} - -export function returnId(internals) { - return internals.id -} - -// TODO: make a versoin that casts the id to string? For adapters -export const internalIdGetters = { id: returnId } - -export function createInternalGetter(Class) { - return (res) => getInternals(strictInstanceOf(Class), res) -} diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 484e71db..e9139450 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -7,6 +7,7 @@ import { } from './bag' import { dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' +import { createTemporalClass, neverValueOf } from './class' import { diffZonedEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' @@ -33,7 +34,6 @@ import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' -import { createTemporalClass } from './temporalClass' import { computeNanosecondsInDay, getCommonTimeZoneOps, @@ -42,7 +42,6 @@ import { queryTimeZoneOps, } from './timeZoneOps' import { isIdPropsEqual, mapProps } from './util' -import { neverValueOf } from './wrapperClass' export const [ ZonedDateTime, From 7def5ff2689c280ecbed47a917306a1687b06fd9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 2 Jun 2023 15:30:48 -0400 Subject: [PATCH 081/805] improved iso field stuff --- packages/temporal-polyfill/src/new/bag.js | 20 ++-- .../temporal-polyfill/src/new/calendar.js | 19 ++-- .../src/new/calendarFields.js | 2 +- .../temporal-polyfill/src/new/calendarImpl.js | 28 ++++-- .../temporal-polyfill/src/new/calendarOps.js | 6 +- packages/temporal-polyfill/src/new/diff.js | 4 +- packages/temporal-polyfill/src/new/instant.js | 4 +- .../temporal-polyfill/src/new/isoFields.js | 94 ++++++++----------- .../temporal-polyfill/src/new/isoFormat.js | 5 +- packages/temporal-polyfill/src/new/isoMath.js | 14 +-- .../temporal-polyfill/src/new/isoParse.js | 12 +-- packages/temporal-polyfill/src/new/now.js | 6 +- packages/temporal-polyfill/src/new/options.js | 16 ++++ .../temporal-polyfill/src/new/plainDate.js | 15 +-- .../src/new/plainDateTime.js | 24 +++-- .../src/new/plainMonthDay.js | 10 +- .../temporal-polyfill/src/new/plainTime.js | 8 +- .../src/new/plainYearMonth.js | 10 +- .../temporal-polyfill/src/new/timeZoneOps.js | 6 +- packages/temporal-polyfill/src/new/util.js | 7 +- .../src/new/zonedDateTime.js | 41 ++++---- 21 files changed, 173 insertions(+), 178 deletions(-) diff --git a/packages/temporal-polyfill/src/new/bag.js b/packages/temporal-polyfill/src/new/bag.js index 147377cc..88df78d7 100644 --- a/packages/temporal-polyfill/src/new/bag.js +++ b/packages/temporal-polyfill/src/new/bag.js @@ -23,13 +23,11 @@ import { durationFieldNames, durationFieldRefiners, } from './durationFields' -import { - constrainIsoDateTimeFields, - constrainIsoTimeFields, -} from './isoFields' import { epochNanoToIsoFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNanoseconds } from './isoParse' import { + constrainIsoDateTimeFields, + constrainIsoTimeFields, optionsToOverflow, toDisambiguation, toObject, @@ -70,11 +68,11 @@ export function bagToZonedDateTimeInternals(bag, options) { ) const timeZone = queryTimeZoneOps(fields.timeZone) - const isoFields = calendarOps.dateFromFields(fields, optionsToOverflow(options)) + const isoDateFields = calendarOps.dateFromFields(fields, optionsToOverflow(options)) const epochNanoseconds = getMatchingInstantFor( timeZone, - { ...isoFields, ...timeFieldsToIso(fields) }, + { ...isoDateFields, ...timeFieldsToIso(fields) }, fields.offset !== undefined ? parseOffsetNanoseconds(fields.offset) : undefined, false, // z? toOffsetHandling(options), @@ -92,11 +90,11 @@ export function bagToZonedDateTimeInternals(bag, options) { export function zonedDateTimeWithBag(zonedDateTime, bag, options) { const { calendar, timeZone } = getInternals(zonedDateTime) const fields = mergeBag(calendar, zonedDateTime, bag, dateTimeFieldNames, ['offset']) - const isoFields = calendar.dateFromFields(fields, optionsToOverflow(options)) + const isoDateFields = calendar.dateFromFields(fields, optionsToOverflow(options)) const epochNanoseconds = getMatchingInstantFor( timeZone, - { ...isoFields, ...timeFieldsToIso(fields) }, + { ...isoDateFields, ...timeFieldsToIso(fields) }, parseOffsetNanoseconds(fields.offset), false, // z? toOffsetHandling(options), @@ -175,7 +173,7 @@ export function bagToPlainTimeInternals(bag, options) { export function plainTimeWithBag(plainTime, bag, options) { const overflowOpt = toOverflowOptions(options) // TODO: single opt! - const fields = pluckProps(plainTime, timeFieldNames) + const fields = pluckProps(timeFieldNames, plainTime) const additionalFields = prepareFields(bag, timeFieldNames) const newInternals = timeFieldsToIso({ ...fields, @@ -372,7 +370,7 @@ function mergeToPlainDate( ) { const { calendar } = getInternals(obj) const receiverFieldNames = calendar.fields(objFieldNames) - const receiverFields = pluckProps(obj, receiverFieldNames) + const receiverFields = pluckProps(receiverFieldNames, obj) const inputFieldNames = calendar.fields(otherFieldNames) const inputFields = prepareFields(other, inputFieldNames, getRequiredDateFields(calendar)) const mergedFieldNames = removeDuplicateStrings(receiverFieldNames.concat(inputFieldNames)) @@ -426,7 +424,7 @@ function forbidInstanceClass(obj, Class) { } /* -If requiredFields not given, then assumed to be 'partial' +If requiredFields not given, then assumed to be 'partial' (defaults won't be applied) */ export function prepareFields(bag, fieldNames, requiredFields) { console.log(builtinRefiners) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 154d0e7c..e66c7e50 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -72,34 +72,31 @@ export const [Calendar, createCalendar] = createTemporalClass( }), dateFromFields(impl, fields, options) { - return createPlainDate({ - calendar: impl, - ...impl.dateFromFields( + return createPlainDate( + impl.dateFromFields( prepareFields(fields, impl.fields(dateFieldNames), getRequiredDateFields(impl)), optionsToOverflow(options), ), - }) + ) }, yearMonthFromFields(impl, fields, options) { - return createPlainYearMonth({ - calendar: impl, - ...impl.yearMonthFromFields( + return createPlainYearMonth( + impl.yearMonthFromFields( prepareFields(fields, impl.fields(yearMonthFieldNames), getRequiredYearMonthFields(impl)), optionsToOverflow(options), ), - }) + ) }, monthDayFromFields(impl, fields, options) { - return createPlainMonthDay({ - calendar: impl, + return createPlainMonthDay( ...impl.monthDayFromFields( // refine y/m/d fields prepareFields(fields, impl.fields(dateFieldNames), getRequiredMonthDayFields(impl)), optionsToOverflow(options), ), - }) + ) }, toString: returnId, diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index 4b39671a..268e0a89 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -120,7 +120,7 @@ function createGetters(getterNames) { }) getters.calendarId = function(internals) { - return internals.calendar.id + return internals.calendar.id // works for either CalendarOpsAdapter or CalendarImpl } return getters diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 5341a74d..ec14cb9c 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -87,7 +87,7 @@ class IsoCalendarImpl { yearMonthFromFields(fields, overflow) { const year = this.readYear(fields) const month = this.refineMonth(fields, year, overflow) - return this.queryIsoFields(year, month) + return this.queryIsoFields(year, month, 1) } monthDayFromFields(fields, overflow) { @@ -139,8 +139,13 @@ class IsoCalendarImpl { // Internal Querying // ----------------- - queryIsoFields(year, month, day) { - return { isoYear: year, isoMonth: month, isoDay: day } + queryIsoFields(year, month, day) { // return isoDateInternals + return { + calendar: this, + isoYear: year, + isoMonth: month, + isoDay: day, + } } queryDateStart(year, month, day) { @@ -198,7 +203,11 @@ class IsoCalendarImpl { } ms = addDaysMilli(ms, weeks * isoDaysInWeek + days) - return epochMilliToIsoFields(ms) + + return { + calendar: this, + ...epochMilliToIsoFields(ms), + } } dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { @@ -443,10 +452,6 @@ class IntlCalendarImpl extends IsoCalendarImpl { return this.queryYearMonthDay(isoDateFields)[1] } - day(isoDateFields) { - return this.queryYearMonthDay(isoDateFields)[2] - } - monthCode(isoDateFields) { const [year, month] = this.queryYearMonthDay(isoDateFields) const leapMonth = this.queryLeapMonth(year) @@ -460,8 +465,11 @@ class IntlCalendarImpl extends IsoCalendarImpl { // Internal Querying // ----------------- - queryIsoFields(year, month, day) { - return epochMilliToIsoFields(this.queryDateStart(year, month, day)) + queryIsoFields(year, month, day) { // returns isoDateInternals + return { + calendar: this, + ...epochMilliToIsoFields(this.queryDateStart(year, month, day)), + } } queryDaysInYear(year) { diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index 344fc411..d36fe4ea 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -23,9 +23,9 @@ export function queryCalendarOps(calendarSlot) { } export function getPublicCalendar(internals) { - const { calendar } = internals - return getInternals(calendar) || // if CalendarOpsAdapter - createCalendar(calendar) // if CalendarImpl + const calendarOps = internals.calendar + return getInternals(calendarOps) || // CalendarOpsAdapter (return internal Calendar) + createCalendar(calendarOps) // CalendarImpl (create outer Calendar) } export function getCommonCalendarOps(internals0, internals1) { diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index d9cb9bb8..f85effe1 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -60,8 +60,8 @@ export function diffZonedEpochNanoseconds( ) } - function isoToZoneEpochNanoseconds(isoFields) { - return getSingleInstantFor(timeZone, isoFields) + function isoToZoneEpochNanoseconds(isoDateTimeFields) { + return getSingleInstantFor(timeZone, isoDateTimeFields) } const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index bd59710b..0a95a5d7 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -144,9 +144,9 @@ export const [ refinedOptions, // TODO: break apart options ) const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - const isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + const isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) - return formatIsoDateTimeFields(isoFields, refinedOptions) + + return formatIsoDateTimeFields(isoDateTimeFields, refinedOptions) + formatOffsetNanoseconds(offsetNanoseconds) + formatTimeZone(timeZone, options) + formatCalendar(calendar, options) diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 73f3c688..e22c1460 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -1,17 +1,21 @@ import { queryCalendarOps } from './calendarOps' +import { getInternals } from './class' import { toIntegerThrowOnInfinity, toIntegerWithoutRounding, toPositiveInteger } from './options' -import { pluckProps } from './util' +import { pluckProps, zipSingleValue } from './util' -export const isoDateSlotRefiners = { - // sorted alphabetically - calendar: queryCalendarOps, // prolly kill this!!! +// Refiners +// ------------------------------------------------------------------------------------------------- + +// Ordered alphabetically +export const isoDateInternalRefiners = { + calendar: queryCalendarOps, isoDay: toPositiveInteger, isoMonth: toPositiveInteger, isoYear: toIntegerWithoutRounding, } +// Ordered alphabetically export const isoTimeFieldRefiners = { - // sorted alphabetically isoHour: toIntegerThrowOnInfinity, isoMicrosecond: toIntegerThrowOnInfinity, isoMillisecond: toIntegerThrowOnInfinity, @@ -20,69 +24,47 @@ export const isoTimeFieldRefiners = { isoSecond: toPositiveInteger, // why different? } -export const isoDateTimeSlotRefiners = { - // keys must be resorted - ...isoDateSlotRefiners, +// Unordered +export const isoDateTimeInternalRefiners = { + ...isoDateInternalRefiners, ...isoTimeFieldRefiners, } -export const isoDateSlotNames = Object.keys(isoDateSlotRefiners) -export const isoDateFieldNames = isoDateSlotNames.slice(1) -export const isoTimeFieldNames = Object.keys(isoTimeFieldRefiners) // no calendar -export const isoDateTimeSlotNames = Object.keys(isoDateTimeSlotRefiners).sort() +// Property Names +// ------------------------------------------------------------------------------------------------- -export const isoTimeFieldDefaults = { - isoHour: 0, - isoMicrosecond: 0, - isoMillisecond: 0, - isoMinute: 0, - isoNanosecond: 0, - isoSecond: 0, -} +export const isoDateInternalNames = Object.keys(isoDateInternalRefiners) +export const isoDateTimeInternalNames = Object.keys(isoDateTimeInternalRefiners).sort() -export function generatePublicIsoDateFields(internals) { - const publicFields = pluckIsoDateSlots(internals) - publicFields.calendar = publicFields.calendar.id // correct? - return publicFields -} +export const isoDateFieldNames = isoDateInternalNames.slice(1) // no calendar +export const isoTimeFieldNames = Object.keys(isoTimeFieldRefiners) -export function generatePublicIsoDateTimeFields(internals) { - const publicFields = pluckIsoDateTimeSlots(internals) - publicFields.calendar = publicFields.calendar.id // correct? - return publicFields -} +// Defaults +// ------------------------------------------------------------------------------------------------- -export function pluckIsoDateTimeSlots(isoFields) { - return pluckProps(isoFields, isoDateTimeSlotNames) -} +export const isoTimeFieldDefaults = zipSingleValue(isoTimeFieldNames, 0) -export function pluckIsoDateSlots(isoFields) { - return pluckProps(isoFields, isoDateSlotNames) -} +// Conversion +// ------------------------------------------------------------------------------------------------- -export function pluckIsoDateFields(isoFields) { - return pluckProps(isoFields, isoDateFieldNames) -} +export const pluckIsoDateInternals = pluckProps.bind(undefined, isoDateInternalNames) +export const pluckIsoDateTimeInternals = pluckProps.bind(undefined, isoDateTimeInternalNames) +export const pluckIsoTimeFields = pluckProps.bind(undefined, isoTimeFieldNames) -export function pluckIsoTimeFields(isoFields) { - return pluckProps(isoFields, isoTimeFieldNames) -} +export const generatePublicIsoDateFields = + generatePublicIsoFields.bind(undefined, pluckIsoDateInternals) -export function constrainIsoDateTimeFields(isoDateTimeFields, overflow = 'reject') { - // ahhhh! calendar gets passed in here!!! -} +export const generatePublicIsoDateTimeFields = + generatePublicIsoFields.bind(undefined, pluckIsoDateTimeInternals) -export function constrainIsoDateFields(isoDateFields, overflow = 'reject') { - // ahhhh! calendar gets passed in here!!! -} - -export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { +function generatePublicIsoFields(pluckFunc, internals) { + const publicFields = pluckFunc(internals) + publicFields.calendar = getPublicIdOrObj(internals.calendar) + return publicFields } -export function isValidIsoFields() { +// Similar to getPublicCalendar and getPublicTimeZone +export function getPublicIdOrObj(ops) { + return getInternals(ops) || // adapter (return internal object) + ops.id // impl (return id) } - -/* -TODO: move AWAY from just 'isofields' because might get confused with getISOFields() -name it 'isodatetimefields' -*/ diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.js index eafc5b9f..52e602f6 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -16,8 +16,9 @@ export function formatPossibleDate(internals, options, formatSimple) { } } -export function formatIsoDateTimeFields(isoFields, options) { - return formatIsoDateFields(isoFields) + 'T' + formatIsoTimeFields(isoFields, options) +export function formatIsoDateTimeFields(isoDateTimeFields, options) { + return formatIsoDateFields(isoDateTimeFields) + + 'T' + formatIsoTimeFields(isoDateTimeFields, options) } export function formatIsoDateFields(isoDateFields) { diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 8a9a778c..8a6b26ae 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -12,6 +12,10 @@ export function epochNanoToMilli(epochNano) { return epochNano.div(nanosecondsInMillisecond).toNumber() } +export function epochSecToNano(epochSec) { + return createLargeInt(epochSec).mult(nanosecondsInSecond) +} + export const epochGetters = { epochNanoseconds(epochNanoseconds) { return epochNanoseconds.toBigInt() @@ -74,7 +78,7 @@ export function computeIsoWeekOfYear(isoDateFields) { export function computeIsoYearOfWeek(isoDateFields) { } -export function isoFieldsToEpochMilli(isoFields) { +export function isoFieldsToEpochMilli(isoDateTimeFields) { } export function isoToEpochMilli(isoYear, isoMonth, isoDate) { @@ -119,17 +123,13 @@ export function epochNanoToSec(epochNano) { return [epochSec, subsecNano] } -export function epochSecToNano(epochSec) { - return createLargeInt(epochSec).mult(nanosecondsInSecond) -} - export function epochNanoToIsoFields() { } -export function isoToUtcEpochNanoseconds(isoFields) { +export function isoToUtcEpochNanoseconds(isoDateTimeFields) { } -export function isoFieldsToEpochNano(isoFields) { +export function isoFieldsToEpochNano(isoDateTimeFields) { } export function isoTimeToNanoseconds(isoTimeFields) { diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index a03dc14a..e1cce1da 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -1,11 +1,11 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { - isValidIsoFields, - pluckIsoDateSlots, - pluckIsoDateTimeSlots, + pluckIsoDateInternals, + pluckIsoDateTimeInternals, pluckIsoTimeFields, } from './isoFields' +import { isValidIsoFields } from './options' import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' @@ -45,7 +45,7 @@ export function stringToZonedDateTimeInternals(s) { export function stringToPlainDateTimeInternals(s) { const parsed = parseDateTime(s) if (parsed) { - return pluckIsoDateTimeSlots(parsed) + return pluckIsoDateTimeInternals(parsed) } throw new Error() @@ -65,7 +65,7 @@ export function stringToPlainYearMonthInternals(s) { if (!parsed) { parsed = parseDateTime(s) if (parsed) { - parsed = pluckIsoDateSlots(parsed) + parsed = pluckIsoDateInternals(parsed) } } @@ -81,7 +81,7 @@ export function stringToMonthDayInternals(s) { if (!parsed) { parsed = parseDateTime(s) if (parsed) { - parsed = pluckIsoDateSlots(parsed) + parsed = pluckIsoDateInternals(parsed) } } diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index 9d90625d..1fccc11a 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -4,7 +4,7 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { createInstant } from './instant' import { IntlDateTimeFormat } from './intlFormat' -import { pluckIsoDateSlots, pluckIsoDateTimeSlots, pluckIsoTimeFields } from './isoFields' +import { pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields } from './isoFields' import { createLargeInt } from './largeInt' import { createPlainDate } from './plainDate' import { createPlainDateTime } from './plainDateTime' @@ -42,7 +42,7 @@ function getCurrentPlainDateTime(calendarArg, timeZoneArg) { function getCurrentPlainDate(calendarArg, timeZoneArg) { return createPlainDate( - pluckIsoDateSlots(getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg)), + pluckIsoDateInternals(getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg)), ) } @@ -57,7 +57,7 @@ function getCurrentInstant() { } function getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg) { - return pluckIsoDateTimeSlots( + return pluckIsoDateTimeInternals( zonedDateTimeInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)), ) } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 6c5714e0..3da9a965 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -186,3 +186,19 @@ export function overflowToOptions(overflow) { export function largestUnitToOptions(largestUnit) { return { largestUnit } } + +// Stuff + +export function constrainIsoDateTimeFields(isoDateTimeFields, overflow = 'reject') { + // ahhhh! calendar gets passed in here!!! +} + +export function constrainIsoDateFields(isoDateFields, overflow = 'reject') { + // ahhhh! calendar gets passed in here!!! +} + +export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { +} + +export function isValidIsoFields() { +} diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 53713266..6addce8b 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -18,16 +18,15 @@ import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { - constrainIsoDateFields, generatePublicIsoDateFields, - isoDateSlotRefiners, + isoDateInternalRefiners, isoTimeFieldDefaults, - pluckIsoDateSlots, + pluckIsoDateInternals, } from './isoFields' import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoFields } from './isoMath' import { stringToPlainDateInternals } from './isoParse' -import { optionsToOverflow } from './options' +import { constrainIsoDateFields, optionsToOverflow } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' import { isIdPropsEqual, mapRefiners } from './util' @@ -50,14 +49,16 @@ export const [ isoMonth, isoDay, calendar: calendarArg, - }, isoDateSlotRefiners), + }, isoDateInternalRefiners), ) }, // internalsConversionMap { - PlainDateTime: pluckIsoDateSlots, - ZonedDateTime: (argInternals) => pluckIsoDateSlots(zonedDateTimeInternalsToIso(argInternals)), + PlainDateTime: pluckIsoDateInternals, + ZonedDateTime(argInternals) { + return pluckIsoDateInternals(zonedDateTimeInternalsToIso(argInternals)) + }, }, // bagToInternals diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 122fb2d8..2c38244f 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -13,19 +13,23 @@ import { diffDateTimes } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { - constrainIsoDateTimeFields, generatePublicIsoDateTimeFields, - isoDateTimeSlotRefiners, + isoDateTimeInternalRefiners, isoTimeFieldDefaults, - pluckIsoDateSlots, - pluckIsoDateTimeSlots, + pluckIsoDateInternals, + pluckIsoDateTimeInternals, pluckIsoTimeFields, } from './isoFields' import { formatCalendar, formatIsoDateTimeFields } from './isoFormat' import { compareIsoFields } from './isoMath' import { stringToPlainDateTimeInternals } from './isoParse' import { moveDateTime } from './move' -import { optionsToOverflow, toDisambiguation, validateRoundingOptions } from './options' +import { + constrainIsoDateTimeFields, + optionsToOverflow, + toDisambiguation, + validateRoundingOptions, +} from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' @@ -68,7 +72,7 @@ export const [ isoMicrosecond, isoNanosecond, calendar: queryCalendarOps(calendarArg), - }, isoDateTimeSlotRefiners), + }, isoDateTimeInternalRefiners), ) }, @@ -76,7 +80,7 @@ export const [ { PlainDate: (argInternals) => ({ ...argInternals, ...isoTimeFieldDefaults }), ZonedDateTime: (argInternals) => { - return pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(argInternals)) + return pluckIsoDateTimeInternals(zonedDateTimeInternalsToIso(argInternals)) }, }, @@ -164,10 +168,10 @@ export const [ }, round(internals, options) { - const isoFields = roundIsoDateTimeFields(internals, validateRoundingOptions(options)) + const isoDateTimeFields = roundIsoDateTimeFields(internals, validateRoundingOptions(options)) return createPlainDateTime({ - ...isoFields, + ...isoDateTimeFields, calendar: internals.calendar, }) }, @@ -205,7 +209,7 @@ export const [ }, toPlainDate(internals) { - return createPlainDate(pluckIsoDateSlots(internals)) + return createPlainDate(pluckIsoDateInternals(internals)) }, toPlainYearMonth() { diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 56ed292d..1b762e15 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -7,15 +7,11 @@ import { isoCalendarId } from './calendarConfig' import { monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' -import { - constrainIsoDateFields, - generatePublicIsoDateFields, - isoDateSlotRefiners, -} from './isoFields' +import { generatePublicIsoDateFields, isoDateInternalRefiners } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoFields, isoEpochFirstLeapYear } from './isoMath' import { stringToMonthDayInternals } from './isoParse' -import { optionsToOverflow } from './options' +import { constrainIsoDateFields, optionsToOverflow } from './options' import { isIdPropsEqual, mapRefiners } from './util' export const [ @@ -36,7 +32,7 @@ export const [ isoMonth, isoDay, calendar: calendarArg, - }, isoDateSlotRefiners), + }, isoDateInternalRefiners), ) }, diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 0914d803..bf91c077 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -9,16 +9,12 @@ import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { - constrainIsoTimeFields, - isoTimeFieldRefiners, - pluckIsoTimeFields, -} from './isoFields' +import { isoTimeFieldRefiners, pluckIsoTimeFields } from './isoFields' import { formatIsoTimeFields } from './isoFormat' import { compareIsoTimeFields } from './isoMath' import { stringToPlainTimeInternals } from './isoParse' import { moveTime } from './move' -import { optionsToOverflow } from './options' +import { constrainIsoTimeFields, optionsToOverflow } from './options' import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 76b986e8..fe9b8741 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -11,15 +11,11 @@ import { createTemporalClass, getInternals, neverValueOf, toLocaleStringMethod } import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { - constrainIsoDateFields, - generatePublicIsoDateFields, - isoDateSlotRefiners, -} from './isoFields' +import { generatePublicIsoDateFields, isoDateInternalRefiners } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoFields } from './isoMath' import { stringToPlainYearMonthInternals } from './isoParse' -import { optionsToOverflow } from './options' +import { constrainIsoDateFields, optionsToOverflow } from './options' import { isIdPropsEqual, mapRefiners } from './util' export const [ @@ -40,7 +36,7 @@ export const [ isoMonth, isoDay: referenceIsoDay, calendar: calendarArg, - }, isoDateSlotRefiners), + }, isoDateInternalRefiners), ) }, diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index 4a3eb34a..559bd1ae 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -29,9 +29,9 @@ export function queryTimeZoneOps(timeZoneSlot) { } export function getPublicTimeZone(internals) { - const { timeZone } = internals - return getInternals(timeZone) || // if TimeZoneOpsAdapter - createTimeZone(timeZone) // if TimeZoneImpl + const timeZoneOps = internals.timeZone + return getInternals(timeZoneOps) || // TimeZoneOpsAdapter (return internal TimeZone) + createTimeZone(timeZoneOps) // TimeZoneImpl (create outer TimeZone) } export function getCommonTimeZoneOps(internals0, internals1) { diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index 1516448b..697c3daf 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -1,4 +1,6 @@ +// in general, prefer .bind over macro functions + export function isObjectLike() { } @@ -10,14 +12,13 @@ export function mapProps(input, refinerMap) { // loops get driven my refinerMap } -export function mapArrayToProps() { - +export function mapArrayToProps() { // propNameToProps } export function remapProps(obj, oldKeys, newKeys) { } -export function pluckProps(obj, props) { +export function pluckProps(propNames, obj) { } export function removeDuplicateStrings(a0, a1) { diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index e9139450..8a1f25ed 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -14,9 +14,10 @@ import { negateDurationFields } from './durationFields' import { createInstant } from './instant' import { resolveZonedFormattable } from './intlFormat' import { + getPublicIdOrObj, isoTimeFieldDefaults, - pluckIsoDateSlots, - pluckIsoDateTimeSlots, + pluckIsoDateInternals, + pluckIsoDateTimeInternals, pluckIsoTimeFields, } from './isoFields' import { @@ -228,15 +229,15 @@ export const [ let { epochNanoseconds, timeZone, calendar } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - let isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + let isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) - isoFields = roundIsoDateTimeFields( - isoFields, + isoDateTimeFields = roundIsoDateTimeFields( + isoDateTimeFields, options, - () => computeNanosecondsInDay(timeZone, isoFields), + () => computeNanosecondsInDay(timeZone, isoDateTimeFields), ) epochNanoseconds = getMatchingInstantFor( - isoFields, + isoDateTimeFields, timeZone, offsetNanoseconds, false, // z @@ -291,15 +292,15 @@ export const [ // TODO: don't let options be accessed twice! once by rounding, twice by formatting let offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - let isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + let isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) - isoFields = roundIsoDateTimeFields( - isoFields, + isoDateTimeFields = roundIsoDateTimeFields( + isoDateTimeFields, options, - () => computeNanosecondsInDay(timeZone, isoFields), + () => computeNanosecondsInDay(timeZone, isoDateTimeFields), ) epochNanoseconds = getMatchingInstantFor( - isoFields, + isoDateTimeFields, timeZone, offsetNanoseconds, false, // z @@ -309,9 +310,9 @@ export const [ ) offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - isoFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) - return formatIsoDateTimeFields(isoFields, options) + + return formatIsoDateTimeFields(isoDateTimeFields, options) + formatOffsetNanoseconds(offsetNanoseconds) + formatTimeZone(timeZone, options) + formatCalendar(calendar, options) @@ -329,7 +330,7 @@ export const [ }, toPlainDate(internals) { - return createPlainDate(pluckIsoDateSlots(zonedDateTimeInternalsToIso(internals))) + return createPlainDate(pluckIsoDateInternals(zonedDateTimeInternalsToIso(internals))) }, toPlainTime(internals) { @@ -337,7 +338,7 @@ export const [ }, toPlainDateTime(internals) { - return createPlainDateTime(pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(internals))) + return createPlainDateTime(pluckIsoDateTimeInternals(zonedDateTimeInternalsToIso(internals))) }, toPlainYearMonth() { @@ -349,17 +350,15 @@ export const [ }, getISOFields(internals) { - const { timeZone, calendar } = internals - return { // maintain alphabetical order - calendar: calendar.id, // correct? - ...pluckIsoDateTimeSlots(zonedDateTimeInternalsToIso(internals)), + calendar: getPublicIdOrObj(internals.calendar), + ...pluckIsoDateTimeInternals(zonedDateTimeInternalsToIso(internals)), offset: formatOffsetNanoseconds( // TODO: more DRY zonedDateTimeInternalsToIso(internals).offsetNanoseconds, ), - timeZone: timeZone.id, // correct? + timeZone: getPublicIdOrObj(internals.timeZone), } }, From f3298c5bd43597728bb9f37fbc1452b5dda8e364 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 2 Jun 2023 18:17:15 -0400 Subject: [PATCH 082/805] more isoField stuff, more validation --- packages/temporal-polyfill/src/new/bag.js | 83 +++++++------ .../src/new/calendarFields.js | 4 +- .../temporal-polyfill/src/new/calendarImpl.js | 2 + .../temporal-polyfill/src/new/duration.js | 16 +-- .../src/new/durationFields.js | 100 ++++++++-------- packages/temporal-polyfill/src/new/instant.js | 4 +- .../temporal-polyfill/src/new/isoFields.js | 109 +++++++++++++++++- packages/temporal-polyfill/src/new/isoMath.js | 19 +-- .../temporal-polyfill/src/new/isoParse.js | 43 ++++--- packages/temporal-polyfill/src/new/options.js | 18 +-- .../temporal-polyfill/src/new/plainDate.js | 22 ++-- .../src/new/plainDateTime.js | 33 +++--- .../src/new/plainMonthDay.js | 22 ++-- .../temporal-polyfill/src/new/plainTime.js | 27 +++-- .../src/new/plainYearMonth.js | 22 ++-- packages/temporal-polyfill/src/new/util.js | 2 + .../src/new/zonedDateTime.js | 3 +- 17 files changed, 314 insertions(+), 215 deletions(-) diff --git a/packages/temporal-polyfill/src/new/bag.js b/packages/temporal-polyfill/src/new/bag.js index 88df78d7..c4b0dec7 100644 --- a/packages/temporal-polyfill/src/new/bag.js +++ b/packages/temporal-polyfill/src/new/bag.js @@ -19,15 +19,14 @@ import { import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { - addSignToDurationFields, durationFieldNames, durationFieldRefiners, + updateDurationFieldSign, } from './durationFields' +import { constrainIsoTimeFields } from './isoFields' import { epochNanoToIsoFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNanoseconds } from './isoParse' import { - constrainIsoDateTimeFields, - constrainIsoTimeFields, optionsToOverflow, toDisambiguation, toObject, @@ -42,16 +41,19 @@ import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './ import { createLazyMap, isObjectLike, pluckProps, removeDuplicateStrings } from './util' import { createZonedDateTime } from './zonedDateTime' +// ahhh: some of these functions return internals, other Plain* objects + // Duration // ------------------------------------------------------------------------------------------------- -export function bagToDurationFields(bag) { - return prepareFields(bag, durationFieldNames, []) +export function bagToDurationInternals(bag) { + const durationFields = prepareFields(bag, durationFieldNames, []) + return updateDurationFieldSign(durationFields) } export function durationWithBag(durationFields, bag) { const partialDurationFields = prepareFields(bag, durationFieldNames) - return addSignToDurationFields({ ...durationFields, ...partialDurationFields }) + return updateDurationFieldSign({ ...durationFields, ...partialDurationFields }) } // high level yo @@ -68,11 +70,13 @@ export function bagToZonedDateTimeInternals(bag, options) { ) const timeZone = queryTimeZoneOps(fields.timeZone) - const isoDateFields = calendarOps.dateFromFields(fields, optionsToOverflow(options)) + const overflowHandling = optionsToOverflow(options) + const isoDateFields = calendarOps.dateFromFields(fields, overflowHandling) + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) const epochNanoseconds = getMatchingInstantFor( timeZone, - { ...isoDateFields, ...timeFieldsToIso(fields) }, + { ...isoDateFields, ...isoTimeFields }, fields.offset !== undefined ? parseOffsetNanoseconds(fields.offset) : undefined, false, // z? toOffsetHandling(options), @@ -90,11 +94,13 @@ export function bagToZonedDateTimeInternals(bag, options) { export function zonedDateTimeWithBag(zonedDateTime, bag, options) { const { calendar, timeZone } = getInternals(zonedDateTime) const fields = mergeBag(calendar, zonedDateTime, bag, dateTimeFieldNames, ['offset']) - const isoDateFields = calendar.dateFromFields(fields, optionsToOverflow(options)) + const overflowHandling = optionsToOverflow(options) + const isoDateFields = calendar.dateFromFields(fields, overflowHandling) + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) const epochNanoseconds = getMatchingInstantFor( timeZone, - { ...isoDateFields, ...timeFieldsToIso(fields) }, + { ...isoDateFields, ...isoTimeFields }, parseOffsetNanoseconds(fields.offset), false, // z? toOffsetHandling(options), @@ -161,27 +167,20 @@ export function plainYearMonthWithBag(plainYearMonth, bag, options) { } export function bagToPlainTimeInternals(bag, options) { - const overflowOpt = toOverflowOptions(options) // TODO: single opt! + const overflowHandling = toOverflowOptions(options) // TODO: single opt! + const fields = prepareFields(bag, timeFieldNames, []) - return constrainIsoTimeFields( - timeFieldsToIso( - prepareFields(bag, timeFieldNames, []), - ), - overflowOpt, - ) + return constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) } export function plainTimeWithBag(plainTime, bag, options) { - const overflowOpt = toOverflowOptions(options) // TODO: single opt! const fields = pluckProps(timeFieldNames, plainTime) const additionalFields = prepareFields(bag, timeFieldNames) - const newInternals = timeFieldsToIso({ - ...fields, - ...additionalFields, - }) - return createPlainTime( - constrainIsoTimeFields(newInternals, overflowOpt), - ) + const newFields = { ...fields, ...additionalFields } + const overflowHandling = toOverflowOptions(options) // TODO: single opt! + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(newFields), overflowHandling) + + return createPlainTime(isoTimeFields) } export function bagToPlainDateSlots(bag, options) { @@ -193,20 +192,14 @@ export function bagToPlainDateSlots(bag, options) { getRequiredDateFields(calendarOps), ) - return { - calendar: calendarOps, - ...calendarOps.dateFromFields(fields, optionsToOverflow(options)), - } + return calendarOps.dateFromFields(fields, optionsToOverflow(options)) } export function plainDateWithBag(plainDate, bag, options) { const { calendar } = getInternals(plainDate) const fields = mergeBag(calendar, plainDate, bag, dateFieldNames) - return { - calendar, - ...calendar.dateFromFields(fields, optionsToOverflow(options)), - } + return calendar.dateFromFields(fields, optionsToOverflow(options)) } export function bagToPlainDateTimeInternals(bag, options) { @@ -217,23 +210,27 @@ export function bagToPlainDateTimeInternals(bag, options) { dateTimeFieldNames, getRequiredDateFields(calendarOps), ) - const plainDateTimeInternals = calendarOps.dateFromFields(fields, optionsToOverflow(options)) + const overflowHandling = optionsToOverflow(options) + const isoDateInternals = calendarOps.dateFromFields(fields, overflowHandling) + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) - return constrainIsoDateTimeFields({ - ...plainDateTimeInternals, - ...timeFieldsToIso(fields), - }) + return { + ...isoDateInternals, + ...isoTimeFields, + } } export function plainDateTimeWithBag(plainDate, bag, options) { const { calendar } = getInternals(plainDate) const fields = mergeBag(calendar, plainDate, bag, dateTimeFieldNames) - const plainDateTimeInternals = calendar.dateFromFields(fields, optionsToOverflow(options)) + const overflowHandling = optionsToOverflow(options) + const isoDateInternals = calendar.dateFromFields(fields, overflowHandling) + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) - return constrainIsoDateTimeFields({ - ...plainDateTimeInternals, - ...timeFieldsToIso(fields), - }) + return { + ...isoDateInternals, + ...isoTimeFields, + } } // to PlainYearMonth/PlainMonthDay diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index 268e0a89..b9a90f61 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -113,9 +113,9 @@ export const dateTimeGetters = { } function createGetters(getterNames) { - const getters = mapArrayToProps(getterNames, (fieldName) => { + const getters = mapArrayToProps(getterNames, (propName) => { return (internals) => { - return internals.calendar[fieldName](internals) + return internals.calendar[propName](internals) } }) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index ec14cb9c..986f412b 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -139,6 +139,7 @@ class IsoCalendarImpl { // Internal Querying // ----------------- + // year/month/day already constrained! queryIsoFields(year, month, day) { // return isoDateInternals return { calendar: this, @@ -465,6 +466,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { // Internal Querying // ----------------- + // year/month/day already constrained! queryIsoFields(year, month, day) { // returns isoDateInternals return { calendar: this, diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index a5085294..055be8bd 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -1,15 +1,15 @@ -import { bagToDurationFields, durationWithBag } from './bag' +import { bagToDurationInternals, durationWithBag } from './bag' import { createTemporalClass, neverValueOf } from './class' import { diffZonedEpochNanoseconds } from './diff' import { absolutizeDurationFields, addDurationFields, - durationFieldGetters, + durationGetters, negateDurationFields, - refineDurationFields, + refineDurationInternals, } from './durationFields' import { isoToUtcEpochNanoseconds } from './isoMath' -import { stringToDurationFields } from './isoParse' +import { stringToDurationInternals } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNanoseconds } from './move' import { @@ -51,7 +51,7 @@ export const [ microseconds = 0, nanoseconds = 0, ) => { - return refineDurationFields({ + return refineDurationInternals({ years, months, weeks, @@ -69,10 +69,10 @@ export const [ {}, // bagToInternals - bagToDurationFields, + bagToDurationInternals, // stringToInternals - stringToDurationFields, + stringToDurationInternals, // handleUnusedOptions noop, @@ -81,7 +81,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - ...durationFieldGetters, + ...durationGetters, blank(internals) { return !internals.sign diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 1486264b..7738420e 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -1,18 +1,20 @@ -import { isoTimeFieldDefaults, isoTimeFieldNames } from './isoFields' +import { isoTimeFieldNames } from './isoFields' import { toIntegerWithoutRounding } from './options' -import { mapRefiners, remapProps } from './util' +import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './util' +// Refiners +// ------------------------------------------------------------------------------------------------- + +// Ordered alphabetically const durationDateFieldRefiners = { - // sorted alphabetically days: toIntegerWithoutRounding, months: toIntegerWithoutRounding, weeks: toIntegerWithoutRounding, years: toIntegerWithoutRounding, - // does not have 'sign' } +// Ordered alphabetically const durationTimeFieldRefiners = { - // sorted alphabetically hours: toIntegerWithoutRounding, microseconds: toIntegerWithoutRounding, milliseconds: toIntegerWithoutRounding, @@ -21,69 +23,75 @@ const durationTimeFieldRefiners = { seconds: toIntegerWithoutRounding, } -export const durationFieldRefiners = { // does not include 'sign' - // keys must be resorted +// Unordered +export const durationFieldRefiners = { ...durationDateFieldRefiners, ...durationTimeFieldRefiners, } -export const durationDateFieldNames = Object.keys(durationDateFieldRefiners) -export const durationTimeFieldNames = Object.keys(durationTimeFieldRefiners) +// Property Names +// ------------------------------------------------------------------------------------------------- + +const durationDateFieldNames = Object.keys(durationDateFieldRefiners) +const durationTimeFieldNames = Object.keys(durationTimeFieldRefiners) export const durationFieldNames = Object.keys(durationFieldRefiners).sort() +const durationInternalNames = [...durationFieldNames, 'sign'] + +// Getters +// ------------------------------------------------------------------------------------------------- + +export const durationGetters = mapArrayToProps(durationInternalNames, (propName) => { + return (durationInternals) => { + return durationInternals[propName] + } +}) -export const durationTimeFieldDefaults = remapProps( - isoTimeFieldDefaults, - isoTimeFieldNames, - durationTimeFieldNames, -) - -export const durationFieldDefaults = { // does not include 'sign' - years: 0, - months: 0, - // TODO: weeks!!! - days: 0, +// Defaults +// ------------------------------------------------------------------------------------------------- + +const durationDateFieldDefaults = zipSingleValue(durationDateFieldNames, 0) +export const durationTimeFieldDefaults = zipSingleValue(durationTimeFieldNames, 0) +export const durationFieldDefaults = { + ...durationDateFieldDefaults, ...durationTimeFieldDefaults, } -export const durationFieldGetters = durationFieldNames - .concat(['sign']) - .reduce((accum, durationFieldName, i) => { - accum[durationFieldName] = function(internals) { - return internals[durationFieldName] - } - return accum - }, {}) // TODO: somehow leverage remapProps instead? +// Refining / Conversion +// ------------------------------------------------------------------------------------------------- -export function negateDurationFields(internals) { - // recomputes sign +export function refineDurationInternals(rawDurationFields) { + return updateDurationFieldSign(mapRefiners(rawDurationFields, durationFieldRefiners)) } -export function absolutizeDurationFields(internals) { - // recomputes sign +export function updateDurationFieldSign(fields) { + fields.sign = computeDurationFieldSign(fields) + return fields } -export function durationHasDateParts(internals) { - return Boolean(computeDurationFieldsSign(internals, durationDateFieldNames)) +export function durationTimeFieldsToIso(durationTimeFields) { + return remapProps(durationTimeFields, durationTimeFieldNames, isoTimeFieldNames) } -export function durationTimeFieldsToIso(durationFields0) { - return remapProps(durationFields0, durationTimeFieldNames, isoTimeFieldNames) -} +// Math +// ------------------------------------------------------------------------------------------------- -export function refineDurationFields(input) { - return addSignToDurationFields(mapRefiners(input, durationFieldRefiners)) +export function addDurationFields(durationFields0, durationFields1, sign) { + // recomputes sign } -export function addSignToDurationFields(fields) { - fields.sign = computeDurationFieldsSign(fields) - return fields +export function negateDurationFields(internals) { + // recomputes sign } -function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { - // should throw error if mismatch - // TODO: audit repeat uses of this +export function absolutizeDurationFields(internals) { + // recomputes sign } -export function addDurationFields(durationFields0, durationFields1, sign) { +export function durationHasDateParts(internals) { + return Boolean(computeDurationFieldSign(internals, durationDateFieldNames)) +} +function computeDurationFieldSign(internals, fieldNames = durationFieldNames) { + // should throw error if mismatch + // TODO: audit repeat uses of this } diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 0a95a5d7..71f05531 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -4,6 +4,7 @@ import { createTemporalClass, neverValueOf } from './class' import { diffEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' +import { validateEpochNano } from './isoFields' import { formatCalendar, formatIsoDateTimeFields, @@ -16,7 +17,6 @@ import { nanosecondsInMicrosecond, nanosecondsInMillisecond, nanosecondsInSecond, - regulateEpochNanoseconds, } from './isoMath' import { compareLargeInts, createLargeInt, toLargeInt } from './largeInt' import { moveEpochNanoseconds } from './move' @@ -38,7 +38,7 @@ export const [ // constructorToInternals (epochNanoseconds) => { - return regulateEpochNanoseconds(toLargeInt(epochNanoseconds)) + return validateEpochNano(toLargeInt(epochNanoseconds)) // TODO: strictly BigInt }, // internalsConversionMap diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index e22c1460..251fd772 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -1,7 +1,18 @@ import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' -import { toIntegerThrowOnInfinity, toIntegerWithoutRounding, toPositiveInteger } from './options' -import { pluckProps, zipSingleValue } from './util' +import { + computeIsoDaysInMonth, + isoFieldsToEpochNano, + isoMonthsInYear, + nanosecondsInIsoDay, +} from './isoMath' +import { compareLargeInts, createLargeInt } from './largeInt' +import { + toIntegerThrowOnInfinity, + toIntegerWithoutRounding, + toPositiveInteger, +} from './options' +import { clamp, mapRefiners, pluckProps, zipSingleValue } from './util' // Refiners // ------------------------------------------------------------------------------------------------- @@ -44,6 +55,100 @@ export const isoTimeFieldNames = Object.keys(isoTimeFieldRefiners) export const isoTimeFieldDefaults = zipSingleValue(isoTimeFieldNames, 0) +// Refining +// ------------------------------------------------------------------------------------------------- + +export function refineIsoTimeInternals(rawIsoTimeInternals) { + return constrainIsoTimeFields( + mapRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), + ) +} + +export function refineIsoDateInternals(rawIsoDateInternals) { + return constrainIsoDateInternals( + mapRefiners(rawIsoDateInternals, isoDateInternalRefiners), + ) +} + +export function refineIsoDateTimeInternals(rawIsoDateTimeInternals) { + return constrainIsoDateTimeInternals( + mapRefiners(rawIsoDateTimeInternals, isoDateTimeInternalRefiners), + ) +} + +// Constraining +// ------------------------------------------------------------------------------------------------- + +export function constrainIsoDateTimeInternals(isoDateTimeInternals) { + return validateIsoDateTimeInternals({ + ...constrainIsoDateInternals(isoDateTimeInternals), + ...constrainIsoTimeFields(isoDateTimeInternals), + }) +} + +export function constrainIsoDateInternals(isoDateInternals) { + return validateIsoDateTimeInternals({ + calendar: isoDateInternals.calendar, + isoYear: isoDateInternals.isoYear, + isoMonth: clamp(isoDateInternals.isoMonth, 1, isoMonthsInYear), // TODO: must error! + isoDay: clamp( // TODO: must error! + isoDateInternals.isoDay, + 1, + computeIsoDaysInMonth(isoDateInternals.isoYear, isoDateInternals.isoMonth), + ), + }) +} + +export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { + return { + isoHour: clamp(isoTimeFields.isoHour, 1, 23, overflow), + isoMinute: clamp(isoTimeFields.isoMinute, 1, 59, overflow), + isoSecond: clamp(isoTimeFields.isoSecond, 1, 59, overflow), + isoMillisecond: clamp(isoTimeFields.isoMillisecond, 1, 999, overflow), + isoMicrosecond: clamp(isoTimeFields.isoMicrosecond, 1, 999, overflow), + isoNanosecond: clamp(isoTimeFields.isoNanosecond, 1, 999, overflow), + } +} + +// Validation +// TODO: move elsewhere +// ------------------------------------------------------------------------------------------------- + +const epochNanoMax = createLargeInt(nanosecondsInIsoDay).mult(100000000) // inclusive +const epochNanoMin = createLargeInt.mult(-1) // inclusive +const isoYearMin = -271821 +const isoYearMax = 275760 + +function validateIsoDateTimeInternals(isoDateTimeInternals) { + const { isoYear } = isoDateTimeInternals + clamp(isoYear, isoYearMin, isoYearMax) // TODO: must error! + + const nudge = + isoYear === isoYearMin + ? 1 + : isoYear === isoYearMax + ? -1 + : 0 + + if (nudge) { + const epochNano = isoFieldsToEpochNano(isoDateTimeInternals) + validateEpochNano(epochNano && epochNano.add((nanosecondsInIsoDay - 1) * nudge)) + } + + return isoDateTimeInternals +} + +export function validateEpochNano(epochNano) { + if ( + epochNano == null || // TODO: pick null or undefined + compareLargeInts(epochNano, epochNanoMin) === 1 || // epochNano < epochNanoMin + compareLargeInts(epochNanoMax, epochNano) === 1 // epochNanoMax < epochNano + ) { + throw new RangeError('aahh') + } + return epochNano +} + // Conversion // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 8a6b26ae..8e060218 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -32,11 +32,7 @@ export const epochGetters = { }, } -export function regulateEpochNanoseconds(epochNanoseconds) { - // ensure the browser allows it -} - -// Stuff +// ISO Calendar system export const isoMonthsInYear = 12 export const isoDaysInWeek = 7 @@ -78,21 +74,26 @@ export function computeIsoWeekOfYear(isoDateFields) { export function computeIsoYearOfWeek(isoDateFields) { } +// isoDateTimeFieldsToLegacyDate +function generateLegacyDate(isoDateTimeFields) { +} + +// + export function isoFieldsToEpochMilli(isoDateTimeFields) { } export function isoToEpochMilli(isoYear, isoMonth, isoDate) { } +// diff (diffEpochMilliByDays) export function diffDaysMilli(milli0, milli1) { } +// move (moveEpochMilliByDays) export function addDaysMilli(epochMilli, milli) { } -export function generateLegacyDate(isoDateTimeFields) { -} - export function epochMilliToIsoFields() { } @@ -130,6 +131,8 @@ export function isoToUtcEpochNanoseconds(isoDateTimeFields) { } export function isoFieldsToEpochNano(isoDateTimeFields) { + // if result is out-of-bounds, will return null or undefined? + // NOTE: caller should always check result } export function isoTimeToNanoseconds(isoTimeFields) { diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index e1cce1da..7ee7edc6 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -1,11 +1,13 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { + constrainIsoDateInternals, + constrainIsoDateTimeInternals, + constrainIsoTimeFields, pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields, } from './isoFields' -import { isValidIsoFields } from './options' import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' @@ -111,12 +113,10 @@ export function stringToPlainTimeInternals(s) { throw new Error() } - let otherParsed = parseMonthDay(s) - if (otherParsed && isValidIsoFields(otherParsed)) { + if (parseMonthDay(s)) { throw new Error() } - otherParsed = parseYearMonth(s) - if (otherParsed && isValidIsoFields(otherParsed)) { + if (parseYearMonth(s)) { throw new Error() } @@ -157,33 +157,38 @@ export function stringToTimeZoneId(s) { // ------------------------------------------------------------------------------------------------- export function parseDateTime(s) { - // { isYear, isoMonth, isoDay, - // isoHour, isMinute, isoSecond, etc... - // hasTime, hasZ, offset, - // calendar, timeZone } - // - // TODO: make calendar default to ISO! + return constrainIsoDateTimeInternals({ + // { isYear, isoMonth, isoDay, + // isoHour, isMinute, isoSecond, etc... + // hasTime, hasZ, offset, + // calendar, timeZone } + }) } export function parseYearMonth(s) { - // { isYear, isoMonth, isoDay - // calendar, timeZone } + return constrainIsoDateInternals({ + // { isYear, isoMonth, isoDay + // calendar, timeZone } + }) } export function parseMonthDay(s) { - // { isYear, isoMonth, isoDay - // calendar, timeZone } + return constrainIsoDateInternals({ + // { isYear, isoMonth, isoDay + // calendar, timeZone } + }) } export function parseTime(s) { - // { isoHour, isoMinute, isoSecond, etc... - // calendar, timeZone } + return constrainIsoTimeFields({ + // { isoHour, isoMinute, isoSecond, etc... } + }) } export function parseOffsetNanoseconds(s) { // number } -export function stringToDurationFields(s) { - +export function stringToDurationInternals(s) { + // includes sign } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 3da9a965..cde4df03 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,4 +1,6 @@ +// TODO: for unit parsing, ensure ceiling and correct increment + export function strictNumber(input) { } @@ -186,19 +188,3 @@ export function overflowToOptions(overflow) { export function largestUnitToOptions(largestUnit) { return { largestUnit } } - -// Stuff - -export function constrainIsoDateTimeFields(isoDateTimeFields, overflow = 'reject') { - // ahhhh! calendar gets passed in here!!! -} - -export function constrainIsoDateFields(isoDateFields, overflow = 'reject') { - // ahhhh! calendar gets passed in here!!! -} - -export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { -} - -export function isValidIsoFields() { -} diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 6addce8b..85926acf 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -19,17 +19,17 @@ import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { generatePublicIsoDateFields, - isoDateInternalRefiners, isoTimeFieldDefaults, pluckIsoDateInternals, + refineIsoDateInternals, } from './isoFields' import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoFields } from './isoMath' import { stringToPlainDateInternals } from './isoParse' -import { constrainIsoDateFields, optionsToOverflow } from './options' +import { optionsToOverflow } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' -import { isIdPropsEqual, mapRefiners } from './util' +import { isIdPropsEqual } from './util' export const [ PlainDate, @@ -42,15 +42,13 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (isoYear, isoMonth, isoDay, calendarArg = isoCalendarId) => { - return constrainIsoDateFields( - mapRefiners({ - isoYear, - isoMonth, - isoDay, - calendar: calendarArg, - }, isoDateInternalRefiners), - ) + (isoYear, isoMonth, isoDay, calendar = isoCalendarId) => { + return refineIsoDateInternals({ + isoYear, + isoMonth, + isoDay, + calendar, + }) }, // internalsConversionMap diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 2c38244f..83bc61d5 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -14,18 +14,17 @@ import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { generatePublicIsoDateTimeFields, - isoDateTimeInternalRefiners, isoTimeFieldDefaults, pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields, + refineIsoDateTimeInternals, } from './isoFields' import { formatCalendar, formatIsoDateTimeFields } from './isoFormat' import { compareIsoFields } from './isoMath' import { stringToPlainDateTimeInternals } from './isoParse' import { moveDateTime } from './move' import { - constrainIsoDateTimeFields, optionsToOverflow, toDisambiguation, validateRoundingOptions, @@ -34,7 +33,7 @@ import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { isIdPropsEqual, mapRefiners } from './util' +import { isIdPropsEqual } from './util' import { createZonedDateTime } from './zonedDateTime' export const [ @@ -58,22 +57,20 @@ export const [ isoMillisecond = 0, isoMicrosecond = 0, isoNanosecond = 0, - calendarArg = isoCalendarId, + calendar = isoCalendarId, ) => { - return constrainIsoDateTimeFields( - mapRefiners({ - isoYear, - isoMonth, - isoDay, - isoHour, - isoMinute, - isoSecond, - isoMillisecond, - isoMicrosecond, - isoNanosecond, - calendar: queryCalendarOps(calendarArg), - }, isoDateTimeInternalRefiners), - ) + return refineIsoDateTimeInternals({ + isoYear, + isoMonth, + isoDay, + isoHour, + isoMinute, + isoSecond, + isoMillisecond, + isoMicrosecond, + isoNanosecond, + calendar, + }) }, // internalsConversionMap diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 1b762e15..39d1a201 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -7,12 +7,12 @@ import { isoCalendarId } from './calendarConfig' import { monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' -import { generatePublicIsoDateFields, isoDateInternalRefiners } from './isoFields' +import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoFields, isoEpochFirstLeapYear } from './isoMath' import { stringToMonthDayInternals } from './isoParse' -import { constrainIsoDateFields, optionsToOverflow } from './options' -import { isIdPropsEqual, mapRefiners } from './util' +import { optionsToOverflow } from './options' +import { isIdPropsEqual } from './util' export const [ PlainMonthDay, @@ -25,15 +25,13 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (isoMonth, isoDay, calendarArg = isoCalendarId, referenceIsoYear = isoEpochFirstLeapYear) => { - return constrainIsoDateFields( - mapRefiners({ - isoYear: referenceIsoYear, - isoMonth, - isoDay, - calendar: calendarArg, - }, isoDateInternalRefiners), - ) + (isoMonth, isoDay, calendar = isoCalendarId, referenceIsoYear = isoEpochFirstLeapYear) => { + return refineIsoDateInternals({ + isoYear: referenceIsoYear, + isoMonth, + isoDay, + calendar, + }) }, // internalsConversionMap diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index bf91c077..f4bdd0ca 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -9,16 +9,15 @@ import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { isoTimeFieldRefiners, pluckIsoTimeFields } from './isoFields' +import { pluckIsoTimeFields, refineIsoTimeInternals } from './isoFields' import { formatIsoTimeFields } from './isoFormat' import { compareIsoTimeFields } from './isoMath' import { stringToPlainTimeInternals } from './isoParse' import { moveTime } from './move' -import { constrainIsoTimeFields, optionsToOverflow } from './options' +import { optionsToOverflow } from './options' import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' -import { mapRefiners } from './util' export const [ PlainTime, @@ -39,22 +38,22 @@ export const [ isoMicrosecond = 0, isoNanosecond = 0, ) => { - return constrainIsoTimeFields( - mapRefiners({ - isoHour, - isoMinute, - isoSecond, - isoMillisecond, - isoMicrosecond, - isoNanosecond, - }, isoTimeFieldRefiners), - ) + return refineIsoTimeInternals({ + isoHour, + isoMinute, + isoSecond, + isoMillisecond, + isoMicrosecond, + isoNanosecond, + }) }, // internalsConversionMap { PlainDateTime: pluckIsoTimeFields, - ZonedDateTime: (argInternals) => pluckIsoTimeFields(zonedDateTimeInternalsToIso(argInternals)), + ZonedDateTime(argInternals) { + return pluckIsoTimeFields(zonedDateTimeInternalsToIso(argInternals)) + }, }, // bagToInternals diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index fe9b8741..c45b5e38 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -11,12 +11,12 @@ import { createTemporalClass, getInternals, neverValueOf, toLocaleStringMethod } import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { generatePublicIsoDateFields, isoDateInternalRefiners } from './isoFields' +import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoFields } from './isoMath' import { stringToPlainYearMonthInternals } from './isoParse' -import { constrainIsoDateFields, optionsToOverflow } from './options' -import { isIdPropsEqual, mapRefiners } from './util' +import { optionsToOverflow } from './options' +import { isIdPropsEqual } from './util' export const [ PlainYearMonth, @@ -29,15 +29,13 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (isoYear, isoMonth, calendarArg = isoCalendarId, referenceIsoDay = 1) => { - return constrainIsoDateFields( - mapRefiners({ - isoYear, - isoMonth, - isoDay: referenceIsoDay, - calendar: calendarArg, - }, isoDateInternalRefiners), - ) + (isoYear, isoMonth, calendar = isoCalendarId, referenceIsoDay = 1) => { + return refineIsoDateInternals({ + isoYear, + isoMonth, + isoDay: referenceIsoDay, + calendar, + }) }, // internalsConversionMap diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index 697c3daf..af86361a 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -1,6 +1,8 @@ // in general, prefer .bind over macro functions +// always prefer [...a] over [].concat(a) + export function isObjectLike() { } diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 8a1f25ed..c1c64993 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -19,6 +19,7 @@ import { pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields, + validateEpochNano, } from './isoFields' import { formatCalendar, @@ -57,7 +58,7 @@ export const [ // constructorToInternals (epochNanoseconds, timeZoneArg, calendarArg) => { return { - epochNanoseconds: toLargeInt(epochNanoseconds), // TODO: stricter + epochNanoseconds: validateEpochNano(toLargeInt(epochNanoseconds)), // TODO: strictly BigInt timeZone: queryTimeZoneOps(timeZoneArg), calendar: queryCalendarOps(calendarArg), } From ade6937effb5453b1fa15a00c601ab895d147041 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 2 Jun 2023 18:26:46 -0400 Subject: [PATCH 083/805] more stuff --- packages/temporal-polyfill/src/new/global.js | 2 +- packages/temporal-polyfill/src/new/impl.js | 3 +++ packages/temporal-polyfill/src/new/index.js | 4 +--- packages/temporal-polyfill/src/new/intlFormat.js | 7 +++---- 4 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 packages/temporal-polyfill/src/new/impl.js diff --git a/packages/temporal-polyfill/src/new/global.js b/packages/temporal-polyfill/src/new/global.js index 9c253123..2f0ecbc6 100644 --- a/packages/temporal-polyfill/src/new/global.js +++ b/packages/temporal-polyfill/src/new/global.js @@ -1,4 +1,4 @@ -import { DateTimeFormat, Temporal, toTemporalInstant } from './index' +import { DateTimeFormat, Temporal, toTemporalInstant } from './impl' import { defineProps } from './util' defineProps(globalThis, { Temporal }) diff --git a/packages/temporal-polyfill/src/new/impl.js b/packages/temporal-polyfill/src/new/impl.js new file mode 100644 index 00000000..d6c918b2 --- /dev/null +++ b/packages/temporal-polyfill/src/new/impl.js @@ -0,0 +1,3 @@ +export { Temporal } from './temporal' +export { DateTimeFormat } from './intlFormat' +export { toTemporalInstant } from './instant' diff --git a/packages/temporal-polyfill/src/new/index.js b/packages/temporal-polyfill/src/new/index.js index d6c918b2..f356c4c3 100644 --- a/packages/temporal-polyfill/src/new/index.js +++ b/packages/temporal-polyfill/src/new/index.js @@ -1,3 +1 @@ -export { Temporal } from './temporal' -export { DateTimeFormat } from './intlFormat' -export { toTemporalInstant } from './instant' +export * from './impl' diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index 8709095e..6e04668c 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -28,8 +28,7 @@ export function hashIntlFormatParts(intlFormat, epochMilliseconds) { // ------------------------------------------------------------------------------------------------- // AHHH... problem with resolvedOptions... need to whitelist original - -// TODO: rename to intlFormat? +// PERFORMANCE: avoid using our DateTimeFormat for toLocaleString, because creates two objects export const IntlDateTimeFormat = Intl.DateTimeFormat @@ -39,7 +38,7 @@ export class DateTimeFormat extends IntlDateTimeFormat { return format ? format.format(formattable) : super.format(formattable) - // must use super because .format is always bound: + // can't use the origMethd.call trick because .format() is always bound // https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype.format } @@ -243,7 +242,7 @@ function timeInternalsToEpochNano(internals, resolvedOptions) { function dateTimeInternalsToEpochNano(internals, resolvedOptions, temporalName) { checkCalendarsCompatible( internals.calendar.id, - resolvedOptions.calendarId, + resolvedOptions.calendar, strictCalendarCheck[temporalName], ) From 87e329fedad9e0a3746341672df2b0e752592540 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 3 Jun 2023 14:14:49 -0400 Subject: [PATCH 084/805] get iso math in order --- packages/temporal-polyfill/src/new/bag.js | 22 +- .../src/new/calendarFields.js | 2 +- .../temporal-polyfill/src/new/calendarImpl.js | 37 ++- packages/temporal-polyfill/src/new/diff.js | 39 +-- .../temporal-polyfill/src/new/duration.js | 4 +- packages/temporal-polyfill/src/new/instant.js | 39 ++- .../temporal-polyfill/src/new/intlFormat.js | 6 +- .../temporal-polyfill/src/new/isoFields.js | 85 +---- packages/temporal-polyfill/src/new/isoMath.js | 301 ++++++++++++------ .../temporal-polyfill/src/new/isoParse.js | 8 +- .../temporal-polyfill/src/new/largeInt.js | 13 +- packages/temporal-polyfill/src/new/move.js | 23 +- packages/temporal-polyfill/src/new/now.js | 5 +- .../temporal-polyfill/src/new/plainDate.js | 10 +- .../src/new/plainDateTime.js | 11 +- .../src/new/plainMonthDay.js | 4 +- .../temporal-polyfill/src/new/plainTime.js | 4 +- .../src/new/plainYearMonth.js | 6 +- packages/temporal-polyfill/src/new/round.js | 32 +- .../temporal-polyfill/src/new/timeZone.js | 6 +- .../temporal-polyfill/src/new/timeZoneImpl.js | 20 +- .../temporal-polyfill/src/new/timeZoneOps.js | 39 ++- packages/temporal-polyfill/src/new/util.js | 3 + .../src/new/zonedDateTime.js | 43 +-- 24 files changed, 417 insertions(+), 345 deletions(-) diff --git a/packages/temporal-polyfill/src/new/bag.js b/packages/temporal-polyfill/src/new/bag.js index c4b0dec7..0bdc3ce4 100644 --- a/packages/temporal-polyfill/src/new/bag.js +++ b/packages/temporal-polyfill/src/new/bag.js @@ -23,8 +23,7 @@ import { durationFieldRefiners, updateDurationFieldSign, } from './durationFields' -import { constrainIsoTimeFields } from './isoFields' -import { epochNanoToIsoFields, isoEpochFirstLeapYear } from './isoMath' +import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNanoseconds } from './isoParse' import { optionsToOverflow, @@ -38,7 +37,7 @@ import { createPlainMonthDay } from './plainMonthDay' import { createPlainTime } from './plainTime' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { createLazyMap, isObjectLike, pluckProps, removeDuplicateStrings } from './util' +import { isObjectLike, pluckProps, removeDuplicateStrings } from './util' import { createZonedDateTime } from './zonedDateTime' // ahhh: some of these functions return internals, other Plain* objects @@ -287,23 +286,6 @@ export function plainMonthDayToPlainDate(plainMonthDay, bag) { ) } -// to PlainDateTime -// ------------------------------------------------------------------------------------------------- - -export const zonedDateTimeInternalsToIso = createLazyMap(( - internals, // { epochNanoseconds, timeZone } -) => { // { isoYear..., offsetNanoseconds } - const offsetNanoseconds = internals.timeZone.getOffsetNanosecondsFor(internals.epochNanoseconds) - const isoDateTimeFields = epochNanoToIsoFields( - internals.epochNanoseconds.sub(offsetNanoseconds), // subtraction correct? - ) - - return { - ...isoDateTimeFields, - offsetNanoseconds, - } -}) - // to ZonedDateTime // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index b9a90f61..5421c57c 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -86,7 +86,7 @@ export const dateBasicNames = ['day', 'month', 'year'] export const yearMonthBasicNames = yearMonthFieldNames.slice(1) // monthCode/year export const monthDayBasicNames = ['day', 'monthCode'] -export const yearStatNames = Object.keys(yearStatRefiners) // ordered, for predictable macros +export const yearStatNames = Object.keys(yearStatRefiners) export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) // unordered export const dateStatNames = Object.keys(dateStatRefiners) // unordered diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 986f412b..7fd4b9e7 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -16,12 +16,16 @@ import { monthFieldNames, yearStatNames, } from './calendarFields' -import { computeIntlMonthsInYearSpan, computeIsoMonthsInYearSpan, diffYearMonthDay } from './diff' +import { + computeIntlMonthsInYearSpan, + computeIsoMonthsInYearSpan, + diffDaysMilli, + diffYearMonthDay, +} from './diff' import { durationFieldDefaults } from './durationFields' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' import { isoDateFieldNames, isoTimeFieldDefaults } from './isoFields' import { - addDaysMilli, computeIsoDayOfWeek, computeIsoDaysInMonth, computeIsoDaysInYear, @@ -29,15 +33,14 @@ import { computeIsoMonthsInYear, computeIsoWeekOfYear, computeIsoYearOfWeek, - diffDaysMilli, - epochMilliToIsoFields, + epochMilliToIso, isoDaysInWeek, isoEpochFirstLeapYear, isoEpochOriginYear, - isoFieldsToEpochMilli, isoToEpochMilli, + isoArgsToEpochMilli, } from './isoMath' -import { addIntlMonths, addIsoMonths } from './move' +import { addDaysMilli, addIntlMonths, addIsoMonths } from './move' import { constrainInt } from './options' import { buildWeakMapCache, twoDigit } from './util' @@ -150,7 +153,7 @@ class IsoCalendarImpl { } queryDateStart(year, month, day) { - return isoToEpochMilli(year, month, day) + return isoArgsToEpochMilli(year, month, day) } queryYearMonthDay(isoDateFields) { @@ -169,7 +172,7 @@ class IsoCalendarImpl { // ------------------------ dayOfYear(isoDateFields) { - const dayEpochMilliseconds = isoFieldsToEpochMilli({ + const dayEpochMilliseconds = isoToEpochMilli({ ...isoDateFields, ...isoTimeFieldDefaults, }) @@ -198,7 +201,7 @@ class IsoCalendarImpl { ms = this.queryDateStart(year, months, day) } else if (weeks || days) { - ms = isoFieldsToEpochMilli(isoDateFields) + ms = isoToEpochMilli(isoDateFields) } else { return isoDateFields } @@ -207,7 +210,7 @@ class IsoCalendarImpl { return { calendar: this, - ...epochMilliToIsoFields(ms), + ...epochMilliToIso(ms), } } @@ -217,8 +220,8 @@ class IsoCalendarImpl { if (largestUnit <= 'week') { // TODO let weeks = 0 let days = diffDaysMilli( - isoFieldsToEpochMilli(startIsoDateFields), - isoFieldsToEpochMilli(endIsoDateFields), + isoToEpochMilli(startIsoDateFields), + isoToEpochMilli(endIsoDateFields), ) const sign = Math.sign(days) @@ -470,7 +473,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { queryIsoFields(year, month, day) { // returns isoDateInternals return { calendar: this, - ...epochMilliToIsoFields(this.queryDateStart(year, month, day)), + ...epochMilliToIso(this.queryDateStart(year, month, day)), } } @@ -604,17 +607,17 @@ export function queryCalendarImpl(calendarId) { function createIntlFieldCache(epochMillisecondsToIntlFields) { return buildWeakMapCache((isoDateFields) => { - const epochMilliseconds = isoFieldsToEpochMilli(isoDateFields) + const epochMilliseconds = isoToEpochMilli(isoDateFields) return epochMillisecondsToIntlFields(epochMilliseconds) }) } function createJapaneseFieldCache() { const epochMillisecondsToIntlFields = createEpochMillisecondsToIntlFields(japaneseCalendarId) - const primaryEraMilli = isoToEpochMilli(1868, 9, 8) + const primaryEraMilli = isoArgsToEpochMilli(1868, 9, 8) return buildWeakMapCache((isoDateFields) => { - const epochMilliseconds = isoFieldsToEpochMilli(isoDateFields) + const epochMilliseconds = isoToEpochMilli(isoDateFields) const intlFields = epochMillisecondsToIntlFields(epochMilliseconds) if (epochMilliseconds < primaryEraMilli) { @@ -693,7 +696,7 @@ function createIntlMonthCache(epochMillisecondsToIntlFields) { } function buildYear(year) { - let ms = isoToEpochMilli(year - yearCorrection) + let ms = isoArgsToEpochMilli(year - yearCorrection) let intlFields const msReversed = [] const monthStrsReversed = [] diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index f85effe1..4feb4491 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -1,19 +1,20 @@ import { pluckIsoTimeFields } from './isoFields' import { - addDaysToIsoFields, - epochNanosecondsToIso, + isoToEpochNano, isoMonthsInYear, - isoTimeToNanoseconds, - isoToUtcEpochNanoseconds, - nanosecondsInIsoDay, + isoTimeFieldsToNano, + nanoInUtcDay, nanosecondsToTimeDuration, } from './isoMath' import { compareLargeInts } from './largeInt' -import { moveDateTime, moveZonedEpochNanoseconds } from './move' +import { addDaysToIsoFields, moveDateTime, moveZonedEpochNanoseconds } from './move' import { roundLargeNanoseconds, roundRelativeDuration } from './round' -import { getSingleInstantFor } from './timeZoneOps' +import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { identityFunc } from './util' +export function diffDaysMilli(milli0, milli1) { // diffEpochMilliByDays +} + // Diffing // ------------------------------------------------------------------------------------------------- @@ -65,9 +66,9 @@ export function diffZonedEpochNanoseconds( } const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) - const startIsoFields = epochNanosecondsToIso(startEpochNanoseconds, timeZone) + const startIsoFields = zonedEpochNanoToIso(timeZone, startEpochNanoseconds) const startIsoTimeFields = pluckIsoTimeFields(startIsoFields) - const endIsoFields = epochNanosecondsToIso(endEpochNanoseconds, timeZone) + const endIsoFields = zonedEpochNanoToIso(timeZone, endEpochNanoseconds) let midIsoFields = { ...endIsoFields, ...startIsoTimeFields } let midEpochNanoseconds = isoToZoneEpochNanoseconds(midIsoFields) const midSign = compareLargeInts(midEpochNanoseconds, endEpochNanoseconds) @@ -108,8 +109,8 @@ export function diffDateTimes( roundingMode, roundingIncrement, ) { - const startEpochNanoseconds = isoToUtcEpochNanoseconds(startIsoFields) - const endEpochNanoseconds = isoToUtcEpochNanoseconds(endIsoFields) + const startEpochNanoseconds = isoToEpochNano(startIsoFields) + const endEpochNanoseconds = isoToEpochNano(endIsoFields) if (largestUnit < 'day') { // TODO return diffEpochNanoseconds( @@ -124,8 +125,8 @@ export function diffDateTimes( // TODO: what about day optimization? const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) - const startTimeNanoseconds = isoTimeToNanoseconds(startIsoFields) // number - const endTimeNanoseconds = isoTimeToNanoseconds(endIsoFields) // number + const startTimeNanoseconds = isoTimeFieldsToNano(startIsoFields) // number + const endTimeNanoseconds = isoTimeFieldsToNano(endIsoFields) // number let timeNanosecondDiff = endTimeNanoseconds - startTimeNanoseconds const timeSign = Math.sign(timeNanosecondDiff) let midIsoFields = startIsoFields @@ -135,7 +136,7 @@ export function diffDateTimes( ...addDaysToIsoFields(startIsoFields, sign), ...pluckIsoTimeFields(startIsoFields), } - timeNanosecondDiff += nanosecondsInIsoDay + timeNanosecondDiff += nanoInUtcDay } const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnit) @@ -148,7 +149,7 @@ export function diffDateTimes( { ...dateDiff, ...timeDiff, sign }, endEpochNanoseconds, startIsoFields, // marker - isoToUtcEpochNanoseconds, // markerToEpochNanoseconds + isoToEpochNano, // markerToEpochNanoseconds moveDateTime.bind(undefined, calendar), // moveMarker smallestUnit, roundingMode, @@ -168,8 +169,8 @@ export function diffDates( ) { if (largestUnit < 'day') { // TODO return diffEpochNanoseconds( - isoToUtcEpochNanoseconds(startIsoDateFields), - isoToUtcEpochNanoseconds(endIsoDateFields), + isoToEpochNano(startIsoDateFields), + isoToEpochNano(endIsoDateFields), largestUnit, smallestUnit, roundingMode, @@ -181,9 +182,9 @@ export function diffDates( return roundRelativeDuration( dateDiff, - isoToUtcEpochNanoseconds(endIsoDateFields), + isoToEpochNano(endIsoDateFields), startIsoDateFields, // marker - isoToUtcEpochNanoseconds, // markerToEpochNanoseconds + isoToEpochNano, // markerToEpochNanoseconds calendar.dateAdd.bind(calendar), // moveMarker smallestUnit, roundingMode, diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 055be8bd..6610fe0e 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -8,7 +8,7 @@ import { negateDurationFields, refineDurationInternals, } from './durationFields' -import { isoToUtcEpochNanoseconds } from './isoMath' +import { isoToEpochNano } from './isoMath' import { stringToDurationInternals } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNanoseconds } from './move' @@ -227,7 +227,7 @@ function createMarkerSystem(markerInternals) { } else { return [ markerInternals, // marker (IsoDateFields) - isoToUtcEpochNanoseconds, // markerToEpochNanoseconds + isoToEpochNano, // markerToEpochNanoseconds calendar.dateAdd.bind(calendar), // moveMarker calendar.dateUntil.bind(calendar), // diffMarkers ] diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 71f05531..690296cc 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -4,7 +4,6 @@ import { createTemporalClass, neverValueOf } from './class' import { diffEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' -import { validateEpochNano } from './isoFields' import { formatCalendar, formatIsoDateTimeFields, @@ -13,12 +12,13 @@ import { } from './isoFormat' import { epochGetters, - epochNanosecondsToIso, - nanosecondsInMicrosecond, - nanosecondsInMillisecond, - nanosecondsInSecond, + epochMicroToNano, + epochMilliToNano, + epochNanoToIso, + epochSecToNano, + validateEpochNano, } from './isoMath' -import { compareLargeInts, createLargeInt, toLargeInt } from './largeInt' +import { compareLargeInts, toLargeInt } from './largeInt' import { moveEpochNanoseconds } from './move' import { toObject } from './options' import { roundLargeNanoseconds } from './round' @@ -144,7 +144,7 @@ export const [ refinedOptions, // TODO: break apart options ) const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - const isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + const isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) return formatIsoDateTimeFields(isoDateTimeFields, refinedOptions) + formatOffsetNanoseconds(offsetNanoseconds) + @@ -163,14 +163,12 @@ export const [ // ----------------------------------------------------------------------------------------------- { - fromEpochSeconds(epochSeconds) { - return createInstant(createLargeInt(epochSeconds).mult(nanosecondsInSecond)) - }, + fromEpochSeconds: epochSecToInstant, fromEpochMilliseconds: epochMilliToInstant, - fromEpochMicroseconds(epochMicroseconds) { - return createInstant(toLargeInt(epochMicroseconds).mult(nanosecondsInMicrosecond)) + fromEpochMicroseconds(epochMicro) { + return epochMicroToInstant(toLargeInt(epochMicro)) }, fromEpochNanoseconds(epochNanoseconds) { @@ -183,11 +181,24 @@ function stringToEpochNanoseconds(str) { // TODO } +// Unit Conversion +// ------------------------------------------------------------------------------------------------- + +function epochSecToInstant(epochSec) { + return createInstant(epochSecToNano(epochSec)) +} + function epochMilliToInstant(epochMilli) { - return createInstant(createLargeInt(epochMilli).mult(nanosecondsInMillisecond)) + return createInstant(epochMilliToNano(epochMilli)) } -// a method for Date +function epochMicroToInstant(epochMicro) { + return createInstant(epochMicroToNano(epochMicro)) +} + +// Legacy Date +// ------------------------------------------------------------------------------------------------- + export function toTemporalInstant() { return epochMilliToInstant(this.valueOf()) } diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index 6e04668c..0fc26754 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' import { dateBasicNames, timeFieldDefaults } from './calendarFields' import { getInternals, getTemporalName } from './class' -import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' +import { epochNanoToMilliFloor, isoEpochOriginYear } from './isoMath' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createLazyMap, @@ -127,7 +127,7 @@ export function resolveZonedFormattable( ) return [ - epochNanoToMilli(internals.epochNanoseconds), + epochNanoToMilliFloor(internals.epochNanoseconds), format, ] } @@ -145,7 +145,7 @@ function resolveFormattable( const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) return [ - epochNanoToMilli(epochNano), + epochNanoToMilliFloor(epochNano), getSpecificFormat(transformOptions, resolvedOptions), ] } diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 251fd772..34e1b7cc 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -1,18 +1,16 @@ import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { - computeIsoDaysInMonth, - isoFieldsToEpochNano, - isoMonthsInYear, - nanosecondsInIsoDay, + constrainIsoDateInternals, + constrainIsoDateTimeInternals, + constrainIsoTimeFields, } from './isoMath' -import { compareLargeInts, createLargeInt } from './largeInt' import { toIntegerThrowOnInfinity, toIntegerWithoutRounding, toPositiveInteger, } from './options' -import { clamp, mapRefiners, pluckProps, zipSingleValue } from './util' +import { mapRefiners, pluckProps, zipSingleValue } from './util' // Refiners // ------------------------------------------------------------------------------------------------- @@ -48,6 +46,7 @@ export const isoDateInternalNames = Object.keys(isoDateInternalRefiners) export const isoDateTimeInternalNames = Object.keys(isoDateTimeInternalRefiners).sort() export const isoDateFieldNames = isoDateInternalNames.slice(1) // no calendar +const isoDateTimeFieldNames = isoDateTimeInternalRefiners.slice(1) // no calendar export const isoTimeFieldNames = Object.keys(isoTimeFieldRefiners) // Defaults @@ -76,84 +75,12 @@ export function refineIsoDateTimeInternals(rawIsoDateTimeInternals) { ) } -// Constraining -// ------------------------------------------------------------------------------------------------- - -export function constrainIsoDateTimeInternals(isoDateTimeInternals) { - return validateIsoDateTimeInternals({ - ...constrainIsoDateInternals(isoDateTimeInternals), - ...constrainIsoTimeFields(isoDateTimeInternals), - }) -} - -export function constrainIsoDateInternals(isoDateInternals) { - return validateIsoDateTimeInternals({ - calendar: isoDateInternals.calendar, - isoYear: isoDateInternals.isoYear, - isoMonth: clamp(isoDateInternals.isoMonth, 1, isoMonthsInYear), // TODO: must error! - isoDay: clamp( // TODO: must error! - isoDateInternals.isoDay, - 1, - computeIsoDaysInMonth(isoDateInternals.isoYear, isoDateInternals.isoMonth), - ), - }) -} - -export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { - return { - isoHour: clamp(isoTimeFields.isoHour, 1, 23, overflow), - isoMinute: clamp(isoTimeFields.isoMinute, 1, 59, overflow), - isoSecond: clamp(isoTimeFields.isoSecond, 1, 59, overflow), - isoMillisecond: clamp(isoTimeFields.isoMillisecond, 1, 999, overflow), - isoMicrosecond: clamp(isoTimeFields.isoMicrosecond, 1, 999, overflow), - isoNanosecond: clamp(isoTimeFields.isoNanosecond, 1, 999, overflow), - } -} - -// Validation -// TODO: move elsewhere -// ------------------------------------------------------------------------------------------------- - -const epochNanoMax = createLargeInt(nanosecondsInIsoDay).mult(100000000) // inclusive -const epochNanoMin = createLargeInt.mult(-1) // inclusive -const isoYearMin = -271821 -const isoYearMax = 275760 - -function validateIsoDateTimeInternals(isoDateTimeInternals) { - const { isoYear } = isoDateTimeInternals - clamp(isoYear, isoYearMin, isoYearMax) // TODO: must error! - - const nudge = - isoYear === isoYearMin - ? 1 - : isoYear === isoYearMax - ? -1 - : 0 - - if (nudge) { - const epochNano = isoFieldsToEpochNano(isoDateTimeInternals) - validateEpochNano(epochNano && epochNano.add((nanosecondsInIsoDay - 1) * nudge)) - } - - return isoDateTimeInternals -} - -export function validateEpochNano(epochNano) { - if ( - epochNano == null || // TODO: pick null or undefined - compareLargeInts(epochNano, epochNanoMin) === 1 || // epochNano < epochNanoMin - compareLargeInts(epochNanoMax, epochNano) === 1 // epochNanoMax < epochNano - ) { - throw new RangeError('aahh') - } - return epochNano -} - // Conversion // ------------------------------------------------------------------------------------------------- export const pluckIsoDateInternals = pluckProps.bind(undefined, isoDateInternalNames) export const pluckIsoDateTimeInternals = pluckProps.bind(undefined, isoDateTimeInternalNames) +export const pluckIsoDateTimeFields = pluckProps.bind(undefined, isoDateTimeFieldNames) export const pluckIsoTimeFields = pluckProps.bind(undefined, isoTimeFieldNames) export const generatePublicIsoDateFields = diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 8e060218..0c3c815b 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,45 +1,16 @@ -import { createLargeInt } from './largeInt' +import { pluckIsoDateTimeFields } from './isoFields' +import { compareLargeInts, createLargeInt } from './largeInt' +import { clamp, positiveModulo } from './util' -export const nanosecondsInMicrosecond = 1000 -export const nanosecondsInMillisecond = 1000000 -export const nanosecondsInSecond = 1000000000 -export const nanosecondsInHour = 3600000000000 -export const nanosecondsInIsoDay = 86400000000000 +// ISO Calendar +// ------------------------------------------------------------------------------------------------- -export const nanosecondsInUnit = {} // include iso-day as well - -export function epochNanoToMilli(epochNano) { - return epochNano.div(nanosecondsInMillisecond).toNumber() -} - -export function epochSecToNano(epochSec) { - return createLargeInt(epochSec).mult(nanosecondsInSecond) -} - -export const epochGetters = { - epochNanoseconds(epochNanoseconds) { - return epochNanoseconds.toBigInt() - }, - - epochMicroseconds(epochNanoseconds) { - return epochNanoseconds.div(nanosecondsInMicrosecond).toBigInt() - }, - - epochMilliseconds: epochNanoToMilli, - - epochSeconds(epochNanoseconds) { - return epochNanoseconds.div(nanosecondsInSecond).toNumber() - }, -} - -// ISO Calendar system - -export const isoMonthsInYear = 12 -export const isoDaysInWeek = 7 export const isoEpochOriginYear = 1970 export const isoEpochFirstLeapYear = 1972 +export const isoMonthsInYear = 12 +export const isoDaysInWeek = 7 -export function computeIsoMonthsInYear(isoYear) { +export function computeIsoMonthsInYear(isoYear) { // for methods return isoMonthsInYear } @@ -65,7 +36,7 @@ export function computeIsoIsLeapYear(isoYear) { } export function computeIsoDayOfWeek(isoDateFields) { - return generateLegacyDate(isoDateFields).getDay() + 1 + return isoToLegacyDate(isoDateFields).getDay() + 1 } export function computeIsoWeekOfYear(isoDateFields) { @@ -74,101 +45,177 @@ export function computeIsoWeekOfYear(isoDateFields) { export function computeIsoYearOfWeek(isoDateFields) { } -// isoDateTimeFieldsToLegacyDate -function generateLegacyDate(isoDateTimeFields) { -} - -// +// Constraining +// ------------------------------------------------------------------------------------------------- -export function isoFieldsToEpochMilli(isoDateTimeFields) { +export function constrainIsoDateTimeInternals(isoDateTimeInternals) { + return validateIsoDateTimeInternals({ + ...constrainIsoDateInternals(isoDateTimeInternals), + ...constrainIsoTimeFields(isoDateTimeInternals), + }) } -export function isoToEpochMilli(isoYear, isoMonth, isoDate) { +export function constrainIsoDateInternals(isoDateInternals) { + return validateIsoDateTimeInternals({ + calendar: isoDateInternals.calendar, + isoYear: isoDateInternals.isoYear, + isoMonth: clamp(isoDateInternals.isoMonth, 1, isoMonthsInYear), // TODO: must error! + isoDay: clamp( // TODO: must error! + isoDateInternals.isoDay, + 1, + computeIsoDaysInMonth(isoDateInternals.isoYear, isoDateInternals.isoMonth), + ), + }) } -// diff (diffEpochMilliByDays) -export function diffDaysMilli(milli0, milli1) { +export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { + return { + isoHour: clamp(isoTimeFields.isoHour, 1, 23, overflow), + isoMinute: clamp(isoTimeFields.isoMinute, 1, 59, overflow), + isoSecond: clamp(isoTimeFields.isoSecond, 1, 59, overflow), + isoMillisecond: clamp(isoTimeFields.isoMillisecond, 1, 999, overflow), + isoMicrosecond: clamp(isoTimeFields.isoMicrosecond, 1, 999, overflow), + isoNanosecond: clamp(isoTimeFields.isoNanosecond, 1, 999, overflow), + } } -// move (moveEpochMilliByDays) -export function addDaysMilli(epochMilli, milli) { -} +// Epoch Unit Conversion +// ------------------------------------------------------------------------------------------------- -export function epochMilliToIsoFields() { +export const secInDay = 86400 +const millInUtcDay = 86400000 +export const milliInSec = 1000 + +export const nanoInMicro = 1000 // consolidate with other 1000 units +export const nanoInMilli = 1000000 +export const nanoInSec = 1000000000 +export const nanoInHour = 3600000000000 +export const nanoInUtcDay = 86400000000000 +export const nanosecondsInUnit = { + microsecond: nanoInMicro, + millisecond: nanoInMilli, + second: nanoInSec, + hour: nanoInHour, + day: nanoInUtcDay, } -// TIME math... +// nano -> * (with floor) -export function isoTimeFieldsToNanoseconds() { +export function epochNanoToSecFloor(epochNano) { + return epochNanoToSec(epochNano)[0] +} +export function epochNanoToMilliFloor(epochNano) { + return epochNanoToMicro(epochNano)[0] } -export function nanosecondsToIsoTimeFields() { - /* - const dayDelta = Math.floor(nanoseconds / nanosecondsInIsoDay) - nanoseconds %= nanosecondsInIsoDay - */ - // return [isoTimeFields, dayDelta] +function epochNanoToMicroFloor(epochNano) { + return epochNanoToMilli(epochNano)[0] } -// does floor -export function epochNanoToSec(epochNano) { - let epochSec = epochNano.div(nanosecondsInSecond).toNumber() // does truncation - let subsecNano = epochNano.sub(createLargeInt(epochSec).mult(nanosecondsInSecond)).toNumber() +// nano -> * (with remainder) - if (subsecNano < 0) { - epochSec-- - subsecNano += nanosecondsInSecond - } +export function epochNanoToUtcDays(epochNano) { + // TODO: use seconds instead? + const [epochMilli, nanoRemainder] = epochNanoToMilli(epochNano) + const days = Math.floor(epochMilli / millInUtcDay) + const milliRemainder = positiveModulo(epochMilli, millInUtcDay) - return [epochSec, subsecNano] + return [ + days, + milliRemainder * nanoInMilli + nanoRemainder, + ] } -export function epochNanoToIsoFields() { +export function epochNanoToSec(epochNano) { + return epochNano.shift(9) } -export function isoToUtcEpochNanoseconds(isoDateTimeFields) { +export function epochNanoToMilli(epochNano) { + return epochNano.shift(6) } -export function isoFieldsToEpochNano(isoDateTimeFields) { - // if result is out-of-bounds, will return null or undefined? - // NOTE: caller should always check result +export function epochNanoToMicro(epochNano) { + const [epochMilli, nanoRemainder] = epochNanoToMilli(epochNano) + + return [ + createLargeInt(epochMilli).mult(nanoInMicro), + nanoRemainder * nanoInMicro, + ] } -export function isoTimeToNanoseconds(isoTimeFields) { +// * -> nano + +export function epochSecToNano(epochSec) { + return createLargeInt(epochSec).mult(nanoInSec) } -export function nanosecondsToTimeDuration(nanoseconds) { // nanoseconds is a number - // returns an (incomplete?) Duration? - // good idea to put here? +export function epochMilliToNano(epochMilli) { + return createLargeInt(epochMilli).mult(nanoInMilli) } -export function epochNanosecondsToIso(epochNanoseconds, timeZone) { +export function epochMicroToNano(epochMicro) { + return epochMicro.mult(nanoInMicro) } -export function compareIsoFields() { - // uses Date.UTC +// Epoch Getters +// ------------------------------------------------------------------------------------------------- + +export const epochGetters = { + epochSeconds: epochNanoToSecFloor, + + epochMilliseconds: epochNanoToMilliFloor, + + epochMicroseconds(epochNano) { + return epochNanoToMicroFloor(epochNano).toBigInt() + }, + + epochNanoseconds(epochNano) { + return epochNano.toBigInt() + }, } -export function compareIsoTimeFields() { - // uses conversion to milliseconds +// Validation +// ------------------------------------------------------------------------------------------------- + +const epochNanoMax = createLargeInt(nanoInUtcDay).mult(100000000) // inclusive +const epochNanoMin = createLargeInt.mult(-1) // inclusive +const isoYearMax = 275760 // shortcut. isoYear at epochNanoMax +const isoYearMin = -271821 // shortcut. isoYear at epochNanoMin + +function validateIsoDateTimeInternals(isoDateTimeInternals) { // validateIsoInternals? + const { isoYear } = isoDateTimeInternals + clamp(isoYear, isoYearMin, isoYearMax) // TODO: must error! + + const nudge = isoYear === isoYearMin ? 1 : isoYear === isoYearMax ? -1 : 0 + + if (nudge) { + const epochNano = isoToEpochNano(isoDateTimeInternals) + validateEpochNano(epochNano && epochNano.add((nanoInUtcDay - 1) * nudge)) + } + + return isoDateTimeInternals } -export function addDaysToIsoFields() { - // short-circuit if nothing to add +export function validateEpochNano(epochNano) { + if ( + epochNano == null || // TODO: pick null or undefined + compareLargeInts(epochNano, epochNanoMin) === 1 || // epochNano < epochNanoMin + compareLargeInts(epochNanoMax, epochNano) === 1 // epochNanoMax < epochNano + ) { + throw new RangeError('aahh') + } + return epochNano } -export const milliInSec = 1000 -export const nanoInMicro = 1000 -export const nanoInMilli = 1000 -export const secInDay = 86400 +// ISO <-> Epoch Conversion +// ------------------------------------------------------------------------------------------------- -export function isoToEpochSec(...args) { // doesn't accept beyond sec - return isoToEpochMilli(...args) / milliInSec // no need for rounding -} +// ISO Fields -> Epoch +// (could be out-of-bounds, return undefined!) -export function isoFieldsToEpochSec(isoDateTimeFields) { - const epochSec = isoToEpochSec( +export function isoToEpochSec(isoDateTimeFields) { + const epochSec = isoArgsToEpochSec( isoDateTimeFields.year, isoDateTimeFields.month, isoDateTimeFields.day, @@ -183,3 +230,71 @@ export function isoFieldsToEpochSec(isoDateTimeFields) { return [epochSec, subsecNano] } + +export function isoToEpochMilli(isoDateTimeFields) { + return isoArgsToEpochMilli(...pluckIsoDateTimeFields(isoDateTimeFields)) +} + +export function isoToEpochNano(isoDateTimeFields) { +} + +// ISO Arguments -> Epoch +// (could be out-of-bounds, return undefined!) + +export function isoArgsToEpochSec(...args) { // doesn't accept beyond sec + return isoArgsToEpochMilli(...args) / milliInSec // no need for rounding +} + +export function isoArgsToEpochMilli( + isoYear, + isoMonth = 1, + isoDate, // rest are optional... + isoHour, + isMinute, + isoSec, + isoMilli, +) { +} + +function isoToLegacyDate(isoDateTimeFields) { +} + +// Epoch -> ISO Fields + +export function epochNanoToIso() { +} + +export function epochMilliToIso() { +} + +// Comparison +// ------------------------------------------------------------------------------------------------- + +export function compareIsoDateTimeFields() { + // TODO: (use Math.sign technique?) +} + +export function compareIsoTimeFields() { +} + +// ISO Time +// ------------------------------------------------------------------------------------------------- + +export function isoTimeFieldsToNano(isoTimeFields) { +} + +export function nanoToIsoTimeFields() { + /* + const dayDelta = Math.floor(nanoseconds / nanosecondsInIsoDay) + nanoseconds %= nanosecondsInIsoDay + */ + // return [isoTimeFields, dayDelta] +} + +// Duration +// ------------------------------------------------------------------------------------------------- + +export function nanosecondsToTimeDuration(nanoseconds) { // nanoseconds is a number + // returns an (incomplete?) Duration? + // good idea to put here? +} diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index 7ee7edc6..ea7eb930 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -1,13 +1,15 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { - constrainIsoDateInternals, - constrainIsoDateTimeInternals, - constrainIsoTimeFields, pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields, } from './isoFields' +import { + constrainIsoDateInternals, + constrainIsoDateTimeInternals, + constrainIsoTimeFields, +} from './isoMath' import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js index c35a5937..950e9d3a 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -2,7 +2,7 @@ export const LargeInt = null export function createLargeInt() { - + // always from number (right?) } export function toLargeInt() { @@ -12,3 +12,14 @@ export function toLargeInt() { export function compareLargeInts() { } + +/* +div() { + // rethink the need for this! only ever used for converting to well-known units + // epochNano -> epoch[Sec/Milli/Micro] + // just need to convert to Milli, the rest is easy + + INSTEAD + .shift(n) -> [number, number] +} +*/ diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 88e23085..6691de53 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -4,12 +4,17 @@ import { durationTimeFieldsToIso, } from './durationFields' import { - epochNanosecondsToIso, isoMonthsInYear, - isoTimeFieldsToNanoseconds, - nanosecondsToIsoTimeFields, + isoTimeFieldsToNano, + nanoToIsoTimeFields, } from './isoMath' -import { getSingleInstantFor } from './timeZoneOps' +import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' + +export function addDaysMilli(epochMilli, milli) { // moveEpochMilliByDays +} +export function addDaysToIsoFields() { + // short-circuit if nothing to add +} export function moveEpochNanoseconds(epochNanoseconds, durationFields) { return epochNanoseconds.add(onlyDurationTimeFieldsToIso(durationFields)) @@ -22,14 +27,14 @@ export function moveZonedEpochNanoseconds( durationFields, overflowHandling, ) { - const durationTimeNanoseconds = isoTimeFieldsToNanoseconds( + const durationTimeNanoseconds = isoTimeFieldsToNano( durationTimeFieldsToIso(durationFields), ) if (!durationHasDateParts(durationFields)) { epochNanoseconds = epochNanoseconds.add(durationTimeNanoseconds) } else { - const isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds, timeZone) + const isoDateTimeFields = zonedEpochNanoToIso(timeZone, epochNanoseconds) const movedIsoDateFields = calendar.dateAdd( isoDateTimeFields, { @@ -127,9 +132,9 @@ export function addIntlMonths(year, month, monthDelta, calendarImpl) { // ------------------------------------------------------------------------------------------------- function addIsoTimeFields(isoTimeFields0, isoTimeFields1) { - return nanosecondsToIsoTimeFields( // returns [movedIsoTimeFields, dayDelta] - isoTimeFieldsToNanoseconds(isoTimeFields0) + - isoTimeFieldsToNanoseconds(isoTimeFields1), + return nanoToIsoTimeFields( // returns [movedIsoTimeFields, dayDelta] + isoTimeFieldsToNano(isoTimeFields0) + + isoTimeFieldsToNano(isoTimeFields1), ) } diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index 1fccc11a..6fd972db 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -1,5 +1,4 @@ import { nanoInMilli } from '../dateUtils/units' -import { zonedDateTimeInternalsToIso } from './bag' import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { createInstant } from './instant' @@ -9,7 +8,7 @@ import { createLargeInt } from './largeInt' import { createPlainDate } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime } from './plainTime' -import { queryTimeZoneOps } from './timeZoneOps' +import { queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' import { createPropDescriptors, createTemporalNameDescriptors } from './util' import { createZonedDateTime } from './zonedDateTime' @@ -58,7 +57,7 @@ function getCurrentInstant() { function getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg) { return pluckIsoDateTimeInternals( - zonedDateTimeInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)), + zonedInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)), ) } diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 85926acf..1c75ae0f 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -4,7 +4,6 @@ import { dateToPlainMonthDay, dateToPlainYearMonth, plainDateWithBag, - zonedDateTimeInternalsToIso, } from './bag' import { isoCalendarId } from './calendarConfig' import { dateGetters } from './calendarFields' @@ -24,11 +23,12 @@ import { refineIsoDateInternals, } from './isoFields' import { formatCalendar, formatIsoDateFields } from './isoFormat' -import { compareIsoFields } from './isoMath' +import { compareIsoDateTimeFields } from './isoMath' import { stringToPlainDateInternals } from './isoParse' import { optionsToOverflow } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' +import { zonedInternalsToIso } from './timeZoneOps' import { isIdPropsEqual } from './util' export const [ @@ -55,7 +55,7 @@ export const [ { PlainDateTime: pluckIsoDateInternals, ZonedDateTime(argInternals) { - return pluckIsoDateInternals(zonedDateTimeInternalsToIso(argInternals)) + return pluckIsoDateInternals(zonedInternalsToIso(argInternals)) }, }, @@ -118,7 +118,7 @@ export const [ equals(internals, other) { const otherInternals = toPlainDateInternals(other) - return !compareIsoFields(internals, otherInternals) && + return !compareIsoDateTimeFields(internals, otherInternals) && isIdPropsEqual(internals.calendar, otherInternals.calendar) }, @@ -160,7 +160,7 @@ export const [ { compare(arg0, arg1) { - return compareIsoFields( + return compareIsoDateTimeFields( toPlainDateInternals(arg0), toPlainDateInternals(arg1), ) diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 83bc61d5..ce316b1a 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -3,7 +3,6 @@ import { dateToPlainMonthDay, dateToPlainYearMonth, plainDateTimeWithBag, - zonedDateTimeInternalsToIso, } from './bag' import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' @@ -21,7 +20,7 @@ import { refineIsoDateTimeInternals, } from './isoFields' import { formatCalendar, formatIsoDateTimeFields } from './isoFormat' -import { compareIsoFields } from './isoMath' +import { compareIsoDateTimeFields } from './isoMath' import { stringToPlainDateTimeInternals } from './isoParse' import { moveDateTime } from './move' import { @@ -32,7 +31,7 @@ import { import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' -import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' import { isIdPropsEqual } from './util' import { createZonedDateTime } from './zonedDateTime' @@ -77,7 +76,7 @@ export const [ { PlainDate: (argInternals) => ({ ...argInternals, ...isoTimeFieldDefaults }), ZonedDateTime: (argInternals) => { - return pluckIsoDateTimeInternals(zonedDateTimeInternalsToIso(argInternals)) + return pluckIsoDateTimeInternals(zonedInternalsToIso(argInternals)) }, }, @@ -175,7 +174,7 @@ export const [ equals(internals, other) { const otherInternals = toPlainDateTimeInternals(other) - return !compareIsoFields(internals, otherInternals) && + return !compareIsoDateTimeFields(internals, otherInternals) && isIdPropsEqual(internals.calendar, otherInternals.calendar) }, @@ -231,7 +230,7 @@ export const [ { compare(arg0, arg1) { - return compareIsoFields( + return compareIsoDateTimeFields( toPlainDateTimeInternals(arg0), toPlainDateTimeInternals(arg1), ) diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 39d1a201..0b8ed8b1 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -9,7 +9,7 @@ import { getPublicCalendar } from './calendarOps' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' -import { compareIsoFields, isoEpochFirstLeapYear } from './isoMath' +import { compareIsoDateTimeFields, isoEpochFirstLeapYear } from './isoMath' import { stringToMonthDayInternals } from './isoParse' import { optionsToOverflow } from './options' import { isIdPropsEqual } from './util' @@ -61,7 +61,7 @@ export const [ equals(internals, otherArg) { const otherInternals = toPlainMonthDayInternals(otherArg) - return !compareIsoFields(internals, otherInternals) && + return !compareIsoDateTimeFields(internals, otherInternals) && isIdPropsEqual(internals.calendar, otherInternals.calendar) }, diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index f4bdd0ca..7201e72c 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -2,7 +2,6 @@ import { bagToPlainTimeInternals, createZonedDateTimeConverter, plainTimeWithBag, - zonedDateTimeInternalsToIso, } from './bag' import { timeGetters } from './calendarFields' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' @@ -18,6 +17,7 @@ import { optionsToOverflow } from './options' import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' +import { zonedInternalsToIso } from './timeZoneOps' export const [ PlainTime, @@ -52,7 +52,7 @@ export const [ { PlainDateTime: pluckIsoTimeFields, ZonedDateTime(argInternals) { - return pluckIsoTimeFields(zonedDateTimeInternalsToIso(argInternals)) + return pluckIsoTimeFields(zonedInternalsToIso(argInternals)) }, }, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index c45b5e38..9fe39e29 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -13,7 +13,7 @@ import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' -import { compareIsoFields } from './isoMath' +import { compareIsoDateTimeFields } from './isoMath' import { stringToPlainYearMonthInternals } from './isoParse' import { optionsToOverflow } from './options' import { isIdPropsEqual } from './util' @@ -107,7 +107,7 @@ export const [ equals(internals, otherArg) { const otherInternals = toPlainYearMonthInternals(otherArg) - return !compareIsoFields(internals, otherInternals) && + return !compareIsoDateTimeFields(internals, otherInternals) && isIdPropsEqual(internals.calendar, otherInternals.calendar) }, @@ -133,7 +133,7 @@ export const [ { compare(arg0, arg1) { - return compareIsoFields( + return compareIsoDateTimeFields( toPlainYearMonthInternals(arg0), toPlainYearMonthInternals(arg1), ) diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 59ce1e4e..117f99b9 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -1,13 +1,14 @@ import { durationFieldDefaults, durationTimeFieldDefaults } from './durationFields' import { isoTimeFieldDefaults } from './isoFields' import { - addDaysToIsoFields, - isoTimeFieldsToNanoseconds, - nanosecondsInIsoDay, + epochNanoToUtcDays, + isoTimeFieldsToNano, + nanoInUtcDay, + nanoToIsoTimeFields, nanosecondsInUnit, - nanosecondsToIsoTimeFields, } from './isoMath' import { createLargeInt } from './largeInt' +import { addDaysToIsoFields } from './move' import { computeNanosecondsInDay } from './timeZoneOps' import { identityFunc } from './util' @@ -31,10 +32,10 @@ export function roundIsoDateTimeFields( if (smallestUnit === 'day') { const nanosecondsInDay = timeZoneOps ? computeNanosecondsInDay(timeZoneOps, isoDateTimeFields) - : nanosecondsInIsoDay + : nanoInUtcDay dayDelta = roundNanoseconds( - isoTimeFieldsToNanoseconds(isoDateTimeFields), + isoTimeFieldsToNano(isoDateTimeFields), nanosecondsInDay, roundingMode, ) @@ -62,11 +63,11 @@ export function roundIsoTimeFields( roundingIncrement, ) { const nanoseconds = roundNanoseconds( - isoTimeFieldsToNanoseconds(isoTimeFields), + isoTimeFieldsToNano(isoTimeFields), nanosecondsInUnit[smallestUnit] * roundingIncrement, roundingMode, ) - return nanosecondsToIsoTimeFields(nanoseconds) + return nanoToIsoTimeFields(nanoseconds) } // Rounding Duration @@ -143,7 +144,7 @@ export function roundLargeNanoseconds( roundingMode, roundingIncrement, ) { - let [timeNanoseconds, days] = splitDayTimeNanoseconds(largeNanoseconds) + let [days, timeNanoseconds] = epochNanoToUtcDays(largeNanoseconds) timeNanoseconds = roundNanoseconds( timeNanoseconds, @@ -151,17 +152,10 @@ export function roundLargeNanoseconds( roundingMode, ) - const dayDelta = Math.trunc(timeNanoseconds / nanosecondsInIsoDay) - timeNanoseconds %= nanosecondsInIsoDay + const dayDelta = Math.trunc(timeNanoseconds / nanoInUtcDay) + timeNanoseconds %= nanoInUtcDay - return createLargeInt(nanosecondsInIsoDay).mult(days + dayDelta).add(timeNanoseconds) -} - -function splitDayTimeNanoseconds(largeNanoseconds) { - const days = largeNanoseconds.div(nanosecondsInIsoDay) - const dayNanoseconds = createLargeInt(nanosecondsInIsoDay).mult(days) - const timeNanoseconds = largeNanoseconds.sub(dayNanoseconds) - return [timeNanoseconds, days] + return createLargeInt(nanoInUtcDay).mult(days + dayDelta).add(timeNanoseconds) } function roundNanoseconds(num, nanoIncrement, roundingMode) { diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 7a75a296..75bd9cbc 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -5,11 +5,10 @@ import { queryCalendarOps } from './calendarOps' import { createTemporalClass, internalIdGetters, returnId } from './class' import { createInstant, toInstantEpochNanoseconds } from './instant' import { formatOffsetNanoseconds } from './isoFormat' -import { epochNanosecondsToIso } from './isoMath' import { stringToTimeZoneId } from './isoParse' import { toDisambiguation } from './options' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' -import { getSingleInstantFor } from './timeZoneOps' +import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { noop } from './util' export const [TimeZone, createTimeZone] = createTemporalClass( @@ -50,10 +49,9 @@ export const [TimeZone, createTimeZone] = createTemporalClass( getPlainDateTimeFor(impl, instantArg, calendarArg) { const epochNanoseconds = toInstantEpochNanoseconds(instantArg) - const offsetNanoseconds = impl.getOffsetNanosecondsFor(impl, epochNanoseconds) return createPlainDateTime({ - ...epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)), + ...zonedEpochNanoToIso(impl, epochNanoseconds), calendar: queryCalendarOps(calendarArg), }) }, diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index 624ac012..040e03c7 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -4,18 +4,19 @@ import { parseIntlYear } from './calendarImpl' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' import { epochNanoToSec, + epochNanoToSecFloor, epochSecToNano, - isoFieldsToEpochNano, - isoFieldsToEpochSec, + isoToEpochNano, isoToEpochSec, - milliInSec, nanosecondsInSecond, secInDay, + isoArgsToEpochSec, + milliInSec, nanoInSec, secInDay, } from './isoMath' import { parseOffsetNanoseconds } from './isoParse' import { clamp, compareNumbers, createLazyMap } from './util' const periodDur = secInDay * 60 -const minPossibleTransition = isoToEpochSec(1847) -const maxPossibleTransition = isoToEpochSec(new Date().getUTCFullYear() + 10) +const minPossibleTransition = isoArgsToEpochSec(1847) +const maxPossibleTransition = isoArgsToEpochSec(new Date().getUTCFullYear() + 10) const intlTimeZoneImplCache = {} @@ -45,7 +46,7 @@ export class FixedTimeZoneImpl { } getPossibleInstantsFor(isoDateTimeFields) { - return [isoFieldsToEpochNano(isoDateTimeFields).add(this.offsetNano)] + return [isoToEpochNano(isoDateTimeFields).add(this.offsetNano)] } getTransition(epochNano, direction) { @@ -63,12 +64,11 @@ export class IntlTimeZoneImpl { } getOffsetNanosecondsFor(epochNano) { - const [epochSec] = epochNanoToSec(epochNano) - return this.store.getOffsetSec(epochSec) * nanosecondsInSecond + return this.store.getOffsetSec(epochNanoToSecFloor(epochNano)) * nanoInSec } getPossibleInstantsFor(isoDateTimeFields) { - const [zonedEpochSec, subsecNano] = isoFieldsToEpochSec(isoDateTimeFields) + const [zonedEpochSec, subsecNano] = isoToEpochSec(isoDateTimeFields) return this.store.getPossibleEpochSec(zonedEpochSec) .map((epochSec) => epochSecToNano(epochSec).add(subsecNano)) } @@ -211,7 +211,7 @@ function createComputeOffsetSec(timeZoneId) { return (epochSec) => { const intlParts = hashIntlFormatParts(format, epochSec * milliInSec) - const zonedEpochSec = isoToEpochSec( + const zonedEpochSec = isoArgsToEpochSec( parseIntlYear(intlParts).year, parseInt(intlParts.month), parseInt(intlParts.day), diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index 559bd1ae..553a7f2f 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -8,16 +8,17 @@ import { import { Instant, createInstant } from './instant' import { isoTimeFieldDefaults } from './isoFields' import { - addDaysToIsoFields, - epochNanoToIsoFields, - isoFieldsToEpochNano, - nanosecondsInIsoDay, + epochNanoToIso, + isoToEpochNano, + nanoInUtcDay, } from './isoMath' +import { addDaysToIsoFields } from './move' import { strictArray, strictNumber } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' import { createTimeZone } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' +import { createLazyMap } from './util' export const utcTimeZoneId = 'UTC' @@ -64,7 +65,7 @@ export function getMatchingInstantFor( if (offsetNano !== undefined && offsetHandling !== 'ignore') { // we ALWAYS use Z as a zero offset if (offsetHandling === 'use' || hasZ) { - return isoFieldsToEpochNano(isoDateTimeFields).sub(offsetNano) + return isoToEpochNano(isoDateTimeFields).sub(offsetNano) } const matchingEpochNano = findMatchingEpochNano( @@ -89,7 +90,7 @@ export function getMatchingInstantFor( function findMatchingEpochNano(timeZoneOps, isoDateTimeFields, offsetNano, fuzzy) { const possibleEpochNanos = timeZoneOps.getPossibleInstantsFor(isoDateTimeFields) - const zonedEpochNano = isoFieldsToEpochNano(isoDateTimeFields) + const zonedEpochNano = isoToEpochNano(isoDateTimeFields) if (fuzzy) { offsetNano = roundToMinute(offsetNano) @@ -136,11 +137,11 @@ export function getSingleInstantFor( // within a transition that jumps forward... // ('compatible' means 'later') - const zonedEpochNano = isoFieldsToEpochNano(isoDateTimeFields) + const zonedEpochNano = isoToEpochNano(isoDateTimeFields) const gapNano = computeGapNear(timeZoneOps, zonedEpochNano) epochNanos = timeZoneOps.getPossibleInstantsFor( - epochNanoToIsoFields( + epochNanoToIso( zonedEpochNano.add(gapNano * ( disambig === 'earlier' ? -1 @@ -158,14 +159,30 @@ export function getSingleInstantFor( function computeGapNear(timeZoneOps, zonedEpochNano) { const startOffsetNano = timeZoneOps.getOffsetNanosecondsFor( - zonedEpochNano.add(-nanosecondsInIsoDay), + zonedEpochNano.add(-nanoInUtcDay), ) const endOffsetNano = timeZoneOps.getOffsetNanosecondsFor( - zonedEpochNano.add(nanosecondsInIsoDay), + zonedEpochNano.add(nanoInUtcDay), ) return endOffsetNano - startOffsetNano } +export const zonedInternalsToIso = createLazyMap((internals) => { + const { timeZone, epochNanoseconds } = internals + const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) + const isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) + + return { + ...isoDateTimeFields, + offsetNanoseconds, + } +}) + +export function zonedEpochNanoToIso(timeZoneOps, epochNano) { + const offsetNano = timeZoneOps.getOffsetNanosecondsFor(epochNano) + return epochNanoToIso(epochNano.add(offsetNano)) +} + // Adapter // ------- @@ -188,7 +205,7 @@ export const TimeZoneOpsAdapter = createWrapperClass( function validateOffsetNano(offsetNano) { offsetNano = strictNumber(offsetNano) - if (Math.abs(offsetNano) >= nanosecondsInIsoDay) { + if (Math.abs(offsetNano) >= nanoInUtcDay) { throw new RangeError('out of range') } diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index af86361a..467a076c 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -3,6 +3,8 @@ // always prefer [...a] over [].concat(a) +// monitor use of floor/trunc and modding. many are wrong + export function isObjectLike() { } @@ -18,6 +20,7 @@ export function mapArrayToProps() { // propNameToProps } export function remapProps(obj, oldKeys, newKeys) { + // TODO: put key args in front so can use bind? } export function pluckProps(propNames, obj) { diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index c1c64993..6c1d6760 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -2,7 +2,6 @@ import { bagToZonedDateTimeInternals, dateToPlainMonthDay, dateToPlainYearMonth, - zonedDateTimeInternalsToIso, zonedDateTimeWithBag, } from './bag' import { dateTimeGetters } from './calendarFields' @@ -19,7 +18,6 @@ import { pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields, - validateEpochNano, } from './isoFields' import { formatCalendar, @@ -27,7 +25,12 @@ import { formatOffsetNanoseconds, formatTimeZone, } from './isoFormat' -import { epochGetters, epochNanosecondsToIso, nanosecondsInHour } from './isoMath' +import { + epochGetters, + epochNanoToIso, + nanoInHour, + validateEpochNano, +} from './isoMath' import { stringToZonedDateTimeInternals } from './isoParse' import { compareLargeInts, toLargeInt } from './largeInt' import { moveZonedEpochNanoseconds } from './move' @@ -42,6 +45,7 @@ import { getMatchingInstantFor, getPublicTimeZone, queryTimeZoneOps, + zonedInternalsToIso, } from './timeZoneOps' import { isIdPropsEqual, mapProps } from './util' @@ -88,27 +92,27 @@ export const [ ...mapProps(dateTimeGetters, (getter) => { return function(internals) { - return getter(zonedDateTimeInternalsToIso(internals)) + return getter(zonedInternalsToIso(internals)) } }), hoursInDay(internals) { return computeNanosecondsInDay( internals.timeZone, - zonedDateTimeInternalsToIso(internals), - ) / nanosecondsInHour + zonedInternalsToIso(internals), + ) / nanoInHour }, // TODO: make this a getter? offsetNanoseconds(internals) { // TODO: more DRY - return zonedDateTimeInternalsToIso(internals).offsetNanoseconds + return zonedInternalsToIso(internals).offsetNanoseconds }, offset(internals) { return formatOffsetNanoseconds( // TODO: more DRY - zonedDateTimeInternalsToIso(internals).offsetNanoseconds, + zonedInternalsToIso(internals).offsetNanoseconds, ) }, }, @@ -124,7 +128,7 @@ export const [ withPlainTime(internals, plainTimeArg) { const { calendar, timeZone } = internals const isoFields = { - ...zonedDateTimeInternalsToIso(internals), + ...zonedInternalsToIso(internals), ...toPlainTimeInternals(plainTimeArg), } @@ -149,7 +153,7 @@ export const [ withPlainDate(internals, plainDateArg) { const { calendar, timeZone } = internals const isoFields = { - ...zonedDateTimeInternalsToIso(internals), + ...zonedInternalsToIso(internals), ...toPlainDateInternals(plainDateArg), } @@ -230,7 +234,7 @@ export const [ let { epochNanoseconds, timeZone, calendar } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - let isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + let isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) isoDateTimeFields = roundIsoDateTimeFields( isoDateTimeFields, @@ -258,7 +262,7 @@ export const [ let { epochNanoseconds, timeZone, calendar } = internals const isoFields = { - ...zonedDateTimeInternalsToIso(internals), + ...zonedInternalsToIso(internals), ...isoTimeFieldDefaults, } @@ -293,7 +297,7 @@ export const [ // TODO: don't let options be accessed twice! once by rounding, twice by formatting let offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - let isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + let isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) isoDateTimeFields = roundIsoDateTimeFields( isoDateTimeFields, @@ -310,8 +314,9 @@ export const [ true, // fuzzy ) + // waa? non-dry code? offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - isoDateTimeFields = epochNanosecondsToIso(epochNanoseconds.add(offsetNanoseconds)) + isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) return formatIsoDateTimeFields(isoDateTimeFields, options) + formatOffsetNanoseconds(offsetNanoseconds) + @@ -331,15 +336,15 @@ export const [ }, toPlainDate(internals) { - return createPlainDate(pluckIsoDateInternals(zonedDateTimeInternalsToIso(internals))) + return createPlainDate(pluckIsoDateInternals(zonedInternalsToIso(internals))) }, toPlainTime(internals) { - return createPlainTime(pluckIsoTimeFields(zonedDateTimeInternalsToIso(internals))) + return createPlainTime(pluckIsoTimeFields(zonedInternalsToIso(internals))) }, toPlainDateTime(internals) { - return createPlainDateTime(pluckIsoDateTimeInternals(zonedDateTimeInternalsToIso(internals))) + return createPlainDateTime(pluckIsoDateTimeInternals(zonedInternalsToIso(internals))) }, toPlainYearMonth() { @@ -354,10 +359,10 @@ export const [ return { // maintain alphabetical order calendar: getPublicIdOrObj(internals.calendar), - ...pluckIsoDateTimeInternals(zonedDateTimeInternalsToIso(internals)), + ...pluckIsoDateTimeInternals(zonedInternalsToIso(internals)), offset: formatOffsetNanoseconds( // TODO: more DRY - zonedDateTimeInternalsToIso(internals).offsetNanoseconds, + zonedInternalsToIso(internals).offsetNanoseconds, ), timeZone: getPublicIdOrObj(internals.timeZone), } From 414cfd83bf6fa150fff76d1fe19c49a0854f809e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 6 Jun 2023 14:59:31 -0400 Subject: [PATCH 085/805] proper bigint math --- .../temporal-polyfill/src/new/calendarImpl.js | 2 +- packages/temporal-polyfill/src/new/instant.js | 10 +-- .../temporal-polyfill/src/new/intlFormat.js | 6 +- packages/temporal-polyfill/src/new/isoMath.js | 60 ++++++---------- .../temporal-polyfill/src/new/largeInt.js | 70 ++++++++++++++----- packages/temporal-polyfill/src/new/now.js | 4 +- packages/temporal-polyfill/src/new/options.js | 9 +++ packages/temporal-polyfill/src/new/round.js | 8 +-- .../temporal-polyfill/src/new/timeZoneImpl.js | 8 +-- packages/temporal-polyfill/src/new/util.js | 20 ++++-- .../src/new/zonedDateTime.js | 8 +-- 11 files changed, 124 insertions(+), 81 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 7fd4b9e7..c30d3ce5 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -34,11 +34,11 @@ import { computeIsoWeekOfYear, computeIsoYearOfWeek, epochMilliToIso, + isoArgsToEpochMilli, isoDaysInWeek, isoEpochFirstLeapYear, isoEpochOriginYear, isoToEpochMilli, - isoArgsToEpochMilli, } from './isoMath' import { addDaysMilli, addIntlMonths, addIsoMonths } from './move' import { constrainInt } from './options' diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 690296cc..765a811c 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -18,9 +18,9 @@ import { epochSecToNano, validateEpochNano, } from './isoMath' -import { compareLargeInts, toLargeInt } from './largeInt' +import { compareLargeInts } from './largeInt' import { moveEpochNanoseconds } from './move' -import { toObject } from './options' +import { toEpochNano, toObject } from './options' import { roundLargeNanoseconds } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { noop } from './util' @@ -38,7 +38,7 @@ export const [ // constructorToInternals (epochNanoseconds) => { - return validateEpochNano(toLargeInt(epochNanoseconds)) // TODO: strictly BigInt + return validateEpochNano(toEpochNano(epochNanoseconds)) }, // internalsConversionMap @@ -168,11 +168,11 @@ export const [ fromEpochMilliseconds: epochMilliToInstant, fromEpochMicroseconds(epochMicro) { - return epochMicroToInstant(toLargeInt(epochMicro)) + return epochMicroToInstant(toEpochNano(epochMicro)) }, fromEpochNanoseconds(epochNanoseconds) { - return createInstant(toLargeInt(epochNanoseconds)) + return createInstant(toEpochNano(epochNanoseconds)) }, }, ) diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index 0fc26754..6e04668c 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' import { dateBasicNames, timeFieldDefaults } from './calendarFields' import { getInternals, getTemporalName } from './class' -import { epochNanoToMilliFloor, isoEpochOriginYear } from './isoMath' +import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createLazyMap, @@ -127,7 +127,7 @@ export function resolveZonedFormattable( ) return [ - epochNanoToMilliFloor(internals.epochNanoseconds), + epochNanoToMilli(internals.epochNanoseconds), format, ] } @@ -145,7 +145,7 @@ function resolveFormattable( const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) return [ - epochNanoToMilliFloor(epochNano), + epochNanoToMilli(epochNano), getSpecificFormat(transformOptions, resolvedOptions), ] } diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 0c3c815b..c00c898e 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,6 +1,6 @@ import { pluckIsoDateTimeFields } from './isoFields' -import { compareLargeInts, createLargeInt } from './largeInt' -import { clamp, positiveModulo } from './util' +import { compareLargeInts, numberToLargeInt } from './largeInt' +import { clamp } from './util' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -83,7 +83,6 @@ export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { // ------------------------------------------------------------------------------------------------- export const secInDay = 86400 -const millInUtcDay = 86400000 export const milliInSec = 1000 export const nanoInMicro = 1000 // consolidate with other 1000 units @@ -101,57 +100,44 @@ export const nanosecondsInUnit = { // nano -> * (with floor) -export function epochNanoToSecFloor(epochNano) { - return epochNanoToSec(epochNano)[0] +export function epochNanoToSec(epochNano) { + return epochNanoToSecMod(epochNano)[0] } -export function epochNanoToMilliFloor(epochNano) { - return epochNanoToMicro(epochNano)[0] +export function epochNanoToMilli(epochNano) { + return epochNanoToMilliMod(epochNano)[0] } -function epochNanoToMicroFloor(epochNano) { - return epochNanoToMilli(epochNano)[0] +function epochNanoToMicro(epochNano) { + return epochNanoToMicroMod(epochNano)[0] } // nano -> * (with remainder) -export function epochNanoToUtcDays(epochNano) { - // TODO: use seconds instead? - const [epochMilli, nanoRemainder] = epochNanoToMilli(epochNano) - const days = Math.floor(epochMilli / millInUtcDay) - const milliRemainder = positiveModulo(epochMilli, millInUtcDay) - - return [ - days, - milliRemainder * nanoInMilli + nanoRemainder, - ] +export function epochNanoToUtcDaysMod(epochNano) { + return epochNano.divMod(nanoInUtcDay) } -export function epochNanoToSec(epochNano) { - return epochNano.shift(9) +export function epochNanoToSecMod(epochNano) { + return epochNano.divMod(nanoInSec) } -export function epochNanoToMilli(epochNano) { - return epochNano.shift(6) +function epochNanoToMilliMod(epochNano) { + return epochNano.divMod(nanoInMilli) } -export function epochNanoToMicro(epochNano) { - const [epochMilli, nanoRemainder] = epochNanoToMilli(epochNano) - - return [ - createLargeInt(epochMilli).mult(nanoInMicro), - nanoRemainder * nanoInMicro, - ] +function epochNanoToMicroMod(epochNano) { + return epochNano.divMod(nanoInMicro, true) // preserveLargeInt=true } // * -> nano export function epochSecToNano(epochSec) { - return createLargeInt(epochSec).mult(nanoInSec) + return numberToLargeInt(epochSec).mult(nanoInSec) } export function epochMilliToNano(epochMilli) { - return createLargeInt(epochMilli).mult(nanoInMilli) + return numberToLargeInt(epochMilli).mult(nanoInMilli) } export function epochMicroToNano(epochMicro) { @@ -162,12 +148,12 @@ export function epochMicroToNano(epochMicro) { // ------------------------------------------------------------------------------------------------- export const epochGetters = { - epochSeconds: epochNanoToSecFloor, + epochSeconds: epochNanoToSec, - epochMilliseconds: epochNanoToMilliFloor, + epochMilliseconds: epochNanoToMilli, epochMicroseconds(epochNano) { - return epochNanoToMicroFloor(epochNano).toBigInt() + return epochNanoToMicro(epochNano).toBigInt() }, epochNanoseconds(epochNano) { @@ -178,8 +164,8 @@ export const epochGetters = { // Validation // ------------------------------------------------------------------------------------------------- -const epochNanoMax = createLargeInt(nanoInUtcDay).mult(100000000) // inclusive -const epochNanoMin = createLargeInt.mult(-1) // inclusive +const epochNanoMax = numberToLargeInt(nanoInUtcDay).mult(100000000) // inclusive +const epochNanoMin = epochNanoMax.mult(-1) // inclusive const isoYearMax = 275760 // shortcut. isoYear at epochNanoMax const isoYearMin = -271821 // shortcut. isoYear at epochNanoMin diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js index 950e9d3a..8548c6eb 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -1,25 +1,61 @@ - -export const LargeInt = null - -export function createLargeInt() { - // always from number (right?) +import { compareNumbers, divMod } from './util' + +const maxLow = 1e8 // exclusive // TODO: explain why +const maxLowBigInt = typeof BigInt !== 'undefined' && BigInt(maxLow) + +export class LargeInt { + constructor(high, low) { + this.high = high + this.low = low + } + + addLargeInt(n) { + return balanceAndCreate(this.high + n.high, this.low + n.low) + } + + add(n) { + return balanceAndCreate(this.high, this.low + n) + } + + mult(multiplier) { + return balanceAndCreate(this.high * multiplier, this.low * multiplier) + } + + divMod(divisor, preserveLargeInt) { + const { high, low } = this + const [newHigh, highRemainder] = divMod(high, divisor) + const [newLow, remainder] = divMod(highRemainder * maxLow + low, divisor) + + return [ + preserveLargeInt + ? balanceAndCreate(newHigh, newLow) + : newHigh * maxLow + newLow, + remainder, + ] + } + + toNumber() { + return this.high * maxLow + this.low + } + + toBigInt() { + return BigInt(this.high) * maxLowBigInt + BigInt(this.low) + } } -export function toLargeInt() { - +function balanceAndCreate(high, low) { + const [extraHigh, newLow] = divMod(low, maxLow) + return new LargeInt(high + extraHigh, newLow) } -export function compareLargeInts() { - +export function numberToLargeInt(n) { + return new LargeInt(...divMod(n, maxLow)) } -/* -div() { - // rethink the need for this! only ever used for converting to well-known units - // epochNano -> epoch[Sec/Milli/Micro] - // just need to convert to Milli, the rest is easy +export function bigIntToLargeInt(n) { + return new LargeInt(...divMod(n, maxLowBigInt).map(Number)) +} - INSTEAD - .shift(n) -> [number, number] +export function compareLargeInts(a, b) { + return compareNumbers(a.high, b.high) || compareNumbers(a.low, b.low) } -*/ diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index 6fd972db..ed0dc136 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -4,7 +4,7 @@ import { queryCalendarOps } from './calendarOps' import { createInstant } from './instant' import { IntlDateTimeFormat } from './intlFormat' import { pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields } from './isoFields' -import { createLargeInt } from './largeInt' +import { numberToLargeInt } from './largeInt' import { createPlainDate } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime } from './plainTime' @@ -73,7 +73,7 @@ function getCurrentZonedDateTimeSlots( } function getCurrentEpochNanoseconds() { - return createLargeInt(Date.now()).mult(nanoInMilli) + return numberToLargeInt(Date.now()).mult(nanoInMilli) } // TimeZone diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index cde4df03..8be831d4 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,6 +1,8 @@ // TODO: for unit parsing, ensure ceiling and correct increment +import { bigIntToLargeInt } from './largeInt' + export function strictNumber(input) { } @@ -21,6 +23,13 @@ export function strictArray() { export function toObject() { } +export function toEpochNano(input) { + if (typeof input !== 'bigint') { + throw new TypeError('aaah') + } + return bigIntToLargeInt(input) +} + export function toNumber(value) { if (typeof value === 'bigint') { throw new TypeError('Cannot convert BigInt to number') diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 117f99b9..62edc8d3 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -1,13 +1,13 @@ import { durationFieldDefaults, durationTimeFieldDefaults } from './durationFields' import { isoTimeFieldDefaults } from './isoFields' import { - epochNanoToUtcDays, + epochNanoToUtcDaysMod, isoTimeFieldsToNano, nanoInUtcDay, nanoToIsoTimeFields, nanosecondsInUnit, } from './isoMath' -import { createLargeInt } from './largeInt' +import { numberToLargeInt } from './largeInt' import { addDaysToIsoFields } from './move' import { computeNanosecondsInDay } from './timeZoneOps' import { identityFunc } from './util' @@ -144,7 +144,7 @@ export function roundLargeNanoseconds( roundingMode, roundingIncrement, ) { - let [days, timeNanoseconds] = epochNanoToUtcDays(largeNanoseconds) + let [days, timeNanoseconds] = epochNanoToUtcDaysMod(largeNanoseconds) timeNanoseconds = roundNanoseconds( timeNanoseconds, @@ -155,7 +155,7 @@ export function roundLargeNanoseconds( const dayDelta = Math.trunc(timeNanoseconds / nanoInUtcDay) timeNanoseconds %= nanoInUtcDay - return createLargeInt(nanoInUtcDay).mult(days + dayDelta).add(timeNanoseconds) + return numberToLargeInt(nanoInUtcDay).mult(days + dayDelta).add(timeNanoseconds) } function roundNanoseconds(num, nanoIncrement, roundingMode) { diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index 040e03c7..450d34f2 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -4,11 +4,11 @@ import { parseIntlYear } from './calendarImpl' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' import { epochNanoToSec, - epochNanoToSecFloor, + epochNanoToSecMod, epochSecToNano, + isoArgsToEpochSec, isoToEpochNano, isoToEpochSec, - isoArgsToEpochSec, milliInSec, nanoInSec, secInDay, } from './isoMath' import { parseOffsetNanoseconds } from './isoParse' @@ -64,7 +64,7 @@ export class IntlTimeZoneImpl { } getOffsetNanosecondsFor(epochNano) { - return this.store.getOffsetSec(epochNanoToSecFloor(epochNano)) * nanoInSec + return this.store.getOffsetSec(epochNanoToSec(epochNano)) * nanoInSec } getPossibleInstantsFor(isoDateTimeFields) { @@ -77,7 +77,7 @@ export class IntlTimeZoneImpl { exclusive for both directions */ getTransition(epochNano, direction) { - const [epochSec, subsecNano] = epochNanoToSec(epochNano) + const [epochSec, subsecNano] = epochNanoToSecMod(epochNano) const resEpochSec = this.store.getTransition( epochSec + ((direction > 0 || subsecNano) ? 1 : 0), direction, diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index 467a076c..5890320f 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -88,10 +88,6 @@ export function identityFunc(thing) { export function noop() { } -export function positiveModulo(n, max) { - return (n % max + max) % max -} - export function twoDigit(num) { // as a string } @@ -103,3 +99,19 @@ export function clamp() { export function isIdPropsEqual(obj0, obj1) { } + +/* +Works with BigInt or Number (as long as the same) +*/ +export function divMod(n, divisor) { + const remainder = floorMod(n, divisor) + const quotient = (n - remainder) / divisor + return [quotient, remainder] +} + +/* +Works with BigInt or Number (as long as the same) +*/ +export function floorMod(n, divisor) { + return (n % divisor + divisor) % divisor +} diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 6c1d6760..816d241a 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -32,9 +32,9 @@ import { validateEpochNano, } from './isoMath' import { stringToZonedDateTimeInternals } from './isoParse' -import { compareLargeInts, toLargeInt } from './largeInt' +import { compareLargeInts } from './largeInt' import { moveZonedEpochNanoseconds } from './move' -import { optionsToOverflow } from './options' +import { optionsToOverflow, toEpochNano } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime, toPlainTimeInternals } from './plainTime' @@ -62,8 +62,8 @@ export const [ // constructorToInternals (epochNanoseconds, timeZoneArg, calendarArg) => { return { - epochNanoseconds: validateEpochNano(toLargeInt(epochNanoseconds)), // TODO: strictly BigInt - timeZone: queryTimeZoneOps(timeZoneArg), + epochNanoseconds: validateEpochNano(toEpochNano(epochNanoseconds)), + timeZone: queryTimeZoneOps(timeZoneArg), // TODO: validate string/object somehow? calendar: queryCalendarOps(calendarArg), } }, From 09e194936ac571511584ff48de4ae2d759616e89 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 6 Jun 2023 18:00:32 -0400 Subject: [PATCH 086/805] rearrange bag utils --- packages/temporal-polyfill/src/new/bag.js | 404 +++++++++--------- .../temporal-polyfill/src/new/calendar.js | 8 +- .../temporal-polyfill/src/new/duration.js | 6 +- .../src/new/durationFields.js | 10 +- .../temporal-polyfill/src/new/plainDate.js | 16 +- .../src/new/plainDateTime.js | 16 +- .../src/new/plainMonthDay.js | 12 +- .../temporal-polyfill/src/new/plainTime.js | 8 +- .../src/new/plainYearMonth.js | 24 +- .../src/new/zonedDateTime.js | 16 +- 10 files changed, 265 insertions(+), 255 deletions(-) diff --git a/packages/temporal-polyfill/src/new/bag.js b/packages/temporal-polyfill/src/new/bag.js index 0bdc3ce4..7a2591dd 100644 --- a/packages/temporal-polyfill/src/new/bag.js +++ b/packages/temporal-polyfill/src/new/bag.js @@ -21,7 +21,7 @@ import { getInternals } from './class' import { durationFieldNames, durationFieldRefiners, - updateDurationFieldSign, + updateDurationFieldsSign, } from './durationFields' import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNanoseconds } from './isoParse' @@ -40,27 +40,12 @@ import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './ import { isObjectLike, pluckProps, removeDuplicateStrings } from './util' import { createZonedDateTime } from './zonedDateTime' -// ahhh: some of these functions return internals, other Plain* objects - -// Duration +// ZonedDateTime // ------------------------------------------------------------------------------------------------- -export function bagToDurationInternals(bag) { - const durationFields = prepareFields(bag, durationFieldNames, []) - return updateDurationFieldSign(durationFields) -} - -export function durationWithBag(durationFields, bag) { - const partialDurationFields = prepareFields(bag, durationFieldNames) - return updateDurationFieldSign({ ...durationFields, ...partialDurationFields }) -} - -// high level yo -// ------------------------------------------------------------------------------------------------- - -export function bagToZonedDateTimeInternals(bag, options) { - const calendarOps = extractCalendarOpsFromBag(bag) - const fields = refineBag( +export function refineZonedDateTimeBag(bag, options) { + const calendarOps = getCalendarOps(bag) + const fields = refineCalendarFields( calendarOps, bag, dateTimeFieldNames, @@ -90,9 +75,9 @@ export function bagToZonedDateTimeInternals(bag, options) { } } -export function zonedDateTimeWithBag(zonedDateTime, bag, options) { +export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { const { calendar, timeZone } = getInternals(zonedDateTime) - const fields = mergeBag(calendar, zonedDateTime, bag, dateTimeFieldNames, ['offset']) + const fields = mergeCalendarFields(calendar, zonedDateTime, bag, dateTimeFieldNames, ['offset']) const overflowHandling = optionsToOverflow(options) const isoDateFields = calendar.dateFromFields(fields, overflowHandling) const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) @@ -107,84 +92,72 @@ export function zonedDateTimeWithBag(zonedDateTime, bag, options) { false, // fuzzy ) - return createZonedDateTime({ + return { epochNanoseconds, timeZone, calendar, - }) -} - -export function bagToPlainMonthDayInternals(bag, options) { - let calendar = extractCalendarFieldFromBag(bag) - let calendarAbsent = !calendar - - if (calendarAbsent) { - calendar = bag.calendar - calendarAbsent = calendar === undefined - calendar = queryCalendarOps(calendarAbsent ? isoCalendarId : calendar) } +} - const fieldNames = calendar.fields(dateFieldNames) - const fields = prepareFields(bag, fieldNames, []) +export function createZonedDateTimeConverter(getAdditionalIsoFields) { + return (internals, options) => { + const refinedOptions = toObject(options) // required!!! + const epochNanoseconds = getSingleInstantFor( + internals.timeZone, + { + ...internals, + ...getAdditionalIsoFields(refinedOptions), + }, + ) - // Callers who omit the calendar are not writing calendar-independent - // code. In that case, `monthCode`/`year` can be omitted; `month` and - // `day` are sufficient. Add a `year` to satisfy calendar validation. - if ( - calendarAbsent && - fields.month !== undefined && - fields.monthCode === undefined && - fields.year === undefined - ) { - fields.year = isoEpochFirstLeapYear + return createZonedDateTime({ + epochNanoseconds, + timeZone: internals.timeZone, + calendar: internals.calendar, + }) } - - return calendar.monthDayFromFields(calendar, fields, optionsToOverflow(options)) } -export function plainMonthDayWithBag(plainMonthDay, bag, options) { - const { calendar } = getInternals(plainMonthDay) - const fields = mergeBag(calendar, plainMonthDay, bag, dateFieldNames) - return calendar.monthDayFromFields(fields, optionsToOverflow(options)) -} +// PlainDateTime +// ------------------------------------------------------------------------------------------------- -export function bagToPlainYearMonthInternals(bag, options) { - const calendarOps = extractCalendarOpsFromBag(bag) - const fields = refineBag( +export function refinePlainDateTimeBag(bag, options) { + const calendarOps = getCalendarOps(bag) + const fields = refineCalendarFields( calendarOps, bag, - yearMonthFieldNames, - getRequiredYearMonthFields(calendarOps), + dateTimeFieldNames, + getRequiredDateFields(calendarOps), ) - return calendarOps.yearMonthFromFields(fields, optionsToOverflow(options)) -} + const overflowHandling = optionsToOverflow(options) + const isoDateInternals = calendarOps.dateFromFields(fields, overflowHandling) + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) -export function plainYearMonthWithBag(plainYearMonth, bag, options) { - const { calendar } = getInternals(plainYearMonth) - const fields = mergeBag(calendar, plainYearMonth, bag, yearMonthFieldNames) - return calendar.yearMonthFromFields(fields, optionsToOverflow(options)) + return { + ...isoDateInternals, + ...isoTimeFields, + } } -export function bagToPlainTimeInternals(bag, options) { - const overflowHandling = toOverflowOptions(options) // TODO: single opt! - const fields = prepareFields(bag, timeFieldNames, []) +export function mergePlainDateTimeBag(plainDate, bag, options) { + const { calendar } = getInternals(plainDate) + const fields = mergeCalendarFields(calendar, plainDate, bag, dateTimeFieldNames) + const overflowHandling = optionsToOverflow(options) + const isoDateInternals = calendar.dateFromFields(fields, overflowHandling) + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) - return constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) + return { + ...isoDateInternals, + ...isoTimeFields, + } } -export function plainTimeWithBag(plainTime, bag, options) { - const fields = pluckProps(timeFieldNames, plainTime) - const additionalFields = prepareFields(bag, timeFieldNames) - const newFields = { ...fields, ...additionalFields } - const overflowHandling = toOverflowOptions(options) // TODO: single opt! - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(newFields), overflowHandling) - - return createPlainTime(isoTimeFields) -} +// PlainDate +// ------------------------------------------------------------------------------------------------- -export function bagToPlainDateSlots(bag, options) { - const calendarOps = extractCalendarOpsFromBag(bag) - const fields = refineBag( +export function refinePlainDateBag(bag, options) { + const calendarOps = getCalendarOps(bag) + const fields = refineCalendarFields( calendarOps, bag, dateFieldNames, @@ -194,52 +167,63 @@ export function bagToPlainDateSlots(bag, options) { return calendarOps.dateFromFields(fields, optionsToOverflow(options)) } -export function plainDateWithBag(plainDate, bag, options) { +export function mergePlainDateBag(plainDate, bag, options) { const { calendar } = getInternals(plainDate) - const fields = mergeBag(calendar, plainDate, bag, dateFieldNames) + const fields = mergeCalendarFields(calendar, plainDate, bag, dateFieldNames) return calendar.dateFromFields(fields, optionsToOverflow(options)) } -export function bagToPlainDateTimeInternals(bag, options) { - const calendarOps = extractCalendarOpsFromBag(bag) - const fields = refineBag( - calendarOps, - bag, - dateTimeFieldNames, - getRequiredDateFields(calendarOps), +function convertToPlainDate( + obj, + objFieldNames, + additionalFields, // bag or obj + additionalFieldNames, +) { + const { calendar } = getInternals(obj) + const receiverFieldNames = calendar.fields(objFieldNames) + const receiverFields = pluckProps(receiverFieldNames, obj) + const inputFieldNames = calendar.fields(additionalFieldNames) + const inputFields = refineFields( + additionalFields, + inputFieldNames, + getRequiredDateFields(calendar), ) - const overflowHandling = optionsToOverflow(options) - const isoDateInternals = calendarOps.dateFromFields(fields, overflowHandling) - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) + const mergedFieldNames = removeDuplicateStrings(receiverFieldNames.concat(inputFieldNames)) + let mergedFields = calendar.mergeFields(receiverFields, inputFields) + mergedFields = refineFields(mergedFields, mergedFieldNames, []) - return { - ...isoDateInternals, - ...isoTimeFields, - } + return createPlainDate({ + ...calendar.dateFromFields(mergedFields, 'reject'), + calendar, + }) } -export function plainDateTimeWithBag(plainDate, bag, options) { - const { calendar } = getInternals(plainDate) - const fields = mergeBag(calendar, plainDate, bag, dateTimeFieldNames) - const overflowHandling = optionsToOverflow(options) - const isoDateInternals = calendar.dateFromFields(fields, overflowHandling) - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) +// PlainYearMonth +// ------------------------------------------------------------------------------------------------- - return { - ...isoDateInternals, - ...isoTimeFields, - } +export function refinePlainYearMonthBag(bag, options) { + const calendarOps = getCalendarOps(bag) + const fields = refineCalendarFields( + calendarOps, + bag, + yearMonthFieldNames, + getRequiredYearMonthFields(calendarOps), + ) + return calendarOps.yearMonthFromFields(fields, optionsToOverflow(options)) } -// to PlainYearMonth/PlainMonthDay -// ------------------------------------------------------------------------------------------------- +export function mergePlainYearMonthBag(plainYearMonth, bag, options) { + const { calendar } = getInternals(plainYearMonth) + const fields = mergeCalendarFields(calendar, plainYearMonth, bag, yearMonthFieldNames) + return calendar.yearMonthFromFields(fields, optionsToOverflow(options)) +} -export function dateToPlainYearMonth( +export function convertToPlainYearMonth( dateObj, // PlainDate/PlainDateTime/ZonedDateTime ) { const calendarOps = getInternals(dateObj).calendar - const fields = refineBag( + const fields = refineCalendarFields( calendarOps, dateObj, yearMonthBasicNames, @@ -248,37 +232,72 @@ export function dateToPlainYearMonth( return createPlainYearMonth(calendarOps.yearMonthFromFields(fields, 'constrain')) } -export function dateToPlainMonthDay( +export function convertPlainYearMonthToFirst(plainYearMonth) { + return convertPlainYearMonthToDate(plainYearMonth, { day: 1 }) +} + +export function convertPlainYearMonthToDate(plainYearMonth, bag) { + return convertToPlainDate( + plainYearMonth, + yearMonthBasicNames, // what to extract from plainYearMonth + bag, + ['day'], // what to extract from bag + ) +} + +// PlainMonthDay +// ------------------------------------------------------------------------------------------------- + +export function refinePlainMonthDayBag(bag, options) { + let calendar = extractCalendarOps(bag) + let calendarAbsent = !calendar + + if (calendarAbsent) { + calendar = bag.calendar + calendarAbsent = calendar === undefined + calendar = queryCalendarOps(calendarAbsent ? isoCalendarId : calendar) + } + + const fieldNames = calendar.fields(dateFieldNames) + const fields = refineFields(bag, fieldNames, []) + + // Callers who omit the calendar are not writing calendar-independent + // code. In that case, `monthCode`/`year` can be omitted; `month` and + // `day` are sufficient. Add a `year` to satisfy calendar validation. + if ( + calendarAbsent && + fields.month !== undefined && + fields.monthCode === undefined && + fields.year === undefined + ) { + fields.year = isoEpochFirstLeapYear + } + + return calendar.monthDayFromFields(calendar, fields, optionsToOverflow(options)) +} + +export function mergePlainMonthDayBag(plainMonthDay, bag, options) { + const { calendar } = getInternals(plainMonthDay) + const fields = mergeCalendarFields(calendar, plainMonthDay, bag, dateFieldNames) + return calendar.monthDayFromFields(fields, optionsToOverflow(options)) +} + +export function convertToPlainMonthDay( dateObj, // PlainDate/PlainDateTime/ZonedDateTime ) { const calendarOps = getInternals(dateObj).calendar - const fields = refineBag( + const fields = refineCalendarFields( calendarOps, dateObj, monthDayBasicNames, getRequiredMonthDayFields(calendarOps), ) - return createPlainMonthDay(calendarOps.monthDayFromFields(fields, 'constrain')) -} - -// to PlainDate -// ------------------------------------------------------------------------------------------------- -export function plainYearMonthToPlainDateFirst(plainYearMonth) { - return plainYearMonthToPlainDate(plainYearMonth, { day: 1 }) -} - -export function plainYearMonthToPlainDate(plainYearMonth, bag) { - return mergeToPlainDate( - plainYearMonth, - yearMonthBasicNames, // what to extract from plainYearMonth - bag, - ['day'], // what to extract from bag - ) + return createPlainMonthDay(calendarOps.monthDayFromFields(fields, 'constrain')) } -export function plainMonthDayToPlainDate(plainMonthDay, bag) { - return mergeToPlainDate( +export function convertPlainMonthDayToDate(plainMonthDay, bag) { + return convertToPlainDate( plainMonthDay, monthDayBasicNames, // what to extract from plainMonthDay bag, @@ -286,32 +305,43 @@ export function plainMonthDayToPlainDate(plainMonthDay, bag) { ) } -// to ZonedDateTime +// PlainTime // ------------------------------------------------------------------------------------------------- -export function createZonedDateTimeConverter(getAdditionalIsoFields) { - return (internals, options) => { - const refinedOptions = toObject(options) // required!!! - const epochNanoseconds = getSingleInstantFor( - internals.timeZone, - { - ...internals, - ...getAdditionalIsoFields(refinedOptions), - }, - ) +export function refinePlainTimeBag(bag, options) { + const overflowHandling = toOverflowOptions(options) // TODO: single opt! + const fields = refineFields(bag, timeFieldNames, []) - return createZonedDateTime({ - epochNanoseconds, - timeZone: internals.timeZone, - calendar: internals.calendar, - }) - } + return constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) +} + +export function mergePlainTimeBag(plainTime, bag, options) { + const fields = pluckProps(timeFieldNames, plainTime) + const additionalFields = refineFields(bag, timeFieldNames) + const newFields = { ...fields, ...additionalFields } + const overflowHandling = toOverflowOptions(options) // TODO: single opt! + const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(newFields), overflowHandling) + + return createPlainTime(isoTimeFields) +} + +// Duration +// ------------------------------------------------------------------------------------------------- + +export function refineDurationBag(bag) { + const durationFields = refineFields(bag, durationFieldNames, []) + return updateDurationFieldsSign(durationFields) +} + +export function mergeDurationBag(durationInternals, bag) { + const partialDurationFields = refineFields(bag, durationFieldNames) + return updateDurationFieldsSign({ ...durationInternals, ...partialDurationFields }) } // Calendar-field processing // ------------------------------------------------------------------------------------------------- -function refineBag( +function refineCalendarFields( calendarOps, bag, validFieldNames, @@ -320,11 +350,11 @@ function refineBag( ) { const fieldNames = calendarOps.fields(validFieldNames) .concat(requiredFieldNames, forcedValidFieldNames) - const fields = prepareFields(bag, fieldNames, requiredFieldNames) + const fields = refineFields(bag, fieldNames, requiredFieldNames) return fields } -function mergeBag( +function mergeCalendarFields( calendarOps, obj, bag, @@ -334,34 +364,30 @@ function mergeBag( // TODO: check bag doesn't have timezone/calendar const fieldNames = calendarOps.fields(validFieldNames) fieldNames.push(...requiredFieldNames) - let fields = prepareFields(obj, fieldNames, requiredFieldNames) - const additionalFields = prepareFields(bag, fieldNames) // partial + let fields = refineFields(obj, fieldNames, requiredFieldNames) + const additionalFields = refineFields(bag, fieldNames) // partial fields = calendarOps.mergeFields(fields, additionalFields) - fields = prepareFields(fields, fieldNames, requiredFieldNames) + fields = refineFields(fields, fieldNames, requiredFieldNames) return [fields] } -function mergeToPlainDate( - obj, - objFieldNames, - other, // bag or obj - otherFieldNames, -) { - const { calendar } = getInternals(obj) - const receiverFieldNames = calendar.fields(objFieldNames) - const receiverFields = pluckProps(receiverFieldNames, obj) - const inputFieldNames = calendar.fields(otherFieldNames) - const inputFields = prepareFields(other, inputFieldNames, getRequiredDateFields(calendar)) - const mergedFieldNames = removeDuplicateStrings(receiverFieldNames.concat(inputFieldNames)) - let mergedFields = calendar.mergeFields(receiverFields, inputFields) - mergedFields = prepareFields(mergedFields, mergedFieldNames, []) - return createPlainDate({ - ...calendar.dateFromFields(mergedFields, 'reject'), - calendar, - }) +function getCalendarOps(bag) { + return extractCalendarOps(bag) || queryCalendarOps(isoCalendarId) +} + +function extractCalendarOps(bag) { + const { calendar } = getInternals(bag) || {} + if (calendar) { + return calendar // CalendarOps + } + + ({ calendar }) = bag + if (calendar) { + return queryCalendarOps(calendar) + } } -// ahhh +// Generic Refining // ------------------------------------------------------------------------------------------------- const builtinRefiners = { @@ -373,6 +399,15 @@ const builtinRefiners = { const builtinDefaults = timeFieldDefaults +/* +If requiredFields not given, then assumed to be 'partial' (defaults won't be applied) +*/ +export function refineFields(bag, fieldNames, requiredFields) { + console.log(builtinRefiners) + console.log(builtinDefaults) + // TODO: error-out if no valid vields +} + export function createComplexBagRefiner(key, ForbiddenClass) { return function(bag) { const internalArg = getInternals(bag)?.[key] @@ -401,28 +436,3 @@ function forbidInstanceClass(obj, Class) { throw new RangeError(`Unexpected ${Class.prototype[Symbol.toStringTag]}`) } } - -/* -If requiredFields not given, then assumed to be 'partial' (defaults won't be applied) -*/ -export function prepareFields(bag, fieldNames, requiredFields) { - console.log(builtinRefiners) - console.log(builtinDefaults) - // TODO: error-out if no valid vields -} - -function extractCalendarOpsFromBag(bag) { - return queryCalendarOps(extractCalendarFieldFromBag(bag) || isoCalendarId) -} - -function extractCalendarFieldFromBag(bag) { - const internals = getInternals(bag) - const { calendar } = internals || {} - if (calendar) { - return calendar - } - ({ calendar }) = bag - if (calendar) { - return queryCalendarOps(calendar) - } -} diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index e66c7e50..ba9c9363 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -1,4 +1,4 @@ -import { createComplexBagRefiner, prepareFields } from './bag' +import { createComplexBagRefiner, refineFields } from './bag' import { getRequiredDateFields, getRequiredMonthDayFields, @@ -74,7 +74,7 @@ export const [Calendar, createCalendar] = createTemporalClass( dateFromFields(impl, fields, options) { return createPlainDate( impl.dateFromFields( - prepareFields(fields, impl.fields(dateFieldNames), getRequiredDateFields(impl)), + refineFields(fields, impl.fields(dateFieldNames), getRequiredDateFields(impl)), optionsToOverflow(options), ), ) @@ -83,7 +83,7 @@ export const [Calendar, createCalendar] = createTemporalClass( yearMonthFromFields(impl, fields, options) { return createPlainYearMonth( impl.yearMonthFromFields( - prepareFields(fields, impl.fields(yearMonthFieldNames), getRequiredYearMonthFields(impl)), + refineFields(fields, impl.fields(yearMonthFieldNames), getRequiredYearMonthFields(impl)), optionsToOverflow(options), ), ) @@ -93,7 +93,7 @@ export const [Calendar, createCalendar] = createTemporalClass( return createPlainMonthDay( ...impl.monthDayFromFields( // refine y/m/d fields - prepareFields(fields, impl.fields(dateFieldNames), getRequiredMonthDayFields(impl)), + refineFields(fields, impl.fields(dateFieldNames), getRequiredMonthDayFields(impl)), optionsToOverflow(options), ), ) diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 6610fe0e..921902ef 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -1,4 +1,4 @@ -import { bagToDurationInternals, durationWithBag } from './bag' +import { refineDurationBag, mergeDurationBag } from './bag' import { createTemporalClass, neverValueOf } from './class' import { diffZonedEpochNanoseconds } from './diff' import { @@ -69,7 +69,7 @@ export const [ {}, // bagToInternals - bagToDurationInternals, + refineDurationBag, // stringToInternals stringToDurationInternals, @@ -92,7 +92,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with: durationWithBag, + with: mergeDurationBag, add: addToDuration.bind(undefined, 1), diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 7738420e..1ee7dd59 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -60,11 +60,11 @@ export const durationFieldDefaults = { // ------------------------------------------------------------------------------------------------- export function refineDurationInternals(rawDurationFields) { - return updateDurationFieldSign(mapRefiners(rawDurationFields, durationFieldRefiners)) + return updateDurationFieldsSign(mapRefiners(rawDurationFields, durationFieldRefiners)) } -export function updateDurationFieldSign(fields) { - fields.sign = computeDurationFieldSign(fields) +export function updateDurationFieldsSign(fields) { + fields.sign = computeDurationFieldsSign(fields) return fields } @@ -88,10 +88,10 @@ export function absolutizeDurationFields(internals) { } export function durationHasDateParts(internals) { - return Boolean(computeDurationFieldSign(internals, durationDateFieldNames)) + return Boolean(computeDurationFieldsSign(internals, durationDateFieldNames)) } -function computeDurationFieldSign(internals, fieldNames = durationFieldNames) { +function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { // should throw error if mismatch // TODO: audit repeat uses of this } diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 1c75ae0f..e237f549 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -1,9 +1,9 @@ import { - bagToPlainDateSlots, + refinePlainDateBag, createZonedDateTimeConverter, - dateToPlainMonthDay, - dateToPlainYearMonth, - plainDateWithBag, + convertToPlainMonthDay, + convertToPlainYearMonth, + mergePlainDateBag, } from './bag' import { isoCalendarId } from './calendarConfig' import { dateGetters } from './calendarFields' @@ -60,7 +60,7 @@ export const [ }, // bagToInternals - bagToPlainDateSlots, + refinePlainDateBag, // stringToInternals stringToPlainDateInternals, @@ -78,7 +78,7 @@ export const [ { with(internals, bag, options) { - return createPlainDate(plainDateWithBag(this, bag, options)) + return createPlainDate(mergePlainDateBag(this, bag, options)) }, withCalendar(internals, calendarArg) { @@ -143,11 +143,11 @@ export const [ }, toPlainYearMonth() { - return dateToPlainYearMonth(this) + return convertToPlainYearMonth(this) }, toPlainMonthDay() { - return dateToPlainMonthDay(this) + return convertToPlainMonthDay(this) }, getISOFields: generatePublicIsoDateFields, diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index ce316b1a..e8f8f044 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -1,8 +1,8 @@ import { - bagToPlainDateTimeInternals, - dateToPlainMonthDay, - dateToPlainYearMonth, - plainDateTimeWithBag, + refinePlainDateTimeBag, + convertToPlainMonthDay, + convertToPlainYearMonth, + mergePlainDateTimeBag, } from './bag' import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' @@ -81,7 +81,7 @@ export const [ }, // bagToInternals - bagToPlainDateTimeInternals, + refinePlainDateTimeBag, // stringToInternals stringToPlainDateTimeInternals, @@ -99,7 +99,7 @@ export const [ { with(internals, bag, options) { - return createPlainDateTime(plainDateTimeWithBag(this, bag, options)) + return createPlainDateTime(mergePlainDateTimeBag(this, bag, options)) }, withPlainTime(internals, plainTimeArg) { @@ -209,11 +209,11 @@ export const [ }, toPlainYearMonth() { - return dateToPlainYearMonth(this) + return convertToPlainYearMonth(this) }, toPlainMonthDay() { - return dateToPlainMonthDay(this) + return convertToPlainMonthDay(this) }, toPlainTime(internals) { diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 0b8ed8b1..75735137 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -1,7 +1,7 @@ import { - bagToPlainMonthDayInternals, - plainMonthDayToPlainDate, - plainMonthDayWithBag, + refinePlainMonthDayBag, + convertPlainMonthDayToDate, + mergePlainMonthDayBag, } from './bag' import { isoCalendarId } from './calendarConfig' import { monthDayGetters } from './calendarFields' @@ -38,7 +38,7 @@ export const [ {}, // bagToInternals - bagToPlainMonthDayInternals, + refinePlainMonthDayBag, // stringToInternals stringToMonthDayInternals, @@ -56,7 +56,7 @@ export const [ { with(internals, bag, options) { - return createPlainMonthDay(plainMonthDayWithBag(this, bag, options)) + return createPlainMonthDay(mergePlainMonthDayBag(this, bag, options)) }, equals(internals, otherArg) { @@ -74,7 +74,7 @@ export const [ valueOf: neverValueOf, toPlainDate(internals, bag) { - return plainMonthDayToPlainDate(this, bag) + return convertPlainMonthDayToDate(this, bag) }, getISOFields: generatePublicIsoDateFields, diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 7201e72c..e6e31428 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -1,7 +1,7 @@ import { - bagToPlainTimeInternals, + refinePlainTimeBag, createZonedDateTimeConverter, - plainTimeWithBag, + mergePlainTimeBag, } from './bag' import { timeGetters } from './calendarFields' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' @@ -57,7 +57,7 @@ export const [ }, // bagToInternals - bagToPlainTimeInternals, + refinePlainTimeBag, // stringToInternals stringToPlainTimeInternals, @@ -75,7 +75,7 @@ export const [ { with(internals, bag, options) { - return plainTimeWithBag(this, bag, options) + return mergePlainTimeBag(this, bag, options) }, add(internals, durationArg) { diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 9fe39e29..a9cbe779 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -1,8 +1,8 @@ import { - bagToPlainYearMonthInternals, - plainYearMonthToPlainDate, - plainYearMonthToPlainDateFirst, - plainYearMonthWithBag, + convertPlainYearMonthToDate, + convertPlainYearMonthToFirst, + mergePlainYearMonthBag, + refinePlainYearMonthBag, } from './bag' import { isoCalendarId } from './calendarConfig' import { yearMonthGetters } from './calendarFields' @@ -42,7 +42,7 @@ export const [ {}, // bagToInternals - bagToPlainYearMonthInternals, + refinePlainYearMonthBag, // stringToInternals stringToPlainYearMonthInternals, @@ -60,7 +60,7 @@ export const [ { with(internals, bag, options) { - return createPlainYearMonth(plainYearMonthWithBag(internals, bag, options)) + return createPlainYearMonth(mergePlainYearMonthBag(internals, bag, options)) }, add(internals, durationArg, options) { @@ -86,8 +86,8 @@ export const [ return createPlainYearMonth( diffDates( calendar, - plainYearMonthToPlainDateFirst(internals), - plainYearMonthToPlainDateFirst(toPlainYearMonthInternals(otherArg)), + convertPlainYearMonthToFirst(internals), + convertPlainYearMonthToFirst(toPlainYearMonthInternals(otherArg)), options, ), ) @@ -98,8 +98,8 @@ export const [ return createPlainYearMonth( diffDates( calendar, - plainYearMonthToPlainDateFirst(toPlainYearMonthInternals(otherArg)), - plainYearMonthToPlainDateFirst(internals), + convertPlainYearMonthToFirst(toPlainYearMonthInternals(otherArg)), + convertPlainYearMonthToFirst(internals), options, // TODO: flip rounding args ), ) @@ -120,7 +120,7 @@ export const [ valueOf: neverValueOf, toPlainDate(internals, bag) { - return plainYearMonthToPlainDate(this, bag) + return convertPlainYearMonthToDate(this, bag) }, getISOFields: generatePublicIsoDateFields, @@ -150,7 +150,7 @@ function movePlainYearMonth( durationFields, overflowHandling, ) { - const plainDate = plainYearMonthToPlainDate(plainYearMonth, { + const plainDate = convertPlainYearMonthToDate(plainYearMonth, { day: durationFields.sign < 0 ? calendar.daysInMonth(plainYearMonth) : 1, diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 816d241a..9438b1f3 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -1,8 +1,8 @@ import { - bagToZonedDateTimeInternals, - dateToPlainMonthDay, - dateToPlainYearMonth, - zonedDateTimeWithBag, + convertToPlainMonthDay, + convertToPlainYearMonth, + mergeZonedDateTimeBag, + refineZonedDateTimeBag, } from './bag' import { dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' @@ -72,7 +72,7 @@ export const [ {}, // bagToInternals - bagToZonedDateTimeInternals, + refineZonedDateTimeBag, // stringToInternals stringToZonedDateTimeInternals, @@ -122,7 +122,7 @@ export const [ { with(internals, bag, options) { - return zonedDateTimeWithBag(this, bag, options) + return createZonedDateTime(mergeZonedDateTimeBag(this, bag, options)) }, withPlainTime(internals, plainTimeArg) { @@ -348,11 +348,11 @@ export const [ }, toPlainYearMonth() { - return dateToPlainYearMonth(this) + return convertToPlainYearMonth(this) }, toPlainMonthDay() { - return dateToPlainMonthDay(this) + return convertToPlainMonthDay(this) }, getISOFields(internals) { From 9c270318092f1d9cd2ea3baff6719e8c1e9575da Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 6 Jun 2023 18:02:45 -0400 Subject: [PATCH 087/805] rename bag file --- packages/temporal-polyfill/src/new/calendar.js | 2 +- .../src/new/{bag.js => convert.js} | 0 packages/temporal-polyfill/src/new/diff.js | 2 +- packages/temporal-polyfill/src/new/duration.js | 2 +- packages/temporal-polyfill/src/new/move.js | 1 + packages/temporal-polyfill/src/new/now.js | 1 + packages/temporal-polyfill/src/new/plainDate.js | 14 +++++++------- .../temporal-polyfill/src/new/plainDateTime.js | 12 ++++++------ .../temporal-polyfill/src/new/plainMonthDay.js | 10 +++++----- packages/temporal-polyfill/src/new/plainTime.js | 8 ++++---- .../temporal-polyfill/src/new/plainYearMonth.js | 10 +++++----- packages/temporal-polyfill/src/new/timeZone.js | 2 +- .../temporal-polyfill/src/new/zonedDateTime.js | 8 ++++---- 13 files changed, 37 insertions(+), 35 deletions(-) rename packages/temporal-polyfill/src/new/{bag.js => convert.js} (100%) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index ba9c9363..66433f09 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -1,4 +1,3 @@ -import { createComplexBagRefiner, refineFields } from './bag' import { getRequiredDateFields, getRequiredMonthDayFields, @@ -11,6 +10,7 @@ import { } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' import { createAdapterMethods, createTemporalClass, internalIdGetters, returnId } from './class' +import { createComplexBagRefiner, refineFields } from './convert' import { createDuration, toDurationInternals } from './duration' import { isoDaysInWeek } from './isoMath' import { stringToCalendarId } from './isoParse' diff --git a/packages/temporal-polyfill/src/new/bag.js b/packages/temporal-polyfill/src/new/convert.js similarity index 100% rename from packages/temporal-polyfill/src/new/bag.js rename to packages/temporal-polyfill/src/new/convert.js diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 4feb4491..f6d3fb31 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -1,8 +1,8 @@ import { pluckIsoTimeFields } from './isoFields' import { - isoToEpochNano, isoMonthsInYear, isoTimeFieldsToNano, + isoToEpochNano, nanoInUtcDay, nanosecondsToTimeDuration, } from './isoMath' diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 921902ef..ffdbe632 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -1,5 +1,5 @@ -import { refineDurationBag, mergeDurationBag } from './bag' import { createTemporalClass, neverValueOf } from './class' +import { mergeDurationBag, refineDurationBag } from './convert' import { diffZonedEpochNanoseconds } from './diff' import { absolutizeDurationFields, diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 6691de53..ee3ea9d2 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -12,6 +12,7 @@ import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' export function addDaysMilli(epochMilli, milli) { // moveEpochMilliByDays } + export function addDaysToIsoFields() { // short-circuit if nothing to add } diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index ed0dc136..e7d5efab 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -78,6 +78,7 @@ function getCurrentEpochNanoseconds() { // TimeZone // -------- +// TODO: use lazy cache util? let queriedCurrentTimeZoneId diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index e237f549..cfc990c9 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -1,10 +1,3 @@ -import { - refinePlainDateBag, - createZonedDateTimeConverter, - convertToPlainMonthDay, - convertToPlainYearMonth, - mergePlainDateBag, -} from './bag' import { isoCalendarId } from './calendarConfig' import { dateGetters } from './calendarFields' import { @@ -13,6 +6,13 @@ import { queryCalendarOps, } from './calendarOps' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { + convertToPlainMonthDay, + convertToPlainYearMonth, + createZonedDateTimeConverter, + mergePlainDateBag, + refinePlainDateBag, +} from './convert' import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index e8f8f044..1c3ab35b 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -1,13 +1,13 @@ -import { - refinePlainDateTimeBag, - convertToPlainMonthDay, - convertToPlainYearMonth, - mergePlainDateTimeBag, -} from './bag' import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' import { getPublicCalendar, queryCalendarOps } from './calendarOps' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { + convertToPlainMonthDay, + convertToPlainYearMonth, + mergePlainDateTimeBag, + refinePlainDateTimeBag, +} from './convert' import { diffDateTimes } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 75735137..56b7bf0b 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -1,12 +1,12 @@ -import { - refinePlainMonthDayBag, - convertPlainMonthDayToDate, - mergePlainMonthDayBag, -} from './bag' import { isoCalendarId } from './calendarConfig' import { monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { + convertPlainMonthDayToDate, + mergePlainMonthDayBag, + refinePlainMonthDayBag, +} from './convert' import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields, isoEpochFirstLeapYear } from './isoMath' diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index e6e31428..46835521 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -1,10 +1,10 @@ +import { timeGetters } from './calendarFields' +import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { - refinePlainTimeBag, createZonedDateTimeConverter, mergePlainTimeBag, -} from './bag' -import { timeGetters } from './calendarFields' -import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' + refinePlainTimeBag, +} from './convert' import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index a9cbe779..1c89473f 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -1,13 +1,13 @@ +import { isoCalendarId } from './calendarConfig' +import { yearMonthGetters } from './calendarFields' +import { getPublicCalendar } from './calendarOps' +import { createTemporalClass, getInternals, neverValueOf, toLocaleStringMethod } from './class' import { convertPlainYearMonthToDate, convertPlainYearMonthToFirst, mergePlainYearMonthBag, refinePlainYearMonthBag, -} from './bag' -import { isoCalendarId } from './calendarConfig' -import { yearMonthGetters } from './calendarFields' -import { getPublicCalendar } from './calendarOps' -import { createTemporalClass, getInternals, neverValueOf, toLocaleStringMethod } from './class' +} from './convert' import { diffDates } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 75bd9cbc..116a8cd9 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -1,8 +1,8 @@ import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' -import { createComplexBagRefiner } from './bag' import { Calendar } from './calendar' import { queryCalendarOps } from './calendarOps' import { createTemporalClass, internalIdGetters, returnId } from './class' +import { createComplexBagRefiner } from './convert' import { createInstant, toInstantEpochNanoseconds } from './instant' import { formatOffsetNanoseconds } from './isoFormat' import { stringToTimeZoneId } from './isoParse' diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 9438b1f3..d75e7e9c 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -1,12 +1,12 @@ +import { dateTimeGetters } from './calendarFields' +import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' +import { createTemporalClass, neverValueOf } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, mergeZonedDateTimeBag, refineZonedDateTimeBag, -} from './bag' -import { dateTimeGetters } from './calendarFields' -import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' -import { createTemporalClass, neverValueOf } from './class' +} from './convert' import { diffZonedEpochNanoseconds } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' From 3a6341e24bafc6718bd2d8b1392b0fec97208e79 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 7 Jun 2023 13:34:03 -0400 Subject: [PATCH 088/805] improve convert utilities --- packages/temporal-polyfill/src/new/class.js | 1 + packages/temporal-polyfill/src/new/convert.js | 317 ++++++++++-------- packages/temporal-polyfill/src/new/options.js | 26 +- .../temporal-polyfill/src/new/plainTime.js | 2 +- .../src/new/plainYearMonth.js | 24 +- packages/temporal-polyfill/src/new/util.js | 1 + 6 files changed, 210 insertions(+), 161 deletions(-) diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js index 040c4753..8891fc38 100644 --- a/packages/temporal-polyfill/src/new/class.js +++ b/packages/temporal-polyfill/src/new/class.js @@ -141,6 +141,7 @@ export function toLocaleStringMethod(internals, locales, options) { // Adapter Utils // ------------------------------------------------------------------------------------------------- +// TODO: rethink this. too meta export function createAdapterMethods() { } diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index 7a2591dd..4e657d4d 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -27,14 +27,12 @@ import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNanoseconds } from './isoParse' import { optionsToOverflow, - toDisambiguation, toObject, - toOffsetHandling, - toOverflowOptions, + toObjectOptional, + toZonedRefiningOptions, } from './options' import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' -import { createPlainTime } from './plainTime' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { isObjectLike, pluckProps, removeDuplicateStrings } from './util' @@ -44,76 +42,80 @@ import { createZonedDateTime } from './zonedDateTime' // ------------------------------------------------------------------------------------------------- export function refineZonedDateTimeBag(bag, options) { - const calendarOps = getCalendarOps(bag) + const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( - calendarOps, + calendar, bag, - dateTimeFieldNames, - getRequiredDateFields(calendarOps).concat(['offset']), - ['timeZone'], + dateTimeFieldNames, // validFieldNames + [...getRequiredDateFields(calendar), 'timeZone'], // requireFields + ['timeZone', 'offset'], // forcedValidFieldNames ) + const { overflow, offset, disambiguation } = toZonedRefiningOptions(options) const timeZone = queryTimeZoneOps(fields.timeZone) - const overflowHandling = optionsToOverflow(options) - const isoDateFields = calendarOps.dateFromFields(fields, overflowHandling) - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) + const isoDateFields = calendar.dateFromFields(fields, overflow) + const isoTimeFields = refineTimeFields(fields, overflow) const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoDateFields, ...isoTimeFields }, - fields.offset !== undefined ? parseOffsetNanoseconds(fields.offset) : undefined, + fields.offset !== undefined && parseOffsetNanoseconds(fields.offset), false, // z? - toOffsetHandling(options), - toDisambiguation(options), + offset, + disambiguation, false, // fuzzy ) return { - epochNanoseconds, + calendar, timeZone, - calendar: calendarOps, + epochNanoseconds, } } export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { const { calendar, timeZone } = getInternals(zonedDateTime) - const fields = mergeCalendarFields(calendar, zonedDateTime, bag, dateTimeFieldNames, ['offset']) - const overflowHandling = optionsToOverflow(options) - const isoDateFields = calendar.dateFromFields(fields, overflowHandling) - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) + const fields = mergeCalendarFields( + calendar, + zonedDateTime, + bag, + dateTimeFieldNames, // validFieldNames + ['offset'], // forcedValidFieldNames + ) + const { overflow, offset, disambiguation } = toZonedRefiningOptions(options) + + const isoDateFields = calendar.dateFromFields(fields, overflow) + const isoTimeFields = refineTimeFields(fields, overflow) const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoDateFields, ...isoTimeFields }, parseOffsetNanoseconds(fields.offset), false, // z? - toOffsetHandling(options), - toDisambiguation(options), + offset, + disambiguation, false, // fuzzy ) return { - epochNanoseconds, - timeZone, calendar, + timeZone, + epochNanoseconds, } } -export function createZonedDateTimeConverter(getAdditionalIsoFields) { +export function createZonedDateTimeConverter(getExtraIsoFields) { return (internals, options) => { - const refinedOptions = toObject(options) // required!!! - const epochNanoseconds = getSingleInstantFor( - internals.timeZone, - { - ...internals, - ...getAdditionalIsoFields(refinedOptions), - }, - ) + const { calendar, timeZone } = internals + const epochNanoseconds = getSingleInstantFor(timeZone, { + ...internals, + ...getExtraIsoFields(toObjectOptional(options)), + }) return createZonedDateTime({ + calendar, + timeZone, epochNanoseconds, - timeZone: internals.timeZone, - calendar: internals.calendar, }) } } @@ -122,140 +124,147 @@ export function createZonedDateTimeConverter(getAdditionalIsoFields) { // ------------------------------------------------------------------------------------------------- export function refinePlainDateTimeBag(bag, options) { - const calendarOps = getCalendarOps(bag) + const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( - calendarOps, + calendar, bag, dateTimeFieldNames, - getRequiredDateFields(calendarOps), + getRequiredDateFields(calendar), ) - const overflowHandling = optionsToOverflow(options) - const isoDateInternals = calendarOps.dateFromFields(fields, overflowHandling) - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) - return { - ...isoDateInternals, - ...isoTimeFields, - } + const overflow = optionsToOverflow(options) + const isoDateInternals = calendar.dateFromFields(fields, overflow) + const isoTimeFields = refineTimeFields(fields, overflow) + + return { ...isoDateInternals, ...isoTimeFields } } export function mergePlainDateTimeBag(plainDate, bag, options) { const { calendar } = getInternals(plainDate) - const fields = mergeCalendarFields(calendar, plainDate, bag, dateTimeFieldNames) - const overflowHandling = optionsToOverflow(options) - const isoDateInternals = calendar.dateFromFields(fields, overflowHandling) - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) + const fields = mergeCalendarFields( + calendar, + plainDate, + bag, + dateTimeFieldNames, + ) - return { - ...isoDateInternals, - ...isoTimeFields, - } + const overflow = optionsToOverflow(options) + const isoDateInternals = calendar.dateFromFields(fields, overflow) + const isoTimeFields = refineTimeFields(fields, overflow) + + return { ...isoDateInternals, ...isoTimeFields } } // PlainDate // ------------------------------------------------------------------------------------------------- export function refinePlainDateBag(bag, options) { - const calendarOps = getCalendarOps(bag) + const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( - calendarOps, + calendar, bag, dateFieldNames, - getRequiredDateFields(calendarOps), + getRequiredDateFields(calendar), ) - return calendarOps.dateFromFields(fields, optionsToOverflow(options)) + return calendar.dateFromFields(fields, optionsToOverflow(options)) } export function mergePlainDateBag(plainDate, bag, options) { const { calendar } = getInternals(plainDate) - const fields = mergeCalendarFields(calendar, plainDate, bag, dateFieldNames) + const fields = mergeCalendarFields( + calendar, + plainDate, + bag, + dateFieldNames, + ) return calendar.dateFromFields(fields, optionsToOverflow(options)) } -function convertToPlainDate( - obj, - objFieldNames, - additionalFields, // bag or obj - additionalFieldNames, +function convertToIso( + input, + inputFieldNames, + extra, + extraFieldNames, ) { - const { calendar } = getInternals(obj) - const receiverFieldNames = calendar.fields(objFieldNames) - const receiverFields = pluckProps(receiverFieldNames, obj) - const inputFieldNames = calendar.fields(additionalFieldNames) - const inputFields = refineFields( - additionalFields, - inputFieldNames, - getRequiredDateFields(calendar), - ) - const mergedFieldNames = removeDuplicateStrings(receiverFieldNames.concat(inputFieldNames)) - let mergedFields = calendar.mergeFields(receiverFields, inputFields) + const { calendar } = getInternals(input) + + inputFieldNames = calendar.fields(inputFieldNames) + input = pluckProps(inputFieldNames, input) + + extraFieldNames = calendar.fields(extraFieldNames) + extra = refineFields(extra, extraFieldNames, getRequiredDateFields(calendar)) + + let mergedFields = calendar.mergeFields(input, extra) + const mergedFieldNames = removeDuplicateStrings(inputFieldNames.concat(extraFieldNames)) mergedFields = refineFields(mergedFields, mergedFieldNames, []) - return createPlainDate({ - ...calendar.dateFromFields(mergedFields, 'reject'), - calendar, - }) + calendar.dateFromFields(mergedFields) } // PlainYearMonth // ------------------------------------------------------------------------------------------------- export function refinePlainYearMonthBag(bag, options) { - const calendarOps = getCalendarOps(bag) + const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( - calendarOps, + calendar, bag, yearMonthFieldNames, - getRequiredYearMonthFields(calendarOps), + getRequiredYearMonthFields(calendar), ) - return calendarOps.yearMonthFromFields(fields, optionsToOverflow(options)) + + return calendar.yearMonthFromFields(fields, optionsToOverflow(options)) } export function mergePlainYearMonthBag(plainYearMonth, bag, options) { const { calendar } = getInternals(plainYearMonth) - const fields = mergeCalendarFields(calendar, plainYearMonth, bag, yearMonthFieldNames) + const fields = mergeCalendarFields( + calendar, + plainYearMonth, + bag, + yearMonthFieldNames, + ) + return calendar.yearMonthFromFields(fields, optionsToOverflow(options)) } export function convertToPlainYearMonth( - dateObj, // PlainDate/PlainDateTime/ZonedDateTime + input, // PlainDate/PlainDateTime/ZonedDateTime ) { - const calendarOps = getInternals(dateObj).calendar + const { calendar } = getInternals(input) const fields = refineCalendarFields( - calendarOps, - dateObj, + calendar, + input, yearMonthBasicNames, - getRequiredYearMonthFields(calendarOps), + getRequiredYearMonthFields(calendar), ) - return createPlainYearMonth(calendarOps.yearMonthFromFields(fields, 'constrain')) -} -export function convertPlainYearMonthToFirst(plainYearMonth) { - return convertPlainYearMonthToDate(plainYearMonth, { day: 1 }) + return createPlainYearMonth( + calendar.yearMonthFromFields(fields), + ) } export function convertPlainYearMonthToDate(plainYearMonth, bag) { - return convertToPlainDate( - plainYearMonth, - yearMonthBasicNames, // what to extract from plainYearMonth - bag, - ['day'], // what to extract from bag + return createPlainDate( + convertPlainYearMonthToIso(plainYearMonth, toObject(bag)), ) } +export function convertPlainYearMonthToIso(plainYearMonth, bag = { day: 1 }) { + return convertToIso(plainYearMonth, yearMonthBasicNames, bag, ['day']) +} + // PlainMonthDay // ------------------------------------------------------------------------------------------------- export function refinePlainMonthDayBag(bag, options) { - let calendar = extractCalendarOps(bag) - let calendarAbsent = !calendar + let calendar = extractBagCalendarOps(bag) + const calendarAbsent = !calendar if (calendarAbsent) { - calendar = bag.calendar - calendarAbsent = calendar === undefined - calendar = queryCalendarOps(calendarAbsent ? isoCalendarId : calendar) + calendar = queryCalendarOps(isoCalendarId) } const fieldNames = calendar.fields(dateFieldNames) @@ -278,30 +287,35 @@ export function refinePlainMonthDayBag(bag, options) { export function mergePlainMonthDayBag(plainMonthDay, bag, options) { const { calendar } = getInternals(plainMonthDay) - const fields = mergeCalendarFields(calendar, plainMonthDay, bag, dateFieldNames) + const fields = mergeCalendarFields( + calendar, + plainMonthDay, + bag, + dateFieldNames, + ) + return calendar.monthDayFromFields(fields, optionsToOverflow(options)) } export function convertToPlainMonthDay( - dateObj, // PlainDate/PlainDateTime/ZonedDateTime + input, // PlainDate/PlainDateTime/ZonedDateTime ) { - const calendarOps = getInternals(dateObj).calendar + const { calendar } = getInternals(input) const fields = refineCalendarFields( - calendarOps, - dateObj, + calendar, + input, monthDayBasicNames, - getRequiredMonthDayFields(calendarOps), + getRequiredMonthDayFields(calendar), ) - return createPlainMonthDay(calendarOps.monthDayFromFields(fields, 'constrain')) + return createPlainMonthDay( + calendar.monthDayFromFields(fields), + ) } export function convertPlainMonthDayToDate(plainMonthDay, bag) { - return convertToPlainDate( - plainMonthDay, - monthDayBasicNames, // what to extract from plainMonthDay - bag, - ['year'], // what to extract from bag + return createPlainDate( + convertToIso(plainMonthDay, monthDayBasicNames, bag, ['year']), ) } @@ -309,20 +323,21 @@ export function convertPlainMonthDayToDate(plainMonthDay, bag) { // ------------------------------------------------------------------------------------------------- export function refinePlainTimeBag(bag, options) { - const overflowHandling = toOverflowOptions(options) // TODO: single opt! const fields = refineFields(bag, timeFieldNames, []) - return constrainIsoTimeFields(timeFieldsToIso(fields), overflowHandling) + return refineTimeFields(fields, optionsToOverflow(options)) } export function mergePlainTimeBag(plainTime, bag, options) { const fields = pluckProps(timeFieldNames, plainTime) - const additionalFields = refineFields(bag, timeFieldNames) - const newFields = { ...fields, ...additionalFields } - const overflowHandling = toOverflowOptions(options) // TODO: single opt! - const isoTimeFields = constrainIsoTimeFields(timeFieldsToIso(newFields), overflowHandling) + const partialFields = refineFields(bag, timeFieldNames) + const mergeFields = { ...fields, ...partialFields } - return createPlainTime(isoTimeFields) + return refineTimeFields(mergeFields, optionsToOverflow(options)) +} + +function refineTimeFields(fields, overflow) { + return constrainIsoTimeFields(timeFieldsToIso(fields), overflow) } // Duration @@ -342,40 +357,38 @@ export function mergeDurationBag(durationInternals, bag) { // ------------------------------------------------------------------------------------------------- function refineCalendarFields( - calendarOps, + calendar, bag, validFieldNames, - requiredFieldNames = [], + requiredFieldNames = [], // a subset of validFieldNames forcedValidFieldNames = [], ) { - const fieldNames = calendarOps.fields(validFieldNames) - .concat(requiredFieldNames, forcedValidFieldNames) - const fields = refineFields(bag, fieldNames, requiredFieldNames) - return fields + const fieldNames = [...calendar.fields(validFieldNames), ...forcedValidFieldNames] + return refineFields(bag, fieldNames, requiredFieldNames) } function mergeCalendarFields( - calendarOps, + calendar, obj, bag, validFieldNames, - requiredFieldNames = [], + forcedValidFieldNames = [], ) { - // TODO: check bag doesn't have timezone/calendar - const fieldNames = calendarOps.fields(validFieldNames) - fieldNames.push(...requiredFieldNames) - let fields = refineFields(obj, fieldNames, requiredFieldNames) - const additionalFields = refineFields(bag, fieldNames) // partial - fields = calendarOps.mergeFields(fields, additionalFields) - fields = refineFields(fields, fieldNames, requiredFieldNames) - return [fields] + rejectInvalidBag(bag) + + const fieldNames = [...calendar.fields(validFieldNames), ...forcedValidFieldNames] + let fields = refineFields(obj, fieldNames, []) + const partialFields = refineFields(bag, fieldNames) + + fields = calendar.mergeFields(fields, partialFields) + return refineFields(fields, fieldNames, []) // guard against ridiculous .mergeField results } -function getCalendarOps(bag) { - return extractCalendarOps(bag) || queryCalendarOps(isoCalendarId) +function getBagCalendarOps(bag) { + return extractBagCalendarOps(bag) || queryCalendarOps(isoCalendarId) } -function extractCalendarOps(bag) { +function extractBagCalendarOps(bag) { const { calendar } = getInternals(bag) || {} if (calendar) { return calendar // CalendarOps @@ -387,6 +400,18 @@ function extractCalendarOps(bag) { } } +function rejectInvalidBag(bag) { + if (getInternals(bag)) { + throw new TypeError('Cant pass any Temporal object') + } + if (bag.calendar !== undefined) { + throw new TypeError('Ah') + } + if (bag.timeZone !== undefined) { + throw new TypeError('Ah') + } +} + // Generic Refining // ------------------------------------------------------------------------------------------------- @@ -399,10 +424,12 @@ const builtinRefiners = { const builtinDefaults = timeFieldDefaults -/* -If requiredFields not given, then assumed to be 'partial' (defaults won't be applied) -*/ -export function refineFields(bag, fieldNames, requiredFields) { +export function refineFields( + bag, + fieldNames, + requiredFields, // a subset of fieldNames + // if not given, then assumed to be 'partial' (defaults won't be applied) +) { console.log(builtinRefiners) console.log(builtinDefaults) // TODO: error-out if no valid vields diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 8be831d4..8d0879ce 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -20,7 +20,12 @@ export function strictArray() { } +export function toObjectOptional(obj) { + return obj === undefined ? {} : toObject(obj) +} + export function toObject() { + // ensures a real object. throws error otherwise } export function toEpochNano(input) { @@ -110,6 +115,20 @@ export function toOffsetHandling() { } +export function toZonedRefiningOptions(options) { + options = toObjectOptional(options) + + return { // TODO: use tuple? + overflow: toOverflow(options), + offset: toOffset(options), + disambiguation: toDisambiguation(options), + } +} + +function toOffset() { + +} + export function toDisambiguation() { } @@ -136,6 +155,10 @@ export function toDiffOptions() { } +export function toOverflow() { + +} + export function toOverflowOptions() { } @@ -171,7 +194,8 @@ export function validateRoundingOptions(options) { export function optionsToLargestUnit() { } -export function optionsToOverflow() { +export function optionsToOverflow(options) { + return toOverflow(toObjectOptional(options).overflow) } export function optionsToTotalUnit() { diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 46835521..7156d6df 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -75,7 +75,7 @@ export const [ { with(internals, bag, options) { - return mergePlainTimeBag(this, bag, options) + return createPlainTime(mergePlainTimeBag(this, bag, options)) }, add(internals, durationArg) { diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 1c89473f..75169fcf 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -1,10 +1,10 @@ import { isoCalendarId } from './calendarConfig' import { yearMonthGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' -import { createTemporalClass, getInternals, neverValueOf, toLocaleStringMethod } from './class' +import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { convertPlainYearMonthToDate, - convertPlainYearMonthToFirst, + convertPlainYearMonthToIso, mergePlainYearMonthBag, refinePlainYearMonthBag, } from './convert' @@ -86,8 +86,8 @@ export const [ return createPlainYearMonth( diffDates( calendar, - convertPlainYearMonthToFirst(internals), - convertPlainYearMonthToFirst(toPlainYearMonthInternals(otherArg)), + convertPlainYearMonthToIso(internals), + convertPlainYearMonthToIso(toPlainYearMonthInternals(otherArg)), options, ), ) @@ -98,8 +98,8 @@ export const [ return createPlainYearMonth( diffDates( calendar, - convertPlainYearMonthToFirst(toPlainYearMonthInternals(otherArg)), - convertPlainYearMonthToFirst(internals), + convertPlainYearMonthToIso(toPlainYearMonthInternals(otherArg)), + convertPlainYearMonthToIso(internals), options, // TODO: flip rounding args ), ) @@ -150,17 +150,13 @@ function movePlainYearMonth( durationFields, overflowHandling, ) { - const plainDate = convertPlainYearMonthToDate(plainYearMonth, { + const isoDateFields = convertPlainYearMonthToIso(plainYearMonth, { day: durationFields.sign < 0 ? calendar.daysInMonth(plainYearMonth) : 1, }) - let isoDateFields = getInternals(plainDate) - isoDateFields = calendar.dateAdd(isoDateFields, durationFields, overflowHandling) - - return createPlainYearMonth({ - ...isoDateFields, - calendar, - }) + return createPlainYearMonth( + calendar.dateAdd(isoDateFields, durationFields, overflowHandling), + ) } diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index 5890320f..482914d5 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -27,6 +27,7 @@ export function pluckProps(propNames, obj) { } export function removeDuplicateStrings(a0, a1) { + // if we use a Set(), can be generalized away from just strings!!! } export function removeUndefines(obj) { // and copy From 152afdeb04d6ac657666b32b9bf467d2e6be8bc3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 7 Jun 2023 20:13:46 -0400 Subject: [PATCH 089/805] cleaner bag refining --- .../temporal-polyfill/src/new/calendar.js | 40 ++++------------ packages/temporal-polyfill/src/new/convert.js | 48 ++++++++++++++----- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 66433f09..d3faa838 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -1,16 +1,12 @@ -import { - getRequiredDateFields, - getRequiredMonthDayFields, - getRequiredYearMonthFields, -} from './calendarConfig' -import { - dateFieldNames, - dateGetterNames, - yearMonthFieldNames, -} from './calendarFields' +import { dateGetterNames } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' import { createAdapterMethods, createTemporalClass, internalIdGetters, returnId } from './class' -import { createComplexBagRefiner, refineFields } from './convert' +import { + createComplexBagRefiner, + refinePlainDateBag, + refinePlainMonthDayBag, + refinePlainYearMonthBag, +} from './convert' import { createDuration, toDurationInternals } from './duration' import { isoDaysInWeek } from './isoMath' import { stringToCalendarId } from './isoParse' @@ -72,31 +68,15 @@ export const [Calendar, createCalendar] = createTemporalClass( }), dateFromFields(impl, fields, options) { - return createPlainDate( - impl.dateFromFields( - refineFields(fields, impl.fields(dateFieldNames), getRequiredDateFields(impl)), - optionsToOverflow(options), - ), - ) + return createPlainDate(refinePlainDateBag(fields, options, impl)) }, yearMonthFromFields(impl, fields, options) { - return createPlainYearMonth( - impl.yearMonthFromFields( - refineFields(fields, impl.fields(yearMonthFieldNames), getRequiredYearMonthFields(impl)), - optionsToOverflow(options), - ), - ) + return createPlainYearMonth(refinePlainYearMonthBag(fields, options, impl)) }, monthDayFromFields(impl, fields, options) { - return createPlainMonthDay( - ...impl.monthDayFromFields( - // refine y/m/d fields - refineFields(fields, impl.fields(dateFieldNames), getRequiredMonthDayFields(impl)), - optionsToOverflow(options), - ), - ) + return createPlainMonthDay(refinePlainMonthDayBag(fields, options, impl)) }, toString: returnId, diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index 4e657d4d..0b5b92c6 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -158,8 +158,7 @@ export function mergePlainDateTimeBag(plainDate, bag, options) { // PlainDate // ------------------------------------------------------------------------------------------------- -export function refinePlainDateBag(bag, options) { - const calendar = getBagCalendarOps(bag) +export function refinePlainDateBag(bag, options, calendar = getBagCalendarOps(bag)) { const fields = refineCalendarFields( calendar, bag, @@ -200,14 +199,13 @@ function convertToIso( const mergedFieldNames = removeDuplicateStrings(inputFieldNames.concat(extraFieldNames)) mergedFields = refineFields(mergedFields, mergedFieldNames, []) - calendar.dateFromFields(mergedFields) + return calendar.dateFromFields(mergedFields) } // PlainYearMonth // ------------------------------------------------------------------------------------------------- -export function refinePlainYearMonthBag(bag, options) { - const calendar = getBagCalendarOps(bag) +export function refinePlainYearMonthBag(bag, options, calendar = getBagCalendarOps(bag)) { const fields = refineCalendarFields( calendar, bag, @@ -259,8 +257,7 @@ export function convertPlainYearMonthToIso(plainYearMonth, bag = { day: 1 }) { // PlainMonthDay // ------------------------------------------------------------------------------------------------- -export function refinePlainMonthDayBag(bag, options) { - let calendar = extractBagCalendarOps(bag) +export function refinePlainMonthDayBag(bag, options, calendar = extractBagCalendarOps(bag)) { const calendarAbsent = !calendar if (calendarAbsent) { @@ -424,15 +421,40 @@ const builtinRefiners = { const builtinDefaults = timeFieldDefaults -export function refineFields( +function refineFields( bag, - fieldNames, - requiredFields, // a subset of fieldNames + validFieldNames, + requiredFieldNames, // a subset of fieldNames // if not given, then assumed to be 'partial' (defaults won't be applied) ) { - console.log(builtinRefiners) - console.log(builtinDefaults) - // TODO: error-out if no valid vields + const res = {} + let any = false + + for (const fieldName in validFieldNames) { + let fieldVal = bag[fieldName] + + if (fieldVal !== undefined) { + any = true + + if (builtinRefiners[fieldName]) { + fieldVal = builtinRefiners[fieldName] + } + + res[fieldName] = fieldVal + } else if (requiredFieldNames) { + if (requiredFieldNames.includes(fieldName)) { + throw new TypeError('Missing required field name') + } + + res[fieldName] = builtinDefaults[fieldName] + } + } + + if (!any) { + throw new TypeError('No valid fields') + } + + return res } export function createComplexBagRefiner(key, ForbiddenClass) { From 8fd78f6072ac4a7fd339a9664eeae64c653150a9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 7 Jun 2023 23:53:06 -0400 Subject: [PATCH 090/805] lots of changes --- .../temporal-polyfill/src/new/calendar.js | 97 ++++++++++------ .../temporal-polyfill/src/new/calendarImpl.js | 1 + .../temporal-polyfill/src/new/calendarOps.js | 109 ++++++++++++------ packages/temporal-polyfill/src/new/class.js | 17 ++- packages/temporal-polyfill/src/new/convert.js | 6 +- .../temporal-polyfill/src/new/duration.js | 3 + .../temporal-polyfill/src/new/isoFormat.js | 4 + packages/temporal-polyfill/src/new/isoMath.js | 3 +- .../temporal-polyfill/src/new/isoParse.js | 2 + .../temporal-polyfill/src/new/timeZone.js | 45 ++++---- .../temporal-polyfill/src/new/timeZoneImpl.js | 6 +- .../temporal-polyfill/src/new/timeZoneOps.js | 61 +++++----- packages/temporal-polyfill/src/new/util.js | 27 +++++ .../src/new/zonedDateTime.js | 4 + 14 files changed, 243 insertions(+), 142 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index d3faa838..47c011be 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -1,6 +1,6 @@ import { dateGetterNames } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' -import { createAdapterMethods, createTemporalClass, internalIdGetters, returnId } from './class' +import { createTemporalClass, internalIdGetters, returnId } from './class' import { createComplexBagRefiner, refinePlainDateBag, @@ -10,16 +10,68 @@ import { import { createDuration, toDurationInternals } from './duration' import { isoDaysInWeek } from './isoMath' import { stringToCalendarId } from './isoParse' -import { optionsToLargestUnit, optionsToOverflow, strictArrayOfStrings, toObject } from './options' +import { optionsToOverflow, strictArray, toObject } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' -import { identityFunc, mapArrayToProps, noop, removeUndefines } from './util' +import { mapArrayToProps, noop, removeUndefines } from './util' + +export const calendarVitalMethods = { + ...mapArrayToProps(dateGetterNames, (propName) => { + return (impl, plainDateArg) => { + return impl[propName](toPlainDateInternals(plainDateArg)) + } + }), + + daysInWeek() { + return isoDaysInWeek + }, + + dateAdd(impl, plainDateArg, durationArg, options) { + return createPlainDate( + impl.dateAdd( + toPlainDateInternals(plainDateArg), + toDurationInternals(durationArg), + optionsToOverflow(options), + ), + ) + }, + + dateUntil(impl, plainDateArg0, plainDateArg1, options) { + return createDuration( + impl.dateUntil( + toPlainDateInternals(plainDateArg0), + toPlainDateInternals(plainDateArg1), + optionsToOverflow(options), + ), + ) + }, + + dateFromFields(impl, fields, options) { + return createPlainDate(refinePlainDateBag(fields, options, impl)) + }, + + yearMonthFromFields(impl, fields, options) { + return createPlainYearMonth(refinePlainYearMonthBag(fields, options, impl)) + }, + + monthDayFromFields(impl, fields, options) { + return createPlainMonthDay(refinePlainMonthDayBag(fields, options, impl)) + }, + + fields(impl, fieldNames) { + return impl.fields(strictArray(fieldNames).map(toString)) + }, + + mergeFields(impl, fields0, fields1) { + return impl.mergeFields( + removeUndefines(toObject(fields0)), + removeUndefines(toObject(fields1)), + ) + }, +} -/* -Must do input validation -*/ export const [Calendar, createCalendar] = createTemporalClass( 'Calendar', @@ -50,39 +102,8 @@ export const [Calendar, createCalendar] = createTemporalClass( // ----------------------------------------------------------------------------------------------- { - ...mapArrayToProps(dateGetterNames, (propName) => { - return (impl, plainDateArg) => { - return impl[propName](toPlainDateInternals(plainDateArg)) - } - }), - - daysInWeek() { - return isoDaysInWeek - }, - - ...createAdapterMethods({ - dateAdd: [createPlainDate, toPlainDateInternals, toDurationInternals, optionsToLargestUnit], - dateUntil: [createDuration, toPlainDateInternals, toPlainDateInternals, optionsToOverflow], - fields: [identityFunc, strictArrayOfStrings], - mergeFields: [identityFunc, removeUndefinesStrict, removeUndefinesStrict], - }), - - dateFromFields(impl, fields, options) { - return createPlainDate(refinePlainDateBag(fields, options, impl)) - }, - - yearMonthFromFields(impl, fields, options) { - return createPlainYearMonth(refinePlainYearMonthBag(fields, options, impl)) - }, - - monthDayFromFields(impl, fields, options) { - return createPlainMonthDay(refinePlainMonthDayBag(fields, options, impl)) - }, + ...calendarVitalMethods, toString: returnId, }, ) - -function removeUndefinesStrict(obj) { - return removeUndefines(toObject(obj)) -} diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index c30d3ce5..f9091132 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -597,6 +597,7 @@ export function queryCalendarImpl(calendarId) { calendarId = calendarIdBase } + // TODO: lazy cache util return calendarImplCache[calendarId] || ( calendarImplCache[calendarId] = new (CalendarImplClass || IntlCalendarImpl)(calendarId) ) diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index d36fe4ea..22e11241 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -1,56 +1,93 @@ -import { createCalendar } from './calendar' +import { Calendar, calendarVitalMethods, createCalendar } from './calendar' import { dateFieldRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' -import { - createAdapterMethods, - createWrapperClass, - getInternals, - getStrictInternals, - internalIdGetters, -} from './class' +import { adapterIdGetters, createWrapperClass, getInternals, getStrictInternals } from './class' import { createDuration } from './duration' -import { largestUnitToOptions, overflowToOptions, strictArrayOfStrings, toObject } from './options' +import { strictArray, toObject, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' -import { identityFunc, mapProps } from './util' +import { createVitalsChecker, getCommonInternal, mapProps } from './util' -export function queryCalendarOps(calendarSlot) { - if (typeof calendarSlot === 'object') { - return new CalendarOpsAdapter(calendarSlot) +const checkCalendarVitals = createVitalsChecker(calendarVitalMethods) + +export function queryCalendarOps(calendarArg) { + if (typeof calendarArg === 'object') { + if (calendarArg instanceof Calendar) { + return getInternals(calendarArg) + } + + checkCalendarVitals(calendarArg) + return new CalendarOpsAdapter(calendarArg) } - return queryCalendarImpl(calendarSlot) // string + + return queryCalendarImpl(toString(calendarArg)) } export function getPublicCalendar(internals) { - const calendarOps = internals.calendar - return getInternals(calendarOps) || // CalendarOpsAdapter (return internal Calendar) - createCalendar(calendarOps) // CalendarImpl (create outer Calendar) -} + const { calendar } = internals -export function getCommonCalendarOps(internals0, internals1) { - // TODO + return getInternals(calendar) || // CalendarOpsAdapter (return internal Calendar) + createCalendar(calendar) // CalendarImpl (create outer Calendar) } +export const getCommonCalendarOps = getCommonInternal.bind(undefined, 'calendar') + // Adapter // ------------------------------------------------------------------------------------------------- const getPlainDateInternals = getStrictInternals(PlainDate) +const getPlainYearMonthInternals = getStrictInternals(PlainYearMonth) +const getPlainMonthDayInternals = getStrictInternals(PlainMonthDay) -const CalendarOpsAdapter = createWrapperClass( - internalIdGetters, - createAdapterMethods({ - ...mapProps({ - ...eraYearFieldRefiners, - ...dateFieldRefiners, - ...dateStatRefiners, - }, (refiner) => [refiner, createPlainDate]), - dateAdd: [getPlainDateInternals, createPlainDate, createDuration, overflowToOptions], - dateUntil: [getPlainDateInternals, createPlainDate, createPlainDate, largestUnitToOptions], - dateFromFields: [getPlainDateInternals, identityFunc, overflowToOptions], - yearMonthFromFields: [getStrictInternals(PlainYearMonth), identityFunc, overflowToOptions], - monthDayFromFields: [getStrictInternals(PlainMonthDay), identityFunc, overflowToOptions], - fields: [strictArrayOfStrings, identityFunc], - mergeFields: [toObject, identityFunc, identityFunc], +const CalendarOpsAdapter = createWrapperClass(adapterIdGetters, { + ...mapProps({ + ...eraYearFieldRefiners, + ...dateFieldRefiners, + ...dateStatRefiners, + }, (refiner, propName) => { + return (calendar, isoDateFields) => { + return refiner(calendar[propName](createPlainDate(isoDateFields))) + } }), -) + + dateAdd(calendar, isoDateFields, durationInternals, overflow) { + return getPlainDateInternals( + calendar.dateAdd( + createPlainDate(isoDateFields), + createDuration(durationInternals), + { overflow }, + ), + ) + }, + + dateUntil(calendar, isoDateFields0, isoDateFields1, largestUnit) { + return getPlainDateInternals( + calendar.dateUntil( + createPlainDate(isoDateFields0), + createPlainDate(isoDateFields1), + { largestUnit }, + ), + ) + }, + + dateFromFields(calendar, fields, overflow) { + return getPlainDateInternals(calendar.dateFromFields(fields, { overflow })) + }, + + yearMonthFromFields(calendar, fields, overflow) { + return getPlainYearMonthInternals(calendar.yearMonthFromFields(fields, { overflow })) + }, + + monthDayFromFields(calendar, fields, overflow) { + return getPlainMonthDayInternals(calendar.monthDayFromFields(fields, { overflow })) + }, + + fields(calendar, fieldNames) { + return strictArray(calendar.fields(fieldNames)).map(toString) + }, + + mergeFields(calendar, fields0, fields1) { + return toObject(calendar.mergeFields(fields0, fields1)) + }, +}) diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js index 8891fc38..ea2a934d 100644 --- a/packages/temporal-polyfill/src/new/class.js +++ b/packages/temporal-polyfill/src/new/class.js @@ -1,5 +1,5 @@ import { DateTimeFormat } from './intlFormat' -import { strictInstanceOf } from './options' +import { strictInstanceOf, toString } from './options' import { createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, defineProps, @@ -62,10 +62,15 @@ export function returnId(internals) { return internals.id } -// TODO: make a versoin that casts the id to string? For adapters +function returnIdStrict(internals) { + return toString(internals.id) +} + export const internalIdGetters = { id: returnId } +export const adapterIdGetters = { id: returnIdStrict } // TODO: createStrictInternalGetter +// TODO: move to .bind?? export function getStrictInternals(Class) { return (res) => getInternals(strictInstanceOf(Class), res) } @@ -137,11 +142,3 @@ export function toLocaleStringMethod(internals, locales, options) { const format = new DateTimeFormat(locales, options) return format.format(this) } - -// Adapter Utils -// ------------------------------------------------------------------------------------------------- - -// TODO: rethink this. too meta -export function createAdapterMethods() { - -} diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index 0b5b92c6..9b15fe3c 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -16,6 +16,7 @@ import { yearMonthBasicNames, yearMonthFieldNames, } from './calendarFields' +import { queryCalendarImpl } from './calendarImpl' import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { @@ -261,7 +262,7 @@ export function refinePlainMonthDayBag(bag, options, calendar = extractBagCalend const calendarAbsent = !calendar if (calendarAbsent) { - calendar = queryCalendarOps(isoCalendarId) + calendar = queryCalendarImpl(isoCalendarId) } const fieldNames = calendar.fields(dateFieldNames) @@ -382,7 +383,7 @@ function mergeCalendarFields( } function getBagCalendarOps(bag) { - return extractBagCalendarOps(bag) || queryCalendarOps(isoCalendarId) + return extractBagCalendarOps(bag) || queryCalendarImpl(isoCalendarId) } function extractBagCalendarOps(bag) { @@ -457,6 +458,7 @@ function refineFields( return res } +// use .bind? export function createComplexBagRefiner(key, ForbiddenClass) { return function(bag) { const internalArg = getInternals(bag)?.[key] diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index ffdbe632..d26603fc 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -8,6 +8,7 @@ import { negateDurationFields, refineDurationInternals, } from './durationFields' +import { formatDurationInternals } from './isoFormat' import { isoToEpochNano } from './isoMath' import { stringToDurationInternals } from './isoParse' import { compareLargeInts } from './largeInt' @@ -156,6 +157,8 @@ export const [ ) }, + toString: formatDurationInternals, + valueOf: neverValueOf, }, diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.js index 52e602f6..f86f19cc 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -52,3 +52,7 @@ export function formatCalendar(calendarProtocol, options) { function formatCalendarWithSingleOpt(calendarProtocol, calendarNameOpt) { } + +export function formatDurationInternals(durationInternals, options) { + +} diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index c00c898e..7abd4d82 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -185,7 +185,7 @@ function validateIsoDateTimeInternals(isoDateTimeInternals) { // validateIsoInte export function validateEpochNano(epochNano) { if ( - epochNano == null || // TODO: pick null or undefined + epochNano === undefined || compareLargeInts(epochNano, epochNanoMin) === 1 || // epochNano < epochNanoMin compareLargeInts(epochNanoMax, epochNano) === 1 // epochNanoMax < epochNano ) { @@ -222,6 +222,7 @@ export function isoToEpochMilli(isoDateTimeFields) { } export function isoToEpochNano(isoDateTimeFields) { + // if invalid, should return undefined } // ISO Arguments -> Epoch diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index ea7eb930..4db46dbd 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -13,6 +13,8 @@ import { import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { createZonedDateTime } from './zonedDateTime' +// TODO: rename method names back to parse + // High-level // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 116a8cd9..dbbdd25f 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -11,6 +11,15 @@ import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { noop } from './util' +export const timeZoneVitalMethods = { + getPossibleInstantsFor(impl, plainDateTimeArg) { + return impl.getPossibleInstantsFor(toPlainDateTimeInternals(plainDateTimeArg)) + .map(createInstant) + }, + + getOffsetNanosecondsFor: getImplOffsetNanosecondsFor, +} + export const [TimeZone, createTimeZone] = createTemporalClass( 'TimeZone', @@ -41,18 +50,18 @@ export const [TimeZone, createTimeZone] = createTemporalClass( // ----------------------------------------------------------------------------------------------- { + ...timeZoneVitalMethods, + getOffsetStringFor(impl, instantArg) { - return formatOffsetNanoseconds( - impl.getOffsetNanosecondsFor(toInstantEpochNanoseconds(instantArg)), - ) + return formatOffsetNanoseconds(getImplOffsetNanosecondsFor(impl, instantArg)) }, getPlainDateTimeFor(impl, instantArg, calendarArg) { const epochNanoseconds = toInstantEpochNanoseconds(instantArg) return createPlainDateTime({ - ...zonedEpochNanoToIso(impl, epochNanoseconds), calendar: queryCalendarOps(calendarArg), + ...zonedEpochNanoToIso(impl, epochNanoseconds), }) }, @@ -60,27 +69,23 @@ export const [TimeZone, createTimeZone] = createTemporalClass( return getSingleInstantFor( impl, toPlainDateTimeInternals(plainDateTimeArg), - toDisambiguation(options), + toDisambiguation(options), // TODO: method w/ whole options object ) }, - getPossibleInstantsFor(impl, plainDateTimeArg) { - return impl.getPossibleInstantsFor(toPlainDateTimeInternals(plainDateTimeArg)) - .map(createInstant) - }, + getNextTransition: getImplTransition.bind(undefined, 1), - getOffsetNanosecondsFor(impl, instantArg) { - return impl.getOffsetNanosecondsFor(toInstantEpochNanoseconds(instantArg)) - }, - - getNextTransition(impl, instantArg) { - return impl.getTransition(toInstantEpochNanoseconds(instantArg), 1) - }, - - getPreviousTransition(impl, instantArg) { - return impl.getTransition(toInstantEpochNanoseconds(instantArg), -1) - }, + getPreviousTransition: getImplTransition.bind(undefined, -1), toString: returnId, }, ) + +function getImplOffsetNanosecondsFor(impl, instantArg) { + return impl.getOffsetNanosecondsFor(toInstantEpochNanoseconds(instantArg)) +} + +function getImplTransition(direction, impl, instantArg) { + const epochNano = impl.getTransition(toInstantEpochNanoseconds(instantArg), direction) + return epochNano ? createInstant(epochNano) : null +} diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index 450d34f2..49c9faf2 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -50,7 +50,6 @@ export class FixedTimeZoneImpl { } getTransition(epochNano, direction) { - return null } } @@ -82,10 +81,9 @@ export class IntlTimeZoneImpl { epochSec + ((direction > 0 || subsecNano) ? 1 : 0), direction, ) - if (resEpochSec === undefined) { - return null + if (resEpochSec !== undefined) { + return epochSecToNano(resEpochSec) } - return epochSecToNano(resEpochSec) } } diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index 553a7f2f..2f625856 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -1,9 +1,8 @@ import { - createAdapterMethods, + adapterIdGetters, createWrapperClass, getInternals, getStrictInternals, - internalIdGetters, } from './class' import { Instant, createInstant } from './instant' import { isoTimeFieldDefaults } from './isoFields' @@ -16,29 +15,36 @@ import { addDaysToIsoFields } from './move' import { strictArray, strictNumber } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' -import { createTimeZone } from './timeZone' +import { TimeZone, createTimeZone, timeZoneVitalMethods } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' -import { createLazyMap } from './util' +import { createLazyMap, createVitalsChecker, getCommonInternal } from './util' export const utcTimeZoneId = 'UTC' -export function queryTimeZoneOps(timeZoneSlot) { - if (typeof timeZoneSlot === 'object') { - return new TimeZoneOpsAdapter(timeZoneSlot) +const checkTimeZoneVitals = createVitalsChecker(timeZoneVitalMethods) + +export function queryTimeZoneOps(timeZoneArg) { + if (typeof timeZoneArg === 'object') { + if (timeZoneArg instanceof TimeZone) { + return getInternals(timeZoneArg) + } + + checkTimeZoneVitals(timeZoneArg) + return new TimeZoneOpsAdapter(timeZoneArg) } - return queryTimeZoneImpl(timeZoneSlot) // string + + return queryTimeZoneImpl(toString(timeZoneArg)) } export function getPublicTimeZone(internals) { - const timeZoneOps = internals.timeZone - return getInternals(timeZoneOps) || // TimeZoneOpsAdapter (return internal TimeZone) - createTimeZone(timeZoneOps) // TimeZoneImpl (create outer TimeZone) -} + const { timeZone } = internals -export function getCommonTimeZoneOps(internals0, internals1) { - // TODO + return getInternals(timeZone) || // TimeZoneOpsAdapter (return internal TimeZone) + createTimeZone(timeZone) // TimeZoneImpl (create outer TimeZone) } +export const getCommonTimeZoneOps = getCommonInternal.bind(undefined, 'timeZone') + // Public Utils // ------------ @@ -188,19 +194,16 @@ export function zonedEpochNanoToIso(timeZoneOps, epochNano) { const getStrictInstantEpochNanoseconds = getStrictInternals(Instant) -export const TimeZoneOpsAdapter = createWrapperClass( - internalIdGetters, - createAdapterMethods({ - getOffsetNanosecondsFor: [ - validateOffsetNano, - createInstant, - ], - getPossibleInstantsFor: [ - extractEpochNanos, - createPlainDateTime, - ], - }), -) +export const TimeZoneOpsAdapter = createWrapperClass(adapterIdGetters, { + getOffsetNanosecondsFor(timeZone, epochNano) { + return validateOffsetNano(timeZone.getOffsetNanosecondsFor(createInstant(epochNano))) + }, + + getPossibleInstantsFor(timeZone, isoDateTimeFields) { + return strictArray(timeZone.getPossibleInstantsFor(createPlainDateTime(isoDateTimeFields))) + .map(getStrictInstantEpochNanoseconds) + }, +}) function validateOffsetNano(offsetNano) { offsetNano = strictNumber(offsetNano) @@ -211,7 +214,3 @@ function validateOffsetNano(offsetNano) { return offsetNano } - -function extractEpochNanos(instants) { - return strictArray(instants).map(getStrictInstantEpochNanoseconds) -} diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index 482914d5..2728dd37 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -45,6 +45,9 @@ export function excludeProps(options, propNames) { export function hasAnyMatchingProps(props, propNames) { } +function hasAllMatchingProps(props, propNames) { +} + export function zipSingleValue() { } @@ -98,7 +101,31 @@ export function compareNumbers() { export function clamp() { } +export function getCommonInternal(propName, obj0, obj1) { + const internal0 = obj0[propName] + const internal1 = obj1[propName] + + if (!isIdPropsEqual(internal0, internal1)) { + throw new TypeError(`${propName} not equal`) + } + + return internal0 +} + export function isIdPropsEqual(obj0, obj1) { + return obj0 === obj1 || obj0.id !== obj1.id +} + +export function createVitalsChecker(vitalMethods) { + const vitalNames = Object.keys(vitalMethods) + vitalNames.push('id') + vitalNames.sort() // order matters? + + return (obj) => { + if (!hasAllMatchingProps(obj, vitalNames)) { + throw new TypeError('Invalid protocol') + } + } } /* diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index d75e7e9c..0f70f3ab 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -115,6 +115,10 @@ export const [ zonedInternalsToIso(internals).offsetNanoseconds, ) }, + + timeZoneId(internals) { + return internals.timeZone.id + }, }, // Methods From 88e4fb6148fd9d8b64c0c271f78c2487c650c7b3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 10 Jun 2023 23:48:36 -0400 Subject: [PATCH 091/805] simplify --- .../temporal-polyfill/src/new/calendar.js | 18 ++--- .../src/new/calendarConfig.js | 14 ++-- .../temporal-polyfill/src/new/calendarOps.js | 27 ++++--- packages/temporal-polyfill/src/new/class.js | 76 +++++++++++++------ packages/temporal-polyfill/src/new/convert.js | 35 ++++----- .../temporal-polyfill/src/new/duration.js | 4 +- .../temporal-polyfill/src/new/isoParse.js | 35 +++++---- .../temporal-polyfill/src/new/plainDate.js | 9 +-- .../src/new/plainDateTime.js | 9 +-- .../src/new/plainMonthDay.js | 9 +-- .../temporal-polyfill/src/new/plainTime.js | 4 +- .../src/new/plainYearMonth.js | 9 +-- .../temporal-polyfill/src/new/timeZone.js | 18 ++--- .../temporal-polyfill/src/new/timeZoneImpl.js | 4 +- .../temporal-polyfill/src/new/timeZoneOps.js | 20 ++--- packages/temporal-polyfill/src/new/util.js | 29 +------ .../src/new/zonedDateTime.js | 12 +-- 17 files changed, 167 insertions(+), 165 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 47c011be..6ebf6351 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -1,15 +1,15 @@ import { dateGetterNames } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' -import { createTemporalClass, internalIdGetters, returnId } from './class' +import { createTemporalClass, getObjId, idGetters } from './class' import { - createComplexBagRefiner, + refineComplexBag, refinePlainDateBag, refinePlainMonthDayBag, refinePlainYearMonthBag, } from './convert' import { createDuration, toDurationInternals } from './duration' import { isoDaysInWeek } from './isoMath' -import { stringToCalendarId } from './isoParse' +import { parseCalendarId } from './isoParse' import { optionsToOverflow, strictArray, toObject } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' @@ -17,7 +17,7 @@ import { createPlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' import { mapArrayToProps, noop, removeUndefines } from './util' -export const calendarVitalMethods = { +export const calendarProtocolMethods = { ...mapArrayToProps(dateGetterNames, (propName) => { return (impl, plainDateArg) => { return impl[propName](toPlainDateInternals(plainDateArg)) @@ -85,10 +85,10 @@ export const [Calendar, createCalendar] = createTemporalClass( {}, // bagToInternals - createComplexBagRefiner('calendar', TimeZone), + refineComplexBag.bind(undefined, 'calendar', TimeZone), // stringToInternals - (str) => queryCalendarImpl(stringToCalendarId(str)), + (str) => queryCalendarImpl(parseCalendarId(str)), // handleUnusedOptions noop, @@ -96,14 +96,14 @@ export const [Calendar, createCalendar] = createTemporalClass( // Getters // ----------------------------------------------------------------------------------------------- - internalIdGetters, + idGetters, // Methods // ----------------------------------------------------------------------------------------------- { - ...calendarVitalMethods, + ...calendarProtocolMethods, - toString: returnId, + toString: getObjId, }, ) diff --git a/packages/temporal-polyfill/src/new/calendarConfig.js b/packages/temporal-polyfill/src/new/calendarConfig.js index 391b6cd6..2ed5c949 100644 --- a/packages/temporal-polyfill/src/new/calendarConfig.js +++ b/packages/temporal-polyfill/src/new/calendarConfig.js @@ -3,12 +3,14 @@ export const isoCalendarId = 'iso8601' export const gregoryCalendarId = 'gregory' export const japaneseCalendarId = 'japanese' -// for converting from [era,eraYear] -> year -// if origin is >=0, -// year = origin + eraYear -// if origin is <0, consider the era to be 'reverse' direction -// year = -origin - eraYear -// year = -(origin + eraYear) +/* +for converting from [era,eraYear] -> year +if origin is >=0, + year = origin + eraYear +if origin is <0, consider the era to be 'reverse' direction + year = -origin - eraYear + year = -(origin + eraYear) +*/ export const eraOriginsByCalendarId = { [gregoryCalendarId]: { bce: -1, diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index 22e11241..09db9770 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -1,15 +1,22 @@ -import { Calendar, calendarVitalMethods, createCalendar } from './calendar' +import { Calendar, calendarProtocolMethods, createCalendar } from './calendar' import { dateFieldRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' -import { adapterIdGetters, createWrapperClass, getInternals, getStrictInternals } from './class' +import { + createProtocolChecker, + createWrapperClass, + getCommonInnerObj, + getInternals, + getStrictInternals, + idGettersStrict, +} from './class' import { createDuration } from './duration' import { strictArray, toObject, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' -import { createVitalsChecker, getCommonInternal, mapProps } from './util' +import { mapProps } from './util' -const checkCalendarVitals = createVitalsChecker(calendarVitalMethods) +const checkCalendarProtocol = createProtocolChecker(calendarProtocolMethods) export function queryCalendarOps(calendarArg) { if (typeof calendarArg === 'object') { @@ -17,7 +24,7 @@ export function queryCalendarOps(calendarArg) { return getInternals(calendarArg) } - checkCalendarVitals(calendarArg) + checkCalendarProtocol(calendarArg) return new CalendarOpsAdapter(calendarArg) } @@ -31,16 +38,16 @@ export function getPublicCalendar(internals) { createCalendar(calendar) // CalendarImpl (create outer Calendar) } -export const getCommonCalendarOps = getCommonInternal.bind(undefined, 'calendar') +export const getCommonCalendarOps = getCommonInnerObj.bind(undefined, 'calendar') // Adapter // ------------------------------------------------------------------------------------------------- -const getPlainDateInternals = getStrictInternals(PlainDate) -const getPlainYearMonthInternals = getStrictInternals(PlainYearMonth) -const getPlainMonthDayInternals = getStrictInternals(PlainMonthDay) +const getPlainDateInternals = getStrictInternals.bind(undefined, PlainDate) +const getPlainYearMonthInternals = getStrictInternals.bind(undefined, PlainYearMonth) +const getPlainMonthDayInternals = getStrictInternals.bind(undefined, PlainMonthDay) -const CalendarOpsAdapter = createWrapperClass(adapterIdGetters, { +const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { ...mapProps({ ...eraYearFieldRefiners, ...dateFieldRefiners, diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js index ea2a934d..61cad208 100644 --- a/packages/temporal-polyfill/src/new/class.js +++ b/packages/temporal-polyfill/src/new/class.js @@ -3,6 +3,7 @@ import { strictInstanceOf, toString } from './options' import { createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, defineProps, + hasAllMatchingProps, identityFunc, isObjectLike, mapProps, @@ -48,31 +49,8 @@ export function createWrapperClass( return InternalObj } -export function neverValueOf() { - throw new TypeError('Cannot convert object using valueOf') -} - -export function transformInternalMethod(transformRes, methodName) { - return (impl, ...args) => { - return transformRes(impl[methodName](...args)) - } -} - -export function returnId(internals) { - return internals.id -} - -function returnIdStrict(internals) { - return toString(internals.id) -} - -export const internalIdGetters = { id: returnId } -export const adapterIdGetters = { id: returnIdStrict } - -// TODO: createStrictInternalGetter -// TODO: move to .bind?? -export function getStrictInternals(Class) { - return (res) => getInternals(strictInstanceOf(Class), res) +export function getStrictInternals(Class, res) { + return getInternals(strictInstanceOf(res, Class)) } // Temporal Class @@ -134,6 +112,9 @@ export function createTemporalClass( return [TemporalObj, createInstance, toInternals] } +// Utils for Specific Classes +// ------------------------------------------------------------------------------------------------- + export function toLocaleStringMethod(internals, locales, options) { /* Will create two internal Intl.DateTimeFormats :( @@ -142,3 +123,48 @@ export function toLocaleStringMethod(internals, locales, options) { const format = new DateTimeFormat(locales, options) return format.format(this) } + +export function neverValueOf() { + throw new TypeError('Cannot convert object using valueOf') +} + +// Complex Objects with IDs +// ------------------------------------------------------------------------------------------------- + +export function createProtocolChecker(protocolMethods) { + const propNames = Object.keys(protocolMethods) + propNames.push('id') + propNames.sort() // order matters? + + return (obj) => { + if (!hasAllMatchingProps(obj, propNames)) { + throw new TypeError('Invalid protocol') + } + } +} + +export function getCommonInnerObj(propName, obj0, obj1) { + const internal0 = obj0[propName] + const internal1 = obj1[propName] + + if (!isObjIdsEqual(internal0, internal1)) { + throw new TypeError(`${propName} not equal`) + } + + return internal0 +} + +export function isObjIdsEqual(obj0, obj1) { + return obj0 === obj1 || obj0.id !== obj1.id +} + +export function getObjId(internals) { + return internals.id +} + +function getObjIdStrict(internals) { + return toString(internals.id) +} + +export const idGetters = { id: getObjId } +export const idGettersStrict = { id: getObjIdStrict } diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index 9b15fe3c..b5f3ba70 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -25,7 +25,7 @@ import { updateDurationFieldsSign, } from './durationFields' import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' -import { parseOffsetNanoseconds } from './isoParse' +import { parseOffsetNano } from './isoParse' import { optionsToOverflow, toObject, @@ -60,7 +60,7 @@ export function refineZonedDateTimeBag(bag, options) { const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoDateFields, ...isoTimeFields }, - fields.offset !== undefined && parseOffsetNanoseconds(fields.offset), + fields.offset !== undefined && parseOffsetNano(fields.offset), false, // z? offset, disambiguation, @@ -91,7 +91,7 @@ export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoDateFields, ...isoTimeFields }, - parseOffsetNanoseconds(fields.offset), + parseOffsetNano(fields.offset), false, // z? offset, disambiguation, @@ -458,26 +458,23 @@ function refineFields( return res } -// use .bind? -export function createComplexBagRefiner(key, ForbiddenClass) { - return function(bag) { - const internalArg = getInternals(bag)?.[key] - if (internalArg) { - return internalArg - } +export function refineComplexBag(key, ForbiddenClass, bag) { + const internalArg = getInternals(bag)?.[key] + if (internalArg) { + return internalArg + } - forbidInstanceClass(bag, ForbiddenClass) + forbidInstanceClass(bag, ForbiddenClass) - if (!(key in bag)) { - return bag - } else { - bag = bag[key] + if (!(key in bag)) { + return bag + } else { + bag = bag[key] - forbidInstanceClass(bag, ForbiddenClass) + forbidInstanceClass(bag, ForbiddenClass) - if (isObjectLike(bag) && !(key in bag)) { - return bag - } + if (isObjectLike(bag) && !(key in bag)) { + return bag } } } diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index d26603fc..7c54fc7b 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -10,7 +10,7 @@ import { } from './durationFields' import { formatDurationInternals } from './isoFormat' import { isoToEpochNano } from './isoMath' -import { stringToDurationInternals } from './isoParse' +import { parseDuration } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNanoseconds } from './move' import { @@ -73,7 +73,7 @@ export const [ refineDurationBag, // stringToInternals - stringToDurationInternals, + parseDuration, // handleUnusedOptions noop, diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index 4db46dbd..af7b8ba0 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -11,14 +11,13 @@ import { constrainIsoTimeFields, } from './isoMath' import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' -import { createZonedDateTime } from './zonedDateTime' // TODO: rename method names back to parse // High-level // ------------------------------------------------------------------------------------------------- -export function stringToZonedDateTimeInternals(s) { +export function parseZonedDateTime(s) { const parsed = parseDateTime(s) // TODO: use just 'calendar' and 'timeZone' ? if (parsed) { if (!parsed.timeZoneId) { @@ -31,24 +30,24 @@ export function stringToZonedDateTimeInternals(s) { const epochNanoseconds = getMatchingInstantFor( timeZone, parsed, - parsed.offset !== undefined ? parseOffsetNanoseconds(parsed.offset) : undefined, + parsed.offset !== undefined ? parseOffsetNano(parsed.offset) : undefined, parsed.z, 'reject', 'compatible', true, // fuzzy ) - return createZonedDateTime({ + return { epochNanoseconds, timeZone, calendar, - }) + } } throw new Error() } -export function stringToPlainDateTimeInternals(s) { +export function parsePlainDateTime(s) { const parsed = parseDateTime(s) if (parsed) { return pluckIsoDateTimeInternals(parsed) @@ -57,7 +56,7 @@ export function stringToPlainDateTimeInternals(s) { throw new Error() } -export function stringToPlainDateInternals(s) { +export function parsePlainDate(s) { const parsed = parseDateTime(s) if (parsed) { return parsed @@ -66,7 +65,7 @@ export function stringToPlainDateInternals(s) { throw new Error() } -export function stringToPlainYearMonthInternals(s) { +export function parsePlainYearMonth(s) { let parsed = parseYearMonth(s) if (!parsed) { parsed = parseDateTime(s) @@ -82,7 +81,7 @@ export function stringToPlainYearMonthInternals(s) { throw new Error() } -export function stringToMonthDayInternals(s) { +export function parsePlainMonthDay(s) { let parsed = parseMonthDay(s) if (!parsed) { parsed = parseDateTime(s) @@ -98,7 +97,7 @@ export function stringToMonthDayInternals(s) { throw new Error() } -export function stringToPlainTimeInternals(s) { +export function parsePlainTime(s) { let parsed = parseTime(s) if (!parsed) { @@ -130,7 +129,7 @@ export function stringToPlainTimeInternals(s) { throw new Error() } -export function stringToCalendarId(s) { +export function parseCalendarId(s) { if (s !== isoCalendarId) { s = ( parseDateTime(s) || parseYearMonth(s) || parseMonthDay(s) @@ -140,7 +139,7 @@ export function stringToCalendarId(s) { return s } -export function stringToTimeZoneId(s) { +export function parseTimeZoneId(s) { const parsed = parseDateTime(s) if (parsed !== undefined) { if (parsed.timeZonedId) { @@ -160,7 +159,7 @@ export function stringToTimeZoneId(s) { // Low-level // ------------------------------------------------------------------------------------------------- -export function parseDateTime(s) { +function parseDateTime(s) { return constrainIsoDateTimeInternals({ // { isYear, isoMonth, isoDay, // isoHour, isMinute, isoSecond, etc... @@ -169,30 +168,30 @@ export function parseDateTime(s) { }) } -export function parseYearMonth(s) { +function parseYearMonth(s) { return constrainIsoDateInternals({ // { isYear, isoMonth, isoDay // calendar, timeZone } }) } -export function parseMonthDay(s) { +function parseMonthDay(s) { return constrainIsoDateInternals({ // { isYear, isoMonth, isoDay // calendar, timeZone } }) } -export function parseTime(s) { +function parseTime(s) { return constrainIsoTimeFields({ // { isoHour, isoMinute, isoSecond, etc... } }) } -export function parseOffsetNanoseconds(s) { +export function parseOffsetNano(s) { // number } -export function stringToDurationInternals(s) { +export function parseDuration(s) { // includes sign } diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index cfc990c9..24dea52a 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -5,7 +5,7 @@ import { getPublicCalendar, queryCalendarOps, } from './calendarOps' -import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -24,12 +24,11 @@ import { } from './isoFields' import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' -import { stringToPlainDateInternals } from './isoParse' +import { parsePlainDate } from './isoParse' import { optionsToOverflow } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' import { zonedInternalsToIso } from './timeZoneOps' -import { isIdPropsEqual } from './util' export const [ PlainDate, @@ -63,7 +62,7 @@ export const [ refinePlainDateBag, // stringToInternals - stringToPlainDateInternals, + parsePlainDate, // handleUnusedOptions optionsToOverflow, @@ -119,7 +118,7 @@ export const [ equals(internals, other) { const otherInternals = toPlainDateInternals(other) return !compareIsoDateTimeFields(internals, otherInternals) && - isIdPropsEqual(internals.calendar, otherInternals.calendar) + isObjIdsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 1c3ab35b..3db7907a 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' import { getPublicCalendar, queryCalendarOps } from './calendarOps' -import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -21,7 +21,7 @@ import { } from './isoFields' import { formatCalendar, formatIsoDateTimeFields } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' -import { stringToPlainDateTimeInternals } from './isoParse' +import { parsePlainDateTime } from './isoParse' import { moveDateTime } from './move' import { optionsToOverflow, @@ -32,7 +32,6 @@ import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' -import { isIdPropsEqual } from './util' import { createZonedDateTime } from './zonedDateTime' export const [ @@ -84,7 +83,7 @@ export const [ refinePlainDateTimeBag, // stringToInternals - stringToPlainDateTimeInternals, + parsePlainDateTime, // handleUnusedOptions optionsToOverflow, @@ -175,7 +174,7 @@ export const [ equals(internals, other) { const otherInternals = toPlainDateTimeInternals(other) return !compareIsoDateTimeFields(internals, otherInternals) && - isIdPropsEqual(internals.calendar, otherInternals.calendar) + isObjIdsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 56b7bf0b..3def1aee 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' import { monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' -import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertPlainMonthDayToDate, mergePlainMonthDayBag, @@ -10,9 +10,8 @@ import { import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields, isoEpochFirstLeapYear } from './isoMath' -import { stringToMonthDayInternals } from './isoParse' +import { parsePlainMonthDay } from './isoParse' import { optionsToOverflow } from './options' -import { isIdPropsEqual } from './util' export const [ PlainMonthDay, @@ -41,7 +40,7 @@ export const [ refinePlainMonthDayBag, // stringToInternals - stringToMonthDayInternals, + parsePlainMonthDay, // handleUnusedOptions optionsToOverflow, @@ -62,7 +61,7 @@ export const [ equals(internals, otherArg) { const otherInternals = toPlainMonthDayInternals(otherArg) return !compareIsoDateTimeFields(internals, otherInternals) && - isIdPropsEqual(internals.calendar, otherInternals.calendar) + isObjIdsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 7156d6df..97c7f0de 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -11,7 +11,7 @@ import { negateDurationFields } from './durationFields' import { pluckIsoTimeFields, refineIsoTimeInternals } from './isoFields' import { formatIsoTimeFields } from './isoFormat' import { compareIsoTimeFields } from './isoMath' -import { stringToPlainTimeInternals } from './isoParse' +import { parsePlainTime } from './isoParse' import { moveTime } from './move' import { optionsToOverflow } from './options' import { toPlainDateInternals } from './plainDate' @@ -60,7 +60,7 @@ export const [ refinePlainTimeBag, // stringToInternals - stringToPlainTimeInternals, + parsePlainTime, // handleUnusedOptions optionsToOverflow, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 75169fcf..40a00f1b 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' import { yearMonthGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' -import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertPlainYearMonthToDate, convertPlainYearMonthToIso, @@ -14,9 +14,8 @@ import { negateDurationFields } from './durationFields' import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' -import { stringToPlainYearMonthInternals } from './isoParse' +import { parsePlainYearMonth } from './isoParse' import { optionsToOverflow } from './options' -import { isIdPropsEqual } from './util' export const [ PlainYearMonth, @@ -45,7 +44,7 @@ export const [ refinePlainYearMonthBag, // stringToInternals - stringToPlainYearMonthInternals, + parsePlainYearMonth, // handleUnusedOptions optionsToOverflow, @@ -108,7 +107,7 @@ export const [ equals(internals, otherArg) { const otherInternals = toPlainYearMonthInternals(otherArg) return !compareIsoDateTimeFields(internals, otherInternals) && - isIdPropsEqual(internals.calendar, otherInternals.calendar) + isObjIdsEqual(internals.calendar, otherInternals.calendar) }, toString(internals, options) { diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index dbbdd25f..92892f90 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -1,17 +1,17 @@ import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' import { Calendar } from './calendar' import { queryCalendarOps } from './calendarOps' -import { createTemporalClass, internalIdGetters, returnId } from './class' -import { createComplexBagRefiner } from './convert' +import { createTemporalClass, getObjId, idGetters } from './class' +import { refineComplexBag } from './convert' import { createInstant, toInstantEpochNanoseconds } from './instant' import { formatOffsetNanoseconds } from './isoFormat' -import { stringToTimeZoneId } from './isoParse' +import { parseTimeZoneId } from './isoParse' import { toDisambiguation } from './options' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { noop } from './util' -export const timeZoneVitalMethods = { +export const timeZoneProtocolMethods = { getPossibleInstantsFor(impl, plainDateTimeArg) { return impl.getPossibleInstantsFor(toPlainDateTimeInternals(plainDateTimeArg)) .map(createInstant) @@ -33,10 +33,10 @@ export const [TimeZone, createTimeZone] = createTemporalClass( {}, // bagToInternals - createComplexBagRefiner('timeZone', Calendar), + refineComplexBag.bind(undefined, 'timeZone', Calendar), // stringToInternals - (str) => queryTimeZoneImpl(stringToTimeZoneId(str)), + (str) => queryTimeZoneImpl(parseTimeZoneId(str)), // handleUnusedOptions noop, @@ -44,13 +44,13 @@ export const [TimeZone, createTimeZone] = createTemporalClass( // Getters // ----------------------------------------------------------------------------------------------- - internalIdGetters, + idGetters, // Methods // ----------------------------------------------------------------------------------------------- { - ...timeZoneVitalMethods, + ...timeZoneProtocolMethods, getOffsetStringFor(impl, instantArg) { return formatOffsetNanoseconds(getImplOffsetNanosecondsFor(impl, instantArg)) @@ -77,7 +77,7 @@ export const [TimeZone, createTimeZone] = createTemporalClass( getPreviousTransition: getImplTransition.bind(undefined, -1), - toString: returnId, + toString: getObjId, }, ) diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index 49c9faf2..e0710ac3 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -11,7 +11,7 @@ import { isoToEpochSec, milliInSec, nanoInSec, secInDay, } from './isoMath' -import { parseOffsetNanoseconds } from './isoParse' +import { parseOffsetNano } from './isoParse' import { clamp, compareNumbers, createLazyMap } from './util' const periodDur = secInDay * 60 @@ -21,7 +21,7 @@ const maxPossibleTransition = isoArgsToEpochSec(new Date().getUTCFullYear() + 10 const intlTimeZoneImplCache = {} export function queryTimeZoneImpl(timeZoneId) { - const offsetNano = parseOffsetNanoseconds(timeZoneId) + const offsetNano = parseOffsetNano(timeZoneId) if (offsetNano !== undefined) { return new FixedTimeZoneImpl(timeZoneId, offsetNano) diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index 2f625856..f90f8000 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -1,8 +1,10 @@ import { - adapterIdGetters, + createProtocolChecker, createWrapperClass, + getCommonInnerObj, getInternals, getStrictInternals, + idGettersStrict, } from './class' import { Instant, createInstant } from './instant' import { isoTimeFieldDefaults } from './isoFields' @@ -15,13 +17,13 @@ import { addDaysToIsoFields } from './move' import { strictArray, strictNumber } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' -import { TimeZone, createTimeZone, timeZoneVitalMethods } from './timeZone' +import { TimeZone, createTimeZone, timeZoneProtocolMethods } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' -import { createLazyMap, createVitalsChecker, getCommonInternal } from './util' +import { createLazyMap } from './util' export const utcTimeZoneId = 'UTC' -const checkTimeZoneVitals = createVitalsChecker(timeZoneVitalMethods) +const checkTimeZoneProtocol = createProtocolChecker(timeZoneProtocolMethods) export function queryTimeZoneOps(timeZoneArg) { if (typeof timeZoneArg === 'object') { @@ -29,7 +31,7 @@ export function queryTimeZoneOps(timeZoneArg) { return getInternals(timeZoneArg) } - checkTimeZoneVitals(timeZoneArg) + checkTimeZoneProtocol(timeZoneArg) return new TimeZoneOpsAdapter(timeZoneArg) } @@ -43,7 +45,7 @@ export function getPublicTimeZone(internals) { createTimeZone(timeZone) // TimeZoneImpl (create outer TimeZone) } -export const getCommonTimeZoneOps = getCommonInternal.bind(undefined, 'timeZone') +export const getCommonTimeZoneOps = getCommonInnerObj.bind(undefined, 'timeZone') // Public Utils // ------------ @@ -192,16 +194,16 @@ export function zonedEpochNanoToIso(timeZoneOps, epochNano) { // Adapter // ------- -const getStrictInstantEpochNanoseconds = getStrictInternals(Instant) +const getInstantEpochNano = getStrictInternals.bind(undefined, Instant) -export const TimeZoneOpsAdapter = createWrapperClass(adapterIdGetters, { +export const TimeZoneOpsAdapter = createWrapperClass(idGettersStrict, { getOffsetNanosecondsFor(timeZone, epochNano) { return validateOffsetNano(timeZone.getOffsetNanosecondsFor(createInstant(epochNano))) }, getPossibleInstantsFor(timeZone, isoDateTimeFields) { return strictArray(timeZone.getPossibleInstantsFor(createPlainDateTime(isoDateTimeFields))) - .map(getStrictInstantEpochNanoseconds) + .map(getInstantEpochNano) }, }) diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index 2728dd37..8e80beb5 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -45,7 +45,7 @@ export function excludeProps(options, propNames) { export function hasAnyMatchingProps(props, propNames) { } -function hasAllMatchingProps(props, propNames) { +export function hasAllMatchingProps(props, propNames) { } export function zipSingleValue() { @@ -101,33 +101,6 @@ export function compareNumbers() { export function clamp() { } -export function getCommonInternal(propName, obj0, obj1) { - const internal0 = obj0[propName] - const internal1 = obj1[propName] - - if (!isIdPropsEqual(internal0, internal1)) { - throw new TypeError(`${propName} not equal`) - } - - return internal0 -} - -export function isIdPropsEqual(obj0, obj1) { - return obj0 === obj1 || obj0.id !== obj1.id -} - -export function createVitalsChecker(vitalMethods) { - const vitalNames = Object.keys(vitalMethods) - vitalNames.push('id') - vitalNames.sort() // order matters? - - return (obj) => { - if (!hasAllMatchingProps(obj, vitalNames)) { - throw new TypeError('Invalid protocol') - } - } -} - /* Works with BigInt or Number (as long as the same) */ diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 0f70f3ab..c18b83e9 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -1,6 +1,6 @@ import { dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' -import { createTemporalClass, neverValueOf } from './class' +import { createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -31,7 +31,7 @@ import { nanoInHour, validateEpochNano, } from './isoMath' -import { stringToZonedDateTimeInternals } from './isoParse' +import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNanoseconds } from './move' import { optionsToOverflow, toEpochNano } from './options' @@ -47,7 +47,7 @@ import { queryTimeZoneOps, zonedInternalsToIso, } from './timeZoneOps' -import { isIdPropsEqual, mapProps } from './util' +import { mapProps } from './util' export const [ ZonedDateTime, @@ -75,7 +75,7 @@ export const [ refineZonedDateTimeBag, // stringToInternals - stringToZonedDateTimeInternals, + parseZonedDateTime, // handleUnusedOptions optionsToOverflow, @@ -291,8 +291,8 @@ export const [ const otherInternals = toZonedDateTimeInternals(otherZonedDateTimeArg) return !compareLargeInts(internals.epochNanoseconds, otherInternals.epochNanoseconds) && - isIdPropsEqual(internals.calendar, otherInternals.calendar) && - isIdPropsEqual(internals.timeZone, otherInternals.timeZone) + isObjIdsEqual(internals.calendar, otherInternals.calendar) && + isObjIdsEqual(internals.timeZone, otherInternals.timeZone) }, toString(internals, options) { From 21529209daee7a851179b2eabf02b75c9e47ae7f Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 12 Jun 2023 11:58:04 -0400 Subject: [PATCH 092/805] CalendarImpl improvements --- .../temporal-polyfill/src/new/calendarImpl.js | 379 +++++++----------- packages/temporal-polyfill/src/new/class.js | 5 +- packages/temporal-polyfill/src/new/convert.js | 4 +- packages/temporal-polyfill/src/new/diff.js | 43 +- .../temporal-polyfill/src/new/intlFormat.js | 1 + .../temporal-polyfill/src/new/isoParse.js | 2 - packages/temporal-polyfill/src/new/move.js | 36 ++ packages/temporal-polyfill/src/new/util.js | 2 - 8 files changed, 234 insertions(+), 238 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index f9091132..42218050 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -17,12 +17,11 @@ import { yearStatNames, } from './calendarFields' import { + calendarImplDateUntil, computeIntlMonthsInYearSpan, computeIsoMonthsInYearSpan, diffDaysMilli, - diffYearMonthDay, } from './diff' -import { durationFieldDefaults } from './durationFields' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' import { isoDateFieldNames, isoTimeFieldDefaults } from './isoFields' import { @@ -35,14 +34,13 @@ import { computeIsoYearOfWeek, epochMilliToIso, isoArgsToEpochMilli, - isoDaysInWeek, isoEpochFirstLeapYear, isoEpochOriginYear, isoToEpochMilli, } from './isoMath' -import { addDaysMilli, addIntlMonths, addIsoMonths } from './move' +import { addDaysMilli, addIntlMonths, addIsoMonths, moveDate } from './move' import { constrainInt } from './options' -import { buildWeakMapCache, twoDigit } from './util' +import { buildWeakMapCache, createLazyMap, mapArrayToProps, twoDigit } from './util' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -81,14 +79,14 @@ class IsoCalendarImpl { } dateFromFields(fields, overflow) { - const year = this.readYear(fields) + const year = this.refineYear(fields) const month = this.refineMonth(fields, year, overflow) const day = this.refineDay(fields, month, year, overflow) return this.queryIsoFields(year, month, day) } yearMonthFromFields(fields, overflow) { - const year = this.readYear(fields) + const year = this.refineYear(fields) const month = this.refineMonth(fields, year, overflow) return this.queryIsoFields(year, month, 1) } @@ -103,7 +101,7 @@ class IsoCalendarImpl { ;([year, month] = this.queryYearMonthForMonthDay(monthCodeNumber, isLeapMonth, day)) } else { // year is required - year = this.readYear(fields) + year = this.refineYear(fields) month = this.refineMonth(fields, year, overflow) } @@ -111,24 +109,24 @@ class IsoCalendarImpl { } fields(fieldNames) { - if (getAllowErasInFields(this) && fieldNames.indexOf('year') !== -1) { - return fieldNames.concat(eraYearFieldNames) + if (getAllowErasInFields(this) && fieldNames.includes('year')) { + return [...fieldNames, ...eraYearFieldNames] } return fieldNames } mergeFields(baseFields, additionalFields) { - const merged = Object.assign({}, baseFields) + const merged = { ...baseFields } - removePropSet(merged, additionalFields, monthFieldNames) + removeIfAnyProps(merged, additionalFields, monthFieldNames) if (getAllowErasInFields(this)) { - removePropSet(merged, additionalFields, allYearFieldNames) + removeIfAnyProps(merged, additionalFields, allYearFieldNames) } if (getErasBeginMidYear(this)) { - removePropSet( + removeIfAnyProps( merged, additionalFields, monthDayFieldNames, @@ -142,8 +140,7 @@ class IsoCalendarImpl { // Internal Querying // ----------------- - // year/month/day already constrained! - queryIsoFields(year, month, day) { // return isoDateInternals + queryIsoFields(year, month, day) { return { calendar: this, isoYear: year, @@ -152,10 +149,6 @@ class IsoCalendarImpl { } } - queryDateStart(year, month, day) { - return isoArgsToEpochMilli(year, month, day) - } - queryYearMonthDay(isoDateFields) { return [isoDateFields.isoYear, isoDateFields.isoMonth, isoDateFields.isoDay] } @@ -181,105 +174,22 @@ class IsoCalendarImpl { } dateAdd(isoDateFields, durationFields, overflow) { - // TODO: move all of this into move.js file? - - const { years, months, weeks, days } = durationFields - let ms - - if (years || months) { - let [year, month, day] = this.queryYearMonthDay(isoDateFields) - - if (years) { - year += years - month = constrainInt(month, 1, this.queryMonthsInYear(year), overflow) - } - - if (months) { - ([year, month] = this.addMonths(year, month, months)) - day = constrainInt(day, 1, this.queryDaysInMonth(year, month), overflow) - } - - ms = this.queryDateStart(year, months, day) - } else if (weeks || days) { - ms = isoToEpochMilli(isoDateFields) - } else { - return isoDateFields - } - - ms = addDaysMilli(ms, weeks * isoDaysInWeek + days) - - return { - calendar: this, - ...epochMilliToIso(ms), - } + return moveDate(this, isoDateFields, durationFields, overflow) } dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { - // TODO: move all of this into diff.js file? - - if (largestUnit <= 'week') { // TODO - let weeks = 0 - let days = diffDaysMilli( - isoToEpochMilli(startIsoDateFields), - isoToEpochMilli(endIsoDateFields), - ) - const sign = Math.sign(days) - - if (largestUnit === 'day') { // TODO - weeks = Math.trunc(days / isoDaysInWeek) - days %= isoDaysInWeek - } - - return { ...durationFieldDefaults, weeks, days, sign } - } - - const yearMonthDayStart = this.queryYearMonthDay(startIsoDateFields) - const yearMonthDayEnd = this.queryYearMonthDay(endIsoDateFields) - let [years, months, days, sign] = diffYearMonthDay( - ...yearMonthDayStart, - ...yearMonthDayEnd, - this, - ) - - if (largestUnit === 'month') { // TODO - months = this.queryMonthsInYearSpan(yearMonthDayStart[0], years) - years = 0 - } - - return { ...durationFieldDefaults, years, months, days, sign } - - // TODO: only return DateDurationFields + return calendarImplDateUntil(this, startIsoDateFields, endIsoDateFields, largestUnit) } - // Field "Refining" (Reading & Constraining) - // ----------------------------------------- + // Field Refining + // -------------- - refineMonth(fields, year, overflow) { - return constrainInt( - this.readMonth(fields, year, overflow), - 1, - this.queryMonthsInYear(year), - overflow, - ) - } - - refineDay(fields, month, year, overflow) { - return constrainInt( - fields.day, // day guaranteed to exist because of required*Fields - 1, - this.queryDaysInMonth(year, month), - overflow, - ) - } - - // Field Reading - // ------------- - - readYear(fields) { + refineYear(fields) { let { era, eraYear, year } = fields + const allowEras = getAllowErasInFields(this) - if (getAllowErasInFields(this) && era !== undefined && eraYear !== undefined) { - const yearByEra = this.readYearByEra(era, eraYear) + if (allowEras && era !== undefined && eraYear !== undefined) { + const yearByEra = refineEraYear(this, era, eraYear) if (year !== undefined && year !== yearByEra) { throw new RangeError('The year and era/eraYear must agree') @@ -287,37 +197,21 @@ class IsoCalendarImpl { year = yearByEra } else if (year === undefined) { - // Will never reach this point for ISO calendar system b/c of required*Fields - // TODO: is this true for monthday parsing? - throw new RangeError('Must specify year or era/eraYear') + throw new RangeError('Must specify year' + (allowEras ? ' or era/eraYear' : '')) } return year } - readYearByEra(era, eraYear) { - const eraOrigins = getEraOrigins(this.id) - if (eraOrigins === undefined) { - throw new RangeError('Does not accept era/eraYear') - } - - const eraOrigin = eraOrigins[era] - if (eraOrigin === undefined) { - throw new RangeError('Unknown era') - } - - return eraYearToYear(eraYear, eraOrigin) - } - - readMonth( + refineMonth( fields, year, // optional if known that calendar doesn't support leap months - overflowForLeap = 'reject', + overflow = 'reject', ) { let { month, monthCode } = fields if (monthCode !== undefined) { - const monthByCode = this.readMonthByCode(monthCode, year, overflowForLeap) + const monthByCode = refineMonthCode(this, monthCode, year, overflow) if (month !== undefined && month !== monthByCode) { throw new RangeError('The month and monthCode do not agree') @@ -328,39 +222,71 @@ class IsoCalendarImpl { throw new RangeError('Must specify either month or monthCode') } - return month + return constrainInt( + this.readMonth(fields, year, overflow), + 1, + this.queryMonthsInYear(year), + overflow, + ) } - readMonthByCode( - monthCode, - year, // optional if known that calendar doesn't support leap months - overflowForLeap = 'reject', - ) { - const leapMonth = this.queryLeapMonth(year) - const [monthCodeNumber, isLeapMonth] = parseMonthCode(monthCode) - const month = refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) + refineDay(fields, month, year, overflow) { + return constrainInt( + fields.day, // day guaranteed to exist because of required*Fields + 1, + this.queryDaysInMonth(year, month), + overflow, + ) + } +} - if (isLeapMonth) { - const leapYearMeta = leapYearMetas[getCalendarIdBase(this.id)] - if (leapYearMeta === undefined) { - throw new RangeError('Calendar system doesnt support leap months') - } +// Refining Utils +// -------------- - if ( - leapYearMeta > 0 - ? month > leapYearMeta // max possible leap month - : month !== -leapYearMeta // (negative) constant leap month - ) { - throw new RangeError('Invalid leap-month month code') - } +function refineEraYear(calendar, era, eraYear) { + const eraOrigins = getEraOrigins(calendar.id) + if (eraOrigins === undefined) { + throw new RangeError('Does not accept era/eraYear') + } - if (overflowForLeap === 'reject' && month !== leapMonth) { - throw new RangeError('Invalid leap-month month code') - } + const eraOrigin = eraOrigins[era] + if (eraOrigin === undefined) { + throw new RangeError('Unknown era') + } + + return eraYearToYear(eraYear, eraOrigin) +} + +function refineMonthCode( + calendar, + monthCode, + year, // optional if known that calendar doesn't support leap months + overflow = 'reject', +) { + const leapMonth = calendar.queryLeapMonth(year) + const [monthCodeNumber, isLeapMonth] = parseMonthCode(monthCode) + const month = refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) + + if (isLeapMonth) { + const leapYearMeta = leapYearMetas[getCalendarIdBase(calendar.id)] + if (leapYearMeta === undefined) { + throw new RangeError('Calendar system doesnt support leap months') } - return month + if ( + leapYearMeta > 0 + ? month > leapYearMeta // max possible leap month + : month !== -leapYearMeta // (negative) constant leap month + ) { + throw new RangeError('Invalid leap-month month code') + } + + if (overflow === 'reject' && month !== leapMonth) { + throw new RangeError('Invalid leap-month month code') + } } + + return month } // Prototype Trickery @@ -371,7 +297,6 @@ const isoYearQueryMethods = { queryDaysInYear: computeIsoDaysInYear, queryIsLeapYear: computeIsoIsLeapYear, queryMonthsInYear: computeIsoMonthsInYear, - queryMonthsInYearSpan: computeIsoMonthsInYearSpan, } Object.assign(IsoCalendarImpl.prototype, { @@ -379,7 +304,9 @@ Object.assign(IsoCalendarImpl.prototype, { weekOfYear: computeIsoWeekOfYear, yearOfWeek: computeIsoYearOfWeek, addMonths: addIsoMonths, + queryDateStart: isoArgsToEpochMilli, queryDaysInMonth: computeIsoDaysInMonth, + queryMonthsInYearSpan: computeIsoMonthsInYearSpan, ...isoYearQueryMethods, }) @@ -440,10 +367,10 @@ class IntlCalendarImpl extends IsoCalendarImpl { constructor(id) { super(id) - const epochMillisecondsToIntlFields = createEpochMillisecondsToIntlFields(id) - const [queryYear, yearAtEpoch] = createIntlMonthCache(epochMillisecondsToIntlFields) + const epochMilliToIntlFields = createEpochMilliToIntlFields(id) + const [queryYear, yearAtEpoch] = createIntlMonthCache(epochMilliToIntlFields) - this.isoDateFieldsToIntl = createIntlFieldCache(epochMillisecondsToIntlFields) + this.isoDateFieldsToIntl = createIntlFieldCache(epochMilliToIntlFields) this.queryYear = queryYear this.yearAtEpoch = yearAtEpoch } @@ -469,8 +396,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { // Internal Querying // ----------------- - // year/month/day already constrained! - queryIsoFields(year, month, day) { // returns isoDateInternals + queryIsoFields(year, month, day) { return { calendar: this, ...epochMilliToIso(this.queryDateStart(year, month, day)), @@ -484,18 +410,16 @@ class IntlCalendarImpl extends IsoCalendarImpl { } queryIsLeapYear(year) { - const daysPrev = this.queryDaysInYear(year - 1) const days = this.queryDaysInYear(year) - const daysNext = this.queryDaysInYear(year + 1) - return days > daysPrev && days > daysNext + return days > this.queryDaysInYear(year - 1) && + days > this.queryDaysInYear(year + 1) } queryYearMonthDay(isoDateFields) { const intlFields = this.isoDateFieldsToIntl(isoDateFields) - const { year } = intlFields - const { monthStrToNum } = this.queryYear(year) - const month = monthStrToNum[intlFields.month] - return [year, month, intlFields.day] + const { year, month, day } = intlFields + const { monthStrToIndex } = this.queryYear(year) + return [year, monthStrToIndex[month] + 1, day] } queryYearMonthForMonthDay(monthCodeNumber, isLeapMonth, day) { @@ -532,8 +456,8 @@ class IntlCalendarImpl extends IsoCalendarImpl { } queryMonthsInYear(year) { - const { monthEpochMilliseconds } = this.queryYear(year) - return monthEpochMilliseconds.length + const { monthEpochMilli } = this.queryYear(year) + return monthEpochMilli.length } queryMonthsInYearSpan(yearStart, yearDelta) { @@ -541,30 +465,30 @@ class IntlCalendarImpl extends IsoCalendarImpl { } queryDaysInMonth(year, month) { - const { monthEpochMilliseconds } = this.queryYear(year) + const { monthEpochMilli } = this.queryYear(year) let nextMonth = month + 1 - let nextMonthEpochMilliseconds = monthEpochMilliseconds + let nextMonthEpochMilli = monthEpochMilli - if (nextMonth > monthEpochMilliseconds.length) { + if (nextMonth > monthEpochMilli.length) { nextMonth = 1 - nextMonthEpochMilliseconds = this.queryYear(year + 1).monthEpochMilliseconds + nextMonthEpochMilli = this.queryYear(year + 1).monthEpochMilli } return diffDaysMilli( - monthEpochMilliseconds[month - 1], - nextMonthEpochMilliseconds[nextMonth - 1], + monthEpochMilli[month - 1], + nextMonthEpochMilli[nextMonth - 1], ) } queryDateStart(year, month = 1, day = 1) { return addDaysMilli( - this.queryYear(year).monthEpochMilliseconds[month - 1], + this.queryYear(year).monthEpochMilli[month - 1], day - 1, ) } queryMonthStrs(year) { - return Object.keys(this.queryYear(year).monthStrToNum) + return Object.keys(this.queryYear(year).monthStrToIndex) } } @@ -572,7 +496,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { // ------------------ // era/eraYear/year/day -allYearFieldNames.concat('day').forEach((dateFieldName) => { +[...allYearFieldNames, 'day'].forEach((dateFieldName) => { IntlCalendarImpl.prototype[dateFieldName] = function(isoDateFields) { return this.isoDateFieldsToIntl(isoDateFields)[dateFieldName] } @@ -587,7 +511,9 @@ const calendarImplClasses = { [japaneseCalendarId]: JapaneseCalendarImpl, } -const calendarImplCache = {} +const queryCalendarImplWithClass = createLazyMap((calendarId, CalendarImplClass) => { + return new CalendarImplClass(calendarId) +}) export function queryCalendarImpl(calendarId) { const calendarIdBase = getCalendarIdBase(calendarId) @@ -597,31 +523,38 @@ export function queryCalendarImpl(calendarId) { calendarId = calendarIdBase } - // TODO: lazy cache util - return calendarImplCache[calendarId] || ( - calendarImplCache[calendarId] = new (CalendarImplClass || IntlCalendarImpl)(calendarId) - ) + return queryCalendarImplWithClass(calendarId, CalendarImplClass || IntlCalendarImpl) } // IntlFields Querying // ------------------------------------------------------------------------------------------------- -function createIntlFieldCache(epochMillisecondsToIntlFields) { +/* +interface IntlFields { + era: string + eraYear: number + year: number + month: string + day: number +} +*/ + +function createIntlFieldCache(epochMilliToIntlFields) { return buildWeakMapCache((isoDateFields) => { - const epochMilliseconds = isoToEpochMilli(isoDateFields) - return epochMillisecondsToIntlFields(epochMilliseconds) + const epochMilli = isoToEpochMilli(isoDateFields) + return epochMilliToIntlFields(epochMilli) }) } function createJapaneseFieldCache() { - const epochMillisecondsToIntlFields = createEpochMillisecondsToIntlFields(japaneseCalendarId) + const epochMilliToIntlFields = createEpochMilliToIntlFields(japaneseCalendarId) const primaryEraMilli = isoArgsToEpochMilli(1868, 9, 8) return buildWeakMapCache((isoDateFields) => { - const epochMilliseconds = isoToEpochMilli(isoDateFields) - const intlFields = epochMillisecondsToIntlFields(epochMilliseconds) + const epochMilli = isoToEpochMilli(isoDateFields) + const intlFields = epochMilliToIntlFields(epochMilli) - if (epochMilliseconds < primaryEraMilli) { + if (epochMilli < primaryEraMilli) { intlFields.era = computeGregoryEra(isoDateFields.isoYear) intlFields.eraYear = computeGregoryEraYear(isoDateFields.isoYear) } @@ -630,15 +563,15 @@ function createJapaneseFieldCache() { }) } -function createEpochMillisecondsToIntlFields(calendarId) { +function createEpochMilliToIntlFields(calendarId) { const intlFormat = buildIntlFormat(calendarId) if (!isCalendarIdsRelated(calendarId, intlFormat.resolvedOptions().calendar)) { throw new RangeError('Invalid calendar: ' + calendarId) } - return (epochMilliseconds) => { - const intlParts = hashIntlFormatParts(intlFormat, epochMilliseconds) + return (epochMilli) => { + const intlParts = hashIntlFormatParts(intlFormat, epochMilli) return parseIntlParts(intlParts, calendarId) } } @@ -646,12 +579,11 @@ function createEpochMillisecondsToIntlFields(calendarId) { function parseIntlParts(intlParts, calendarId) { return { ...parseIntlYear(intlParts, calendarId), - month: intlParts.month, // a short month string! + month: intlParts.month, // a short month string day: parseInt(intlParts.day), } } -// best place for this? export function parseIntlYear(intlParts, calendarId) { let year = parseInt(intlParts.relatedYear || intlParts.year) let era @@ -661,16 +593,14 @@ export function parseIntlYear(intlParts, calendarId) { const eraOrigins = getEraOrigins(calendarId) if (eraOrigins !== undefined) { era = normalizeShortEra(intlParts.era) - year = eraYearToYear(eraYear = year, eraOrigins[era] || 0) + eraYear = year // TODO: will this get optimized to next line? + year = eraYearToYear(eraYear, eraOrigins[era] || 0) } } return { era, eraYear, year } } -// DateTimeFormat Utils -// ------------------------------------------------------------------------------------------------- - function buildIntlFormat(calendarId) { return new IntlDateTimeFormat(standardCalendarId, { calendar: calendarId, @@ -685,56 +615,45 @@ function buildIntlFormat(calendarId) { // Intl Month Cache // ------------------------------------------------------------------------------------------------- -function createIntlMonthCache(epochMillisecondsToIntlFields) { - const yearAtEpoch = epochMillisecondsToIntlFields(0) +function createIntlMonthCache(epochMilliToIntlFields) { + const yearAtEpoch = epochMilliToIntlFields(0).year const yearCorrection = yearAtEpoch - isoEpochOriginYear - const yearCache = {} - - function queryYear(year) { - return yearCache[year] || ( // TODO: reusable pattern for this? - yearCache[year] = buildYear(year) - ) - } + const queryYear = createLazyMap(buildYear) function buildYear(year) { - let ms = isoArgsToEpochMilli(year - yearCorrection) + let milli = isoArgsToEpochMilli(year - yearCorrection) let intlFields - const msReversed = [] + const milliReversed = [] const monthStrsReversed = [] // move beyond current year do { - ms = addDaysMilli(ms, 400) - } while ((intlFields = epochMillisecondsToIntlFields(ms)).year <= year) + milli = addDaysMilli(milli, 400) + } while ((intlFields = epochMilliToIntlFields(milli)).year <= year) do { // move to start-of-month - ms = addDaysMilli(ms, 1 - intlFields.day) + milli = addDaysMilli(milli, 1 - intlFields.day) // only record the epochMilli if current year if (intlFields.year === year) { - msReversed.push(ms) + milliReversed.push(milli) monthStrsReversed.push(intlFields.month) } // move to last day of previous month - ms = addDaysMilli(ms, -1) - } while ((intlFields = epochMillisecondsToIntlFields(ms)).year >= year) + milli = addDaysMilli(milli, -1) + } while ((intlFields = epochMilliToIntlFields(milli)).year >= year) return { - monthEpochMilliseconds: msReversed.reverse(), - monthStrToNum: monthStrsReversed.reverse().reduce(accumMonthStrToNum, {}), + monthEpochMilli: milliReversed.reverse(), + monthStrToIndex: mapArrayToProps(monthStrsReversed.reverse()), } } return [queryYear, yearAtEpoch] } -function accumMonthStrToNum(accum, monthStr, index) { - accum[monthStr] = index + 1 - return accum -} - // Era Utils // ------------------------------------------------------------------------------------------------- @@ -759,8 +678,10 @@ function normalizeShortEra(formattedEra) { // Month Utils // ------------------------------------------------------------------------------------------------- +const monthCodeRegExp = /^M(\d{2})(L?)$/ + function parseMonthCode(monthCode) { - const m = monthCode.match(/^M(\d{2})(L?)$/) + const m = monthCodeRegExp.exec(monthCode) if (!m) { throw new RangeError('Invalid monthCode format') } @@ -773,7 +694,7 @@ function parseMonthCode(monthCode) { function refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) { return monthCodeNumber + ( - (isLeapMonth || (leapMonth && monthCodeNumber >= leapMonth)) // TODO: double check this + (isLeapMonth || (leapMonth && monthCodeNumber >= leapMonth)) ? 1 : 0 ) @@ -782,7 +703,7 @@ function refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) { function formatMonthCode(month, leapMonth) { return 'M' + twoDigit( month - ( - (leapMonth && month >= leapMonth) // TODO: double check this + (leapMonth && month >= leapMonth) ? 1 : 0 ), @@ -803,7 +724,7 @@ function getCalendarIdBase(calendarId) { // General Utils // ------------------------------------------------------------------------------------------------- -function removePropSet( +function removeIfAnyProps( targetObj, testObj, testPropNames, diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js index 61cad208..3645b504 100644 --- a/packages/temporal-polyfill/src/new/class.js +++ b/packages/temporal-polyfill/src/new/class.js @@ -134,7 +134,7 @@ export function neverValueOf() { export function createProtocolChecker(protocolMethods) { const propNames = Object.keys(protocolMethods) propNames.push('id') - propNames.sort() // order matters? + propNames.sort() // TODO: order matters? return (obj) => { if (!hasAllMatchingProps(obj, propNames)) { @@ -155,7 +155,8 @@ export function getCommonInnerObj(propName, obj0, obj1) { } export function isObjIdsEqual(obj0, obj1) { - return obj0 === obj1 || obj0.id !== obj1.id + return obj0 === obj1 || // short-circuit + obj0.id === obj1.id // .id could be getter with logic / side-effects (during testing) } export function getObjId(internals) { diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index b5f3ba70..d3ea201f 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -197,7 +197,7 @@ function convertToIso( extra = refineFields(extra, extraFieldNames, getRequiredDateFields(calendar)) let mergedFields = calendar.mergeFields(input, extra) - const mergedFieldNames = removeDuplicateStrings(inputFieldNames.concat(extraFieldNames)) + const mergedFieldNames = removeDuplicateStrings([...inputFieldNames, ...extraFieldNames]) mergedFields = refineFields(mergedFields, mergedFieldNames, []) return calendar.dateFromFields(mergedFields) @@ -382,7 +382,7 @@ function mergeCalendarFields( return refineFields(fields, fieldNames, []) // guard against ridiculous .mergeField results } -function getBagCalendarOps(bag) { +function getBagCalendarOps(bag) { // defaults to ISO return extractBagCalendarOps(bag) || queryCalendarImpl(isoCalendarId) } diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index f6d3fb31..231d6be6 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -1,7 +1,10 @@ +import { durationFieldDefaults } from './durationFields' import { pluckIsoTimeFields } from './isoFields' import { + isoDaysInWeek, isoMonthsInYear, isoTimeFieldsToNano, + isoToEpochMilli, isoToEpochNano, nanoInUtcDay, nanosecondsToTimeDuration, @@ -101,7 +104,7 @@ export function diffZonedEpochNanoseconds( } export function diffDateTimes( - calendar, + calendar, // calendarOps startIsoFields, endIsoFields, largestUnit, @@ -193,6 +196,44 @@ export function diffDates( ) } +export function calendarImplDateUntil( // no rounding + calendar, + startIsoDateFields, + endIsoDateFields, + largestUnit, +) { + if (largestUnit <= 'week') { // TODO + let weeks = 0 + let days = diffDaysMilli( + isoToEpochMilli(startIsoDateFields), + isoToEpochMilli(endIsoDateFields), + ) + const sign = Math.sign(days) + + if (largestUnit === 'week') { // TODO + weeks = Math.trunc(days / isoDaysInWeek) + days %= isoDaysInWeek + } + + return { ...durationFieldDefaults, weeks, days, sign } + } + + const yearMonthDayStart = calendar.queryYearMonthDay(startIsoDateFields) + const yearMonthDayEnd = calendar.queryYearMonthDay(endIsoDateFields) + let [years, months, days, sign] = diffYearMonthDay( + ...yearMonthDayStart, + ...yearMonthDayEnd, + calendar, // TODO: make first param? + ) + + if (largestUnit === 'month') { // TODO + months += calendar.queryMonthsInYearSpan(yearMonthDayStart[0], years) + years = 0 + } + + return { ...durationFieldDefaults, years, months, days, sign } +} + export function diffTimes() { } diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index 6e04668c..b873094a 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -54,6 +54,7 @@ export class DateTimeFormat extends IntlDateTimeFormat { const origMethod = IntlDateTimeFormat.prototype[methodName] if (origMethod) { + // TODO: not sufficient for defining method DateTimeFormat.prototype[methodName] = function(arg0, arg1) { const [formattable0, formattable1, format] = resolveRangeFormattables(this, arg0, arg1) return origMethod.call(format, formattable0, formattable1) diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index af7b8ba0..3eed6e78 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -12,8 +12,6 @@ import { } from './isoMath' import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' -// TODO: rename method names back to parse - // High-level // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index ee3ea9d2..2e08c823 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -4,10 +4,14 @@ import { durationTimeFieldsToIso, } from './durationFields' import { + epochMilliToIso, + isoDaysInWeek, isoMonthsInYear, isoTimeFieldsToNano, + isoToEpochMilli, nanoToIsoTimeFields, } from './isoMath' +import { constrainInt } from './options' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' export function addDaysMilli(epochMilli, milli) { // moveEpochMilliByDays @@ -82,6 +86,38 @@ export function moveDateTime( } } +export function moveDate(calendar, isoDateFields, durationFields, overflow) { + const { years, months, weeks, days } = durationFields + let ms + + if (years || months) { + let [year, month, day] = calendar.queryYearMonthDay(isoDateFields) + + if (years) { + year += years + month = constrainInt(month, 1, calendar.queryMonthsInYear(year), overflow) + } + + if (months) { + ([year, month] = calendar.addMonths(year, month, months)) + day = constrainInt(day, 1, calendar.queryDaysInMonth(year, month), overflow) + } + + ms = calendar.queryDateStart(year, month, day) + } else if (weeks || days) { + ms = isoToEpochMilli(isoDateFields) + } else { + return isoDateFields + } + + ms = addDaysMilli(ms, weeks * isoDaysInWeek + days) + + return { + calendar, + ...epochMilliToIso(ms), + } +} + export function moveTime(isoTimeFields, durationFields) { const [movedIsoTimeFields] = addIsoTimeFields( isoTimeFields, diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/util.js index 8e80beb5..4e0de9c9 100644 --- a/packages/temporal-polyfill/src/new/util.js +++ b/packages/temporal-polyfill/src/new/util.js @@ -1,8 +1,6 @@ // in general, prefer .bind over macro functions -// always prefer [...a] over [].concat(a) - // monitor use of floor/trunc and modding. many are wrong export function isObjectLike() { From e7e43f75b2a02275b7e2b34280d4c0a2a5c40e98 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 12 Jun 2023 21:49:07 -0400 Subject: [PATCH 093/805] lots of unit/diffing changes --- .../temporal-polyfill/src/new/calendarImpl.js | 20 +- packages/temporal-polyfill/src/new/diff.js | 329 +++++++++--------- .../temporal-polyfill/src/new/duration.js | 38 +- .../src/new/durationFields.js | 69 +++- packages/temporal-polyfill/src/new/instant.js | 18 +- .../temporal-polyfill/src/new/isoFields.js | 7 +- packages/temporal-polyfill/src/new/isoMath.js | 135 ++++--- .../temporal-polyfill/src/new/largeInt.js | 34 +- packages/temporal-polyfill/src/new/move.js | 8 +- packages/temporal-polyfill/src/new/options.js | 22 +- packages/temporal-polyfill/src/new/round.js | 135 +++---- .../temporal-polyfill/src/new/timeZoneImpl.js | 2 +- .../src/new/zonedDateTime.js | 10 +- 13 files changed, 467 insertions(+), 360 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 42218050..f27a58d5 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -17,10 +17,10 @@ import { yearStatNames, } from './calendarFields' import { - calendarImplDateUntil, computeIntlMonthsInYearSpan, computeIsoMonthsInYearSpan, - diffDaysMilli, + diffDatesExact, + diffEpochMilliByDay, } from './diff' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' import { isoDateFieldNames, isoTimeFieldDefaults } from './isoFields' @@ -165,12 +165,12 @@ class IsoCalendarImpl { // ------------------------ dayOfYear(isoDateFields) { - const dayEpochMilliseconds = isoToEpochMilli({ + const dayEpochMilli = isoToEpochMilli({ ...isoDateFields, ...isoTimeFieldDefaults, }) - const yearStartEpochMilliseconds = this.queryDateStart(this.year(isoDateFields)) - return diffDaysMilli(yearStartEpochMilliseconds, dayEpochMilliseconds) + const yearStartEpochMilli = this.queryDateStart(this.year(isoDateFields)) + return diffEpochMilliByDay(yearStartEpochMilli, dayEpochMilli) } dateAdd(isoDateFields, durationFields, overflow) { @@ -178,7 +178,7 @@ class IsoCalendarImpl { } dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { - return calendarImplDateUntil(this, startIsoDateFields, endIsoDateFields, largestUnit) + return diffDatesExact(this, startIsoDateFields, endIsoDateFields, largestUnit) } // Field Refining @@ -406,7 +406,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { queryDaysInYear(year) { const milli = this.queryDateStart(year) const milliNext = this.queryDateStart(year + 1) - return diffDaysMilli(milli, milliNext) + return diffEpochMilliByDay(milli, milliNext) } queryIsLeapYear(year) { @@ -460,8 +460,8 @@ class IntlCalendarImpl extends IsoCalendarImpl { return monthEpochMilli.length } - queryMonthsInYearSpan(yearStart, yearDelta) { - return computeIntlMonthsInYearSpan(yearStart, yearDelta, this) + queryMonthsInYearSpan(yearDelta, yearStart) { + return computeIntlMonthsInYearSpan(yearDelta, yearStart, this) } queryDaysInMonth(year, month) { @@ -474,7 +474,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { nextMonthEpochMilli = this.queryYear(year + 1).monthEpochMilli } - return diffDaysMilli( + return diffEpochMilliByDay( monthEpochMilli[month - 1], nextMonthEpochMilli[nextMonth - 1], ) diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 231d6be6..10291fd9 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -1,108 +1,31 @@ -import { durationFieldDefaults } from './durationFields' +import { + durationFieldDefaults, + nanoToDurationFields, + timeNanoToDurationFields, +} from './durationFields' import { pluckIsoTimeFields } from './isoFields' import { + dayIndex, isoDaysInWeek, isoMonthsInYear, isoTimeFieldsToNano, isoToEpochMilli, isoToEpochNano, + milliInDay, + monthIndex, nanoInUtcDay, - nanosecondsToTimeDuration, + unitIndexes, + weekIndex, } from './isoMath' import { compareLargeInts } from './largeInt' -import { addDaysToIsoFields, moveDateTime, moveZonedEpochNanoseconds } from './move' -import { roundLargeNanoseconds, roundRelativeDuration } from './round' +import { addDaysToIsoFields, moveDateTime, moveZonedEpochNano } from './move' +import { roundLargeNano, roundNano, roundRelativeDuration } from './round' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { identityFunc } from './util' -export function diffDaysMilli(milli0, milli1) { // diffEpochMilliByDays -} - -// Diffing +// Dates & Times // ------------------------------------------------------------------------------------------------- -export function diffEpochNanoseconds( - startEpochNanoseconds, - endEpochNanoseconds, - largestUnit, - smallestUnit, - roundingMode, - roundingIncrement, -) { - return roundLargeNanoseconds( - diffExactLargeNanoseconds( - endEpochNanoseconds.subtract(startEpochNanoseconds), - smallestUnit, - roundingMode, - roundingIncrement, - ), - largestUnit, - ) -} - -export function diffZonedEpochNanoseconds( - calendar, - timeZone, - startEpochNanoseconds, - endEpochNanoseconds, - largestUnit, - // for createMarkerSystem's convenience - // TODO: eventually make these universal variables defaultSmallestUnit/defaultRoundingMode - // for input-validation - smallestUnit = 'nanoseconds', - roundingMode = 'halfExpand', - roundingIncrement = 1, -) { - if (largestUnit < 'day') { // TODO - return diffEpochNanoseconds( - startEpochNanoseconds, - endEpochNanoseconds, - largestUnit, - smallestUnit, - roundingMode, - roundingIncrement, - ) - } - - function isoToZoneEpochNanoseconds(isoDateTimeFields) { - return getSingleInstantFor(timeZone, isoDateTimeFields) - } - - const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) - const startIsoFields = zonedEpochNanoToIso(timeZone, startEpochNanoseconds) - const startIsoTimeFields = pluckIsoTimeFields(startIsoFields) - const endIsoFields = zonedEpochNanoToIso(timeZone, endEpochNanoseconds) - let midIsoFields = { ...endIsoFields, ...startIsoTimeFields } - let midEpochNanoseconds = isoToZoneEpochNanoseconds(midIsoFields) - const midSign = compareLargeInts(midEpochNanoseconds, endEpochNanoseconds) - - if (midSign === -sign) { - midIsoFields = { - ...addDaysToIsoFields(endIsoFields, -sign), - ...startIsoTimeFields, - } - midEpochNanoseconds = isoToZoneEpochNanoseconds(midIsoFields) - } - - const dateDiff = calendar.dateUntil(startIsoFields, midIsoFields, largestUnit) - const timeDiff = diffExactLargeNanoseconds( - endEpochNanoseconds.subtract(midEpochNanoseconds), - 'hours', // largestUnit (default?) - ) - - return roundRelativeDuration( - { ...dateDiff, ...timeDiff, sign }, - endEpochNanoseconds, - startEpochNanoseconds, // marker - identityFunc, // markerToEpochNanoseconds - moveZonedEpochNanoseconds.bind(undefined, calendar, timeZone), // moveMarker - smallestUnit, - roundingMode, - roundingIncrement, - largestUnit, - ) -} - export function diffDateTimes( calendar, // calendarOps startIsoFields, @@ -112,68 +35,65 @@ export function diffDateTimes( roundingMode, roundingIncrement, ) { - const startEpochNanoseconds = isoToEpochNano(startIsoFields) - const endEpochNanoseconds = isoToEpochNano(endIsoFields) + const startEpochNano = isoToEpochNano(startIsoFields) + const endEpochNano = isoToEpochNano(endIsoFields) - if (largestUnit < 'day') { // TODO - return diffEpochNanoseconds( - startEpochNanoseconds, - endEpochNanoseconds, + if (unitIndexes[largestUnit] < dayIndex) { + return diffEpochNano( + startEpochNano, + endEpochNano, largestUnit, smallestUnit, roundingMode, roundingIncrement, ) } - // TODO: what about day optimization? - const sign = compareLargeInts(startEpochNanoseconds, endEpochNanoseconds) - const startTimeNanoseconds = isoTimeFieldsToNano(startIsoFields) // number - const endTimeNanoseconds = isoTimeFieldsToNano(endIsoFields) // number - let timeNanosecondDiff = endTimeNanoseconds - startTimeNanoseconds - const timeSign = Math.sign(timeNanosecondDiff) + const sign = compareLargeInts(startEpochNano, endEpochNano) + const startTimeNano = isoTimeFieldsToNano(startIsoFields) + const endTimeNano = isoTimeFieldsToNano(endIsoFields) + let timeNano = endTimeNano - startTimeNano + const timeSign = Math.sign(timeNano) let midIsoFields = startIsoFields + // move start-fields forward so time-diff-sign matches date-diff-sign if (timeSign === -sign) { midIsoFields = { ...addDaysToIsoFields(startIsoFields, sign), ...pluckIsoTimeFields(startIsoFields), } - timeNanosecondDiff += nanoInUtcDay + timeNano += nanoInUtcDay } const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnit) - const timeDiff = nanosecondsToTimeDuration( - timeNanosecondDiff, - 'hours', // largestUnit (default?) - ) + const timeDiff = timeNanoToDurationFields(timeNano) return roundRelativeDuration( { ...dateDiff, ...timeDiff, sign }, - endEpochNanoseconds, - startIsoFields, // marker - isoToEpochNano, // markerToEpochNanoseconds - moveDateTime.bind(undefined, calendar), // moveMarker + endEpochNano, + largestUnit, smallestUnit, roundingMode, roundingIncrement, - largestUnit, + startIsoFields, // marker + isoToEpochNano, // markerToEpochNano + moveDateTime.bind(undefined, calendar), // moveMarker ) } export function diffDates( calendar, - startIsoDateFields, - endIsoDateFields, + startIsoFields, + endIsoFields, largestUnit, smallestUnit, roundingMode, roundingIncrement, ) { - if (largestUnit < 'day') { // TODO - return diffEpochNanoseconds( - isoToEpochNano(startIsoDateFields), - isoToEpochNano(endIsoDateFields), + if (unitIndexes[largestUnit] < dayIndex) { + return diffEpochNano( + isoToEpochNano(startIsoFields), + isoToEpochNano(endIsoFields), largestUnit, smallestUnit, roundingMode, @@ -181,36 +101,38 @@ export function diffDates( ) } - const dateDiff = calendar.dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) + const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnit) return roundRelativeDuration( dateDiff, - isoToEpochNano(endIsoDateFields), - startIsoDateFields, // marker - isoToEpochNano, // markerToEpochNanoseconds - calendar.dateAdd.bind(calendar), // moveMarker + isoToEpochNano(endIsoFields), + largestUnit, smallestUnit, roundingMode, roundingIncrement, - largestUnit, + startIsoFields, // marker + isoToEpochNano, // markerToEpochNano + calendar.dateAdd.bind(calendar), // moveMarker ) } -export function calendarImplDateUntil( // no rounding +export function diffDatesExact( calendar, - startIsoDateFields, - endIsoDateFields, + startIsoFields, + endIsoFields, largestUnit, ) { - if (largestUnit <= 'week') { // TODO + const largestUnitIndex = unitIndexes[largestUnit] + + if (largestUnitIndex <= weekIndex) { let weeks = 0 - let days = diffDaysMilli( - isoToEpochMilli(startIsoDateFields), - isoToEpochMilli(endIsoDateFields), + let days = diffEpochMilliByDay( + isoToEpochMilli(startIsoFields), + isoToEpochMilli(endIsoFields), ) const sign = Math.sign(days) - if (largestUnit === 'week') { // TODO + if (largestUnitIndex === weekIndex) { weeks = Math.trunc(days / isoDaysInWeek) days %= isoDaysInWeek } @@ -218,30 +140,136 @@ export function calendarImplDateUntil( // no rounding return { ...durationFieldDefaults, weeks, days, sign } } - const yearMonthDayStart = calendar.queryYearMonthDay(startIsoDateFields) - const yearMonthDayEnd = calendar.queryYearMonthDay(endIsoDateFields) + const yearMonthDayStart = calendar.queryYearMonthDay(startIsoFields) + const yearMonthDayEnd = calendar.queryYearMonthDay(endIsoFields) let [years, months, days, sign] = diffYearMonthDay( + calendar, ...yearMonthDayStart, ...yearMonthDayEnd, - calendar, // TODO: make first param? ) - if (largestUnit === 'month') { // TODO - months += calendar.queryMonthsInYearSpan(yearMonthDayStart[0], years) + if (largestUnitIndex === monthIndex) { + months += calendar.queryMonthsInYearSpan(years, yearMonthDayStart[0]) years = 0 } return { ...durationFieldDefaults, years, months, days, sign } } -export function diffTimes() { +export function diffTimes( + startIsoFields, + endIsoFields, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, +) { + const startTimeNano = isoTimeFieldsToNano(startIsoFields) + const endTimeNano = isoTimeFieldsToNano(endIsoFields) + const timeNano = roundNano( + endTimeNano - startTimeNano, + smallestUnit, + roundingMode, + roundingIncrement, + ) + + return { + ...durationFieldDefaults, + ...nanoToDurationFields(timeNano, largestUnit), + } +} + +// Epoch +// ------------------------------------------------------------------------------------------------- + +export function diffZonedEpochNano( + calendar, + timeZone, + startEpochNano, + endEpochNano, + largestUnit, + smallestUnit, // optional. internally will default to 'nanoseconds' + roundingMode, // optional. internally will default to 'halfExpand' + roundingIncrement, // optional. internally will default to 1 +) { + if (unitIndexes[largestUnit] < dayIndex) { + return diffEpochNano( + startEpochNano, + endEpochNano, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + ) + } + + const sign = compareLargeInts(startEpochNano, endEpochNano) + const startIsoFields = zonedEpochNanoToIso(timeZone, startEpochNano) + const startIsoTimeFields = pluckIsoTimeFields(startIsoFields) + const endIsoFields = zonedEpochNanoToIso(timeZone, endEpochNano) + const isoToZonedEpochNano = getSingleInstantFor.bind(undefined, timeZone) + let midIsoFields = { ...endIsoFields, ...startIsoTimeFields } + let midEpochNano = isoToZonedEpochNano(midIsoFields) + const midSign = compareLargeInts(midEpochNano, endEpochNano) + + if (midSign === -sign) { + midIsoFields = { + ...addDaysToIsoFields(endIsoFields, -sign), + ...startIsoTimeFields, + } + midEpochNano = isoToZonedEpochNano(midIsoFields) + } + + const dateDiff = calendar.dateUntil(startIsoFields, midIsoFields, largestUnit) + const timeDiffNano = endEpochNano.addLargeInt(midEpochNano, -1).toNumber() + const timeDiff = timeNanoToDurationFields(timeDiffNano) + + return roundRelativeDuration( + { ...dateDiff, ...timeDiff, sign }, + endEpochNano, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, + startEpochNano, // marker + identityFunc, // markerToEpochNano + moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker + ) +} + +export function diffEpochNano( + startEpochNano, + endEpochNano, + largestUnit, + smallestUnit, + roundingMode, + roundingIncrement, +) { + return { + ...durationFieldDefaults, + ...nanoToDurationFields( + roundLargeNano( + endEpochNano.addLargeInt(startEpochNano, -1), + smallestUnit, + roundingMode, + roundingIncrement, + ), + largestUnit, + ), + } +} +/* +Must always be given start-of-day +*/ +export function diffEpochMilliByDay(epochMilli0, epochMilli1) { + return Math.round((epochMilli1 - epochMilli0) / milliInDay) } -// CalendarImpl Utils +// Calendar Utils // ------------------------------------------------------------------------------------------------- -export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calendarImpl) { +function diffYearMonthDay(calendarImpl, year0, month0, day0, year1, month1, day1) { let yearDiff let monthsInYear1 let monthDiff @@ -265,8 +293,8 @@ export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calen const sign = Math.sign(yearDiff) || Math.sign(monthDiff) || daySign if (sign) { - // overshooting day? - correct by moving to penultimate month - if (daySign && daySign !== sign) { + // overshooting day? correct by moving to penultimate month + if (daySign === -sign) { const oldDaysInMonth1 = daysInMonth1 ;([year1, month1] = calendarImpl.addMonths(year1, month1, -sign)) updateYearMonthDay() @@ -275,9 +303,9 @@ export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calen : daysInMonth1 // correcting from future -> past } - // overshooting month? - correct by moving to penultimate year + // overshooting month? correct by moving to penultimate year const monthSign = Math.sign(monthDiff) - if (monthSign && monthSign !== sign) { + if (monthSign === -sign) { const oldMonthsInYear1 = monthsInYear1 year1 -= sign updateYearMonth() @@ -290,11 +318,11 @@ export function diffYearMonthDay(year0, month0, day0, year1, month1, day1, calen return [yearDiff, monthDiff, dayDiff, sign] } -export function computeIsoMonthsInYearSpan(isoYearStart, yearDelta) { +export function computeIsoMonthsInYearSpan(yearDelta) { return yearDelta * isoMonthsInYear } -export function computeIntlMonthsInYearSpan(yearStart, yearDelta, calendarImpl) { +export function computeIntlMonthsInYearSpan(yearDelta, yearStart, calendarImpl) { const yearEnd = yearStart + yearDelta const yearSign = Math.sign(yearDelta) const yearCorrection = yearSign < 0 ? -1 : 0 @@ -306,12 +334,3 @@ export function computeIntlMonthsInYearSpan(yearStart, yearDelta, calendarImpl) return months } - -// Exact Diffing -// ------------------------------------------------------------------------------------------------- - -function diffExactLargeNanoseconds( - nanoseconds, - largestUnit, -) { -} diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 7c54fc7b..995223cb 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -1,9 +1,10 @@ import { createTemporalClass, neverValueOf } from './class' import { mergeDurationBag, refineDurationBag } from './convert' -import { diffZonedEpochNanoseconds } from './diff' +import { diffZonedEpochNano } from './diff' import { absolutizeDurationFields, addDurationFields, + durationFieldsToNano, durationGetters, negateDurationFields, refineDurationInternals, @@ -12,7 +13,7 @@ import { formatDurationInternals } from './isoFormat' import { isoToEpochNano } from './isoMath' import { parseDuration } from './isoParse' import { compareLargeInts } from './largeInt' -import { moveZonedEpochNanoseconds } from './move' +import { moveZonedEpochNano } from './move' import { optionsToLargestUnit, optionsToRelativeTo, @@ -114,7 +115,9 @@ export const [ const roundingMode = optionsToRoundingMode(options) const markerInternals = optionsToRelativeTo(options) // optional - if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { + // TODO: move to round.js? + + if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { // TODO units // TODO: check internals doesn't have large fields return roundDayTimeDuration(internals, smallestUnit, roundingMode, roundingIncrement) } @@ -175,10 +178,10 @@ export const [ getLargestDurationUnit(durationFields1), ) - if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { + if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { // TODO: units return compareLargeInts( - durationDayTimeToNanoseconds(durationFields0), - durationDayTimeToNanoseconds(durationFields1), + durationFieldsToNano(durationFields0), + durationFieldsToNano(durationFields1), ) } @@ -186,11 +189,11 @@ export const [ throw new RangeError('need relativeTo') } - const [marker, markerToEpochNanoseconds, moveMarker] = createMarkerSystem(markerInternals) + const [marker, markerToEpochNano, moveMarker] = createMarkerSystem(markerInternals) return compareLargeInts( - markerToEpochNanoseconds(moveMarker(marker, durationFields0)), - markerToEpochNanoseconds(moveMarker(marker, durationFields1)), + markerToEpochNano(moveMarker(marker, durationFields0)), + markerToEpochNano(moveMarker(marker, durationFields1)), ) }, }, @@ -223,14 +226,14 @@ function createMarkerSystem(markerInternals) { if (epochNanoseconds) { return [ epochNanoseconds, // marker - identityFunc, // markerToEpochNanoseconds - moveZonedEpochNanoseconds.bind(undefined, calendar, timeZone), // moveMarker - diffZonedEpochNanoseconds.bind(undefined, calendar, timeZone), // diffMarkers + identityFunc, // markerToEpochNano + moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker + diffZonedEpochNano.bind(undefined, calendar, timeZone), // diffMarkers ] } else { return [ markerInternals, // marker (IsoDateFields) - isoToEpochNano, // markerToEpochNanoseconds + isoToEpochNano, // markerToEpochNano calendar.dateAdd.bind(calendar), // moveMarker calendar.dateUntil.bind(calendar), // diffMarkers ] @@ -242,11 +245,11 @@ function spanDuration( largestUnit, // marker system... marker, - markerToEpochNanoseconds, + markerToEpochNano, moveMarker, diffMarkers, ) { - const endMarker = markerToEpochNanoseconds(moveMarker(marker, durationFields)) + const endMarker = markerToEpochNano(moveMarker(marker, durationFields)) const balancedDuration = diffMarkers(marker, endMarker, largestUnit) return [balancedDuration, endMarker] } @@ -259,8 +262,3 @@ function balanceDurationDayTime( function getLargestDurationUnit(durationFields) { } - -function durationDayTimeToNanoseconds( - durationFields, // NOT BALANCED -) { -} diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 1ee7dd59..18fcb3e3 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -1,11 +1,28 @@ import { isoTimeFieldNames } from './isoFields' +import { + arbitraryFieldsToLargeNano, + hourIndex, + nanoInUnit, + nanoToArbitraryFields, + unitIndexes, +} from './isoMath' import { toIntegerWithoutRounding } from './options' import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './util' // Refiners // ------------------------------------------------------------------------------------------------- -// Ordered alphabetically +// Ordered by ascending size +const durationTimeFieldRefiners = { + nanoseconds: toIntegerWithoutRounding, + microseconds: toIntegerWithoutRounding, + milliseconds: toIntegerWithoutRounding, + seconds: toIntegerWithoutRounding, + minutes: toIntegerWithoutRounding, + hours: toIntegerWithoutRounding, +} + +// Ordered by ascending size const durationDateFieldRefiners = { days: toIntegerWithoutRounding, months: toIntegerWithoutRounding, @@ -13,29 +30,20 @@ const durationDateFieldRefiners = { years: toIntegerWithoutRounding, } -// Ordered alphabetically -const durationTimeFieldRefiners = { - hours: toIntegerWithoutRounding, - microseconds: toIntegerWithoutRounding, - milliseconds: toIntegerWithoutRounding, - minutes: toIntegerWithoutRounding, - nanoseconds: toIntegerWithoutRounding, - seconds: toIntegerWithoutRounding, -} - -// Unordered +// Ordered by ascending size export const durationFieldRefiners = { - ...durationDateFieldRefiners, ...durationTimeFieldRefiners, + ...durationDateFieldRefiners, } // Property Names // ------------------------------------------------------------------------------------------------- -const durationDateFieldNames = Object.keys(durationDateFieldRefiners) -const durationTimeFieldNames = Object.keys(durationTimeFieldRefiners) -export const durationFieldNames = Object.keys(durationFieldRefiners).sort() -const durationInternalNames = [...durationFieldNames, 'sign'] +const durationDateFieldNames = Object.keys(durationDateFieldRefiners).sort() +const durationTimeFieldNames = Object.keys(durationTimeFieldRefiners).sort() +export const durationFieldNamesAsc = Object.keys(durationFieldRefiners) +export const durationFieldNames = durationFieldNamesAsc.sort() +const durationInternalNames = [...durationFieldNames, 'sign'] // unordered // Getters // ------------------------------------------------------------------------------------------------- @@ -72,7 +80,7 @@ export function durationTimeFieldsToIso(durationTimeFields) { return remapProps(durationTimeFields, durationTimeFieldNames, isoTimeFieldNames) } -// Math +// Field Math // ------------------------------------------------------------------------------------------------- export function addDurationFields(durationFields0, durationFields1, sign) { @@ -95,3 +103,28 @@ function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { // should throw error if mismatch // TODO: audit repeat uses of this } + +// Nano Math +// ------------------------------------------------------------------------------------------------- + +export function durationFieldsToNano(durationFields, largestUnit = 'day') { + return arbitraryFieldsToLargeNano(durationFields, unitIndexes[largestUnit], durationFieldNamesAsc) +} + +export function durationFieldsToTimeNano(durationFields) { + return arbitraryFieldsToLargeNano(durationFields, hourIndex, durationFieldNamesAsc).toNumber() +} + +export function nanoToDurationFields(largeNano, largestUnit = 'day') { + const divisor = nanoInUnit[largestUnit] + const [largeUnitNum, remainder] = largeNano.divModTrunc(divisor) + + return { + ...nanoToArbitraryFields(remainder, unitIndexes[largestUnit] - 1, durationFieldNamesAsc), + [largestUnit]: largeUnitNum.toNumber(), + } +} + +export function timeNanoToDurationFields(nano) { + return nanoToArbitraryFields(nano, hourIndex, durationFieldNamesAsc) +} diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 765a811c..ec971840 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { createTemporalClass, neverValueOf } from './class' -import { diffEpochNanoseconds } from './diff' +import { diffEpochNano } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { @@ -19,9 +19,9 @@ import { validateEpochNano, } from './isoMath' import { compareLargeInts } from './largeInt' -import { moveEpochNanoseconds } from './move' +import { moveEpochNano } from './move' import { toEpochNano, toObject } from './options' -import { roundLargeNanoseconds } from './round' +import { roundLargeNano } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { noop } from './util' import { createZonedDateTime } from './zonedDateTime' @@ -84,7 +84,7 @@ export const [ add(epochNanoseconds, durationArg) { return createInstant( - moveEpochNanoseconds( + moveEpochNano( epochNanoseconds, toDurationInternals(durationArg), ), @@ -93,7 +93,7 @@ export const [ subtract(epochNanoseconds, durationArg) { return createInstant( - moveEpochNanoseconds( + moveEpochNano( epochNanoseconds, negateDurationFields(toDurationInternals(durationArg)), ), @@ -101,7 +101,7 @@ export const [ }, until(epochNanoseconds, otherArg, options) { - return diffEpochNanoseconds( + return diffEpochNano( epochNanoseconds, toInstantEpochNanoseconds(otherArg), options, // TODO: must be given better options??? @@ -109,7 +109,7 @@ export const [ }, since(epochNanoseconds, otherArg, options) { - return diffEpochNanoseconds( + return diffEpochNano( toInstantEpochNanoseconds(otherArg), epochNanoseconds, options, // TODO: reverse rounding option @@ -118,7 +118,7 @@ export const [ round(epochNanoseconds, options) { return createInstant( - roundLargeNanoseconds( + roundLargeNano( epochNanoseconds, options, // TODO: break apart options ), @@ -139,7 +139,7 @@ export const [ const calendar = queryCalendarOps(refinedOptions.calendar || isoCalendarId) const timeZone = queryTimeZoneOps(refinedOptions.timeZone || utcTimeZoneId) - epochNanoseconds = roundLargeNanoseconds( + epochNanoseconds = roundLargeNano( epochNanoseconds, refinedOptions, // TODO: break apart options ) diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 34e1b7cc..1705fb64 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -23,7 +23,7 @@ export const isoDateInternalRefiners = { isoYear: toIntegerWithoutRounding, } -// Ordered alphabetically +// Ordered by ascending size export const isoTimeFieldRefiners = { isoHour: toIntegerThrowOnInfinity, isoMicrosecond: toIntegerThrowOnInfinity, @@ -42,12 +42,13 @@ export const isoDateTimeInternalRefiners = { // Property Names // ------------------------------------------------------------------------------------------------- -export const isoDateInternalNames = Object.keys(isoDateInternalRefiners) +const isoDateInternalNames = Object.keys(isoDateInternalRefiners) export const isoDateTimeInternalNames = Object.keys(isoDateTimeInternalRefiners).sort() export const isoDateFieldNames = isoDateInternalNames.slice(1) // no calendar const isoDateTimeFieldNames = isoDateTimeInternalRefiners.slice(1) // no calendar -export const isoTimeFieldNames = Object.keys(isoTimeFieldRefiners) +export const isoTimeFieldNamesAsc = Object.keys(isoTimeFieldRefiners) +export const isoTimeFieldNames = isoTimeFieldNamesAsc.sort() // Defaults // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 7abd4d82..f0fbcea7 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,6 +1,6 @@ -import { pluckIsoDateTimeFields } from './isoFields' -import { compareLargeInts, numberToLargeInt } from './largeInt' -import { clamp } from './util' +import { isoTimeFieldNamesAsc, pluckIsoDateTimeFields } from './isoFields' +import { LargeInt, compareLargeInts, numberToLargeInt } from './largeInt' +import { clamp, divMod, mapArrayToProps } from './util' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -79,10 +79,11 @@ export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { } } -// Epoch Unit Conversion +// Unit Definitions // ------------------------------------------------------------------------------------------------- -export const secInDay = 86400 +export const secInDay = 86400 // TODO: rename 'sec' -> 'seconds' +export const milliInDay = 86400000 // TODO: not DRY export const milliInSec = 1000 export const nanoInMicro = 1000 // consolidate with other 1000 units @@ -90,33 +91,54 @@ export const nanoInMilli = 1000000 export const nanoInSec = 1000000000 export const nanoInHour = 3600000000000 export const nanoInUtcDay = 86400000000000 -export const nanosecondsInUnit = { + +// Ordered by ascending size +export const nanoInUnit = { + nanosecond: 1, microsecond: nanoInMicro, millisecond: nanoInMilli, second: nanoInSec, hour: nanoInHour, day: nanoInUtcDay, -} + week: 0, + month: 0, + year: 0, +} + +export const unitNamesAsc = Object.keys(nanoInUnit) +export const unitIndexes = mapArrayToProps(unitNamesAsc) + +// Matches indexes in nanoInUnit +// (most are not used) +export const nanoIndex = 0 +export const microIndex = 1 +export const milliIndex = 2 +export const secondsIndex = 3 +export const minuteIndex = 4 +export const hourIndex = 5 +export const dayIndex = 6 +export const weekIndex = 7 +export const monthIndex = 8 +export const yearIndex = 9 + +// Epoch Unit Conversion +// ------------------------------------------------------------------------------------------------- -// nano -> * (with floor) +// nano -> [micro/milli/sec] (with floor) export function epochNanoToSec(epochNano) { - return epochNanoToSecMod(epochNano)[0] + return epochNanoToSecMod(epochNano)[0].toNumber() } export function epochNanoToMilli(epochNano) { - return epochNanoToMilliMod(epochNano)[0] + return epochNanoToMilliMod(epochNano)[0].toNumber() } function epochNanoToMicro(epochNano) { return epochNanoToMicroMod(epochNano)[0] } -// nano -> * (with remainder) - -export function epochNanoToUtcDaysMod(epochNano) { - return epochNano.divMod(nanoInUtcDay) -} +// nano -> [micro/milli/sec] (with remainder) export function epochNanoToSecMod(epochNano) { return epochNano.divMod(nanoInSec) @@ -127,10 +149,10 @@ function epochNanoToMilliMod(epochNano) { } function epochNanoToMicroMod(epochNano) { - return epochNano.divMod(nanoInMicro, true) // preserveLargeInt=true + return epochNano.divMod(nanoInMicro) } -// * -> nano +// [micro/milli/sec] -> nano export function epochSecToNano(epochSec) { return numberToLargeInt(epochSec).mult(nanoInSec) @@ -144,6 +166,59 @@ export function epochMicroToNano(epochMicro) { return epochMicro.mult(nanoInMicro) } +// fields <-> nano + +export function isoTimeFieldsToNano(isoTimeFields) { + return arbitraryFieldsToNano(isoTimeFields, hourIndex, isoTimeFieldNamesAsc) +} + +export function nanoToIsoTimeAndDay(nano) { + const [dayDelta, timeNano] = divMod(nano, nanoInUtcDay) + + return [ + nanoToArbitraryFields(timeNano, hourIndex, isoTimeFieldNamesAsc), + dayDelta, + ] +} + +// nano field utils + +export function arbitraryFieldsToLargeNano(fields, unitIndex, fieldNames) { + let largeNano = new LargeInt(0, 0) + + for (; unitIndex >= nanoIndex; unitIndex--) { + const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + largeNano = largeNano.addLargeInt( + numberToLargeInt(fields[fieldNames[unitIndex]]).mult(divisor), + ) + } + + return largeNano +} + +export function arbitraryFieldsToNano(fields, unitIndex, fieldNames) { + let nano = 0 + + for (; unitIndex >= nanoIndex; unitIndex--) { + const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + nano += fields[fieldNames[unitIndex]] * divisor + } + + return nano +} + +export function nanoToArbitraryFields(nano, unitIndex, fieldNames) { + const fields = {} + + for (; unitIndex >= nanoIndex; unitIndex--) { + const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + fields[fieldNames[unitIndex]] = nano / divisor + nano %= divisor + } + + return fields +} + // Epoch Getters // ------------------------------------------------------------------------------------------------- @@ -166,8 +241,8 @@ export const epochGetters = { const epochNanoMax = numberToLargeInt(nanoInUtcDay).mult(100000000) // inclusive const epochNanoMin = epochNanoMax.mult(-1) // inclusive -const isoYearMax = 275760 // shortcut. isoYear at epochNanoMax -const isoYearMin = -271821 // shortcut. isoYear at epochNanoMin +const isoYearMax = 275760 // optimization. isoYear at epochNanoMax +const isoYearMin = -271821 // optimization. isoYear at epochNanoMin function validateIsoDateTimeInternals(isoDateTimeInternals) { // validateIsoInternals? const { isoYear } = isoDateTimeInternals @@ -263,25 +338,3 @@ export function compareIsoDateTimeFields() { export function compareIsoTimeFields() { } - -// ISO Time -// ------------------------------------------------------------------------------------------------- - -export function isoTimeFieldsToNano(isoTimeFields) { -} - -export function nanoToIsoTimeFields() { - /* - const dayDelta = Math.floor(nanoseconds / nanosecondsInIsoDay) - nanoseconds %= nanosecondsInIsoDay - */ - // return [isoTimeFields, dayDelta] -} - -// Duration -// ------------------------------------------------------------------------------------------------- - -export function nanosecondsToTimeDuration(nanoseconds) { // nanoseconds is a number - // returns an (incomplete?) Duration? - // good idea to put here? -} diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js index 8548c6eb..5c7d4398 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -1,7 +1,6 @@ import { compareNumbers, divMod } from './util' const maxLow = 1e8 // exclusive // TODO: explain why -const maxLowBigInt = typeof BigInt !== 'undefined' && BigInt(maxLow) export class LargeInt { constructor(high, low) { @@ -9,8 +8,8 @@ export class LargeInt { this.low = low } - addLargeInt(n) { - return balanceAndCreate(this.high + n.high, this.low + n.low) + addLargeInt(n, sign = 1) { + return balanceAndCreate(this.high + n.high * sign, this.low + n.low * sign) } add(n) { @@ -21,25 +20,41 @@ export class LargeInt { return balanceAndCreate(this.high * multiplier, this.low * multiplier) } - divMod(divisor, preserveLargeInt) { + divMod(divisor) { const { high, low } = this const [newHigh, highRemainder] = divMod(high, divisor) const [newLow, remainder] = divMod(highRemainder * maxLow + low, divisor) return [ - preserveLargeInt - ? balanceAndCreate(newHigh, newLow) - : newHigh * maxLow + newLow, + balanceAndCreate(newHigh, newLow), remainder, ] } + divModTrunc(divisor) { // TODO: rename a lot of stuff? + let [largeInt, remainder] = this.divMod(divisor) + + if (largeInt.computeSign() === -1 && remainder) { + largeInt = largeInt.add(1) + remainder -= divisor + } + + return [largeInt, remainder] + } + + /* + different than Duration::sign, for minification + */ + computeSign() { + return Math.sign(this.high) || Math.sign(this.low) + } + toNumber() { return this.high * maxLow + this.low } toBigInt() { - return BigInt(this.high) * maxLowBigInt + BigInt(this.low) + return BigInt(this.high) * BigInt(maxLow) + BigInt(this.low) } } @@ -53,7 +68,8 @@ export function numberToLargeInt(n) { } export function bigIntToLargeInt(n) { - return new LargeInt(...divMod(n, maxLowBigInt).map(Number)) + // must create BigInt lazily for if browser lacks support + return new LargeInt(...divMod(n, BigInt(maxLow)).map(Number)) } export function compareLargeInts(a, b) { diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 2e08c823..62954d79 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -9,7 +9,7 @@ import { isoMonthsInYear, isoTimeFieldsToNano, isoToEpochMilli, - nanoToIsoTimeFields, + nanoToIsoTimeAndDay, } from './isoMath' import { constrainInt } from './options' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' @@ -21,11 +21,11 @@ export function addDaysToIsoFields() { // short-circuit if nothing to add } -export function moveEpochNanoseconds(epochNanoseconds, durationFields) { +export function moveEpochNano(epochNanoseconds, durationFields) { return epochNanoseconds.add(onlyDurationTimeFieldsToIso(durationFields)) } -export function moveZonedEpochNanoseconds( +export function moveZonedEpochNano( calendar, timeZone, epochNanoseconds, @@ -169,7 +169,7 @@ export function addIntlMonths(year, month, monthDelta, calendarImpl) { // ------------------------------------------------------------------------------------------------- function addIsoTimeFields(isoTimeFields0, isoTimeFields1) { - return nanoToIsoTimeFields( // returns [movedIsoTimeFields, dayDelta] + return nanoToIsoTimeAndDay( isoTimeFieldsToNano(isoTimeFields0) + isoTimeFieldsToNano(isoTimeFields1), ) diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 8d0879ce..bcc0d381 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,8 +1,10 @@ +import { durationFieldNamesAsc } from './durationFields' +import { unitIndexes } from './isoMath' +import { bigIntToLargeInt } from './largeInt' +import { mapArrayToProps } from './util' // TODO: for unit parsing, ensure ceiling and correct increment -import { bigIntToLargeInt } from './largeInt' - export function strictNumber(input) { } @@ -221,3 +223,19 @@ export function overflowToOptions(overflow) { export function largestUnitToOptions(largestUnit) { return { largestUnit } } + +// Units +// ------------------------------------------------------------------------------------------------- + +const unitIndexesPlural = mapArrayToProps(durationFieldNamesAsc) + +export function toUnit(unitName) { + unitName = toString(unitName) + const unitIndex = unitIndexes[unitName] ?? unitIndexesPlural[unitName] + + if (unitIndex === undefined) { + throw new RangeError('Invalid unit') + } + + return unitIndexes[unitName] +} diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 62edc8d3..b05f79ef 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -1,13 +1,18 @@ -import { durationFieldDefaults, durationTimeFieldDefaults } from './durationFields' +import { + durationFieldDefaults, + durationFieldsToNano, + durationFieldsToTimeNano, + durationTimeFieldDefaults, + nanoToDurationFields, + timeNanoToDurationFields, +} from './durationFields' import { isoTimeFieldDefaults } from './isoFields' import { - epochNanoToUtcDaysMod, isoTimeFieldsToNano, + nanoInUnit, nanoInUtcDay, - nanoToIsoTimeFields, - nanosecondsInUnit, + nanoToIsoTimeAndDay, } from './isoMath' -import { numberToLargeInt } from './largeInt' import { addDaysToIsoFields } from './move' import { computeNanosecondsInDay } from './timeZoneOps' import { identityFunc } from './util' @@ -34,7 +39,7 @@ export function roundIsoDateTimeFields( ? computeNanosecondsInDay(timeZoneOps, isoDateTimeFields) : nanoInUtcDay - dayDelta = roundNanoseconds( + dayDelta = roundWithDivisor( isoTimeFieldsToNano(isoDateTimeFields), nanosecondsInDay, roundingMode, @@ -58,16 +63,17 @@ export function roundIsoDateTimeFields( export function roundIsoTimeFields( isoTimeFields, - smallestUnit, // time + smallestUnit, roundingMode, roundingIncrement, ) { - const nanoseconds = roundNanoseconds( + const timeNano = roundNano( isoTimeFieldsToNano(isoTimeFields), - nanosecondsInUnit[smallestUnit] * roundingIncrement, + smallestUnit, roundingMode, + roundingIncrement, ) - return nanoToIsoTimeFields(nanoseconds) + return nanoToIsoTimeAndDay(timeNano) } // Rounding Duration @@ -79,13 +85,17 @@ export function roundDayTimeDuration( roundingMode, roundingIncrement, ) { - const largeNanoseconds = durationDayTimeToNanoseconds(durationFields) - const r = roundLargeNanoseconds(largeNanoseconds, smallestUnit, roundingMode, roundingIncrement) - return nanosecondsToDurationDayTime(r) + const largeNano = durationFieldsToNano(durationFields) + const r = roundLargeNano(largeNano, smallestUnit, roundingMode, roundingIncrement) + return { + ...durationFieldDefaults, + ...nanoToDurationFields(r), + } } export function roundRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + // ^has sign endEpochNanoseconds, largestUnit, smallestUnit, @@ -138,28 +148,18 @@ export function roundRelativeDuration( // Rounding Numbers // ------------------------------------------------------------------------------------------------- -export function roundLargeNanoseconds( - largeNanoseconds, - smallestUnit, - roundingMode, - roundingIncrement, -) { - let [days, timeNanoseconds] = epochNanoToUtcDaysMod(largeNanoseconds) - - timeNanoseconds = roundNanoseconds( - timeNanoseconds, - nanosecondsInUnit[smallestUnit] * roundingIncrement, - roundingMode, - ) - - const dayDelta = Math.trunc(timeNanoseconds / nanoInUtcDay) - timeNanoseconds %= nanoInUtcDay +export function roundLargeNano(largeNano, smallestUnit, roundingMode, roundingIncrement) { + const divisor = nanoInUnit[smallestUnit] * roundingIncrement + const [n, remainder] = largeNano.divModTrunc(divisor) + return n.mult(divisor).add(roundWithMode(remainder / divisor, roundingMode)) +} - return numberToLargeInt(nanoInUtcDay).mult(days + dayDelta).add(timeNanoseconds) +export function roundNano(nano, smallestUnit, roundingMode, roundingIncrement) { + return roundWithDivisor(nano, nanoInUnit[smallestUnit] * roundingIncrement, roundingMode) } -function roundNanoseconds(num, nanoIncrement, roundingMode) { - return roundWithMode(num / nanoIncrement, roundingMode) * nanoIncrement +function roundWithDivisor(num, divisor, roundingMode) { + return roundWithMode(num / divisor, roundingMode) * divisor } function roundWithMode(num, roundingMode) { @@ -170,10 +170,12 @@ function roundWithMode(num, roundingMode) { export function totalDayTimeDuration( // assumes iso-length days durationFields, - unit, + unitName, ) { - const largeNanoseconds = durationDayTimeToNanoseconds(durationFields) - return largeNanoseconds.divide(nanosecondsInUnit[unit]).toNumber() + const largeNano = durationFieldsToNano(durationFields) + const divisor = nanoInUnit[unitName] + const [fullUnit, remainder] = largeNano.divModTrunc(divisor) + return fullUnit.toNumber() + (remainder / divisor) } export function totalRelativeDuration( @@ -214,23 +216,19 @@ function nudgeDurationTime( roundingMode, roundingIncrement, ) { - const nano = durationTimeToNanoseconds(durationFields) - const roundedNano = roundNanoseconds( - nano, - nanosecondsInUnit[smallestUnit] * roundingIncrement, - roundingMode, - ) - - const [durationTimeFields, dayDelta] = nanosecondsToDurationTime(roundedNano) - const nudgedDurationFields = { + const timeNano = durationFieldsToTimeNano(durationFields) + const roundedTimeNano = roundNano(timeNano, smallestUnit, roundingMode, roundingIncrement) + const roundedFields = nanoToDurationFields(roundedTimeNano) + const dayDelta = roundedFields.days + const nudgedDurationFields = { // TODO: what about sign? ...durationFields, + ...roundedFields, days: durationFields.days + dayDelta, - ...durationTimeFields, } return [ nudgedDurationFields, - endEpochNanoseconds.add(roundedNano - nano), + endEpochNanoseconds.add(roundedTimeNano - timeNano), dayDelta, ] } @@ -247,9 +245,8 @@ function nudgeRelativeDurationTime( moveMarker, ) { const { sign } = durationFields - const divisor = nanosecondsInUnit[smallestUnit] * roundingIncrement - const nano = durationTimeToNanoseconds(durationFields) - let roundedNano = roundNanoseconds(nano, divisor, roundingMode) + const timeNano = durationFieldsToTimeNano(durationFields) + let roundedTimeNano = roundNano(timeNano, smallestUnit, roundingMode, roundingIncrement) const [dayEpochNanoseconds0, dayEpochNanoseconds1] = clampRelativeDuration( { ...durationFields, ...durationTimeFieldDefaults }, @@ -262,22 +259,22 @@ function nudgeRelativeDurationTime( ) const daySpanEpochNanoseconds = dayEpochNanoseconds1.subtract(dayEpochNanoseconds0).toNumber() - const beyondDay = roundedNano - daySpanEpochNanoseconds + const beyondDay = roundedTimeNano - daySpanEpochNanoseconds let dayDelta = 0 if (!beyondDay || Math.sign(beyondDay) === sign) { dayDelta++ - roundedNano = roundNanoseconds(beyondDay, divisor, roundingMode) - endEpochNanoseconds = dayEpochNanoseconds1.add(roundedNano) + roundedTimeNano = roundNano(beyondDay, smallestUnit, roundingMode, roundingIncrement) + endEpochNanoseconds = dayEpochNanoseconds1.add(roundedTimeNano) } else { - endEpochNanoseconds = dayEpochNanoseconds0.add(roundedNano) + endEpochNanoseconds = dayEpochNanoseconds0.add(roundedTimeNano) } - const [durationTimeFields] = nanosecondsToDurationTime(roundedNano) + const durationTimeFields = timeNanoToDurationFields(roundedTimeNano) const nudgedDurationFields = { ...durationFields, - days: durationFields.days + dayDelta, ...durationTimeFields, + days: durationFields.days + dayDelta, } return [nudgedDurationFields, endEpochNanoseconds, dayDelta] @@ -381,31 +378,3 @@ function clampRelativeDuration( function clearDurationFields(durationFields, firstUnit, lastUnit) { } - -// Duration Time -// ------------- - -function durationTimeToNanoseconds( - durationTimeFields, // time-fields must be cumulatively less than a day -) { - // returns Number -} - -function nanosecondsToDurationTime( - nanoseconds, // can be signed -) { - // returns [durationTimeFields, dayDelta] -} - -// Duration Day-Time -// ----------------- - -function durationDayTimeToNanoseconds( - durationFields, // NOT BALANCED -) { - // returns LargeInt -} - -function nanosecondsToDurationDayTime(largeNano) { - // returns DurationFields (even tho year/week/month will be 0) -} diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index e0710ac3..bc63da06 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -78,7 +78,7 @@ export class IntlTimeZoneImpl { getTransition(epochNano, direction) { const [epochSec, subsecNano] = epochNanoToSecMod(epochNano) const resEpochSec = this.store.getTransition( - epochSec + ((direction > 0 || subsecNano) ? 1 : 0), + epochSec.toNumber() + ((direction > 0 || subsecNano) ? 1 : 0), direction, ) if (resEpochSec !== undefined) { diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index c18b83e9..fd321272 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -7,7 +7,7 @@ import { mergeZonedDateTimeBag, refineZonedDateTimeBag, } from './convert' -import { diffZonedEpochNanoseconds } from './diff' +import { diffZonedEpochNano } from './diff' import { toDurationInternals } from './duration' import { negateDurationFields } from './durationFields' import { createInstant } from './instant' @@ -33,7 +33,7 @@ import { } from './isoMath' import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' -import { moveZonedEpochNanoseconds } from './move' +import { moveZonedEpochNano } from './move' import { optionsToOverflow, toEpochNano } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' @@ -214,7 +214,7 @@ export const [ until(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) - return diffZonedEpochNanoseconds( + return diffZonedEpochNano( getCommonCalendarOps(internals, otherInternals), getCommonTimeZoneOps(internals, otherInternals), internals.epochNanoseconds, @@ -225,7 +225,7 @@ export const [ since(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) - return diffZonedEpochNanoseconds( + return diffZonedEpochNano( getCommonCalendarOps(internals, otherInternals), getCommonTimeZoneOps(internals, otherInternals), otherInternals.epochNanoseconds, @@ -393,7 +393,7 @@ export const [ // ------------------------------------------------------------------------------------------------- function moveZonedDateTimeInternals(internals, durationFields, overflowHandling) { - return moveZonedEpochNanoseconds( + return moveZonedEpochNano( internals.calendar, internals.timeZone, internals.epochNanoseconds, From 25327891fddc8c97fb284c81770377058b79c719 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 16:05:31 -0400 Subject: [PATCH 094/805] move some files around --- .../temporal-polyfill/src/new/calendar.js | 2 +- .../src/new/calendarFields.js | 2 +- .../temporal-polyfill/src/new/calendarImpl.js | 2 +- .../temporal-polyfill/src/new/calendarOps.js | 2 +- packages/temporal-polyfill/src/new/class.js | 2 +- packages/temporal-polyfill/src/new/convert.js | 2 +- packages/temporal-polyfill/src/new/diff.js | 13 ++- .../temporal-polyfill/src/new/duration.js | 2 +- .../src/new/durationFields.js | 6 +- packages/temporal-polyfill/src/new/global.js | 2 +- packages/temporal-polyfill/src/new/instant.js | 2 +- .../temporal-polyfill/src/new/intlFormat.js | 2 +- .../temporal-polyfill/src/new/isoFields.js | 2 +- packages/temporal-polyfill/src/new/isoMath.js | 103 +++--------------- .../temporal-polyfill/src/new/largeInt.js | 2 +- packages/temporal-polyfill/src/new/now.js | 2 +- packages/temporal-polyfill/src/new/options.js | 4 +- packages/temporal-polyfill/src/new/round.js | 8 +- .../temporal-polyfill/src/new/temporal.js | 2 +- .../temporal-polyfill/src/new/timeZone.js | 2 +- .../temporal-polyfill/src/new/timeZoneImpl.js | 4 +- .../temporal-polyfill/src/new/timeZoneOps.js | 4 +- packages/temporal-polyfill/src/new/units.js | 81 ++++++++++++++ .../src/new/{util.js => utils.js} | 0 .../src/new/zonedDateTime.js | 4 +- 25 files changed, 133 insertions(+), 124 deletions(-) create mode 100644 packages/temporal-polyfill/src/new/units.js rename packages/temporal-polyfill/src/new/{util.js => utils.js} (100%) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 6ebf6351..8a64ec30 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -15,7 +15,7 @@ import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' -import { mapArrayToProps, noop, removeUndefines } from './util' +import { mapArrayToProps, noop, removeUndefines } from './utils' export const calendarProtocolMethods = { ...mapArrayToProps(dateGetterNames, (propName) => { diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index 5421c57c..061614b8 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -1,6 +1,6 @@ import { isoTimeFieldNames } from './isoFields' import { toBoolean, toInteger, toIntegerThrowOnInfinity, toPositiveInteger } from './options' -import { mapArrayToProps, remapProps, zipSingleValue } from './util' +import { mapArrayToProps, remapProps, zipSingleValue } from './utils' // Refiners // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index f27a58d5..7057fdf9 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -40,7 +40,7 @@ import { } from './isoMath' import { addDaysMilli, addIntlMonths, addIsoMonths, moveDate } from './move' import { constrainInt } from './options' -import { buildWeakMapCache, createLazyMap, mapArrayToProps, twoDigit } from './util' +import { buildWeakMapCache, createLazyMap, mapArrayToProps, twoDigit } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index 09db9770..0b8a86fb 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -14,7 +14,7 @@ import { strictArray, toObject, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' -import { mapProps } from './util' +import { mapProps } from './utils' const checkCalendarProtocol = createProtocolChecker(calendarProtocolMethods) diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js index 3645b504..1ae836da 100644 --- a/packages/temporal-polyfill/src/new/class.js +++ b/packages/temporal-polyfill/src/new/class.js @@ -8,7 +8,7 @@ import { isObjectLike, mapProps, noop, -} from './util' +} from './utils' // Wrapper Class // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index d3ea201f..6833b6b4 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -36,7 +36,7 @@ import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { isObjectLike, pluckProps, removeDuplicateStrings } from './util' +import { isObjectLike, pluckProps, removeDuplicateStrings } from './utils' import { createZonedDateTime } from './zonedDateTime' // ZonedDateTime diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 10291fd9..d7532334 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -5,23 +5,24 @@ import { } from './durationFields' import { pluckIsoTimeFields } from './isoFields' import { - dayIndex, isoDaysInWeek, isoMonthsInYear, isoTimeFieldsToNano, isoToEpochMilli, isoToEpochNano, - milliInDay, +} from './isoMath' +import { compareLargeInts } from './largeInt' +import { addDaysToIsoFields, moveDateTime, moveZonedEpochNano } from './move' +import { + dayIndex, milliInDay, monthIndex, nanoInUtcDay, unitIndexes, weekIndex, -} from './isoMath' -import { compareLargeInts } from './largeInt' -import { addDaysToIsoFields, moveDateTime, moveZonedEpochNano } from './move' +} from './units' import { roundLargeNano, roundNano, roundRelativeDuration } from './round' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' -import { identityFunc } from './util' +import { identityFunc } from './utils' // Dates & Times // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 995223cb..5282058b 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -28,7 +28,7 @@ import { totalDayTimeDuration, totalRelativeDuration, } from './round' -import { identityFunc, noop } from './util' +import { identityFunc, noop } from './utils' export const [ Duration, diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 18fcb3e3..162a167b 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -1,13 +1,13 @@ import { isoTimeFieldNames } from './isoFields' +import { toIntegerWithoutRounding } from './options' import { arbitraryFieldsToLargeNano, hourIndex, nanoInUnit, nanoToArbitraryFields, unitIndexes, -} from './isoMath' -import { toIntegerWithoutRounding } from './options' -import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './util' +} from './units' +import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './utils' // Refiners // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/global.js b/packages/temporal-polyfill/src/new/global.js index 2f0ecbc6..8bf11dfc 100644 --- a/packages/temporal-polyfill/src/new/global.js +++ b/packages/temporal-polyfill/src/new/global.js @@ -1,5 +1,5 @@ import { DateTimeFormat, Temporal, toTemporalInstant } from './impl' -import { defineProps } from './util' +import { defineProps } from './utils' defineProps(globalThis, { Temporal }) defineProps(Intl, { DateTimeFormat }) diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index ec971840..98429e35 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -23,7 +23,7 @@ import { moveEpochNano } from './move' import { toEpochNano, toObject } from './options' import { roundLargeNano } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' -import { noop } from './util' +import { noop } from './utils' import { createZonedDateTime } from './zonedDateTime' export const [ diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index b873094a..8825f66a 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -9,7 +9,7 @@ import { hasAnyMatchingProps, identityFunc, zipSingleValue, -} from './util' +} from './utils' export const standardCalendarId = 'en-GB' // gives 24-hour clock diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 1705fb64..36212349 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -10,7 +10,7 @@ import { toIntegerWithoutRounding, toPositiveInteger, } from './options' -import { mapRefiners, pluckProps, zipSingleValue } from './util' +import { mapRefiners, pluckProps, zipSingleValue } from './utils' // Refiners // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index f0fbcea7..7732987d 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,6 +1,16 @@ import { isoTimeFieldNamesAsc, pluckIsoDateTimeFields } from './isoFields' -import { LargeInt, compareLargeInts, numberToLargeInt } from './largeInt' -import { clamp, divMod, mapArrayToProps } from './util' +import { compareLargeInts, numberToLargeInt } from './largeInt' +import { + arbitraryFieldsToNano, + hourIndex, + milliInSec, + nanoInMicro, + nanoInMilli, + nanoInSec, + nanoInUtcDay, + nanoToArbitraryFields, +} from './units' +import { clamp, divMod } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -79,48 +89,6 @@ export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { } } -// Unit Definitions -// ------------------------------------------------------------------------------------------------- - -export const secInDay = 86400 // TODO: rename 'sec' -> 'seconds' -export const milliInDay = 86400000 // TODO: not DRY -export const milliInSec = 1000 - -export const nanoInMicro = 1000 // consolidate with other 1000 units -export const nanoInMilli = 1000000 -export const nanoInSec = 1000000000 -export const nanoInHour = 3600000000000 -export const nanoInUtcDay = 86400000000000 - -// Ordered by ascending size -export const nanoInUnit = { - nanosecond: 1, - microsecond: nanoInMicro, - millisecond: nanoInMilli, - second: nanoInSec, - hour: nanoInHour, - day: nanoInUtcDay, - week: 0, - month: 0, - year: 0, -} - -export const unitNamesAsc = Object.keys(nanoInUnit) -export const unitIndexes = mapArrayToProps(unitNamesAsc) - -// Matches indexes in nanoInUnit -// (most are not used) -export const nanoIndex = 0 -export const microIndex = 1 -export const milliIndex = 2 -export const secondsIndex = 3 -export const minuteIndex = 4 -export const hourIndex = 5 -export const dayIndex = 6 -export const weekIndex = 7 -export const monthIndex = 8 -export const yearIndex = 9 - // Epoch Unit Conversion // ------------------------------------------------------------------------------------------------- @@ -135,7 +103,7 @@ export function epochNanoToMilli(epochNano) { } function epochNanoToMicro(epochNano) { - return epochNanoToMicroMod(epochNano)[0] + return epochNanoToMicroMod(epochNano)[0].toBigInt() } // nano -> [micro/milli/sec] (with remainder) @@ -181,56 +149,13 @@ export function nanoToIsoTimeAndDay(nano) { ] } -// nano field utils - -export function arbitraryFieldsToLargeNano(fields, unitIndex, fieldNames) { - let largeNano = new LargeInt(0, 0) - - for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = nanoInUnit[unitNamesAsc[unitIndex]] - largeNano = largeNano.addLargeInt( - numberToLargeInt(fields[fieldNames[unitIndex]]).mult(divisor), - ) - } - - return largeNano -} - -export function arbitraryFieldsToNano(fields, unitIndex, fieldNames) { - let nano = 0 - - for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = nanoInUnit[unitNamesAsc[unitIndex]] - nano += fields[fieldNames[unitIndex]] * divisor - } - - return nano -} - -export function nanoToArbitraryFields(nano, unitIndex, fieldNames) { - const fields = {} - - for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = nanoInUnit[unitNamesAsc[unitIndex]] - fields[fieldNames[unitIndex]] = nano / divisor - nano %= divisor - } - - return fields -} - // Epoch Getters // ------------------------------------------------------------------------------------------------- export const epochGetters = { epochSeconds: epochNanoToSec, - epochMilliseconds: epochNanoToMilli, - - epochMicroseconds(epochNano) { - return epochNanoToMicro(epochNano).toBigInt() - }, - + epochMicroseconds: epochNanoToMicro, epochNanoseconds(epochNano) { return epochNano.toBigInt() }, diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js index 5c7d4398..7960714e 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -1,4 +1,4 @@ -import { compareNumbers, divMod } from './util' +import { compareNumbers, divMod } from './utils' const maxLow = 1e8 // exclusive // TODO: explain why diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js index e7d5efab..ef8d5fc7 100644 --- a/packages/temporal-polyfill/src/new/now.js +++ b/packages/temporal-polyfill/src/new/now.js @@ -9,7 +9,7 @@ import { createPlainDate } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime } from './plainTime' import { queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' -import { createPropDescriptors, createTemporalNameDescriptors } from './util' +import { createPropDescriptors, createTemporalNameDescriptors } from './utils' import { createZonedDateTime } from './zonedDateTime' export const Now = Object.defineProperties({}, { diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index bcc0d381..d126d541 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,7 +1,7 @@ import { durationFieldNamesAsc } from './durationFields' -import { unitIndexes } from './isoMath' import { bigIntToLargeInt } from './largeInt' -import { mapArrayToProps } from './util' +import { unitIndexes } from './units' +import { mapArrayToProps } from './utils' // TODO: for unit parsing, ensure ceiling and correct increment diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index b05f79ef..87b928c9 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -9,13 +9,15 @@ import { import { isoTimeFieldDefaults } from './isoFields' import { isoTimeFieldsToNano, - nanoInUnit, - nanoInUtcDay, nanoToIsoTimeAndDay, } from './isoMath' import { addDaysToIsoFields } from './move' +import { + nanoInUnit, + nanoInUtcDay, +} from './units' import { computeNanosecondsInDay } from './timeZoneOps' -import { identityFunc } from './util' +import { identityFunc } from './utils' export function roundToMinute(nanoseconds) { // can be positive or negative diff --git a/packages/temporal-polyfill/src/new/temporal.js b/packages/temporal-polyfill/src/new/temporal.js index 39dc9ce4..c4b2cc28 100644 --- a/packages/temporal-polyfill/src/new/temporal.js +++ b/packages/temporal-polyfill/src/new/temporal.js @@ -8,7 +8,7 @@ import { PlainMonthDay } from './plainMonthDay' import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' -import { defineProps } from './util' +import { defineProps } from './utils' import { ZonedDateTime } from './zonedDateTime' export const Temporal = defineProps({}, { diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 92892f90..8eb83f02 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -9,7 +9,7 @@ import { parseTimeZoneId } from './isoParse' import { toDisambiguation } from './options' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' -import { noop } from './util' +import { noop } from './utils' export const timeZoneProtocolMethods = { getPossibleInstantsFor(impl, plainDateTimeArg) { diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index bc63da06..a423c889 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -9,10 +9,10 @@ import { isoArgsToEpochSec, isoToEpochNano, isoToEpochSec, - milliInSec, nanoInSec, secInDay, } from './isoMath' import { parseOffsetNano } from './isoParse' -import { clamp, compareNumbers, createLazyMap } from './util' +import { milliInSec, nanoInSec, secInDay } from './units' +import { clamp, compareNumbers, createLazyMap } from './utils' const periodDur = secInDay * 60 const minPossibleTransition = isoArgsToEpochSec(1847) diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index f90f8000..c3b2ac39 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -11,15 +11,15 @@ import { isoTimeFieldDefaults } from './isoFields' import { epochNanoToIso, isoToEpochNano, - nanoInUtcDay, } from './isoMath' import { addDaysToIsoFields } from './move' +import { nanoInUtcDay } from './units' import { strictArray, strictNumber } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' import { TimeZone, createTimeZone, timeZoneProtocolMethods } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' -import { createLazyMap } from './util' +import { createLazyMap } from './utils' export const utcTimeZoneId = 'UTC' diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js new file mode 100644 index 00000000..a4e7b6c2 --- /dev/null +++ b/packages/temporal-polyfill/src/new/units.js @@ -0,0 +1,81 @@ +import { LargeInt, numberToLargeInt } from './largeInt' +import { mapArrayToProps } from './utils' + +export const secInDay = 86400 // TODO: rename 'sec' -> 'seconds' +export const milliInDay = 86400000 // TODO: not DRY +export const milliInSec = 1000 + +export const nanoInMicro = 1000 // consolidate with other 1000 units +export const nanoInMilli = 1000000 +export const nanoInSec = 1000000000 +export const nanoInHour = 3600000000000 +export const nanoInUtcDay = 86400000000000 + +// Ordered by ascending size +export const nanoInUnit = { + nanosecond: 1, + microsecond: nanoInMicro, + millisecond: nanoInMilli, + second: nanoInSec, + hour: nanoInHour, + day: nanoInUtcDay, + week: 0, + month: 0, + year: 0, +} + +export const unitNamesAsc = Object.keys(nanoInUnit) +export const unitIndexes = mapArrayToProps(unitNamesAsc) + +// Matches indexes in nanoInUnit +// (most are not used) +export const nanoIndex = 0 +export const microIndex = 1 +export const milliIndex = 2 +export const secondsIndex = 3 +export const minuteIndex = 4 +export const hourIndex = 5 +export const dayIndex = 6 +export const weekIndex = 7 +export const monthIndex = 8 +export const yearIndex = 9 + +// Utils +// ------------------------------------------------------------------------------------------------- +// TODO: rename to 'given' + +export function arbitraryFieldsToLargeNano(fields, unitIndex, fieldNames) { + let largeNano = new LargeInt(0, 0) + + for (; unitIndex >= nanoIndex; unitIndex--) { + const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + largeNano = largeNano.addLargeInt( + numberToLargeInt(fields[fieldNames[unitIndex]]).mult(divisor), + ) + } + + return largeNano +} + +export function arbitraryFieldsToNano(fields, unitIndex, fieldNames) { + let nano = 0 + + for (; unitIndex >= nanoIndex; unitIndex--) { + const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + nano += fields[fieldNames[unitIndex]] * divisor + } + + return nano +} + +export function nanoToArbitraryFields(nano, unitIndex, fieldNames) { + const fields = {} + + for (; unitIndex >= nanoIndex; unitIndex--) { + const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) + nano %= divisor + } + + return fields +} diff --git a/packages/temporal-polyfill/src/new/util.js b/packages/temporal-polyfill/src/new/utils.js similarity index 100% rename from packages/temporal-polyfill/src/new/util.js rename to packages/temporal-polyfill/src/new/utils.js diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index fd321272..fc8e6297 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -28,12 +28,12 @@ import { import { epochGetters, epochNanoToIso, - nanoInHour, validateEpochNano, } from './isoMath' import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' +import { nanoInHour } from './units' import { optionsToOverflow, toEpochNano } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' @@ -47,7 +47,7 @@ import { queryTimeZoneOps, zonedInternalsToIso, } from './timeZoneOps' -import { mapProps } from './util' +import { mapProps } from './utils' export const [ ZonedDateTime, From 2959d4e4242ee8f234de2f981b7a02d1b3092a5e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 16:12:18 -0400 Subject: [PATCH 095/805] more --- .../src/new/durationFields.js | 16 +++++----- packages/temporal-polyfill/src/new/isoMath.js | 32 +++++++++---------- packages/temporal-polyfill/src/new/round.js | 5 +-- packages/temporal-polyfill/src/new/units.js | 7 ++-- 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 162a167b..b0cccb60 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -1,10 +1,10 @@ import { isoTimeFieldNames } from './isoFields' import { toIntegerWithoutRounding } from './options' import { - arbitraryFieldsToLargeNano, + givenFieldsToLargeNano, hourIndex, nanoInUnit, - nanoToArbitraryFields, + nanoToGivenFields, unitIndexes, } from './units' import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './utils' @@ -104,15 +104,15 @@ function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { // TODO: audit repeat uses of this } -// Nano Math +// Field <-> Nanosecond Conversion // ------------------------------------------------------------------------------------------------- export function durationFieldsToNano(durationFields, largestUnit = 'day') { - return arbitraryFieldsToLargeNano(durationFields, unitIndexes[largestUnit], durationFieldNamesAsc) + return givenFieldsToLargeNano(durationFields, unitIndexes[largestUnit], durationFieldNamesAsc) } export function durationFieldsToTimeNano(durationFields) { - return arbitraryFieldsToLargeNano(durationFields, hourIndex, durationFieldNamesAsc).toNumber() + return givenFieldsToLargeNano(durationFields, hourIndex, durationFieldNamesAsc).toNumber() } export function nanoToDurationFields(largeNano, largestUnit = 'day') { @@ -120,11 +120,11 @@ export function nanoToDurationFields(largeNano, largestUnit = 'day') { const [largeUnitNum, remainder] = largeNano.divModTrunc(divisor) return { - ...nanoToArbitraryFields(remainder, unitIndexes[largestUnit] - 1, durationFieldNamesAsc), - [largestUnit]: largeUnitNum.toNumber(), + [largestUnit]: largeUnitNum.toNumber(), // BUG!!! doesn't work + ...nanoToGivenFields(remainder, unitIndexes[largestUnit] - 1, durationFieldNamesAsc), } } export function timeNanoToDurationFields(nano) { - return nanoToArbitraryFields(nano, hourIndex, durationFieldNamesAsc) + return nanoToGivenFields(nano, hourIndex, durationFieldNamesAsc) } diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 7732987d..6a64ba92 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,14 +1,14 @@ import { isoTimeFieldNamesAsc, pluckIsoDateTimeFields } from './isoFields' import { compareLargeInts, numberToLargeInt } from './largeInt' import { - arbitraryFieldsToNano, + givenFieldsToNano, hourIndex, milliInSec, nanoInMicro, nanoInMilli, nanoInSec, nanoInUtcDay, - nanoToArbitraryFields, + nanoToGivenFields, } from './units' import { clamp, divMod } from './utils' @@ -89,6 +89,19 @@ export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { } } +// Field <-> Nanosecond Conversion +// ------------------------------------------------------------------------------------------------- + +export function isoTimeFieldsToNano(isoTimeFields) { + return givenFieldsToNano(isoTimeFields, hourIndex, isoTimeFieldNamesAsc) +} + +export function nanoToIsoTimeAndDay(nano) { + const [dayDelta, timeNano] = divMod(nano, nanoInUtcDay) + const isoTimeFields = nanoToGivenFields(timeNano, hourIndex, isoTimeFieldNamesAsc) + return [isoTimeFields, dayDelta] +} + // Epoch Unit Conversion // ------------------------------------------------------------------------------------------------- @@ -134,21 +147,6 @@ export function epochMicroToNano(epochMicro) { return epochMicro.mult(nanoInMicro) } -// fields <-> nano - -export function isoTimeFieldsToNano(isoTimeFields) { - return arbitraryFieldsToNano(isoTimeFields, hourIndex, isoTimeFieldNamesAsc) -} - -export function nanoToIsoTimeAndDay(nano) { - const [dayDelta, timeNano] = divMod(nano, nanoInUtcDay) - - return [ - nanoToArbitraryFields(timeNano, hourIndex, isoTimeFieldNamesAsc), - dayDelta, - ] -} - // Epoch Getters // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 87b928c9..9d5577e5 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -12,11 +12,8 @@ import { nanoToIsoTimeAndDay, } from './isoMath' import { addDaysToIsoFields } from './move' -import { - nanoInUnit, - nanoInUtcDay, -} from './units' import { computeNanosecondsInDay } from './timeZoneOps' +import { nanoInUnit, nanoInUtcDay } from './units' import { identityFunc } from './utils' export function roundToMinute(nanoseconds) { // can be positive or negative diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js index a4e7b6c2..04d6d99e 100644 --- a/packages/temporal-polyfill/src/new/units.js +++ b/packages/temporal-polyfill/src/new/units.js @@ -42,9 +42,8 @@ export const yearIndex = 9 // Utils // ------------------------------------------------------------------------------------------------- -// TODO: rename to 'given' -export function arbitraryFieldsToLargeNano(fields, unitIndex, fieldNames) { +export function givenFieldsToLargeNano(fields, unitIndex, fieldNames) { let largeNano = new LargeInt(0, 0) for (; unitIndex >= nanoIndex; unitIndex--) { @@ -57,7 +56,7 @@ export function arbitraryFieldsToLargeNano(fields, unitIndex, fieldNames) { return largeNano } -export function arbitraryFieldsToNano(fields, unitIndex, fieldNames) { +export function givenFieldsToNano(fields, unitIndex, fieldNames) { let nano = 0 for (; unitIndex >= nanoIndex; unitIndex--) { @@ -68,7 +67,7 @@ export function arbitraryFieldsToNano(fields, unitIndex, fieldNames) { return nano } -export function nanoToArbitraryFields(nano, unitIndex, fieldNames) { +export function nanoToGivenFields(nano, unitIndex, fieldNames) { const fields = {} for (; unitIndex >= nanoIndex; unitIndex--) { From c8b986f89454e742ad4d54cefa91a5692f50fa1d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 16:13:20 -0400 Subject: [PATCH 096/805] different getSplit --- packages/temporal-polyfill/src/new/timeZoneImpl.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index a423c889..795452cc 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -89,7 +89,7 @@ export class IntlTimeZoneImpl { function createIntlTimeZoneStore(computeOffsetSec) { const getSample = createLazyMap(computeOffsetSec) // always given startEpochSec/endEpochSec - const getSplit = createLazyMap((startEpochSec) => [startEpochSec, startEpochSec + periodDur]) + const getSplit = createLazyMap((startEpochSec, endEpochSec) => [startEpochSec, endEpochSec]) let minTransition = minPossibleTransition let maxTransition = maxPossibleTransition @@ -127,7 +127,7 @@ function createIntlTimeZoneStore(computeOffsetSec) { return startOffsetSec } - const split = getSplit(startEpochSec) + const split = getSplit(startEpochSec, endEpochSec) return pinch(split, startOffsetSec, endOffsetSec, epochSec) } @@ -148,7 +148,7 @@ function createIntlTimeZoneStore(computeOffsetSec) { const endOffsetSec = getSample(endEpochSec) if (startOffsetSec !== endOffsetSec) { - const split = getSplit(startEpochSec) + const split = getSplit(startEpochSec, endEpochSec) pinch(split, startOffsetSec, endOffsetSec) const transitionEpochSec = split[0] From c08d9bbd9911751aa461e5e133c305e1a4e852b6 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 16:37:31 -0400 Subject: [PATCH 097/805] unit indexes --- .../temporal-polyfill/src/new/calendarImpl.js | 4 +- .../temporal-polyfill/src/new/calendarOps.js | 5 +- packages/temporal-polyfill/src/new/diff.js | 73 ++++++------- .../temporal-polyfill/src/new/duration.js | 50 ++++----- .../src/new/durationFields.js | 16 +-- packages/temporal-polyfill/src/new/options.js | 9 +- packages/temporal-polyfill/src/new/round.js | 101 +++++++++++------- 7 files changed, 142 insertions(+), 116 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 7057fdf9..ec5e18d3 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -177,8 +177,8 @@ class IsoCalendarImpl { return moveDate(this, isoDateFields, durationFields, overflow) } - dateUntil(startIsoDateFields, endIsoDateFields, largestUnit) { - return diffDatesExact(this, startIsoDateFields, endIsoDateFields, largestUnit) + dateUntil(startIsoDateFields, endIsoDateFields, largestUnitIndex) { + return diffDatesExact(this, startIsoDateFields, endIsoDateFields, largestUnitIndex) } // Field Refining diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index 0b8a86fb..a6df275b 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -14,6 +14,7 @@ import { strictArray, toObject, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' +import { unitNamesAsc } from './units' import { mapProps } from './utils' const checkCalendarProtocol = createProtocolChecker(calendarProtocolMethods) @@ -68,12 +69,12 @@ const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { ) }, - dateUntil(calendar, isoDateFields0, isoDateFields1, largestUnit) { + dateUntil(calendar, isoDateFields0, isoDateFields1, largestUnitIndex) { return getPlainDateInternals( calendar.dateUntil( createPlainDate(isoDateFields0), createPlainDate(isoDateFields1), - { largestUnit }, + { largestUnit: unitNamesAsc[largestUnitIndex] }, ), ) }, diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index d7532334..3cb9a78c 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -13,15 +13,14 @@ import { } from './isoMath' import { compareLargeInts } from './largeInt' import { addDaysToIsoFields, moveDateTime, moveZonedEpochNano } from './move' +import { roundLargeNano, roundNano, roundRelativeDuration } from './round' +import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { dayIndex, milliInDay, monthIndex, nanoInUtcDay, - unitIndexes, weekIndex, } from './units' -import { roundLargeNano, roundNano, roundRelativeDuration } from './round' -import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { identityFunc } from './utils' // Dates & Times @@ -31,20 +30,20 @@ export function diffDateTimes( calendar, // calendarOps startIsoFields, endIsoFields, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ) { const startEpochNano = isoToEpochNano(startIsoFields) const endEpochNano = isoToEpochNano(endIsoFields) - if (unitIndexes[largestUnit] < dayIndex) { + if (largestUnitIndex < dayIndex) { return diffEpochNano( startEpochNano, endEpochNano, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ) @@ -66,14 +65,14 @@ export function diffDateTimes( timeNano += nanoInUtcDay } - const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnit) + const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnitIndex) const timeDiff = timeNanoToDurationFields(timeNano) return roundRelativeDuration( { ...dateDiff, ...timeDiff, sign }, endEpochNano, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, startIsoFields, // marker @@ -86,29 +85,29 @@ export function diffDates( calendar, startIsoFields, endIsoFields, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ) { - if (unitIndexes[largestUnit] < dayIndex) { + if (largestUnitIndex < dayIndex) { return diffEpochNano( isoToEpochNano(startIsoFields), isoToEpochNano(endIsoFields), - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ) } - const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnit) + const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnitIndex) return roundRelativeDuration( dateDiff, isoToEpochNano(endIsoFields), - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, startIsoFields, // marker @@ -121,10 +120,8 @@ export function diffDatesExact( calendar, startIsoFields, endIsoFields, - largestUnit, + largestUnitIndex, ) { - const largestUnitIndex = unitIndexes[largestUnit] - if (largestUnitIndex <= weekIndex) { let weeks = 0 let days = diffEpochMilliByDay( @@ -160,8 +157,8 @@ export function diffDatesExact( export function diffTimes( startIsoFields, endIsoFields, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ) { @@ -169,14 +166,14 @@ export function diffTimes( const endTimeNano = isoTimeFieldsToNano(endIsoFields) const timeNano = roundNano( endTimeNano - startTimeNano, - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, ) return { ...durationFieldDefaults, - ...nanoToDurationFields(timeNano, largestUnit), + ...nanoToDurationFields(timeNano, largestUnitIndex), } } @@ -188,17 +185,17 @@ export function diffZonedEpochNano( timeZone, startEpochNano, endEpochNano, - largestUnit, - smallestUnit, // optional. internally will default to 'nanoseconds' + largestUnitIndex, + smallestUnitIndex, // optional. internally will default to 'nanoseconds' roundingMode, // optional. internally will default to 'halfExpand' roundingIncrement, // optional. internally will default to 1 ) { - if (unitIndexes[largestUnit] < dayIndex) { + if (largestUnitIndex < dayIndex) { return diffEpochNano( startEpochNano, endEpochNano, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ) @@ -221,15 +218,15 @@ export function diffZonedEpochNano( midEpochNano = isoToZonedEpochNano(midIsoFields) } - const dateDiff = calendar.dateUntil(startIsoFields, midIsoFields, largestUnit) + const dateDiff = calendar.dateUntil(startIsoFields, midIsoFields, largestUnitIndex) const timeDiffNano = endEpochNano.addLargeInt(midEpochNano, -1).toNumber() const timeDiff = timeNanoToDurationFields(timeDiffNano) return roundRelativeDuration( { ...dateDiff, ...timeDiff, sign }, endEpochNano, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, startEpochNano, // marker @@ -241,8 +238,8 @@ export function diffZonedEpochNano( export function diffEpochNano( startEpochNano, endEpochNano, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ) { @@ -251,11 +248,11 @@ export function diffEpochNano( ...nanoToDurationFields( roundLargeNano( endEpochNano.addLargeInt(startEpochNano, -1), - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, ), - largestUnit, + largestUnitIndex, ), } } diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 5282058b..50cef12c 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -28,6 +28,7 @@ import { totalDayTimeDuration, totalRelativeDuration, } from './round' +import { dayIndex } from './units' import { identityFunc, noop } from './utils' export const [ @@ -109,29 +110,29 @@ export const [ }, round(internals, options) { - const largestUnit = optionsToLargestUnit(options) // accepts auto? - const smallestUnit = optionsToSmallestUnit(options) + const largestUnitIndex = optionsToLargestUnit(options) // accepts auto? + const smallestUnitIndex = optionsToSmallestUnit(options) const roundingIncrement = optionsToRoundingIncrement(options) const roundingMode = optionsToRoundingMode(options) const markerInternals = optionsToRelativeTo(options) // optional // TODO: move to round.js? - if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { // TODO units + if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { // TODO: check internals doesn't have large fields - return roundDayTimeDuration(internals, smallestUnit, roundingMode, roundingIncrement) + return roundDayTimeDuration(internals, smallestUnitIndex, roundingMode, roundingIncrement) } if (!markerInternals) { throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnitIndex) return roundRelativeDuration( - ...spanDuration(internals, largestUnit, ...markerSystem), - largestUnit, - smallestUnit, + ...spanDuration(internals, largestUnitIndex, ...markerSystem), + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, ...markerSystem, @@ -139,23 +140,23 @@ export const [ }, total(internals, options) { - const totalUnit = optionsToTotalUnit(options) + const totalUnitIndex = optionsToTotalUnit(options) const markerInternals = optionsToRelativeTo(options) // optional - const largestUnit = getLargestDurationUnit(internals) + const largestUnitIndex = getLargestDurationUnit(internals) - if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { - return totalDayTimeDuration(internals, totalUnit) + if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { + return totalDayTimeDuration(internals, totalUnitIndex) } if (!markerInternals) { throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnitIndex) return totalRelativeDuration( - ...spanDuration(internals, largestUnit, ...markerSystem), - totalUnit, + ...spanDuration(internals, largestUnitIndex, ...markerSystem), + totalUnitIndex, ...markerSystem, ) }, @@ -173,12 +174,12 @@ export const [ const durationFields0 = toDurationInternals(durationArg0) const durationFields1 = toDurationInternals(durationArg1) const markerInternals = optionsToRelativeTo(options) // optional - const largestUnit = Math.max( + const largestUnitIndex = Math.max( getLargestDurationUnit(durationFields0), getLargestDurationUnit(durationFields1), ) - if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { // TODO: units + if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { return compareLargeInts( durationFieldsToNano(durationFields0), durationFieldsToNano(durationFields1), @@ -205,19 +206,19 @@ export const [ function addToDuration(direction, internals, otherArg, options) { const otherFields = toDurationInternals(otherArg) const markerInternals = optionsToRelativeTo(options) // optional - const largestUnit = Math.max( + const largestUnitIndex = Math.max( getLargestDurationUnit(internals), getLargestDurationUnit(otherFields), ) const addedDurationFields = addDurationFields(internals, otherFields, direction) - if (largestUnit < 'day' || (largestUnit === 'day' && !markerInternals)) { + if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { return balanceDurationDayTime(addedDurationFields) } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) - return spanDuration(internals, largestUnit, ...markerSystem)[0] + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnitIndex) + return spanDuration(internals, largestUnitIndex, ...markerSystem)[0] } function createMarkerSystem(markerInternals) { @@ -242,7 +243,7 @@ function createMarkerSystem(markerInternals) { function spanDuration( durationFields, - largestUnit, + largestUnitIndex, // marker system... marker, markerToEpochNano, @@ -250,15 +251,16 @@ function spanDuration( diffMarkers, ) { const endMarker = markerToEpochNano(moveMarker(marker, durationFields)) - const balancedDuration = diffMarkers(marker, endMarker, largestUnit) + const balancedDuration = diffMarkers(marker, endMarker, largestUnitIndex) return [balancedDuration, endMarker] } function balanceDurationDayTime( durationFields, - largestUnit, // day/time + largestUnitIndex, // day/time ) { } function getLargestDurationUnit(durationFields) { + // TODO: rename to getLargestDurationUnitIndex } diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index b0cccb60..f72dcdd5 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -1,11 +1,13 @@ import { isoTimeFieldNames } from './isoFields' import { toIntegerWithoutRounding } from './options' import { + dayIndex, givenFieldsToLargeNano, hourIndex, nanoInUnit, nanoToGivenFields, unitIndexes, + unitNamesAsc, } from './units' import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './utils' @@ -107,21 +109,21 @@ function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { // Field <-> Nanosecond Conversion // ------------------------------------------------------------------------------------------------- -export function durationFieldsToNano(durationFields, largestUnit = 'day') { - return givenFieldsToLargeNano(durationFields, unitIndexes[largestUnit], durationFieldNamesAsc) +export function durationFieldsToNano(durationFields, largestUnitIndex = dayIndex) { + return givenFieldsToLargeNano(durationFields, largestUnitIndex, durationFieldNamesAsc) } export function durationFieldsToTimeNano(durationFields) { - return givenFieldsToLargeNano(durationFields, hourIndex, durationFieldNamesAsc).toNumber() + return durationFieldsToNano(durationFields, hourIndex).toNumber() } -export function nanoToDurationFields(largeNano, largestUnit = 'day') { - const divisor = nanoInUnit[largestUnit] +export function nanoToDurationFields(largeNano, largestUnitIndex = dayIndex) { + const divisor = nanoInUnit[unitNamesAsc[largestUnitIndex]] // best to use unitNamesAsc? const [largeUnitNum, remainder] = largeNano.divModTrunc(divisor) return { - [largestUnit]: largeUnitNum.toNumber(), // BUG!!! doesn't work - ...nanoToGivenFields(remainder, unitIndexes[largestUnit] - 1, durationFieldNamesAsc), + [durationFieldNamesAsc[largestUnitIndex]]: largeUnitNum.toNumber(), + ...nanoToGivenFields(remainder, largestUnitIndex - 1, durationFieldNamesAsc), } } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index d126d541..b225cc59 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,6 +1,6 @@ import { durationFieldNamesAsc } from './durationFields' import { bigIntToLargeInt } from './largeInt' -import { unitIndexes } from './units' +import { unitIndexes, unitNamesAsc } from './units' import { mapArrayToProps } from './utils' // TODO: for unit parsing, ensure ceiling and correct increment @@ -194,6 +194,7 @@ export function validateRoundingOptions(options) { } export function optionsToLargestUnit() { + // TODO: rename to optionsToLargestUnitIndex } export function optionsToOverflow(options) { @@ -201,6 +202,7 @@ export function optionsToOverflow(options) { } export function optionsToTotalUnit() { + // TODO: rename to optionsToTotalUnitIndex } export function optionsToRelativeTo() { @@ -208,6 +210,7 @@ export function optionsToRelativeTo() { } export function optionsToSmallestUnit(options) { + // TODO: rename to optionsToSmallestUnitIndex } export function optionsToRoundingIncrement(options) { @@ -220,8 +223,8 @@ export function overflowToOptions(overflow) { return { overflow } } -export function largestUnitToOptions(largestUnit) { - return { largestUnit } +export function largestUnitToOptions(largestUnitIndex) { + return { largestUnit: unitNamesAsc[largestUnitIndex] } } // Units diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 9d5577e5..d20bb4d6 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -1,5 +1,6 @@ import { durationFieldDefaults, + durationFieldNamesAsc, durationFieldsToNano, durationFieldsToTimeNano, durationTimeFieldDefaults, @@ -13,7 +14,7 @@ import { } from './isoMath' import { addDaysToIsoFields } from './move' import { computeNanosecondsInDay } from './timeZoneOps' -import { nanoInUnit, nanoInUtcDay } from './units' +import { dayIndex, nanoInUnit, nanoInUtcDay, nanoIndex, unitNamesAsc, weekIndex } from './units' import { identityFunc } from './utils' export function roundToMinute(nanoseconds) { // can be positive or negative @@ -25,7 +26,7 @@ export function roundToMinute(nanoseconds) { // can be positive or negative export function roundIsoDateTimeFields( isoDateTimeFields, - smallestUnit, // day/time + smallestUnitIndex, // day/time roundingMode, roundingIncrement, timeZoneOps = undefined, @@ -33,7 +34,7 @@ export function roundIsoDateTimeFields( let isoTimeFields let dayDelta - if (smallestUnit === 'day') { + if (smallestUnitIndex === dayIndex) { const nanosecondsInDay = timeZoneOps ? computeNanosecondsInDay(timeZoneOps, isoDateTimeFields) : nanoInUtcDay @@ -48,7 +49,7 @@ export function roundIsoDateTimeFields( } else { ([isoTimeFields, dayDelta] = roundIsoTimeFields( isoDateTimeFields, - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, )) @@ -62,13 +63,13 @@ export function roundIsoDateTimeFields( export function roundIsoTimeFields( isoTimeFields, - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, ) { const timeNano = roundNano( isoTimeFieldsToNano(isoTimeFields), - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, ) @@ -80,12 +81,12 @@ export function roundIsoTimeFields( export function roundDayTimeDuration( durationFields, - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, ) { const largeNano = durationFieldsToNano(durationFields) - const r = roundLargeNano(largeNano, smallestUnit, roundingMode, roundingIncrement) + const r = roundLargeNano(largeNano, smallestUnitIndex, roundingMode, roundingIncrement) return { ...durationFieldDefaults, ...nanoToDurationFields(r), @@ -96,8 +97,8 @@ export function roundRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) // ^has sign endEpochNanoseconds, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, roundingMode, roundingIncrement, // marker system... @@ -105,12 +106,12 @@ export function roundRelativeDuration( markerToEpochMilliseconds, moveMarker, ) { - if (smallestUnit === 'nanoseconds' && roundingIncrement === 1) { + if (smallestUnitIndex === nanoIndex && roundingIncrement === 1) { return durationFields } let [roundedDurationFields, roundedEpochNanoseconds, grew] = ( - smallestUnit >= 'day' + smallestUnitIndex >= dayIndex ? nudgeRelativeDuration : markerToEpochMilliseconds === identityFunc // marker is ZonedDateTime's epochNanoseconds? ? nudgeRelativeDurationTime @@ -118,7 +119,7 @@ export function roundRelativeDuration( )( durationFields, endEpochNanoseconds, - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, // marker system only needed for nudgeRelativeDuration... @@ -132,8 +133,8 @@ export function roundRelativeDuration( roundedDurationFields = bubbleRelativeDuration( roundedDurationFields, roundedEpochNanoseconds, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, // marker system... marker, moveMarker, @@ -147,14 +148,18 @@ export function roundRelativeDuration( // Rounding Numbers // ------------------------------------------------------------------------------------------------- -export function roundLargeNano(largeNano, smallestUnit, roundingMode, roundingIncrement) { - const divisor = nanoInUnit[smallestUnit] * roundingIncrement +export function roundLargeNano(largeNano, smallestUnitIndex, roundingMode, roundingIncrement) { + const divisor = nanoInUnit[unitNamesAsc[smallestUnitIndex]] * roundingIncrement const [n, remainder] = largeNano.divModTrunc(divisor) return n.mult(divisor).add(roundWithMode(remainder / divisor, roundingMode)) } -export function roundNano(nano, smallestUnit, roundingMode, roundingIncrement) { - return roundWithDivisor(nano, nanoInUnit[smallestUnit] * roundingIncrement, roundingMode) +export function roundNano(nano, smallestUnitIndex, roundingMode, roundingIncrement) { + return roundWithDivisor( + nano, + nanoInUnit[unitNamesAsc[smallestUnitIndex]] * roundingIncrement, + roundingMode, + ) } function roundWithDivisor(num, divisor, roundingMode) { @@ -180,7 +185,7 @@ export function totalDayTimeDuration( // assumes iso-length days export function totalRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, - totalUnit, + totalUnitIndex, // marker system... marker, markerToEpochMilliseconds, @@ -189,8 +194,8 @@ export function totalRelativeDuration( const { sign } = durationFields const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( - clearDurationFields(durationFields, 'nanoseconds', totalUnit - 1), - totalUnit, + clearDurationFields(durationFields, nanoIndex, totalUnitIndex - 1), + totalUnitIndex, sign, // marker system... marker, @@ -202,7 +207,7 @@ export function totalRelativeDuration( endEpochNanoseconds.subtract(epochNanoseconds0).toNumber() / epochNanoseconds1.subtract(epochNanoseconds0).toNumber() - return durationFields[totalUnit] + portion + return durationFields[durationFieldNamesAsc[totalUnitIndex]] + portion } // Nudge @@ -211,12 +216,12 @@ export function totalRelativeDuration( function nudgeDurationTime( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, // NOT NEEDED, just for adding result to - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, ) { const timeNano = durationFieldsToTimeNano(durationFields) - const roundedTimeNano = roundNano(timeNano, smallestUnit, roundingMode, roundingIncrement) + const roundedTimeNano = roundNano(timeNano, smallestUnitIndex, roundingMode, roundingIncrement) const roundedFields = nanoToDurationFields(roundedTimeNano) const dayDelta = roundedFields.days const nudgedDurationFields = { // TODO: what about sign? @@ -235,7 +240,7 @@ function nudgeDurationTime( function nudgeRelativeDurationTime( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, // NOT NEEDED, just for conformance - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, // marker system... @@ -245,7 +250,7 @@ function nudgeRelativeDurationTime( ) { const { sign } = durationFields const timeNano = durationFieldsToTimeNano(durationFields) - let roundedTimeNano = roundNano(timeNano, smallestUnit, roundingMode, roundingIncrement) + let roundedTimeNano = roundNano(timeNano, smallestUnitIndex, roundingMode, roundingIncrement) const [dayEpochNanoseconds0, dayEpochNanoseconds1] = clampRelativeDuration( { ...durationFields, ...durationTimeFieldDefaults }, @@ -263,7 +268,7 @@ function nudgeRelativeDurationTime( if (!beyondDay || Math.sign(beyondDay) === sign) { dayDelta++ - roundedTimeNano = roundNano(beyondDay, smallestUnit, roundingMode, roundingIncrement) + roundedTimeNano = roundNano(beyondDay, smallestUnitIndex, roundingMode, roundingIncrement) endEpochNanoseconds = dayEpochNanoseconds1.add(roundedTimeNano) } else { endEpochNanoseconds = dayEpochNanoseconds0.add(roundedTimeNano) @@ -282,7 +287,7 @@ function nudgeRelativeDurationTime( function nudgeRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, - smallestUnit, + smallestUnitIndex, roundingMode, roundingIncrement, // marker system... @@ -292,12 +297,19 @@ function nudgeRelativeDuration( ) { const { sign } = durationFields - const baseDurationFields = clearDurationFields(durationFields, 'nanoseconds', smallestUnit - 1) - baseDurationFields[smallestUnit] = Math.trunc(durationFields[smallestUnit] / roundingIncrement) + const baseDurationFields = clearDurationFields( + durationFields, + nanoIndex, + smallestUnitIndex - 1, + ) + + baseDurationFields[smallestUnitIndex] = Math.trunc( + durationFields[smallestUnitIndex] / roundingIncrement, + ) const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( baseDurationFields, - smallestUnit, + smallestUnitIndex, roundingIncrement * sign, // marker system... marker, @@ -312,7 +324,7 @@ function nudgeRelativeDuration( const roundedPortion = roundWithMode(portion * sign, roundingMode) // -1/0/1 if (roundedPortion) { // enlarged? - baseDurationFields[smallestUnit] += roundingIncrement * sign + baseDurationFields[smallestUnitIndex] += roundingIncrement * sign return [baseDurationFields, epochNanoseconds1, roundedPortion] } else { @@ -326,8 +338,8 @@ function nudgeRelativeDuration( function bubbleRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, - largestUnit, - smallestUnit, + largestUnitIndex, + smallestUnitIndex, // marker system... marker, markerToEpochMilliseconds, @@ -335,13 +347,21 @@ function bubbleRelativeDuration( ) { const { sign } = durationFields - for (let currentUnit = smallestUnit + 1; currentUnit < largestUnit; currentUnit++) { // TODO - if (currentUnit === 'week') { // correct? + for ( + let currentUnitIndex = smallestUnitIndex + 1; + currentUnitIndex < largestUnitIndex; + currentUnitIndex++ + ) { + if (currentUnitIndex === weekIndex) { // correct? continue } - const baseDurationFields = clearDurationFields(durationFields, 'nanoseconds', currentUnit - 1) - baseDurationFields[currentUnit] += sign + const baseDurationFields = clearDurationFields( + durationFields, + nanoIndex, + currentUnitIndex - 1, + ) + baseDurationFields[durationFieldNamesAsc[currentUnitIndex]] += sign const thresholdEpochNanoseconds = markerToEpochMilliseconds( moveMarker(marker, baseDurationFields), @@ -375,5 +395,6 @@ function clampRelativeDuration( return [epochNanoseconds0, epochNanoseconds1] } -function clearDurationFields(durationFields, firstUnit, lastUnit) { +function clearDurationFields(durationFields, firstUnitIndex, lastUnitIndex) { + // TODO: always assume `nanoIndex` as firstUnitIndex } From 94ce8f5129133da1f6a9fd1970ffd3a8e5a3610e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 16:51:56 -0400 Subject: [PATCH 098/805] removed nanoInUnit --- .../src/new/durationFields.js | 6 +- packages/temporal-polyfill/src/new/round.js | 15 ++-- packages/temporal-polyfill/src/new/units.js | 70 +++++++++++-------- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index f72dcdd5..148cabee 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -4,10 +4,8 @@ import { dayIndex, givenFieldsToLargeNano, hourIndex, - nanoInUnit, nanoToGivenFields, - unitIndexes, - unitNamesAsc, + unitIndexToNano, } from './units' import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './utils' @@ -118,7 +116,7 @@ export function durationFieldsToTimeNano(durationFields) { } export function nanoToDurationFields(largeNano, largestUnitIndex = dayIndex) { - const divisor = nanoInUnit[unitNamesAsc[largestUnitIndex]] // best to use unitNamesAsc? + const divisor = unitIndexToNano[largestUnitIndex] const [largeUnitNum, remainder] = largeNano.divModTrunc(divisor) return { diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index d20bb4d6..7be4937c 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -8,13 +8,10 @@ import { timeNanoToDurationFields, } from './durationFields' import { isoTimeFieldDefaults } from './isoFields' -import { - isoTimeFieldsToNano, - nanoToIsoTimeAndDay, -} from './isoMath' +import { isoTimeFieldsToNano, nanoToIsoTimeAndDay } from './isoMath' import { addDaysToIsoFields } from './move' import { computeNanosecondsInDay } from './timeZoneOps' -import { dayIndex, nanoInUnit, nanoInUtcDay, nanoIndex, unitNamesAsc, weekIndex } from './units' +import { dayIndex, nanoInUtcDay, nanoIndex, unitIndexToNano, weekIndex } from './units' import { identityFunc } from './utils' export function roundToMinute(nanoseconds) { // can be positive or negative @@ -149,7 +146,7 @@ export function roundRelativeDuration( // ------------------------------------------------------------------------------------------------- export function roundLargeNano(largeNano, smallestUnitIndex, roundingMode, roundingIncrement) { - const divisor = nanoInUnit[unitNamesAsc[smallestUnitIndex]] * roundingIncrement + const divisor = unitIndexToNano[smallestUnitIndex] * roundingIncrement const [n, remainder] = largeNano.divModTrunc(divisor) return n.mult(divisor).add(roundWithMode(remainder / divisor, roundingMode)) } @@ -157,7 +154,7 @@ export function roundLargeNano(largeNano, smallestUnitIndex, roundingMode, round export function roundNano(nano, smallestUnitIndex, roundingMode, roundingIncrement) { return roundWithDivisor( nano, - nanoInUnit[unitNamesAsc[smallestUnitIndex]] * roundingIncrement, + unitIndexToNano[smallestUnitIndex] * roundingIncrement, roundingMode, ) } @@ -174,10 +171,10 @@ function roundWithMode(num, roundingMode) { export function totalDayTimeDuration( // assumes iso-length days durationFields, - unitName, + totalUnitIndex, ) { const largeNano = durationFieldsToNano(durationFields) - const divisor = nanoInUnit[unitName] + const divisor = unitIndexToNano[totalUnitIndex] const [fullUnit, remainder] = largeNano.divModTrunc(divisor) return fullUnit.toNumber() + (remainder / divisor) } diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js index 04d6d99e..066f15b4 100644 --- a/packages/temporal-polyfill/src/new/units.js +++ b/packages/temporal-polyfill/src/new/units.js @@ -1,34 +1,6 @@ import { LargeInt, numberToLargeInt } from './largeInt' import { mapArrayToProps } from './utils' -export const secInDay = 86400 // TODO: rename 'sec' -> 'seconds' -export const milliInDay = 86400000 // TODO: not DRY -export const milliInSec = 1000 - -export const nanoInMicro = 1000 // consolidate with other 1000 units -export const nanoInMilli = 1000000 -export const nanoInSec = 1000000000 -export const nanoInHour = 3600000000000 -export const nanoInUtcDay = 86400000000000 - -// Ordered by ascending size -export const nanoInUnit = { - nanosecond: 1, - microsecond: nanoInMicro, - millisecond: nanoInMilli, - second: nanoInSec, - hour: nanoInHour, - day: nanoInUtcDay, - week: 0, - month: 0, - year: 0, -} - -export const unitNamesAsc = Object.keys(nanoInUnit) -export const unitIndexes = mapArrayToProps(unitNamesAsc) - -// Matches indexes in nanoInUnit -// (most are not used) export const nanoIndex = 0 export const microIndex = 1 export const milliIndex = 2 @@ -40,6 +12,42 @@ export const weekIndex = 7 export const monthIndex = 8 export const yearIndex = 9 +export const unitNamesAsc = [ // TODO: better way to compress this? + 'nanosecond', + 'microsecond', + 'millisecond', + 'second', + 'hour', + 'day', + 'week', + 'month', + 'year', +] + +export const unitIndexes = mapArrayToProps(unitNamesAsc) + +// Nanoseconds +// ------------------------------------------------------------------------------------------------- + +export const secInDay = 86400 +export const milliInDay = 86400000 // TODO: not DRY +export const milliInSec = 1000 + +export const nanoInMicro = 1000 // consolidate with other 1000 units +export const nanoInMilli = 1000000 +export const nanoInSec = 1000000000 +export const nanoInHour = 3600000000000 +export const nanoInUtcDay = 86400000000000 + +export const unitIndexToNano = [ + 1, // nano-in-nano + nanoInMicro, + nanoInMilli, + nanoInSec, + nanoInHour, + nanoInUtcDay, +] + // Utils // ------------------------------------------------------------------------------------------------- @@ -47,7 +55,7 @@ export function givenFieldsToLargeNano(fields, unitIndex, fieldNames) { let largeNano = new LargeInt(0, 0) for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + const divisor = unitIndexToNano[unitIndex] largeNano = largeNano.addLargeInt( numberToLargeInt(fields[fieldNames[unitIndex]]).mult(divisor), ) @@ -60,7 +68,7 @@ export function givenFieldsToNano(fields, unitIndex, fieldNames) { let nano = 0 for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + const divisor = unitIndexToNano[unitIndex] nano += fields[fieldNames[unitIndex]] * divisor } @@ -71,7 +79,7 @@ export function nanoToGivenFields(nano, unitIndex, fieldNames) { const fields = {} for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = nanoInUnit[unitNamesAsc[unitIndex]] + const divisor = unitIndexToNano[unitIndex] fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) nano %= divisor } From 1c633f98a8fc8ea149896b26f7ad668736eb91ed Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 17:03:59 -0400 Subject: [PATCH 099/805] rename divmod and LargeInt methods --- .../src/new/durationFields.js | 2 +- packages/temporal-polyfill/src/new/instant.js | 2 +- packages/temporal-polyfill/src/new/isoMath.js | 12 ++++----- .../temporal-polyfill/src/new/largeInt.js | 25 +++++++++++-------- packages/temporal-polyfill/src/new/move.js | 6 ++--- packages/temporal-polyfill/src/new/round.js | 14 +++++------ .../temporal-polyfill/src/new/timeZoneImpl.js | 4 +-- .../temporal-polyfill/src/new/timeZoneOps.js | 12 ++++----- packages/temporal-polyfill/src/new/utils.js | 2 +- .../src/new/zonedDateTime.js | 8 +++--- 10 files changed, 45 insertions(+), 42 deletions(-) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 148cabee..4ffa4712 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -117,7 +117,7 @@ export function durationFieldsToTimeNano(durationFields) { export function nanoToDurationFields(largeNano, largestUnitIndex = dayIndex) { const divisor = unitIndexToNano[largestUnitIndex] - const [largeUnitNum, remainder] = largeNano.divModTrunc(divisor) + const [largeUnitNum, remainder] = largeNano.divTruncMod(divisor) return { [durationFieldNamesAsc[largestUnitIndex]]: largeUnitNum.toNumber(), diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 98429e35..373acd83 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -144,7 +144,7 @@ export const [ refinedOptions, // TODO: break apart options ) const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - const isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) + const isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) return formatIsoDateTimeFields(isoDateTimeFields, refinedOptions) + formatOffsetNanoseconds(offsetNanoseconds) + diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 6a64ba92..fb79dd2b 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -10,7 +10,7 @@ import { nanoInUtcDay, nanoToGivenFields, } from './units' -import { clamp, divMod } from './utils' +import { clamp, divFloorMod } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -97,7 +97,7 @@ export function isoTimeFieldsToNano(isoTimeFields) { } export function nanoToIsoTimeAndDay(nano) { - const [dayDelta, timeNano] = divMod(nano, nanoInUtcDay) + const [dayDelta, timeNano] = divFloorMod(nano, nanoInUtcDay) const isoTimeFields = nanoToGivenFields(timeNano, hourIndex, isoTimeFieldNamesAsc) return [isoTimeFields, dayDelta] } @@ -122,15 +122,15 @@ function epochNanoToMicro(epochNano) { // nano -> [micro/milli/sec] (with remainder) export function epochNanoToSecMod(epochNano) { - return epochNano.divMod(nanoInSec) + return epochNano.divFloorMod(nanoInSec) } function epochNanoToMilliMod(epochNano) { - return epochNano.divMod(nanoInMilli) + return epochNano.divFloorMod(nanoInMilli) } function epochNanoToMicroMod(epochNano) { - return epochNano.divMod(nanoInMicro) + return epochNano.divFloorMod(nanoInMicro) } // [micro/milli/sec] -> nano @@ -175,7 +175,7 @@ function validateIsoDateTimeInternals(isoDateTimeInternals) { // validateIsoInte if (nudge) { const epochNano = isoToEpochNano(isoDateTimeInternals) - validateEpochNano(epochNano && epochNano.add((nanoInUtcDay - 1) * nudge)) + validateEpochNano(epochNano && epochNano.addNumber((nanoInUtcDay - 1) * nudge)) } return isoDateTimeInternals diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js index 7960714e..ed60bfa5 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -1,4 +1,4 @@ -import { compareNumbers, divMod } from './utils' +import { compareNumbers, divFloorMod } from './utils' const maxLow = 1e8 // exclusive // TODO: explain why @@ -12,7 +12,10 @@ export class LargeInt { return balanceAndCreate(this.high + n.high * sign, this.low + n.low * sign) } - add(n) { + /* + different than PlainTime/Duration::add, for minification + */ + addNumber(n) { return balanceAndCreate(this.high, this.low + n) } @@ -20,10 +23,10 @@ export class LargeInt { return balanceAndCreate(this.high * multiplier, this.low * multiplier) } - divMod(divisor) { + divFloorMod(divisor) { const { high, low } = this - const [newHigh, highRemainder] = divMod(high, divisor) - const [newLow, remainder] = divMod(highRemainder * maxLow + low, divisor) + const [newHigh, highRemainder] = divFloorMod(high, divisor) + const [newLow, remainder] = divFloorMod(highRemainder * maxLow + low, divisor) return [ balanceAndCreate(newHigh, newLow), @@ -31,11 +34,11 @@ export class LargeInt { ] } - divModTrunc(divisor) { // TODO: rename a lot of stuff? - let [largeInt, remainder] = this.divMod(divisor) + divTruncMod(divisor) { + let [largeInt, remainder] = this.divFloorMod(divisor) if (largeInt.computeSign() === -1 && remainder) { - largeInt = largeInt.add(1) + largeInt = largeInt.addNumber(1) remainder -= divisor } @@ -59,17 +62,17 @@ export class LargeInt { } function balanceAndCreate(high, low) { - const [extraHigh, newLow] = divMod(low, maxLow) + const [extraHigh, newLow] = divFloorMod(low, maxLow) return new LargeInt(high + extraHigh, newLow) } export function numberToLargeInt(n) { - return new LargeInt(...divMod(n, maxLow)) + return new LargeInt(...divFloorMod(n, maxLow)) } export function bigIntToLargeInt(n) { // must create BigInt lazily for if browser lacks support - return new LargeInt(...divMod(n, BigInt(maxLow)).map(Number)) + return new LargeInt(...divFloorMod(n, BigInt(maxLow)).map(Number)) } export function compareLargeInts(a, b) { diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 62954d79..986a0aa1 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -22,7 +22,7 @@ export function addDaysToIsoFields() { } export function moveEpochNano(epochNanoseconds, durationFields) { - return epochNanoseconds.add(onlyDurationTimeFieldsToIso(durationFields)) + return epochNanoseconds.addNumber(onlyDurationTimeFieldsToIso(durationFields)) } export function moveZonedEpochNano( @@ -37,7 +37,7 @@ export function moveZonedEpochNano( ) if (!durationHasDateParts(durationFields)) { - epochNanoseconds = epochNanoseconds.add(durationTimeNanoseconds) + epochNanoseconds = epochNanoseconds.addNumber(durationTimeNanoseconds) } else { const isoDateTimeFields = zonedEpochNanoToIso(timeZone, epochNanoseconds) const movedIsoDateFields = calendar.dateAdd( @@ -53,7 +53,7 @@ export function moveZonedEpochNano( ...movedIsoDateFields, // date parts } epochNanoseconds = getSingleInstantFor(timeZone, movedIsoDateTimeFields) - .add(durationTimeNanoseconds) + .addNumber(durationTimeNanoseconds) } return epochNanoseconds diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 7be4937c..55d69977 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -147,8 +147,8 @@ export function roundRelativeDuration( export function roundLargeNano(largeNano, smallestUnitIndex, roundingMode, roundingIncrement) { const divisor = unitIndexToNano[smallestUnitIndex] * roundingIncrement - const [n, remainder] = largeNano.divModTrunc(divisor) - return n.mult(divisor).add(roundWithMode(remainder / divisor, roundingMode)) + const [fullUnits, remainder] = largeNano.divTruncMod(divisor) + return fullUnits.mult(divisor).addNumber(roundWithMode(remainder / divisor, roundingMode)) } export function roundNano(nano, smallestUnitIndex, roundingMode, roundingIncrement) { @@ -175,8 +175,8 @@ export function totalDayTimeDuration( // assumes iso-length days ) { const largeNano = durationFieldsToNano(durationFields) const divisor = unitIndexToNano[totalUnitIndex] - const [fullUnit, remainder] = largeNano.divModTrunc(divisor) - return fullUnit.toNumber() + (remainder / divisor) + const [fullUnits, remainder] = largeNano.divTruncMod(divisor) + return fullUnits.toNumber() + (remainder / divisor) } export function totalRelativeDuration( @@ -229,7 +229,7 @@ function nudgeDurationTime( return [ nudgedDurationFields, - endEpochNanoseconds.add(roundedTimeNano - timeNano), + endEpochNanoseconds.addNumber(roundedTimeNano - timeNano), dayDelta, ] } @@ -266,9 +266,9 @@ function nudgeRelativeDurationTime( if (!beyondDay || Math.sign(beyondDay) === sign) { dayDelta++ roundedTimeNano = roundNano(beyondDay, smallestUnitIndex, roundingMode, roundingIncrement) - endEpochNanoseconds = dayEpochNanoseconds1.add(roundedTimeNano) + endEpochNanoseconds = dayEpochNanoseconds1.addNumber(roundedTimeNano) } else { - endEpochNanoseconds = dayEpochNanoseconds0.add(roundedTimeNano) + endEpochNanoseconds = dayEpochNanoseconds0.addNumber(roundedTimeNano) } const durationTimeFields = timeNanoToDurationFields(roundedTimeNano) diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index 795452cc..828af7f7 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -46,7 +46,7 @@ export class FixedTimeZoneImpl { } getPossibleInstantsFor(isoDateTimeFields) { - return [isoToEpochNano(isoDateTimeFields).add(this.offsetNano)] + return [isoToEpochNano(isoDateTimeFields).addNumber(this.offsetNano)] } getTransition(epochNano, direction) { @@ -69,7 +69,7 @@ export class IntlTimeZoneImpl { getPossibleInstantsFor(isoDateTimeFields) { const [zonedEpochSec, subsecNano] = isoToEpochSec(isoDateTimeFields) return this.store.getPossibleEpochSec(zonedEpochSec) - .map((epochSec) => epochSecToNano(epochSec).add(subsecNano)) + .map((epochSec) => epochSecToNano(epochSec).addNumber(subsecNano)) } /* diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index c3b2ac39..b7714dbf 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -13,12 +13,12 @@ import { isoToEpochNano, } from './isoMath' import { addDaysToIsoFields } from './move' -import { nanoInUtcDay } from './units' import { strictArray, strictNumber } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' import { TimeZone, createTimeZone, timeZoneProtocolMethods } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' +import { nanoInUtcDay } from './units' import { createLazyMap } from './utils' export const utcTimeZoneId = 'UTC' @@ -150,7 +150,7 @@ export function getSingleInstantFor( epochNanos = timeZoneOps.getPossibleInstantsFor( epochNanoToIso( - zonedEpochNano.add(gapNano * ( + zonedEpochNano.addNumber(gapNano * ( disambig === 'earlier' ? -1 : 1 // 'later' or 'compatible' @@ -167,10 +167,10 @@ export function getSingleInstantFor( function computeGapNear(timeZoneOps, zonedEpochNano) { const startOffsetNano = timeZoneOps.getOffsetNanosecondsFor( - zonedEpochNano.add(-nanoInUtcDay), + zonedEpochNano.addNumber(-nanoInUtcDay), ) const endOffsetNano = timeZoneOps.getOffsetNanosecondsFor( - zonedEpochNano.add(nanoInUtcDay), + zonedEpochNano.addNumber(nanoInUtcDay), ) return endOffsetNano - startOffsetNano } @@ -178,7 +178,7 @@ function computeGapNear(timeZoneOps, zonedEpochNano) { export const zonedInternalsToIso = createLazyMap((internals) => { const { timeZone, epochNanoseconds } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - const isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) + const isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) return { ...isoDateTimeFields, @@ -188,7 +188,7 @@ export const zonedInternalsToIso = createLazyMap((internals) => { export function zonedEpochNanoToIso(timeZoneOps, epochNano) { const offsetNano = timeZoneOps.getOffsetNanosecondsFor(epochNano) - return epochNanoToIso(epochNano.add(offsetNano)) + return epochNanoToIso(epochNano.addNumber(offsetNano)) } // Adapter diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 4e0de9c9..10eac2b5 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -102,7 +102,7 @@ export function clamp() { /* Works with BigInt or Number (as long as the same) */ -export function divMod(n, divisor) { +export function divFloorMod(n, divisor) { const remainder = floorMod(n, divisor) const quotient = (n - remainder) / divisor return [quotient, remainder] diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index fc8e6297..b139c356 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -33,7 +33,6 @@ import { import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' -import { nanoInHour } from './units' import { optionsToOverflow, toEpochNano } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' @@ -47,6 +46,7 @@ import { queryTimeZoneOps, zonedInternalsToIso, } from './timeZoneOps' +import { nanoInHour } from './units' import { mapProps } from './utils' export const [ @@ -238,7 +238,7 @@ export const [ let { epochNanoseconds, timeZone, calendar } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - let isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) + let isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) isoDateTimeFields = roundIsoDateTimeFields( isoDateTimeFields, @@ -301,7 +301,7 @@ export const [ // TODO: don't let options be accessed twice! once by rounding, twice by formatting let offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - let isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) + let isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) isoDateTimeFields = roundIsoDateTimeFields( isoDateTimeFields, @@ -320,7 +320,7 @@ export const [ // waa? non-dry code? offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - isoDateTimeFields = epochNanoToIso(epochNanoseconds.add(offsetNanoseconds)) + isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) return formatIsoDateTimeFields(isoDateTimeFields, options) + formatOffsetNanoseconds(offsetNanoseconds) + From 32f07b9fd25ea779423cd03713da908720ab37c7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 18:13:44 -0400 Subject: [PATCH 100/805] fix adding bugs --- .../temporal-polyfill/src/new/calendarImpl.js | 27 +++-- packages/temporal-polyfill/src/new/diff.js | 6 +- .../src/new/durationFields.js | 8 ++ .../temporal-polyfill/src/new/largeInt.js | 8 +- packages/temporal-polyfill/src/new/move.js | 102 ++++++++---------- .../temporal-polyfill/src/new/plainTime.js | 4 +- packages/temporal-polyfill/src/new/round.js | 4 +- .../temporal-polyfill/src/new/timeZoneOps.js | 4 +- packages/temporal-polyfill/src/new/units.js | 13 ++- 9 files changed, 89 insertions(+), 87 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index ec5e18d3..8aeb04ae 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -38,8 +38,9 @@ import { isoEpochOriginYear, isoToEpochMilli, } from './isoMath' -import { addDaysMilli, addIntlMonths, addIsoMonths, moveDate } from './move' +import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { constrainInt } from './options' +import { milliInDay } from './units' import { buildWeakMapCache, createLazyMap, mapArrayToProps, twoDigit } from './utils' // Base ISO Calendar @@ -303,7 +304,7 @@ Object.assign(IsoCalendarImpl.prototype, { dayOfWeek: computeIsoDayOfWeek, weekOfYear: computeIsoWeekOfYear, yearOfWeek: computeIsoYearOfWeek, - addMonths: addIsoMonths, + addMonths: moveByIsoMonths, queryDateStart: isoArgsToEpochMilli, queryDaysInMonth: computeIsoDaysInMonth, queryMonthsInYearSpan: computeIsoMonthsInYearSpan, @@ -390,7 +391,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { } addMonths(year, month, monthDelta) { - return addIntlMonths(year, month, monthDelta, this) + return moveByIntlMonths(year, month, monthDelta, this) } // Internal Querying @@ -481,10 +482,8 @@ class IntlCalendarImpl extends IsoCalendarImpl { } queryDateStart(year, month = 1, day = 1) { - return addDaysMilli( - this.queryYear(year).monthEpochMilli[month - 1], - day - 1, - ) + return this.queryYear(year).monthEpochMilli[month - 1] + + (day - 1) * milliInDay } queryMonthStrs(year) { @@ -621,29 +620,29 @@ function createIntlMonthCache(epochMilliToIntlFields) { const queryYear = createLazyMap(buildYear) function buildYear(year) { - let milli = isoArgsToEpochMilli(year - yearCorrection) + let epochMilli = isoArgsToEpochMilli(year - yearCorrection) let intlFields const milliReversed = [] const monthStrsReversed = [] // move beyond current year do { - milli = addDaysMilli(milli, 400) - } while ((intlFields = epochMilliToIntlFields(milli)).year <= year) + epochMilli += 400 * milliInDay + } while ((intlFields = epochMilliToIntlFields(epochMilli)).year <= year) do { // move to start-of-month - milli = addDaysMilli(milli, 1 - intlFields.day) + epochMilli += (1 - intlFields.day) * milliInDay // only record the epochMilli if current year if (intlFields.year === year) { - milliReversed.push(milli) + milliReversed.push(epochMilli) monthStrsReversed.push(intlFields.month) } // move to last day of previous month - milli = addDaysMilli(milli, -1) - } while ((intlFields = epochMilliToIntlFields(milli)).year >= year) + epochMilli -= milliInDay + } while ((intlFields = epochMilliToIntlFields(epochMilli)).year >= year) return { monthEpochMilli: milliReversed.reverse(), diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 3cb9a78c..e2bfa84e 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -12,7 +12,7 @@ import { isoToEpochNano, } from './isoMath' import { compareLargeInts } from './largeInt' -import { addDaysToIsoFields, moveDateTime, moveZonedEpochNano } from './move' +import { moveDateByDays, moveDateTime, moveZonedEpochNano } from './move' import { roundLargeNano, roundNano, roundRelativeDuration } from './round' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { @@ -59,7 +59,7 @@ export function diffDateTimes( // move start-fields forward so time-diff-sign matches date-diff-sign if (timeSign === -sign) { midIsoFields = { - ...addDaysToIsoFields(startIsoFields, sign), + ...moveDateByDays(startIsoFields, sign), ...pluckIsoTimeFields(startIsoFields), } timeNano += nanoInUtcDay @@ -212,7 +212,7 @@ export function diffZonedEpochNano( if (midSign === -sign) { midIsoFields = { - ...addDaysToIsoFields(endIsoFields, -sign), + ...moveDateByDays(endIsoFields, -sign), ...startIsoTimeFields, } midEpochNano = isoToZonedEpochNano(midIsoFields) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 4ffa4712..56c017cc 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -13,6 +13,7 @@ import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './util // ------------------------------------------------------------------------------------------------- // Ordered by ascending size +// TODO: derive durationFieldNamesAsc from unitNamesAsc, and use zipWithSingleValue w/ refiner func? const durationTimeFieldRefiners = { nanoseconds: toIntegerWithoutRounding, microseconds: toIntegerWithoutRounding, @@ -80,6 +81,13 @@ export function durationTimeFieldsToIso(durationTimeFields) { return remapProps(durationTimeFields, durationTimeFieldNames, isoTimeFieldNames) } +export function durationTimeFieldsToIsoStrict(durationFields) { + if (durationHasDateParts(durationFields)) { + throw new RangeError('Operation not allowed') + } + return durationTimeFieldsToIso(durationFields) +} + // Field Math // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js index ed60bfa5..c2bb8327 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -35,14 +35,14 @@ export class LargeInt { } divTruncMod(divisor) { - let [largeInt, remainder] = this.divFloorMod(divisor) + let [fullUnits, remainder] = this.divFloorMod(divisor) - if (largeInt.computeSign() === -1 && remainder) { - largeInt = largeInt.addNumber(1) + if (fullUnits.computeSign() === -1 && remainder) { + fullUnits = fullUnits.addNumber(1) remainder -= divisor } - return [largeInt, remainder] + return [fullUnits, remainder] } /* diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 986a0aa1..e195d472 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -1,7 +1,9 @@ import { + durationFieldsToNano, durationHasDateParts, durationTimeFieldDefaults, durationTimeFieldsToIso, + durationTimeFieldsToIsoStrict, } from './durationFields' import { epochMilliToIso, @@ -13,33 +15,24 @@ import { } from './isoMath' import { constrainInt } from './options' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' +import { hourIndex, milliInDay, nanoInUtcDay } from './units' -export function addDaysMilli(epochMilli, milli) { // moveEpochMilliByDays -} - -export function addDaysToIsoFields() { - // short-circuit if nothing to add -} - -export function moveEpochNano(epochNanoseconds, durationFields) { - return epochNanoseconds.addNumber(onlyDurationTimeFieldsToIso(durationFields)) -} +// Epoch +// ------------------------------------------------------------------------------------------------- export function moveZonedEpochNano( calendar, timeZone, - epochNanoseconds, + epochNano, durationFields, overflowHandling, ) { - const durationTimeNanoseconds = isoTimeFieldsToNano( - durationTimeFieldsToIso(durationFields), - ) + const durationTimeNano = isoTimeFieldsToNano(durationTimeFieldsToIso(durationFields)) if (!durationHasDateParts(durationFields)) { - epochNanoseconds = epochNanoseconds.addNumber(durationTimeNanoseconds) + epochNano = epochNano.addNumber(durationTimeNano) } else { - const isoDateTimeFields = zonedEpochNanoToIso(timeZone, epochNanoseconds) + const isoDateTimeFields = zonedEpochNanoToIso(timeZone, epochNano) const movedIsoDateFields = calendar.dateAdd( isoDateTimeFields, { @@ -52,29 +45,33 @@ export function moveZonedEpochNano( ...isoDateTimeFields, // time parts ...movedIsoDateFields, // date parts } - epochNanoseconds = getSingleInstantFor(timeZone, movedIsoDateTimeFields) - .addNumber(durationTimeNanoseconds) + epochNano = getSingleInstantFor(timeZone, movedIsoDateTimeFields) + .addNumber(durationTimeNano) } - return epochNanoseconds + return epochNano } +export function moveEpochNano(epochNanoseconds, durationFields) { + return epochNanoseconds.addNumber(durationTimeFieldsToIsoStrict(durationFields)) +} + +// Date & Time +// ------------------------------------------------------------------------------------------------- + export function moveDateTime( calendar, isoDateTimeFields, durationFields, overflowHandling, ) { - const [movedIsoTimeFields, dayDelta] = addIsoTimeFields( - isoDateTimeFields, - durationTimeFieldsToIso(durationFields), - ) + const [movedIsoTimeFields, dayDelta] = moveTime(isoDateTimeFields, durationFields) const movedIsoDateFields = calendar.dateAdd( isoDateTimeFields, // only date parts will be used { ...durationFields, // date parts - ...durationTimeFieldDefaults, // time parts (must be zero so calendar doesn't round)??? + ...durationTimeFieldDefaults, // time parts (zero-out so no balancing-up to days) days: durationFields.days + dayDelta, }, overflowHandling, @@ -87,8 +84,12 @@ export function moveDateTime( } export function moveDate(calendar, isoDateFields, durationFields, overflow) { - const { years, months, weeks, days } = durationFields - let ms + let { years, months, weeks, days } = durationFields + let epochMilli + + // convert time fields to days + days += durationFieldsToNano(durationFields, hourIndex) + .divTruncMod(nanoInUtcDay)[0].toNumber() if (years || months) { let [year, month, day] = calendar.queryYearMonthDay(isoDateFields) @@ -103,30 +104,39 @@ export function moveDate(calendar, isoDateFields, durationFields, overflow) { day = constrainInt(day, 1, calendar.queryDaysInMonth(year, month), overflow) } - ms = calendar.queryDateStart(year, month, day) + epochMilli = calendar.queryDateStart(year, month, day) } else if (weeks || days) { - ms = isoToEpochMilli(isoDateFields) + epochMilli = isoToEpochMilli(isoDateFields) } else { return isoDateFields } - ms = addDaysMilli(ms, weeks * isoDaysInWeek + days) + epochMilli += (weeks * isoDaysInWeek + days) * milliInDay return { calendar, - ...epochMilliToIso(ms), + ...epochMilliToIso(epochMilli), + } +} + +export function moveDateByDays(isoDateFields, days) { + if (days) { + isoDateFields = epochMilliToIso(isoToEpochMilli(isoDateFields) + days * milliInDay) } + return isoDateFields } export function moveTime(isoTimeFields, durationFields) { - const [movedIsoTimeFields] = addIsoTimeFields( - isoTimeFields, - onlyDurationTimeFieldsToIso(durationFields), + return nanoToIsoTimeAndDay( + isoTimeFieldsToNano(isoTimeFields) + + isoTimeFieldsToNano(durationTimeFieldsToIsoStrict(durationFields)), ) - return movedIsoTimeFields } -export function addIsoMonths(year, month, monthDelta) { +// Calendar-related Utils +// ------------------------------------------------------------------------------------------------- + +export function moveByIsoMonths(year, month, monthDelta) { year += Math.trunc(monthDelta / isoMonthsInYear) month += monthDelta % isoMonthsInYear @@ -141,7 +151,7 @@ export function addIsoMonths(year, month, monthDelta) { return [year, month] } -export function addIntlMonths(year, month, monthDelta, calendarImpl) { +export function moveByIntlMonths(year, month, monthDelta, calendarImpl) { month += monthDelta if (monthDelta < 0) { @@ -164,23 +174,3 @@ export function addIntlMonths(year, month, monthDelta, calendarImpl) { return [year, month] } - -// Epoch/Time Utils -// ------------------------------------------------------------------------------------------------- - -function addIsoTimeFields(isoTimeFields0, isoTimeFields1) { - return nanoToIsoTimeAndDay( - isoTimeFieldsToNano(isoTimeFields0) + - isoTimeFieldsToNano(isoTimeFields1), - ) -} - -// Utils -// ------------------------------------------------------------------------------------------------- - -function onlyDurationTimeFieldsToIso(durationFields) { - if (durationHasDateParts(durationFields)) { - throw new RangeError('Cant have date parts') - } - return durationTimeFieldsToIso(durationFields) -} diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 97c7f0de..add238f8 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -83,7 +83,7 @@ export const [ moveTime( internals, toDurationInternals(durationArg), - ), + )[0], ) }, @@ -92,7 +92,7 @@ export const [ moveTime( internals, negateDurationFields(toDurationInternals(durationArg)), - ), + )[0], ) }, diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 55d69977..965485ad 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -9,7 +9,7 @@ import { } from './durationFields' import { isoTimeFieldDefaults } from './isoFields' import { isoTimeFieldsToNano, nanoToIsoTimeAndDay } from './isoMath' -import { addDaysToIsoFields } from './move' +import { moveDateByDays } from './move' import { computeNanosecondsInDay } from './timeZoneOps' import { dayIndex, nanoInUtcDay, nanoIndex, unitIndexToNano, weekIndex } from './units' import { identityFunc } from './utils' @@ -53,7 +53,7 @@ export function roundIsoDateTimeFields( } return { - ...addDaysToIsoFields(isoDateTimeFields, dayDelta), + ...moveDateByDays(isoDateTimeFields, dayDelta), ...isoTimeFields, } } diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index b7714dbf..af10e33e 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -12,7 +12,7 @@ import { epochNanoToIso, isoToEpochNano, } from './isoMath' -import { addDaysToIsoFields } from './move' +import { moveDateByDays } from './move' import { strictArray, strictNumber } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' @@ -56,7 +56,7 @@ export function computeNanosecondsInDay( ) { isoDateFields = { ...isoDateFields, ...isoTimeFieldDefaults } const epochNano0 = getSingleInstantFor(timeZoneOps, isoDateFields) - const epochNano1 = getSingleInstantFor(timeZoneOps, addDaysToIsoFields(isoDateFields, 1)) + const epochNano1 = getSingleInstantFor(timeZoneOps, moveDateByDays(isoDateFields, 1)) return epochNano1.sub(epochNano0).toNumber() } diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js index 066f15b4..1a2fa97f 100644 --- a/packages/temporal-polyfill/src/new/units.js +++ b/packages/temporal-polyfill/src/new/units.js @@ -56,9 +56,11 @@ export function givenFieldsToLargeNano(fields, unitIndex, fieldNames) { for (; unitIndex >= nanoIndex; unitIndex--) { const divisor = unitIndexToNano[unitIndex] - largeNano = largeNano.addLargeInt( - numberToLargeInt(fields[fieldNames[unitIndex]]).mult(divisor), - ) + const fieldValue = fields[fieldNames[unitIndex]] + + if (fieldValue) { + largeNano = largeNano.addLargeInt(numberToLargeInt(fieldValue).mult(divisor)) + } } return largeNano @@ -69,7 +71,9 @@ export function givenFieldsToNano(fields, unitIndex, fieldNames) { for (; unitIndex >= nanoIndex; unitIndex--) { const divisor = unitIndexToNano[unitIndex] - nano += fields[fieldNames[unitIndex]] * divisor + const fieldValue = fields[fieldNames[unitIndex]] + + nano += fieldValue * divisor } return nano @@ -80,6 +84,7 @@ export function nanoToGivenFields(nano, unitIndex, fieldNames) { for (; unitIndex >= nanoIndex; unitIndex--) { const divisor = unitIndexToNano[unitIndex] + fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) nano %= divisor } From 2c9ddfc15f9992c1562eb799235681559d745df7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 18:25:29 -0400 Subject: [PATCH 101/805] durationFields more compressed --- .../src/new/durationFields.js | 105 +++++++----------- packages/temporal-polyfill/src/new/options.js | 7 +- packages/temporal-polyfill/src/new/units.js | 2 +- 3 files changed, 44 insertions(+), 70 deletions(-) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 56c017cc..c1fab893 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -6,45 +6,32 @@ import { hourIndex, nanoToGivenFields, unitIndexToNano, + unitNamesAsc, } from './units' import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './utils' -// Refiners +// Property Names // ------------------------------------------------------------------------------------------------- -// Ordered by ascending size -// TODO: derive durationFieldNamesAsc from unitNamesAsc, and use zipWithSingleValue w/ refiner func? -const durationTimeFieldRefiners = { - nanoseconds: toIntegerWithoutRounding, - microseconds: toIntegerWithoutRounding, - milliseconds: toIntegerWithoutRounding, - seconds: toIntegerWithoutRounding, - minutes: toIntegerWithoutRounding, - hours: toIntegerWithoutRounding, -} +export const durationFieldNamesAsc = unitNamesAsc.map((unitName) => unitName + 's') // pluralize +export const durationFieldIndexes = mapArrayToProps(durationFieldNamesAsc) +export const durationFieldNames = durationFieldNamesAsc.sort() -// Ordered by ascending size -const durationDateFieldRefiners = { - days: toIntegerWithoutRounding, - months: toIntegerWithoutRounding, - weeks: toIntegerWithoutRounding, - years: toIntegerWithoutRounding, -} +// unordered +const durationTimeFieldNames = durationFieldNamesAsc.slice(0, dayIndex) +const durationDateFieldNames = durationFieldNamesAsc.slice(dayIndex) +const durationInternalNames = [...durationFieldNames, 'sign'] -// Ordered by ascending size -export const durationFieldRefiners = { - ...durationTimeFieldRefiners, - ...durationDateFieldRefiners, -} +// Defaults +// ------------------------------------------------------------------------------------------------- -// Property Names +export const durationFieldDefaults = zipSingleValue(durationFieldNames, 0) +export const durationTimeFieldDefaults = zipSingleValue(durationTimeFieldNames, 0) + +// Refiners // ------------------------------------------------------------------------------------------------- -const durationDateFieldNames = Object.keys(durationDateFieldRefiners).sort() -const durationTimeFieldNames = Object.keys(durationTimeFieldRefiners).sort() -export const durationFieldNamesAsc = Object.keys(durationFieldRefiners) -export const durationFieldNames = durationFieldNamesAsc.sort() -const durationInternalNames = [...durationFieldNames, 'sign'] // unordered +export const durationFieldRefiners = zipSingleValue(durationFieldNames, toIntegerWithoutRounding) // Getters // ------------------------------------------------------------------------------------------------- @@ -55,17 +42,7 @@ export const durationGetters = mapArrayToProps(durationInternalNames, (propName) } }) -// Defaults -// ------------------------------------------------------------------------------------------------- - -const durationDateFieldDefaults = zipSingleValue(durationDateFieldNames, 0) -export const durationTimeFieldDefaults = zipSingleValue(durationTimeFieldNames, 0) -export const durationFieldDefaults = { - ...durationDateFieldDefaults, - ...durationTimeFieldDefaults, -} - -// Refining / Conversion +// Field <-> Field Conversion // ------------------------------------------------------------------------------------------------- export function refineDurationInternals(rawDurationFields) { @@ -88,30 +65,6 @@ export function durationTimeFieldsToIsoStrict(durationFields) { return durationTimeFieldsToIso(durationFields) } -// Field Math -// ------------------------------------------------------------------------------------------------- - -export function addDurationFields(durationFields0, durationFields1, sign) { - // recomputes sign -} - -export function negateDurationFields(internals) { - // recomputes sign -} - -export function absolutizeDurationFields(internals) { - // recomputes sign -} - -export function durationHasDateParts(internals) { - return Boolean(computeDurationFieldsSign(internals, durationDateFieldNames)) -} - -function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { - // should throw error if mismatch - // TODO: audit repeat uses of this -} - // Field <-> Nanosecond Conversion // ------------------------------------------------------------------------------------------------- @@ -136,3 +89,27 @@ export function nanoToDurationFields(largeNano, largestUnitIndex = dayIndex) { export function timeNanoToDurationFields(nano) { return nanoToGivenFields(nano, hourIndex, durationFieldNamesAsc) } + +// Field Math +// ------------------------------------------------------------------------------------------------- + +export function addDurationFields(durationFields0, durationFields1, sign) { + // recomputes sign +} + +export function negateDurationFields(internals) { + // recomputes sign +} + +export function absolutizeDurationFields(internals) { + // recomputes sign +} + +export function durationHasDateParts(internals) { + return Boolean(computeDurationFieldsSign(internals, durationDateFieldNames)) +} + +function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { + // should throw error if mismatch + // TODO: audit repeat uses of this +} diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index b225cc59..e7cd292c 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,7 +1,6 @@ -import { durationFieldNamesAsc } from './durationFields' +import { durationFieldIndexes } from './durationFields' import { bigIntToLargeInt } from './largeInt' import { unitIndexes, unitNamesAsc } from './units' -import { mapArrayToProps } from './utils' // TODO: for unit parsing, ensure ceiling and correct increment @@ -230,11 +229,9 @@ export function largestUnitToOptions(largestUnitIndex) { // Units // ------------------------------------------------------------------------------------------------- -const unitIndexesPlural = mapArrayToProps(durationFieldNamesAsc) - export function toUnit(unitName) { unitName = toString(unitName) - const unitIndex = unitIndexes[unitName] ?? unitIndexesPlural[unitName] + const unitIndex = unitIndexes[unitName] ?? durationFieldIndexes[unitName] if (unitIndex === undefined) { throw new RangeError('Invalid unit') diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js index 1a2fa97f..28c4273c 100644 --- a/packages/temporal-polyfill/src/new/units.js +++ b/packages/temporal-polyfill/src/new/units.js @@ -12,7 +12,7 @@ export const weekIndex = 7 export const monthIndex = 8 export const yearIndex = 9 -export const unitNamesAsc = [ // TODO: better way to compress this? +export const unitNamesAsc = [ 'nanosecond', 'microsecond', 'millisecond', From f1485514ddaf05b24fd699bed1912bab0d52f2c8 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 18:45:07 -0400 Subject: [PATCH 102/805] duration math --- .../temporal-polyfill/src/new/duration.js | 8 +-- .../src/new/durationFields.js | 54 ++++++++++++++----- packages/temporal-polyfill/src/new/instant.js | 4 +- .../temporal-polyfill/src/new/plainDate.js | 4 +- .../src/new/plainDateTime.js | 4 +- .../temporal-polyfill/src/new/plainTime.js | 4 +- .../src/new/plainYearMonth.js | 4 +- .../src/new/zonedDateTime.js | 4 +- 8 files changed, 57 insertions(+), 29 deletions(-) diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 50cef12c..49293831 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -2,11 +2,11 @@ import { createTemporalClass, neverValueOf } from './class' import { mergeDurationBag, refineDurationBag } from './convert' import { diffZonedEpochNano } from './diff' import { - absolutizeDurationFields, + absDurationInternals, addDurationFields, durationFieldsToNano, durationGetters, - negateDurationFields, + negateDurationInternals, refineDurationInternals, } from './durationFields' import { formatDurationInternals } from './isoFormat' @@ -102,11 +102,11 @@ export const [ subtract: addToDuration.bind(undefined, -1), negated(internals) { - return createDuration(negateDurationFields(internals)) + return createDuration(negateDurationInternals(internals)) }, abs(internals) { - return createDuration(absolutizeDurationFields(internals)) + return createDuration(absDurationInternals(internals)) }, round(internals, options) { diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index c1fab893..8c868167 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -49,11 +49,6 @@ export function refineDurationInternals(rawDurationFields) { return updateDurationFieldsSign(mapRefiners(rawDurationFields, durationFieldRefiners)) } -export function updateDurationFieldsSign(fields) { - fields.sign = computeDurationFieldsSign(fields) - return fields -} - export function durationTimeFieldsToIso(durationTimeFields) { return remapProps(durationTimeFields, durationTimeFieldNames, isoTimeFieldNames) } @@ -93,16 +88,37 @@ export function timeNanoToDurationFields(nano) { // Field Math // ------------------------------------------------------------------------------------------------- -export function addDurationFields(durationFields0, durationFields1, sign) { - // recomputes sign +export function updateDurationFieldsSign(fields) { + fields.sign = computeDurationFieldsSign(fields) + return fields // returns 'internals' } -export function negateDurationFields(internals) { - // recomputes sign +export function addDurationFields(a, b, sign) { // TODO: make version that updates sign? + const res = {} + + for (const fieldName in durationFieldNames) { + res[fieldName] = a[fieldName] + b[fieldName] * sign + } + + return res } -export function absolutizeDurationFields(internals) { - // recomputes sign +export function negateDurationInternals(internals) { + const res = {} + + for (const fieldName in durationFieldNames) { + res[fieldName] = internals[fieldName] * -1 || 0 + } + + res.sign = -internals.sign || 0 + return res +} + +export function absDurationInternals(internals) { + if (internals.sign === -1) { + return negateDurationInternals(internals) + } + return internals } export function durationHasDateParts(internals) { @@ -110,6 +126,18 @@ export function durationHasDateParts(internals) { } function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { - // should throw error if mismatch - // TODO: audit repeat uses of this + let sign = 0 + + for (const fieldName in durationFieldNames) { + const fieldSign = Math.sign(internals[fieldName]) + + if (fieldSign) { + if (sign && sign !== fieldSign) { + throw new RangeError('Cant have mixed signs') + } + sign = fieldSign + } + } + + return sign } diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 373acd83..e12308bc 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -3,7 +3,7 @@ import { queryCalendarOps } from './calendarOps' import { createTemporalClass, neverValueOf } from './class' import { diffEpochNano } from './diff' import { toDurationInternals } from './duration' -import { negateDurationFields } from './durationFields' +import { negateDurationInternals } from './durationFields' import { formatCalendar, formatIsoDateTimeFields, @@ -95,7 +95,7 @@ export const [ return createInstant( moveEpochNano( epochNanoseconds, - negateDurationFields(toDurationInternals(durationArg)), + negateDurationInternals(toDurationInternals(durationArg)), ), ) }, diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 24dea52a..b8c6d8f3 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -15,7 +15,7 @@ import { } from './convert' import { diffDates } from './diff' import { toDurationInternals } from './duration' -import { negateDurationFields } from './durationFields' +import { negateDurationInternals } from './durationFields' import { generatePublicIsoDateFields, isoTimeFieldDefaults, @@ -98,7 +98,7 @@ export const [ subtract(internals, durationArg, options) { return internals.calendar.dateAdd( internals, - negateDurationFields(toDurationInternals(durationArg)), + negateDurationInternals(toDurationInternals(durationArg)), options, ) }, diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 3db7907a..f338db1f 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -10,7 +10,7 @@ import { } from './convert' import { diffDateTimes } from './diff' import { toDurationInternals } from './duration' -import { negateDurationFields } from './durationFields' +import { negateDurationInternals } from './durationFields' import { generatePublicIsoDateTimeFields, isoTimeFieldDefaults, @@ -138,7 +138,7 @@ export const [ moveDateTime( internals.calendar, internals, - negateDurationFields(toDurationInternals(durationArg)), + negateDurationInternals(toDurationInternals(durationArg)), optionsToOverflow(options), ), ) diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index add238f8..dacfedb6 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -7,7 +7,7 @@ import { } from './convert' import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' -import { negateDurationFields } from './durationFields' +import { negateDurationInternals } from './durationFields' import { pluckIsoTimeFields, refineIsoTimeInternals } from './isoFields' import { formatIsoTimeFields } from './isoFormat' import { compareIsoTimeFields } from './isoMath' @@ -91,7 +91,7 @@ export const [ return createPlainTime( moveTime( internals, - negateDurationFields(toDurationInternals(durationArg)), + negateDurationInternals(toDurationInternals(durationArg)), )[0], ) }, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 40a00f1b..e1d5cb65 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -10,7 +10,7 @@ import { } from './convert' import { diffDates } from './diff' import { toDurationInternals } from './duration' -import { negateDurationFields } from './durationFields' +import { negateDurationInternals } from './durationFields' import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' @@ -75,7 +75,7 @@ export const [ return movePlainYearMonth( this, internals.calendar, - negateDurationFields(toDurationInternals(durationArg)), + negateDurationInternals(toDurationInternals(durationArg)), optionsToOverflow(options), ) }, diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index b139c356..2466bc4b 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -9,7 +9,7 @@ import { } from './convert' import { diffZonedEpochNano } from './diff' import { toDurationInternals } from './duration' -import { negateDurationFields } from './durationFields' +import { negateDurationInternals } from './durationFields' import { createInstant } from './instant' import { resolveZonedFormattable } from './intlFormat' import { @@ -206,7 +206,7 @@ export const [ return createZonedDateTime( moveZonedDateTimeInternals( internals, - negateDurationFields(toDurationInternals(durationArg)), + negateDurationInternals(toDurationInternals(durationArg)), options, ), ) From 187276cce29d0fd1057a91aed3aa11caae9f5f5d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 13 Jun 2023 18:52:48 -0400 Subject: [PATCH 103/805] tweaks to units --- packages/temporal-polyfill/src/new/duration.js | 2 ++ packages/temporal-polyfill/src/new/units.js | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 49293831..71596ee1 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -203,6 +203,8 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- +// TODO: move to move.js? + function addToDuration(direction, internals, otherArg, options) { const otherFields = toDurationInternals(otherArg) const markerInternals = optionsToRelativeTo(options) // optional diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js index 28c4273c..aa02f3a0 100644 --- a/packages/temporal-polyfill/src/new/units.js +++ b/packages/temporal-polyfill/src/new/units.js @@ -17,6 +17,7 @@ export const unitNamesAsc = [ 'microsecond', 'millisecond', 'second', + 'minute', 'hour', 'day', 'week', @@ -34,16 +35,18 @@ export const milliInDay = 86400000 // TODO: not DRY export const milliInSec = 1000 export const nanoInMicro = 1000 // consolidate with other 1000 units -export const nanoInMilli = 1000000 -export const nanoInSec = 1000000000 -export const nanoInHour = 3600000000000 -export const nanoInUtcDay = 86400000000000 +export const nanoInMilli = 1_000_000 +export const nanoInSec = 1_000_000_000 +export const nanoInMinute = 60_000_000_000 +export const nanoInHour = 3_600_000_000_000 +export const nanoInUtcDay = 86_400_000_000_000 export const unitIndexToNano = [ 1, // nano-in-nano nanoInMicro, nanoInMilli, nanoInSec, + nanoInMinute, nanoInHour, nanoInUtcDay, ] From e6d3add39b8815340256206d99a1a5e067a66e95 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 14 Jun 2023 17:23:44 -0400 Subject: [PATCH 104/805] improvements to unit/options/toString/rounding --- .../temporal-polyfill/src/new/calendar.js | 6 +- .../temporal-polyfill/src/new/calendarImpl.js | 22 +- packages/temporal-polyfill/src/new/convert.js | 40 +- packages/temporal-polyfill/src/new/diff.js | 4 +- .../temporal-polyfill/src/new/duration.js | 34 +- packages/temporal-polyfill/src/new/instant.js | 5 +- .../temporal-polyfill/src/new/isoFormat.js | 49 +- packages/temporal-polyfill/src/new/isoMath.js | 32 +- packages/temporal-polyfill/src/new/move.js | 8 +- packages/temporal-polyfill/src/new/options.js | 469 ++++++++++++------ .../temporal-polyfill/src/new/plainDate.js | 20 +- .../src/new/plainDateTime.js | 59 ++- .../src/new/plainMonthDay.js | 4 +- .../temporal-polyfill/src/new/plainTime.js | 43 +- .../src/new/plainYearMonth.js | 8 +- packages/temporal-polyfill/src/new/round.js | 12 +- .../temporal-polyfill/src/new/timeZone.js | 4 +- packages/temporal-polyfill/src/new/utils.js | 21 +- .../src/new/zonedDateTime.js | 76 ++- 19 files changed, 588 insertions(+), 328 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 8a64ec30..f37686fa 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -10,7 +10,7 @@ import { import { createDuration, toDurationInternals } from './duration' import { isoDaysInWeek } from './isoMath' import { parseCalendarId } from './isoParse' -import { optionsToOverflow, strictArray, toObject } from './options' +import { refineOverflowOptions, strictArray, toObject } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' @@ -33,7 +33,7 @@ export const calendarProtocolMethods = { impl.dateAdd( toPlainDateInternals(plainDateArg), toDurationInternals(durationArg), - optionsToOverflow(options), + refineOverflowOptions(options), ), ) }, @@ -43,7 +43,7 @@ export const calendarProtocolMethods = { impl.dateUntil( toPlainDateInternals(plainDateArg0), toPlainDateInternals(plainDateArg1), - optionsToOverflow(options), + refineOverflowOptions(options), ), ) }, diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 8aeb04ae..1680223a 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -39,9 +39,9 @@ import { isoToEpochMilli, } from './isoMath' import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' -import { constrainInt } from './options' +import { rejectI } from './options' import { milliInDay } from './units' -import { buildWeakMapCache, createLazyMap, mapArrayToProps, twoDigit } from './utils' +import { buildWeakMapCache, clamp, createLazyMap, mapArrayToProps, twoDigit } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -207,12 +207,12 @@ class IsoCalendarImpl { refineMonth( fields, year, // optional if known that calendar doesn't support leap months - overflow = 'reject', + overflowI = rejectI, ) { let { month, monthCode } = fields if (monthCode !== undefined) { - const monthByCode = refineMonthCode(this, monthCode, year, overflow) + const monthByCode = refineMonthCode(this, monthCode, year, overflowI) if (month !== undefined && month !== monthByCode) { throw new RangeError('The month and monthCode do not agree') @@ -223,20 +223,22 @@ class IsoCalendarImpl { throw new RangeError('Must specify either month or monthCode') } - return constrainInt( - this.readMonth(fields, year, overflow), + return clamp( + this.readMonth(fields, year, overflowI), 1, this.queryMonthsInYear(year), - overflow, + overflowI, + 'month', ) } - refineDay(fields, month, year, overflow) { - return constrainInt( + refineDay(fields, month, year, overflowI) { + return clamp( fields.day, // day guaranteed to exist because of required*Fields 1, this.queryDaysInMonth(year, month), - overflow, + overflowI, + 'day', ) } } diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index 6833b6b4..de9df318 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -27,10 +27,10 @@ import { import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNano } from './isoParse' import { - optionsToOverflow, + normalizeOptions, + refineOverflowOptions, + refineZonedFieldOptions, toObject, - toObjectOptional, - toZonedRefiningOptions, } from './options' import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' @@ -51,7 +51,7 @@ export function refineZonedDateTimeBag(bag, options) { [...getRequiredDateFields(calendar), 'timeZone'], // requireFields ['timeZone', 'offset'], // forcedValidFieldNames ) - const { overflow, offset, disambiguation } = toZonedRefiningOptions(options) + const [overflow, epochDisambig, offsetDisambig] = refineZonedFieldOptions(options) const timeZone = queryTimeZoneOps(fields.timeZone) const isoDateFields = calendar.dateFromFields(fields, overflow) @@ -62,8 +62,8 @@ export function refineZonedDateTimeBag(bag, options) { { ...isoDateFields, ...isoTimeFields }, fields.offset !== undefined && parseOffsetNano(fields.offset), false, // z? - offset, - disambiguation, + offsetDisambig, + epochDisambig, false, // fuzzy ) @@ -83,7 +83,7 @@ export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { dateTimeFieldNames, // validFieldNames ['offset'], // forcedValidFieldNames ) - const { overflow, offset, disambiguation } = toZonedRefiningOptions(options) + const [overflow, epochDisambig, offsetDisambig] = refineZonedFieldOptions(options) const isoDateFields = calendar.dateFromFields(fields, overflow) const isoTimeFields = refineTimeFields(fields, overflow) @@ -93,8 +93,8 @@ export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { { ...isoDateFields, ...isoTimeFields }, parseOffsetNano(fields.offset), false, // z? - offset, - disambiguation, + offsetDisambig, + epochDisambig, false, // fuzzy ) @@ -110,7 +110,7 @@ export function createZonedDateTimeConverter(getExtraIsoFields) { const { calendar, timeZone } = internals const epochNanoseconds = getSingleInstantFor(timeZone, { ...internals, - ...getExtraIsoFields(toObjectOptional(options)), + ...getExtraIsoFields(normalizeOptions(options)), }) return createZonedDateTime({ @@ -133,7 +133,7 @@ export function refinePlainDateTimeBag(bag, options) { getRequiredDateFields(calendar), ) - const overflow = optionsToOverflow(options) + const overflow = refineOverflowOptions(options) const isoDateInternals = calendar.dateFromFields(fields, overflow) const isoTimeFields = refineTimeFields(fields, overflow) @@ -149,7 +149,7 @@ export function mergePlainDateTimeBag(plainDate, bag, options) { dateTimeFieldNames, ) - const overflow = optionsToOverflow(options) + const overflow = refineOverflowOptions(options) const isoDateInternals = calendar.dateFromFields(fields, overflow) const isoTimeFields = refineTimeFields(fields, overflow) @@ -167,7 +167,7 @@ export function refinePlainDateBag(bag, options, calendar = getBagCalendarOps(ba getRequiredDateFields(calendar), ) - return calendar.dateFromFields(fields, optionsToOverflow(options)) + return calendar.dateFromFields(fields, refineOverflowOptions(options)) } export function mergePlainDateBag(plainDate, bag, options) { @@ -179,7 +179,7 @@ export function mergePlainDateBag(plainDate, bag, options) { dateFieldNames, ) - return calendar.dateFromFields(fields, optionsToOverflow(options)) + return calendar.dateFromFields(fields, refineOverflowOptions(options)) } function convertToIso( @@ -214,7 +214,7 @@ export function refinePlainYearMonthBag(bag, options, calendar = getBagCalendarO getRequiredYearMonthFields(calendar), ) - return calendar.yearMonthFromFields(fields, optionsToOverflow(options)) + return calendar.yearMonthFromFields(fields, refineOverflowOptions(options)) } export function mergePlainYearMonthBag(plainYearMonth, bag, options) { @@ -226,7 +226,7 @@ export function mergePlainYearMonthBag(plainYearMonth, bag, options) { yearMonthFieldNames, ) - return calendar.yearMonthFromFields(fields, optionsToOverflow(options)) + return calendar.yearMonthFromFields(fields, refineOverflowOptions(options)) } export function convertToPlainYearMonth( @@ -280,7 +280,7 @@ export function refinePlainMonthDayBag(bag, options, calendar = extractBagCalend fields.year = isoEpochFirstLeapYear } - return calendar.monthDayFromFields(calendar, fields, optionsToOverflow(options)) + return calendar.monthDayFromFields(calendar, fields, refineOverflowOptions(options)) } export function mergePlainMonthDayBag(plainMonthDay, bag, options) { @@ -292,7 +292,7 @@ export function mergePlainMonthDayBag(plainMonthDay, bag, options) { dateFieldNames, ) - return calendar.monthDayFromFields(fields, optionsToOverflow(options)) + return calendar.monthDayFromFields(fields, refineOverflowOptions(options)) } export function convertToPlainMonthDay( @@ -323,7 +323,7 @@ export function convertPlainMonthDayToDate(plainMonthDay, bag) { export function refinePlainTimeBag(bag, options) { const fields = refineFields(bag, timeFieldNames, []) - return refineTimeFields(fields, optionsToOverflow(options)) + return refineTimeFields(fields, refineOverflowOptions(options)) } export function mergePlainTimeBag(plainTime, bag, options) { @@ -331,7 +331,7 @@ export function mergePlainTimeBag(plainTime, bag, options) { const partialFields = refineFields(bag, timeFieldNames) const mergeFields = { ...fields, ...partialFields } - return refineTimeFields(mergeFields, optionsToOverflow(options)) + return refineTimeFields(mergeFields, refineOverflowOptions(options)) } function refineTimeFields(fields, overflow) { diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index e2bfa84e..9ba6ab68 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -31,7 +31,7 @@ export function diffDateTimes( startIsoFields, endIsoFields, largestUnitIndex, - smallestUnitIndex, + smallestUnitIndex, // TODO: nanoDivisor roundingMode, roundingIncrement, ) { @@ -103,7 +103,7 @@ export function diffDates( const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnitIndex) - return roundRelativeDuration( + return roundRelativeDuration( // TODO: return DurationInternals dateDiff, isoToEpochNano(endIsoFields), largestUnitIndex, diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 71596ee1..ca90e9ec 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -15,12 +15,10 @@ import { parseDuration } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' import { - optionsToLargestUnit, - optionsToRelativeTo, - optionsToRoundingIncrement, - optionsToRoundingMode, - optionsToSmallestUnit, - optionsToTotalUnit, + refineDurationRoundOptions, + refineRelativeToOptions, + refineTimeDisplayOptions, + refineTotalOptions, } from './options' import { roundDayTimeDuration, @@ -110,11 +108,13 @@ export const [ }, round(internals, options) { - const largestUnitIndex = optionsToLargestUnit(options) // accepts auto? - const smallestUnitIndex = optionsToSmallestUnit(options) - const roundingIncrement = optionsToRoundingIncrement(options) - const roundingMode = optionsToRoundingMode(options) - const markerInternals = optionsToRelativeTo(options) // optional + const [ + largestUnitIndex, + smallestUnitIndex, + roundingIncrement, + roundingMode, + markerInternals, + ] = refineDurationRoundOptions(options, getLargestDurationUnit(internals)) // TODO: move to round.js? @@ -140,8 +140,7 @@ export const [ }, total(internals, options) { - const totalUnitIndex = optionsToTotalUnit(options) - const markerInternals = optionsToRelativeTo(options) // optional + const [totalUnitIndex, markerInternals] = refineTotalOptions(options) const largestUnitIndex = getLargestDurationUnit(internals) if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { @@ -161,7 +160,9 @@ export const [ ) }, - toString: formatDurationInternals, + toString(internals, options) { + return formatDurationInternals(internals, ...refineTimeDisplayOptions(options)) + }, valueOf: neverValueOf, }, @@ -173,7 +174,7 @@ export const [ compare(durationArg0, durationArg1, options) { const durationFields0 = toDurationInternals(durationArg0) const durationFields1 = toDurationInternals(durationArg1) - const markerInternals = optionsToRelativeTo(options) // optional + const markerInternals = refineRelativeToOptions(options) const largestUnitIndex = Math.max( getLargestDurationUnit(durationFields0), getLargestDurationUnit(durationFields1), @@ -207,7 +208,7 @@ export const [ function addToDuration(direction, internals, otherArg, options) { const otherFields = toDurationInternals(otherArg) - const markerInternals = optionsToRelativeTo(options) // optional + const markerInternals = refineRelativeToOptions(options) // optional const largestUnitIndex = Math.max( getLargestDurationUnit(internals), getLargestDurationUnit(otherFields), @@ -265,4 +266,5 @@ function balanceDurationDayTime( function getLargestDurationUnit(durationFields) { // TODO: rename to getLargestDurationUnitIndex + // TODO: move to DurationFields math } diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index e12308bc..bcafd21e 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -20,9 +20,10 @@ import { } from './isoMath' import { compareLargeInts } from './largeInt' import { moveEpochNano } from './move' -import { toEpochNano, toObject } from './options' +import { refineRoundOptions, toEpochNano, toObject } from './options' import { roundLargeNano } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' +import { hourIndex } from './units' import { noop } from './utils' import { createZonedDateTime } from './zonedDateTime' @@ -120,7 +121,7 @@ export const [ return createInstant( roundLargeNano( epochNanoseconds, - options, // TODO: break apart options + ...refineRoundOptions(options, hourIndex), ), ) }, diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.js index f86f19cc..e70bc58c 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -1,22 +1,26 @@ import { isoCalendarId } from './calendarConfig' -import { toCalendarNameOption } from './options' +import { getObjId } from './class' +import { refineDateDisplayOptions } from './options' export function formatPossibleDate(internals, options, formatSimple) { - const calendarNameOpt = toCalendarNameOption(options) + const calendarDisplay = refineDateDisplayOptions(options) const showCalendar = - calendarNameOpt === 'always' || - calendarNameOpt === 'critical' || - String(internals.calendar) !== isoCalendarId + calendarDisplay === 'always' || // TODO: use indexes + calendarDisplay === 'critical' || + getObjId(internals.calendar) !== isoCalendarId if (showCalendar) { return formatIsoDateFields(internals) + - formatCalendarWithSingleOpt(internals.calendar, calendarNameOpt) + formatCalendarWithSingleOpt(internals.calendar, calendarDisplay) } else { return formatSimple(internals) } } -export function formatIsoDateTimeFields(isoDateTimeFields, options) { +export function formatIsoDateTimeFields( + isoDateTimeFields, + options, // TODO: use spread args +) { return formatIsoDateFields(isoDateTimeFields) + 'T' + formatIsoTimeFields(isoDateTimeFields, options) } @@ -33,26 +37,41 @@ export function formatIsoMonthDayFields(isoDateFields) { } -export function formatIsoTimeFields(isoTimeFields, options) { - +export function formatIsoTimeFields( + isoTimeFields, + options, // TODO: use spread args +) { + // smallestUnit will be <= MINUTE (meaning minute ALWAYS displayed) } -export function formatOffsetNanoseconds(offsetNanoseconds) { +export function formatOffsetNanoseconds( + offsetNanoseconds, + options, // TODO: use spread args +) { } -export function formatTimeZone(timeZoneProtocol, options) { +export function formatTimeZone( + timeZoneProtocol, + options, // TODO: use spread args +) { } -export function formatCalendar(calendarProtocol, options) { - return formatCalendarWithSingleOpt(calendarProtocol, toCalendarNameOption(options)) +export function formatCalendar( + calendarProtocol, + options, // TODO: use spread args +) { + return formatCalendarWithSingleOpt(calendarProtocol, refineDateDisplayOptions(options)) } -function formatCalendarWithSingleOpt(calendarProtocol, calendarNameOpt) { +function formatCalendarWithSingleOpt(calendarProtocol, calendarNameOptIndex) { } -export function formatDurationInternals(durationInternals, options) { +export function formatDurationInternals( + durationInternals, + options, // TODO: use spread args +) { } diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index fb79dd2b..8ef2b8b0 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,5 +1,6 @@ import { isoTimeFieldNamesAsc, pluckIsoDateTimeFields } from './isoFields' import { compareLargeInts, numberToLargeInt } from './largeInt' +import { clampProp, rejectI } from './options' // use 1 instead of rejectI? import { givenFieldsToNano, hourIndex, @@ -10,7 +11,7 @@ import { nanoInUtcDay, nanoToGivenFields, } from './units' -import { clamp, divFloorMod } from './utils' +import { divFloorMod } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -66,26 +67,25 @@ export function constrainIsoDateTimeInternals(isoDateTimeInternals) { } export function constrainIsoDateInternals(isoDateInternals) { + const daysInMonth = computeIsoDaysInMonth(isoDateInternals.isoYear, isoDateInternals.isoMonth) return validateIsoDateTimeInternals({ calendar: isoDateInternals.calendar, isoYear: isoDateInternals.isoYear, - isoMonth: clamp(isoDateInternals.isoMonth, 1, isoMonthsInYear), // TODO: must error! - isoDay: clamp( // TODO: must error! - isoDateInternals.isoDay, - 1, - computeIsoDaysInMonth(isoDateInternals.isoYear, isoDateInternals.isoMonth), - ), + isoMonth: clampProp(isoDateInternals, 'isoMonth', 1, isoMonthsInYear, rejectI), + isoDay: clampProp(isoDateInternals, 'isoDay', 1, daysInMonth, rejectI), }) } -export function constrainIsoTimeFields(isoTimeFields, overflow = 'reject') { +export function constrainIsoTimeFields(isoTimeFields, overflowI = rejectI) { + // TODO: clever way to compress this, using functional programming + // Will this kill need for clampProp? return { - isoHour: clamp(isoTimeFields.isoHour, 1, 23, overflow), - isoMinute: clamp(isoTimeFields.isoMinute, 1, 59, overflow), - isoSecond: clamp(isoTimeFields.isoSecond, 1, 59, overflow), - isoMillisecond: clamp(isoTimeFields.isoMillisecond, 1, 999, overflow), - isoMicrosecond: clamp(isoTimeFields.isoMicrosecond, 1, 999, overflow), - isoNanosecond: clamp(isoTimeFields.isoNanosecond, 1, 999, overflow), + isoHour: clampProp(isoTimeFields, 'isoHour', 0, 23, overflowI), + isoMinute: clampProp(isoTimeFields, 'isoMinute', 0, 59, overflowI), + isoSecond: clampProp(isoTimeFields, 'isoSecond', 0, 59, overflowI), + isoMillisecond: clampProp(isoTimeFields, 'isoMillisecond', 0, 999, overflowI), + isoMicrosecond: clampProp(isoTimeFields, 'isoMicrosecond', 0, 999, overflowI), + isoNanosecond: clampProp(isoTimeFields, 'isoNanosecond', 0, 999, overflowI), } } @@ -168,9 +168,7 @@ const isoYearMax = 275760 // optimization. isoYear at epochNanoMax const isoYearMin = -271821 // optimization. isoYear at epochNanoMin function validateIsoDateTimeInternals(isoDateTimeInternals) { // validateIsoInternals? - const { isoYear } = isoDateTimeInternals - clamp(isoYear, isoYearMin, isoYearMax) // TODO: must error! - + const isoYear = clampProp(isoDateTimeInternals, 'isoYear', isoYearMin, isoYearMax, rejectI) const nudge = isoYear === isoYearMin ? 1 : isoYear === isoYearMax ? -1 : 0 if (nudge) { diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index e195d472..74aa5e69 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -13,9 +13,9 @@ import { isoToEpochMilli, nanoToIsoTimeAndDay, } from './isoMath' -import { constrainInt } from './options' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { hourIndex, milliInDay, nanoInUtcDay } from './units' +import { clamp } from './utils' // Epoch // ------------------------------------------------------------------------------------------------- @@ -83,7 +83,7 @@ export function moveDateTime( } } -export function moveDate(calendar, isoDateFields, durationFields, overflow) { +export function moveDate(calendar, isoDateFields, durationFields, overflowI) { let { years, months, weeks, days } = durationFields let epochMilli @@ -96,12 +96,12 @@ export function moveDate(calendar, isoDateFields, durationFields, overflow) { if (years) { year += years - month = constrainInt(month, 1, calendar.queryMonthsInYear(year), overflow) + month = clamp(month, 1, calendar.queryMonthsInYear(year), overflowI, 'month') } if (months) { ([year, month] = calendar.addMonths(year, month, months)) - day = constrainInt(day, 1, calendar.queryDaysInMonth(year, month), overflow) + day = clamp(day, 1, calendar.queryDaysInMonth(year, month), overflowI, 'day') } epochMilli = calendar.queryDateStart(year, month, day) diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index e7cd292c..90479fe6 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,41 +1,347 @@ import { durationFieldIndexes } from './durationFields' import { bigIntToLargeInt } from './largeInt' -import { unitIndexes, unitNamesAsc } from './units' +import { dayIndex, minuteIndex, nanoIndex, unitIndexes, yearIndex } from './units' +import { clamp, hasAnyMatchingProps, isObjectLike } from './utils' -// TODO: for unit parsing, ensure ceiling and correct increment +// TODO: ensure all callers use *INDEXES* -export function strictNumber(input) { +// Compound Options +// ------------------------------------------------------------------------------------------------- +export function refineOverflowOptions(options) { + return refineOverflow(normalizeOptions(options)) } -export function strictInstanceOf(obj, Class) { +export function refineZonedFieldOptions(options) { + options = normalizeOptions(options) + return [ + refineOverflow(options), + refineEpochDisambig(options), + refineOffsetDisambig(options), + ] } -export function strictArrayOfStrings(obj) { // rethink +export function refineEpochDisambigOptions(options) { + return refineEpochDisambig(normalizeOptions(options)) } -export function strictArrayOfType(obj) { // used? +export function refineDiffOptions( + options, + defaultLargestUnitI, + maxUnitI = yearIndex, + minUnitI = nanoIndex, +) { + options = normalizeOptions(options) + const smallestUnitI = refineSmallestUnit(options, maxUnitI, minUnitI, minUnitI) + const largestUnitI = refineLargestUnit( + options, + maxUnitI, + Math.max(smallestUnitI, minUnitI), + Math.max(smallestUnitI, defaultLargestUnitI), + ) + const roundingMode = refineRoundingMode(options) + const roundingIncrement = refineRoundingInc(options, smallestUnitI) + return [largestUnitI, smallestUnitI, roundingMode, roundingIncrement] } -export function strictArray() { +export function refineRoundOptions(options, maxUnitI = dayIndex) { + options = normalizeRequiredOptions(options, smallestUnitStr) + const smallestUnitI = refineSmallestUnit(options, maxUnitI) // required + return [ + smallestUnitI, + refineRoundingMode(options, halfExpandI), + refineRoundingInc(options, smallestUnitI), + ] +} +export function refineDurationRoundOptions(options, defaultLargestUnitI) { + options = normalizeRequiredOptions(options, smallestUnitStr) + mustHaveMatch(options, [largestUnitStr, smallestUnitStr]) // will register unwanted read? + // ^do a whitelist filter that copies instead? + return [ + ...refineDiffOptions(options, defaultLargestUnitI), // double-refined. oh well + refineRelativeTo(options), + ] } -export function toObjectOptional(obj) { - return obj === undefined ? {} : toObject(obj) +export function refineTotalOptions(options) { + options = normalizeRequiredOptions(options, totalUnitStr) + return [ + refineTotalUnit(options), + refineRelativeTo(options), + ] } -export function toObject() { - // ensures a real object. throws error otherwise +export function refineRelativeToOptions(options) { + return refineRelativeTo(normalizeOptions(options)) +} + +export function refineZonedDateTimeDisplayOptions(options) { + options = normalizeOptions(options) + return [ + refineCalendarDisplay(options), + refineTimeZoneDisplay(options), + refineOffsetDisplay(options), + ...refineTimeDisplayTuple(options), // BAD: this is being misused + ] +} + +export function refineDateTimeDisplayOptions(options) { + options = normalizeOptions(options) + return [ + refineCalendarDisplay(options), + ...refineTimeDisplayTuple(options), // BAD: this is being misused + ] +} + +export function refineDateDisplayOptions(options) { + return refineCalendarDisplay(normalizeOptions(options)) +} + +export function refineTimeDisplayOptions(options) { + return refineTimeDisplayTuple(normalizeOptions(options)) // BAD: this is being misused +} + +function refineTimeDisplayTuple(options) { + return [ + refineSubsecDigits(options), + refineSmallestUnit(options, minuteIndex), + refineRoundingMode(options), + ] + /* + smallestUnit takes precedence + (if smallestUnit not given, treat as nano) + will need to conver to an `inc` - search `Math.pow(10, 9` + */ +} + +// Single Options +// ------------------------------------------------------------------------------------------------- + +const smallestUnitStr = 'smallestUnit' +const largestUnitStr = 'largestUnit' +const totalUnitStr = 'unit' + +const refineSmallestUnit = refineUnitOption.bind(undefined, smallestUnitStr) +const refineLargestUnit = refineUnitOption.bind(undefined, largestUnitStr) +const refineTotalUnit = refineUnitOption.bind(undefined, totalUnitStr) + +export const constrainI = 0 +export const rejectI = 1 // must be truthy for clamp's throwOnOverflow param +const refineOverflow = refineChoiceOption.bind(undefined, 'overflow', [ + 'constrain', + 'reject', +]) + +export const compatibleI = 0 +/* export const rejectI = 1 */ +export const earlierI = 2 +export const laterI = 3 +const refineEpochDisambig = refineChoiceOption.bind(undefined, 'disambiguation', [ + 'compatible', + 'reject', + 'earlier', + 'later', +]) + +export const useI = 0 +/* export const rejectI = 1 */ +export const preferI = 2 +export const ignoreI = 3 +const refineOffsetDisambig = refineChoiceOption.bind(undefined, 'offset', [ + 'use', + 'reject', + 'prefer', + 'ignore', +]) + +export const autoI = 0 +export const neverI = 1 +export const criticalI = 2 +export const alwaysI = 3 +const refineCalendarDisplay = refineChoiceOption.bind(undefined, 'calendarName', [ + 'auto', + 'never', + 'critical', + 'always', +]) + +/* export const autoI = 0 */ +/* export const neverI = 1 */ +/* export const criticalI = 2 */ +const refineTimeZoneDisplay = refineChoiceOption.bind(undefined, 'timeZoneName', [ + 'auto', + 'never', + 'critical', +]) + +/* export const autoI = 0 */ +/* export const neverI = 1 */ +const refineOffsetDisplay = refineChoiceOption.bind(undefined, 'offset', [ + 'auto', + 'never', +]) + +export const truncI = 0 +export const floorI = 1 +export const ceilI = 2 +export const expandI = 3 +export const halfCeilI = 4 +export const halfFloorI = 5 +export const halfExpandI = 6 +export const halfTruncI = 7 +export const halfEvenI = 8 +const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', [ + 'trunc', + 'floor', + 'ceil', + 'expand', + 'halfCeil', + 'halfFloor', + 'halfExpand', // round() should override this as default + 'halfTrunc', + 'halfEven', +]) + +function refineRoundingInc(options, validateWithSmallestUnitI) { + // default to 1 + // with smallestUnit... + /* + if (roundTo === undefined) throw new TypeError('options parameter is required'); + if (ES.Type(roundTo) === 'String') { + const stringParam = roundTo; + roundTo = ObjectCreate(null); + roundTo.smallestUnit = stringParam; + } else { + roundTo = ES.GetOptionsObject(roundTo); + } + const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo); + const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand'); + const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED, ['day']); + const maximumIncrements = { + day: 1, + hour: 24, + minute: 60, + second: 60, + millisecond: 1000, + microsecond: 1000, + nanosecond: 1000 + }; + const maximum = maximumIncrements[smallestUnit]; + const inclusive = maximum === 1; + ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive); + */ +} + +function refineSubsecDigits(options) { + // 'fractionalSecondDigits' + // 'auto'/0-9 + // allow undefined +} + +function refineRelativeTo(options) { + // TODO + // should return ZoneDateTimeINTERNALS or PlainDateINTERNALS + // allow undefined +} + +// Utils +// ------------------------------------------------------------------------------------------------- + +function refineUnitOption(optionName, options, maxUnitI, minUnitI = nanoIndex, defaultUnitI) { + let unitName = options[optionName] + if (unitName === undefined) { + if (defaultUnitI === undefined) { + throw new RangeError('Must specify' + optionName) // best error? + } + return defaultUnitI + } + + unitName = toString(unitName) + const unitIndex = unitIndexes[unitName] ?? durationFieldIndexes[unitName] + + if (unitIndex === undefined) { + throw new RangeError('Invalid unit ' + optionName) // correct error? + } + if (unitIndex < minUnitI || unitIndex > maxUnitI) { // TODO: use clamp? + throw new RangeError('Out of bounds' + optionName) + } + + return unitIndex +} + +// TODO: optimize by using map +// TODO: keep acceting string arrays. good for accepting default first element +function refineChoiceOption(optionName, choices, options, defaultChoice) { + const optionValue = options[optionName] + if (optionValue === undefined) { + return defaultChoice ?? choices[0] + } + const index = choices.indexOf(optionValue) + if (index < 0) { + throw new RangeError('Must be one of the choices') + } + return index +} + +export function normalizeOptions(options) { + if (options === undefined) { + return {} + } + if (!isObjectLike(options)) { + throw new TypeError('Must be object-like') + } + return options +} + +// will NOT check for atomicName in options +function normalizeRequiredOptions(options, atomicName) { + if (typeof options === 'string') { + return { [atomicName]: options } + } + if (!isObjectLike(options)) { + throw new TypeError('Must be object-like') + } + return options +} + +function mustHaveMatch(obj, propNames) { + if (!hasAnyMatchingProps(obj, propNames)) { + throw new TypeError('Need one: ' + JSON.stringify(propNames)) + } } export function toEpochNano(input) { if (typeof input !== 'bigint') { - throw new TypeError('aaah') + throw new TypeError('Needs bigint') } return bigIntToLargeInt(input) } +export function invertRoundingMode(roundingModeI) { + // TODO +} + +export function clampProp(props, propName, min, max, overflowI) { + return clamp(props[propName], min, max, overflowI, propName) +} + +// Primitives +// ------------------------------------------------------------------------------------------------- + +export function strictNumber(input) { +} + +export function strictInstanceOf(obj, Class) { +} + +export function strictArray() { +} + +export function toObject() { + // ensures a real object. throws error otherwise +} + export function toNumber(value) { if (typeof value === 'bigint') { throw new TypeError('Cannot convert BigInt to number') @@ -55,7 +361,6 @@ export function toStringOrUndefined() { } export function toNumberOrUndefined() { - } export function toString(value) { @@ -74,7 +379,6 @@ export function toIntegerThrowOnInfinity(value) { } export function toBoolean() { - } export function toPositiveInteger(valueParam, property) { @@ -102,140 +406,3 @@ export function toIntegerWithoutRounding(valueParam) { } return toInteger(value) // ℝ(value) in spec text; converts -0 to 0 } - -// best place for this? (has 'overflow') -export function constrainInt(subject, minIncl, maxIncl, overflow = 'reject') { - // maybe don't accept min? already vetted to be positive (or non-negative) integer -} - -export function largestOfTwoUnits() { - -} - -export function toOffsetHandling() { - -} - -export function toZonedRefiningOptions(options) { - options = toObjectOptional(options) - - return { // TODO: use tuple? - overflow: toOverflow(options), - offset: toOffset(options), - disambiguation: toDisambiguation(options), - } -} - -function toOffset() { - -} - -export function toDisambiguation() { - -} - -export function toLargestUnit() { - -} - -export function toSmallestUnit() { -} - -export function isTimeUnit(unit) { - return unit !== 'year' && - unit !== 'month' && - unit !== 'week' && - unit !== 'day' -} - -export function toCalendarNameOption() { - -} - -export function toDiffOptions() { - -} - -export function toOverflow() { - -} - -export function toOverflowOptions() { - -} - -export function validateRoundingOptions(options) { - /* - if (roundTo === undefined) throw new TypeError('options parameter is required'); - if (ES.Type(roundTo) === 'String') { - const stringParam = roundTo; - roundTo = ObjectCreate(null); - roundTo.smallestUnit = stringParam; - } else { - roundTo = ES.GetOptionsObject(roundTo); - } - const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo); - const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand'); - const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED, ['day']); - const maximumIncrements = { - day: 1, - hour: 24, - minute: 60, - second: 60, - millisecond: 1000, - microsecond: 1000, - nanosecond: 1000 - }; - const maximum = maximumIncrements[smallestUnit]; - const inclusive = maximum === 1; - ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive); - */ -} - -export function optionsToLargestUnit() { - // TODO: rename to optionsToLargestUnitIndex -} - -export function optionsToOverflow(options) { - return toOverflow(toObjectOptional(options).overflow) -} - -export function optionsToTotalUnit() { - // TODO: rename to optionsToTotalUnitIndex -} - -export function optionsToRelativeTo() { - // should return ZoneDateTimeINTERNALS or PlainDateINTERNALS -} - -export function optionsToSmallestUnit(options) { - // TODO: rename to optionsToSmallestUnitIndex -} - -export function optionsToRoundingIncrement(options) { -} - -export function optionsToRoundingMode(options) { -} - -export function overflowToOptions(overflow) { - return { overflow } -} - -export function largestUnitToOptions(largestUnitIndex) { - return { largestUnit: unitNamesAsc[largestUnitIndex] } -} - -// Units -// ------------------------------------------------------------------------------------------------- - -export function toUnit(unitName) { - unitName = toString(unitName) - const unitIndex = unitIndexes[unitName] ?? durationFieldIndexes[unitName] - - if (unitIndex === undefined) { - throw new RangeError('Invalid unit') - } - - return unitIndexes[unitName] -} diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index b8c6d8f3..a91cc28d 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -14,7 +14,7 @@ import { refinePlainDateBag, } from './convert' import { diffDates } from './diff' -import { toDurationInternals } from './duration' +import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { generatePublicIsoDateFields, @@ -25,10 +25,11 @@ import { import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' import { parsePlainDate } from './isoParse' -import { optionsToOverflow } from './options' +import { invertRoundingMode, refineDiffOptions, refineOverflowOptions } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' import { zonedInternalsToIso } from './timeZoneOps' +import { dayIndex, yearIndex } from './units' export const [ PlainDate, @@ -65,7 +66,7 @@ export const [ parsePlainDate, // handleUnusedOptions - optionsToOverflow, + refineOverflowOptions, // Getters // ----------------------------------------------------------------------------------------------- @@ -106,13 +107,22 @@ export const [ until(internals, otherArg, options) { const otherInternals = toPlainDateInternals(otherArg) const calendar = getCommonCalendarOps(internals, otherInternals) - return diffDates(calendar, internals, otherInternals, options, 1) + const optionsTuple = refineDiffOptions(options, dayIndex, yearIndex, dayIndex) + + return createDuration( + diffDates(calendar, internals, otherInternals, ...optionsTuple), + ) }, since(internals, otherArg, options) { const otherInternals = toPlainDateInternals(otherArg) const calendar = getCommonCalendarOps(internals, otherInternals) - return diffDates(calendar, internals, otherInternals, options, -1) + const optionsTuple = refineDiffOptions(options, dayIndex, yearIndex, dayIndex) + optionsTuple[2] = invertRoundingMode(optionsTuple[2]) + + return createDuration( + diffDates(calendar, otherInternals, internals, ...optionsTuple), + ) }, equals(internals, other) { diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index f338db1f..5b646c2c 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -1,6 +1,6 @@ import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' -import { getPublicCalendar, queryCalendarOps } from './calendarOps' +import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertToPlainMonthDay, @@ -9,7 +9,7 @@ import { refinePlainDateTimeBag, } from './convert' import { diffDateTimes } from './diff' -import { toDurationInternals } from './duration' +import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { generatePublicIsoDateTimeFields, @@ -24,14 +24,18 @@ import { compareIsoDateTimeFields } from './isoMath' import { parsePlainDateTime } from './isoParse' import { moveDateTime } from './move' import { - optionsToOverflow, - toDisambiguation, - validateRoundingOptions, + invertRoundingMode, + refineDateTimeDisplayOptions, + refineDiffOptions, + refineEpochDisambigOptions, + refineOverflowOptions, + refineRoundOptions, } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' import { roundIsoDateTimeFields } from './round' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' +import { dayIndex } from './units' import { createZonedDateTime } from './zonedDateTime' export const [ @@ -86,7 +90,7 @@ export const [ parsePlainDateTime, // handleUnusedOptions - optionsToOverflow, + refineOverflowOptions, // Getters // ----------------------------------------------------------------------------------------------- @@ -128,7 +132,7 @@ export const [ internals.calendar, internals, toDurationInternals(durationArg), - optionsToOverflow(options), + refineOverflowOptions(options), ), ) }, @@ -139,31 +143,37 @@ export const [ internals.calendar, internals, negateDurationInternals(toDurationInternals(durationArg)), - optionsToOverflow(options), + refineOverflowOptions(options), ), ) }, until(internals, otherArg, options) { - return diffDateTimes( - // TODO: give calendar arg - internals, - toPlainDateTimeInternals(otherArg), - options, // TODO: spread out lots of options!!! + const otherInternals = toPlainDateTimeInternals(otherArg) + const calendar = getCommonCalendarOps(internals, otherInternals) + const optionsTuple = refineDiffOptions(options, dayIndex) + + return createDuration( + diffDateTimes(calendar, internals, otherInternals, ...optionsTuple), ) }, since(internals, otherArg, options) { - return diffDateTimes( - // TODO: give calendar arg - toPlainDateTimeInternals(otherArg), - internals, - options, // TODO: flip rounding options + const otherInternals = toPlainDateTimeInternals(otherArg) + const calendar = getCommonCalendarOps(internals, otherInternals) + const optionsTuple = refineDiffOptions(options, dayIndex) + optionsTuple[2] = invertRoundingMode(optionsTuple[2]) + + return createDuration( + diffDateTimes(calendar, otherInternals, internals, ...optionsTuple), ) }, round(internals, options) { - const isoDateTimeFields = roundIsoDateTimeFields(internals, validateRoundingOptions(options)) + const isoDateTimeFields = roundIsoDateTimeFields( + internals, + ...refineRoundOptions(options), + ) return createPlainDateTime({ ...isoDateTimeFields, @@ -178,9 +188,11 @@ export const [ }, toString(internals, options) { - // TODO: don't let options (smallestUnit/fractionalWhatever) be access twice!!! - return formatIsoDateTimeFields(roundIsoDateTimeFields(internals, options), options) + - formatCalendar(internals.calendar, options) + const [calendarDisplayI, ...timeDisplayTuple] = refineDateTimeDisplayOptions(options) + const roundedIsoFields = roundIsoDateTimeFields(internals, ...timeDisplayTuple) + + return formatIsoDateTimeFields(roundedIsoFields, ...timeDisplayTuple) + + formatCalendar(internals.calendar, calendarDisplayI) }, toLocaleString: toLocaleStringMethod, @@ -194,7 +206,8 @@ export const [ ) { const { calendar } = internals const timeZone = queryTimeZoneOps(timeZoneArg) - const epochNanoseconds = getSingleInstantFor(timeZone, internals, toDisambiguation(options)) + const epochDisambig = refineEpochDisambigOptions(options) + const epochNanoseconds = getSingleInstantFor(timeZone, internals, epochDisambig) return createZonedDateTime({ epochNanoseconds, diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 3def1aee..09346acc 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -11,7 +11,7 @@ import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parsePlainMonthDay } from './isoParse' -import { optionsToOverflow } from './options' +import { refineOverflowOptions } from './options' export const [ PlainMonthDay, @@ -43,7 +43,7 @@ export const [ parsePlainMonthDay, // handleUnusedOptions - optionsToOverflow, + refineOverflowOptions, // Getters // ----------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index dacfedb6..26a6eaaf 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -13,11 +13,18 @@ import { formatIsoTimeFields } from './isoFormat' import { compareIsoTimeFields } from './isoMath' import { parsePlainTime } from './isoParse' import { moveTime } from './move' -import { optionsToOverflow } from './options' +import { + invertRoundingMode, + refineDiffOptions, + refineOverflowOptions, + refineRoundOptions, + refineTimeDisplayOptions, +} from './options' import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { roundIsoTimeFields } from './round' import { zonedInternalsToIso } from './timeZoneOps' +import { hourIndex } from './units' export const [ PlainTime, @@ -63,7 +70,7 @@ export const [ parsePlainTime, // handleUnusedOptions - optionsToOverflow, + refineOverflowOptions, // Getters // ----------------------------------------------------------------------------------------------- @@ -96,28 +103,27 @@ export const [ ) }, - until(internals, options) { + until(internals, otherArg, options) { + const otherInternals = toPlainTimeInternals(otherArg) + const optionsTuple = refineDiffOptions(options, hourIndex, hourIndex) + return createDuration( - diffTimes( - internals, - toPlainTimeInternals(internals), - options, - ), + diffTimes(internals, otherInternals, ...optionsTuple), ) }, - since(internals, options) { + since(internals, otherArg, options) { + const otherInternals = toPlainTimeInternals(otherArg) + const optionsTuple = refineDiffOptions(options, hourIndex, hourIndex) + optionsTuple[2] = invertRoundingMode(optionsTuple[2]) + return createDuration( - diffTimes( - toPlainTimeInternals(internals), - internals, - options, // TODO: reverse rounding - ), + diffTimes(otherInternals, internals, ...optionsTuple), ) }, round(internals, options) { - return roundIsoTimeFields(internals, options) + return roundIsoTimeFields(internals, ...refineRoundOptions(options, hourIndex)) }, equals(internals, other) { @@ -126,8 +132,11 @@ export const [ }, toString(internals, options) { - // TODO: don't let options (smallestUnit/fractionalWhatever) be access twice!!! - return formatIsoTimeFields(roundIsoTimeFields(internals, options), options) + const timeDisplayTuple = refineTimeDisplayOptions(options) + return formatIsoTimeFields( + roundIsoTimeFields(internals, ...timeDisplayTuple), + ...timeDisplayTuple, + ) }, toLocaleString: toLocaleStringMethod, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index e1d5cb65..d9d56969 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -15,7 +15,7 @@ import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' import { parsePlainYearMonth } from './isoParse' -import { optionsToOverflow } from './options' +import { refineOverflowOptions } from './options' export const [ PlainYearMonth, @@ -47,7 +47,7 @@ export const [ parsePlainYearMonth, // handleUnusedOptions - optionsToOverflow, + refineOverflowOptions, // Getters // ----------------------------------------------------------------------------------------------- @@ -67,7 +67,7 @@ export const [ this, internals.calendar, toDurationInternals(durationArg), - optionsToOverflow(options), + refineOverflowOptions(options), ) }, @@ -76,7 +76,7 @@ export const [ this, internals.calendar, negateDurationInternals(toDurationInternals(durationArg)), - optionsToOverflow(options), + refineOverflowOptions(options), ) }, diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 965485ad..f5454242 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -14,7 +14,7 @@ import { computeNanosecondsInDay } from './timeZoneOps' import { dayIndex, nanoInUtcDay, nanoIndex, unitIndexToNano, weekIndex } from './units' import { identityFunc } from './utils' -export function roundToMinute(nanoseconds) { // can be positive or negative +export function roundToMinute(epochNano) { } @@ -32,13 +32,13 @@ export function roundIsoDateTimeFields( let dayDelta if (smallestUnitIndex === dayIndex) { - const nanosecondsInDay = timeZoneOps + const nanoInDay = timeZoneOps ? computeNanosecondsInDay(timeZoneOps, isoDateTimeFields) : nanoInUtcDay dayDelta = roundWithDivisor( isoTimeFieldsToNano(isoDateTimeFields), - nanosecondsInDay, + nanoInDay, roundingMode, ) @@ -209,6 +209,10 @@ export function totalRelativeDuration( // Nudge // ------------------------------------------------------------------------------------------------- +/* +These functions actually do the heavy-lifting of rounding to a higher/lower marker, +and return the (day) delta. Also return the (potentially) unbalanced new duration. +*/ function nudgeDurationTime( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) @@ -377,7 +381,7 @@ function bubbleRelativeDuration( function clampRelativeDuration( durationFields, - clampUnit, + clampUnit, // baaa clampDistance, // marker system... marker, diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index 8eb83f02..f97de86c 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -6,7 +6,7 @@ import { refineComplexBag } from './convert' import { createInstant, toInstantEpochNanoseconds } from './instant' import { formatOffsetNanoseconds } from './isoFormat' import { parseTimeZoneId } from './isoParse' -import { toDisambiguation } from './options' +import { refineEpochDisambigOptions } from './options' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { noop } from './utils' @@ -69,7 +69,7 @@ export const [TimeZone, createTimeZone] = createTemporalClass( return getSingleInstantFor( impl, toPlainDateTimeInternals(plainDateTimeArg), - toDisambiguation(options), // TODO: method w/ whole options object + refineEpochDisambigOptions(options), ) }, diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 10eac2b5..2bfccb80 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -1,8 +1,4 @@ -// in general, prefer .bind over macro functions - -// monitor use of floor/trunc and modding. many are wrong - export function isObjectLike() { } @@ -15,6 +11,8 @@ export function mapProps(input, refinerMap) { } export function mapArrayToProps() { // propNameToProps + // TODO: auto uses of this because often a {key:value} will take up same minification space + // as defining an array of strings and running it through this function } export function remapProps(obj, oldKeys, newKeys) { @@ -96,7 +94,20 @@ export function twoDigit(num) { // as a string export function compareNumbers() { } -export function clamp() { +export function clamp( + val, + min, + max, + throwOnOverflow, // 0/1 (matched constrain/reject) + noun, // for error message (required if throwOnOverflow given) +) { + const clamped = Math.min(Math.max(val, min), max) + + if (throwOnOverflow && val !== clamped) { + throw new RangeError(`${noun} must be between ${min}-${max}`) + } + + return clamped } /* diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 2466bc4b..08f59ee3 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -8,7 +8,7 @@ import { refineZonedDateTimeBag, } from './convert' import { diffZonedEpochNano } from './diff' -import { toDurationInternals } from './duration' +import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { createInstant } from './instant' import { resolveZonedFormattable } from './intlFormat' @@ -33,7 +33,14 @@ import { import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' -import { optionsToOverflow, toEpochNano } from './options' +import { + invertRoundingMode, + refineDiffOptions, + refineOverflowOptions, + refineRoundOptions, + refineZonedDateTimeDisplayOptions, + toEpochNano, +} from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime, toPlainTimeInternals } from './plainTime' @@ -46,7 +53,7 @@ import { queryTimeZoneOps, zonedInternalsToIso, } from './timeZoneOps' -import { nanoInHour } from './units' +import { hourIndex, nanoInHour } from './units' import { mapProps } from './utils' export const [ @@ -78,7 +85,7 @@ export const [ parseZonedDateTime, // handleUnusedOptions - optionsToOverflow, + refineOverflowOptions, // Getters // ----------------------------------------------------------------------------------------------- @@ -214,23 +221,36 @@ export const [ until(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) - return diffZonedEpochNano( - getCommonCalendarOps(internals, otherInternals), - getCommonTimeZoneOps(internals, otherInternals), - internals.epochNanoseconds, - otherInternals.epochNanoseconds, - options, // TODO: spread out lots of options!!! + const calendar = getCommonCalendarOps(internals, otherInternals) + const timeZone = getCommonTimeZoneOps(internals, otherInternals) + const optionsTuple = refineDiffOptions(options, hourIndex) + + return createDuration( + diffZonedEpochNano( + calendar, + timeZone, + internals.epochNanoseconds, + otherInternals.epochNanoseconds, + ...optionsTuple, + ), ) }, since(internals, otherArg, options) { const otherInternals = toZonedDateTimeInternals(otherArg) - return diffZonedEpochNano( - getCommonCalendarOps(internals, otherInternals), - getCommonTimeZoneOps(internals, otherInternals), - otherInternals.epochNanoseconds, - internals.epochNanoseconds, - options, // TODO: flip rounding options!!!!! + const calendar = getCommonCalendarOps(internals, otherInternals) + const timeZone = getCommonTimeZoneOps(internals, otherInternals) + const optionsTuple = refineDiffOptions(options, hourIndex) + optionsTuple[2] = invertRoundingMode(optionsTuple[2]) + + return createDuration( + diffZonedEpochNano( + calendar, + timeZone, + otherInternals.epochNanoseconds, + internals.epochNanoseconds, + ...optionsTuple, + ), ) }, @@ -242,8 +262,8 @@ export const [ isoDateTimeFields = roundIsoDateTimeFields( isoDateTimeFields, - options, - () => computeNanosecondsInDay(timeZone, isoDateTimeFields), + ...refineRoundOptions(options), + timeZone, ) epochNanoseconds = getMatchingInstantFor( isoDateTimeFields, @@ -297,16 +317,20 @@ export const [ toString(internals, options) { let { epochNanoseconds, timeZone, calendar } = internals - - // TODO: don't let options be accessed twice! once by rounding, twice by formatting + const [ + calendarDisplayI, + timeZoneDisplayI, + offsetDisplayI, + ...timeDisplayTuple + ] = refineZonedDateTimeDisplayOptions(options) let offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) let isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) isoDateTimeFields = roundIsoDateTimeFields( isoDateTimeFields, - options, - () => computeNanosecondsInDay(timeZone, isoDateTimeFields), + ...timeDisplayTuple, + timeZone, ) epochNanoseconds = getMatchingInstantFor( isoDateTimeFields, @@ -322,10 +346,10 @@ export const [ offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) - return formatIsoDateTimeFields(isoDateTimeFields, options) + - formatOffsetNanoseconds(offsetNanoseconds) + - formatTimeZone(timeZone, options) + - formatCalendar(calendar, options) + return formatIsoDateTimeFields(isoDateTimeFields, ...timeDisplayTuple) + + formatOffsetNanoseconds(offsetNanoseconds, offsetDisplayI) + + formatTimeZone(timeZone, timeZoneDisplayI) + + formatCalendar(calendar, calendarDisplayI) }, toLocaleString(internals, locales, options) { From 7a40ddb6059085aa71396446540ef06f3db5b6a2 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 15 Jun 2023 12:43:27 -0400 Subject: [PATCH 105/805] streamline moving/diffing options --- packages/temporal-polyfill/src/new/convert.js | 24 +++--- packages/temporal-polyfill/src/new/diff.js | 2 +- packages/temporal-polyfill/src/new/move.js | 2 +- packages/temporal-polyfill/src/new/options.js | 26 +++--- .../temporal-polyfill/src/new/plainDate.js | 31 ++++--- .../src/new/plainDateTime.js | 65 ++++++++------- .../temporal-polyfill/src/new/plainTime.js | 51 ++++++------ .../src/new/plainYearMonth.js | 74 ++++++++--------- .../src/new/zonedDateTime.js | 80 +++++++------------ 9 files changed, 173 insertions(+), 182 deletions(-) diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index de9df318..d31c1f10 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -30,7 +30,7 @@ import { normalizeOptions, refineOverflowOptions, refineZonedFieldOptions, - toObject, + toObject, // TODO: shouldn't we use this all over the place? } from './options' import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' @@ -39,6 +39,12 @@ import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './ import { isObjectLike, pluckProps, removeDuplicateStrings } from './utils' import { createZonedDateTime } from './zonedDateTime' +/* +Rules: +- refining/merging return internal object +- converting returns public object +*/ + // ZonedDateTime // ------------------------------------------------------------------------------------------------- @@ -229,6 +235,12 @@ export function mergePlainYearMonthBag(plainYearMonth, bag, options) { return calendar.yearMonthFromFields(fields, refineOverflowOptions(options)) } +export function convertPlainYearMonthToDate(plainYearMonth, bag) { + return createPlainDate( + convertToIso(plainYearMonth, yearMonthBasicNames, toObject(bag), ['day']), + ) +} + export function convertToPlainYearMonth( input, // PlainDate/PlainDateTime/ZonedDateTime ) { @@ -245,16 +257,6 @@ export function convertToPlainYearMonth( ) } -export function convertPlainYearMonthToDate(plainYearMonth, bag) { - return createPlainDate( - convertPlainYearMonthToIso(plainYearMonth, toObject(bag)), - ) -} - -export function convertPlainYearMonthToIso(plainYearMonth, bag = { day: 1 }) { - return convertToIso(plainYearMonth, yearMonthBasicNames, bag, ['day']) -} - // PlainMonthDay // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 9ba6ab68..9b3aa125 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -260,7 +260,7 @@ export function diffEpochNano( /* Must always be given start-of-day */ -export function diffEpochMilliByDay(epochMilli0, epochMilli1) { +export function diffEpochMilliByDay(epochMilli0, epochMilli1) { // diffEpochMilliDays return Math.round((epochMilli1 - epochMilli0) / milliInDay) } diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.js index 74aa5e69..85285da5 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.js @@ -119,7 +119,7 @@ export function moveDate(calendar, isoDateFields, durationFields, overflowI) { } } -export function moveDateByDays(isoDateFields, days) { +export function moveDateByDays(isoDateFields, days) { // moveDateDays if (days) { isoDateFields = epochMilliToIso(isoToEpochMilli(isoDateFields) + days * milliInDay) } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 90479fe6..1d6b96e6 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -26,6 +26,7 @@ export function refineEpochDisambigOptions(options) { } export function refineDiffOptions( + roundingModeInvert, options, defaultLargestUnitI, maxUnitI = yearIndex, @@ -39,7 +40,10 @@ export function refineDiffOptions( Math.max(smallestUnitI, minUnitI), Math.max(smallestUnitI, defaultLargestUnitI), ) - const roundingMode = refineRoundingMode(options) + let roundingMode = refineRoundingMode(options) + if (roundingModeInvert) { + roundingMode = invertRoundingMode(roundingMode) + } const roundingIncrement = refineRoundingInc(options, smallestUnitI) return [largestUnitI, smallestUnitI, roundingMode, roundingIncrement] } @@ -193,16 +197,22 @@ export const halfTruncI = 7 export const halfEvenI = 8 const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', [ 'trunc', - 'floor', - 'ceil', + 'halfTrunc', 'expand', - 'halfCeil', - 'halfFloor', 'halfExpand', // round() should override this as default - 'halfTrunc', 'halfEven', + // ones that invert from floor/ceil... + 'floor', + 'halfFloor', + 'ceil', + 'halfCeil', ]) +function invertRoundingMode(roundingModeI) { + // TODO + // use numbers? +} + function refineRoundingInc(options, validateWithSmallestUnitI) { // default to 1 // with smallestUnit... @@ -318,10 +328,6 @@ export function toEpochNano(input) { return bigIntToLargeInt(input) } -export function invertRoundingMode(roundingModeI) { - // TODO -} - export function clampProp(props, propName, min, max, overflowI) { return clamp(props[propName], min, max, overflowI, propName) } diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index a91cc28d..08193c1a 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -25,7 +25,7 @@ import { import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' import { parsePlainDate } from './isoParse' -import { invertRoundingMode, refineDiffOptions, refineOverflowOptions } from './options' +import { refineDiffOptions, refineOverflowOptions } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' import { zonedInternalsToIso } from './timeZoneOps' @@ -105,24 +105,11 @@ export const [ }, until(internals, otherArg, options) { - const otherInternals = toPlainDateInternals(otherArg) - const calendar = getCommonCalendarOps(internals, otherInternals) - const optionsTuple = refineDiffOptions(options, dayIndex, yearIndex, dayIndex) - - return createDuration( - diffDates(calendar, internals, otherInternals, ...optionsTuple), - ) + return diffPlainDates(internals, toPlainDateInternals(otherArg), options) }, since(internals, otherArg, options) { - const otherInternals = toPlainDateInternals(otherArg) - const calendar = getCommonCalendarOps(internals, otherInternals) - const optionsTuple = refineDiffOptions(options, dayIndex, yearIndex, dayIndex) - optionsTuple[2] = invertRoundingMode(optionsTuple[2]) - - return createDuration( - diffDates(calendar, otherInternals, internals, ...optionsTuple), - ) + return diffPlainDates(toPlainDateInternals(otherArg), internals, options, true) }, equals(internals, other) { @@ -180,7 +167,17 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -// move to options file? +function diffPlainDates(internals0, internals1, options, roundingModeInvert) { + return createDuration( + diffDates( + getCommonCalendarOps(internals0, internals1), + internals0, + internals1, + ...refineDiffOptions(roundingModeInvert, options, dayIndex, yearIndex, dayIndex), + ), + ) +} + function optionalToPlainTimeInternals(timeArg) { return timeArg === undefined ? isoTimeFieldDefaults : toPlainTimeInternals(timeArg) } diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 5b646c2c..d36a404b 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -24,7 +24,6 @@ import { compareIsoDateTimeFields } from './isoMath' import { parsePlainDateTime } from './isoParse' import { moveDateTime } from './move' import { - invertRoundingMode, refineDateTimeDisplayOptions, refineDiffOptions, refineEpochDisambigOptions, @@ -127,46 +126,27 @@ export const [ }, add(internals, durationArg, options) { - return createPlainDateTime( - moveDateTime( - internals.calendar, - internals, - toDurationInternals(durationArg), - refineOverflowOptions(options), - ), + return movePlainDateTime( + internals, + toDurationInternals(durationArg), + options, ) }, subtract(internals, durationArg, options) { - return createPlainDateTime( - moveDateTime( - internals.calendar, - internals, - negateDurationInternals(toDurationInternals(durationArg)), - refineOverflowOptions(options), - ), + return movePlainDateTime( + internals, + negateDurationInternals(toDurationInternals(durationArg)), + options, ) }, until(internals, otherArg, options) { - const otherInternals = toPlainDateTimeInternals(otherArg) - const calendar = getCommonCalendarOps(internals, otherInternals) - const optionsTuple = refineDiffOptions(options, dayIndex) - - return createDuration( - diffDateTimes(calendar, internals, otherInternals, ...optionsTuple), - ) + return diffPlainDateTimes(internals, toPlainDateTimeInternals(otherArg), options) }, since(internals, otherArg, options) { - const otherInternals = toPlainDateTimeInternals(otherArg) - const calendar = getCommonCalendarOps(internals, otherInternals) - const optionsTuple = refineDiffOptions(options, dayIndex) - optionsTuple[2] = invertRoundingMode(optionsTuple[2]) - - return createDuration( - diffDateTimes(calendar, otherInternals, internals, ...optionsTuple), - ) + return diffPlainDateTimes(toPlainDateTimeInternals(otherArg), internals, options, true) }, round(internals, options) { @@ -249,3 +229,28 @@ export const [ }, }, ) + +// Utils +// ------------------------------------------------------------------------------------------------- + +function movePlainDateTime(internals, durationInternals, options) { + return createPlainDateTime( + moveDateTime( + internals.calendar, + internals, + durationInternals, + refineOverflowOptions(options), + ), + ) +} + +function diffPlainDateTimes(internals0, internals1, options, roundingModeInvert) { + return createDuration( + diffDateTimes( + getCommonCalendarOps(internals0, internals1), + internals0, + internals1, + ...refineDiffOptions(roundingModeInvert, options, dayIndex), + ), + ) +} diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 26a6eaaf..d63e502b 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -14,7 +14,6 @@ import { compareIsoTimeFields } from './isoMath' import { parsePlainTime } from './isoParse' import { moveTime } from './move' import { - invertRoundingMode, refineDiffOptions, refineOverflowOptions, refineRoundOptions, @@ -86,44 +85,25 @@ export const [ }, add(internals, durationArg) { - return createPlainTime( - moveTime( - internals, - toDurationInternals(durationArg), - )[0], - ) + return movePlainTime(internals, toDurationInternals(durationArg)) }, subtract(internals, durationArg) { - return createPlainTime( - moveTime( - internals, - negateDurationInternals(toDurationInternals(durationArg)), - )[0], - ) + return movePlainTime(internals, negateDurationInternals(toDurationInternals(durationArg))) }, until(internals, otherArg, options) { - const otherInternals = toPlainTimeInternals(otherArg) - const optionsTuple = refineDiffOptions(options, hourIndex, hourIndex) - - return createDuration( - diffTimes(internals, otherInternals, ...optionsTuple), - ) + return diffPlainTimes(internals, toPlainTimeInternals(otherArg), options) }, since(internals, otherArg, options) { - const otherInternals = toPlainTimeInternals(otherArg) - const optionsTuple = refineDiffOptions(options, hourIndex, hourIndex) - optionsTuple[2] = invertRoundingMode(optionsTuple[2]) - - return createDuration( - diffTimes(otherInternals, internals, ...optionsTuple), - ) + return diffPlainTimes(toPlainTimeInternals(otherArg), internals, options, true) }, round(internals, options) { - return roundIsoTimeFields(internals, ...refineRoundOptions(options, hourIndex)) + return createPlainTime( + roundIsoTimeFields(internals, ...refineRoundOptions(options, hourIndex)), + ) }, equals(internals, other) { @@ -169,3 +149,20 @@ export const [ }, }, ) + +// Utils +// ------------------------------------------------------------------------------------------------- + +function movePlainTime(internals, durationInternals) { + return createPlainTime(moveTime(internals, durationInternals)[0]) +} + +function diffPlainTimes(internals0, internals1, options, roundingModeInvert) { + return createDuration( + diffTimes( + internals0, + internals1, + ...refineDiffOptions(roundingModeInvert, options, hourIndex, hourIndex), + ), + ) +} diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index d9d56969..94d82a64 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -1,21 +1,22 @@ import { isoCalendarId } from './calendarConfig' import { yearMonthGetters } from './calendarFields' -import { getPublicCalendar } from './calendarOps' +import { getCommonCalendarOps, getPublicCalendar } from './calendarOps' import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertPlainYearMonthToDate, - convertPlainYearMonthToIso, mergePlainYearMonthBag, refinePlainYearMonthBag, } from './convert' import { diffDates } from './diff' -import { toDurationInternals } from './duration' +import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' import { parsePlainYearMonth } from './isoParse' -import { refineOverflowOptions } from './options' +import { moveDateByDays } from './move' +import { refineDiffOptions, refineOverflowOptions } from './options' +import { dayIndex, yearIndex } from './units' export const [ PlainYearMonth, @@ -64,44 +65,26 @@ export const [ add(internals, durationArg, options) { return movePlainYearMonth( - this, - internals.calendar, + internals, toDurationInternals(durationArg), - refineOverflowOptions(options), + options, ) }, subtract(internals, durationArg, options) { return movePlainYearMonth( - this, - internals.calendar, + internals, negateDurationInternals(toDurationInternals(durationArg)), - refineOverflowOptions(options), + options, ) }, until(internals, otherArg, options) { - const { calendar } = internals - return createPlainYearMonth( - diffDates( - calendar, - convertPlainYearMonthToIso(internals), - convertPlainYearMonthToIso(toPlainYearMonthInternals(otherArg)), - options, - ), - ) + return diffPlainYearMonths(internals, toPlainYearMonthInternals(otherArg), options) }, since(internals, otherArg, options) { - const { calendar } = internals - return createPlainYearMonth( - diffDates( - calendar, - convertPlainYearMonthToIso(toPlainYearMonthInternals(otherArg)), - convertPlainYearMonthToIso(internals), - options, // TODO: flip rounding args - ), - ) + return diffPlainYearMonths(toPlainYearMonthInternals(otherArg), internals, options, true) }, equals(internals, otherArg) { @@ -143,19 +126,38 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- +function diffPlainYearMonths(internals0, internals1, options, roundingModeInvert) { + return createDuration( + diffDates( + getCommonCalendarOps(internals0, internals1), + movePlainYearMonthToDay(internals0), + movePlainYearMonthToDay(internals1), + ...refineDiffOptions(roundingModeInvert, options, yearIndex, yearIndex, dayIndex), + ), + ) +} + function movePlainYearMonth( - plainYearMonth, - calendar, + internals, durationFields, - overflowHandling, + options, ) { - const isoDateFields = convertPlainYearMonthToIso(plainYearMonth, { - day: durationFields.sign < 0 - ? calendar.daysInMonth(plainYearMonth) + const { calendar } = internals + const isoDateFields = movePlainYearMonthToDay( + internals, + durationFields.sign < 0 + ? calendar.daysInMonth(internals) : 1, - }) + ) return createPlainYearMonth( - calendar.dateAdd(isoDateFields, durationFields, overflowHandling), + calendar.dateAdd(isoDateFields, durationFields, refineOverflowOptions(options)), + ) +} + +function movePlainYearMonthToDay(internals, day = 1) { + return moveDateByDays( + internals, + day - internals.calendar.day(internals), ) } diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 08f59ee3..8b3b04d8 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -34,7 +34,6 @@ import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' import { - invertRoundingMode, refineDiffOptions, refineOverflowOptions, refineRoundOptions, @@ -200,58 +199,27 @@ export const [ }, add(internals, durationArg, options) { - return createZonedDateTime( - moveZonedDateTimeInternals( - internals, - toDurationInternals(durationArg), - options, - ), + return moveZonedDateTime( + internals, + toDurationInternals(durationArg), + options, ) }, subtract(internals, durationArg, options) { - return createZonedDateTime( - moveZonedDateTimeInternals( - internals, - negateDurationInternals(toDurationInternals(durationArg)), - options, - ), + return moveZonedDateTime( + internals, + negateDurationInternals(toDurationInternals(durationArg)), + options, ) }, until(internals, otherArg, options) { - const otherInternals = toZonedDateTimeInternals(otherArg) - const calendar = getCommonCalendarOps(internals, otherInternals) - const timeZone = getCommonTimeZoneOps(internals, otherInternals) - const optionsTuple = refineDiffOptions(options, hourIndex) - - return createDuration( - diffZonedEpochNano( - calendar, - timeZone, - internals.epochNanoseconds, - otherInternals.epochNanoseconds, - ...optionsTuple, - ), - ) + return diffZonedDateTimes(internals, toZonedDateTimeInternals(otherArg), options) }, since(internals, otherArg, options) { - const otherInternals = toZonedDateTimeInternals(otherArg) - const calendar = getCommonCalendarOps(internals, otherInternals) - const timeZone = getCommonTimeZoneOps(internals, otherInternals) - const optionsTuple = refineDiffOptions(options, hourIndex) - optionsTuple[2] = invertRoundingMode(optionsTuple[2]) - - return createDuration( - diffZonedEpochNano( - calendar, - timeZone, - otherInternals.epochNanoseconds, - internals.epochNanoseconds, - ...optionsTuple, - ), - ) + return diffZonedDateTimes(toZonedDateTimeInternals(otherArg), internals, options, true) }, round(internals, options) { @@ -416,12 +384,26 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -function moveZonedDateTimeInternals(internals, durationFields, overflowHandling) { - return moveZonedEpochNano( - internals.calendar, - internals.timeZone, - internals.epochNanoseconds, - durationFields, - overflowHandling, +function moveZonedDateTime(internals, durationFields, overflowHandling) { + return createZonedDateTime( + moveZonedEpochNano( + internals.calendar, + internals.timeZone, + internals.epochNanoseconds, + durationFields, + overflowHandling, + ), + ) +} + +function diffZonedDateTimes(internals, otherInternals, options, roundingModeInvert) { + return createDuration( + diffZonedEpochNano( + getCommonCalendarOps(internals, otherInternals), + getCommonTimeZoneOps(internals, otherInternals), + internals.epochNanoseconds, + otherInternals.epochNanoseconds, + ...refineDiffOptions(roundingModeInvert, options, hourIndex), + ), ) } From 5b863c0eb87fad38210d951fb6297633ec3cdfe1 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 15 Jun 2023 13:21:52 -0400 Subject: [PATCH 106/805] improve stuff --- packages/temporal-polyfill/src/new/diff.js | 2 +- .../temporal-polyfill/src/new/duration.js | 20 +++++++------ packages/temporal-polyfill/src/new/instant.js | 28 ++++++++++--------- packages/temporal-polyfill/src/new/round.js | 1 + packages/temporal-polyfill/src/new/units.js | 2 +- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 9b3aa125..edfb5ede 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -103,7 +103,7 @@ export function diffDates( const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnitIndex) - return roundRelativeDuration( // TODO: return DurationInternals + return roundRelativeDuration( dateDiff, isoToEpochNano(endIsoFields), largestUnitIndex, diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index ca90e9ec..7b3b23eb 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -120,7 +120,9 @@ export const [ if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { // TODO: check internals doesn't have large fields - return roundDayTimeDuration(internals, smallestUnitIndex, roundingMode, roundingIncrement) + return createDuration( + roundDayTimeDuration(internals, smallestUnitIndex, roundingMode, roundingIncrement), + ) } if (!markerInternals) { @@ -129,13 +131,15 @@ export const [ const markerSystem = createMarkerSystem(markerInternals, internals, largestUnitIndex) - return roundRelativeDuration( - ...spanDuration(internals, largestUnitIndex, ...markerSystem), - largestUnitIndex, - smallestUnitIndex, - roundingMode, - roundingIncrement, - ...markerSystem, + return createDuration( + roundRelativeDuration( + ...spanDuration(internals, largestUnitIndex, ...markerSystem), + largestUnitIndex, + smallestUnitIndex, + roundingMode, + roundingIncrement, + ...markerSystem, + ), ) }, diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index bcafd21e..d49825b3 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -2,7 +2,7 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { createTemporalClass, neverValueOf } from './class' import { diffEpochNano } from './diff' -import { toDurationInternals } from './duration' +import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { formatCalendar, @@ -20,10 +20,10 @@ import { } from './isoMath' import { compareLargeInts } from './largeInt' import { moveEpochNano } from './move' -import { refineRoundOptions, toEpochNano, toObject } from './options' +import { refineDiffOptions, refineRoundOptions, toEpochNano, toObject } from './options' import { roundLargeNano } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' -import { hourIndex } from './units' +import { hourIndex, secondsIndex } from './units' import { noop } from './utils' import { createZonedDateTime } from './zonedDateTime' @@ -102,19 +102,11 @@ export const [ }, until(epochNanoseconds, otherArg, options) { - return diffEpochNano( - epochNanoseconds, - toInstantEpochNanoseconds(otherArg), - options, // TODO: must be given better options??? - ) + return diffInstants(epochNanoseconds, toInstantEpochNanoseconds(otherArg), options) }, since(epochNanoseconds, otherArg, options) { - return diffEpochNano( - toInstantEpochNanoseconds(otherArg), - epochNanoseconds, - options, // TODO: reverse rounding option - ) + return diffInstants(toInstantEpochNanoseconds(otherArg), epochNanoseconds, options, true) }, round(epochNanoseconds, options) { @@ -182,6 +174,16 @@ function stringToEpochNanoseconds(str) { // TODO } +function diffInstants(epochNano0, epochNano1, options, roundingModeInvert) { + return createDuration( + diffEpochNano( + epochNano0, + epochNano1, + ...refineDiffOptions(roundingModeInvert, options, secondsIndex, hourIndex), + ), + ) +} + // Unit Conversion // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index f5454242..20210436 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -84,6 +84,7 @@ export function roundDayTimeDuration( ) { const largeNano = durationFieldsToNano(durationFields) const r = roundLargeNano(largeNano, smallestUnitIndex, roundingMode, roundingIncrement) + return { ...durationFieldDefaults, ...nanoToDurationFields(r), diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js index aa02f3a0..054aab0c 100644 --- a/packages/temporal-polyfill/src/new/units.js +++ b/packages/temporal-polyfill/src/new/units.js @@ -4,7 +4,7 @@ import { mapArrayToProps } from './utils' export const nanoIndex = 0 export const microIndex = 1 export const milliIndex = 2 -export const secondsIndex = 3 +export const secondsIndex = 3 // secondIndex export const minuteIndex = 4 export const hourIndex = 5 export const dayIndex = 6 From 4a1fa35ac2bf149182f4e215420dbe0346eb1b78 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 15 Jun 2023 15:21:13 -0400 Subject: [PATCH 107/805] fix toString/rounding --- packages/temporal-polyfill/src/new/diff.js | 15 +- .../temporal-polyfill/src/new/duration.js | 9 +- packages/temporal-polyfill/src/new/instant.js | 60 +++--- .../temporal-polyfill/src/new/isoFormat.js | 71 ++++--- packages/temporal-polyfill/src/new/options.js | 71 +++++-- .../temporal-polyfill/src/new/plainDate.js | 4 +- .../src/new/plainDateTime.js | 17 +- .../temporal-polyfill/src/new/plainTime.js | 12 +- packages/temporal-polyfill/src/new/round.js | 173 ++++++++++-------- .../temporal-polyfill/src/new/timeZone.js | 4 +- .../src/new/zonedDateTime.js | 28 +-- 11 files changed, 263 insertions(+), 201 deletions(-) diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index edfb5ede..3a318da4 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -13,7 +13,7 @@ import { } from './isoMath' import { compareLargeInts } from './largeInt' import { moveDateByDays, moveDateTime, moveZonedEpochNano } from './move' -import { roundLargeNano, roundNano, roundRelativeDuration } from './round' +import { computeNanoInc, roundByInc, roundByIncLarge, roundRelativeDuration } from './round' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { dayIndex, milliInDay, @@ -164,12 +164,8 @@ export function diffTimes( ) { const startTimeNano = isoTimeFieldsToNano(startIsoFields) const endTimeNano = isoTimeFieldsToNano(endIsoFields) - const timeNano = roundNano( - endTimeNano - startTimeNano, - smallestUnitIndex, - roundingMode, - roundingIncrement, - ) + const nanoInc = computeNanoInc(smallestUnitIndex, roundingIncrement) + const timeNano = roundByInc(endTimeNano - startTimeNano, nanoInc, roundingMode) return { ...durationFieldDefaults, @@ -246,11 +242,10 @@ export function diffEpochNano( return { ...durationFieldDefaults, ...nanoToDurationFields( - roundLargeNano( + roundByIncLarge( endEpochNano.addLargeInt(startEpochNano, -1), - smallestUnitIndex, + computeNanoInc(smallestUnitIndex, roundingIncrement), roundingMode, - roundingIncrement, ), largestUnitIndex, ), diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 7b3b23eb..a430ee02 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -22,6 +22,7 @@ import { } from './options' import { roundDayTimeDuration, + roundDurationToNano, roundRelativeDuration, totalDayTimeDuration, totalRelativeDuration, @@ -165,7 +166,13 @@ export const [ }, toString(internals, options) { - return formatDurationInternals(internals, ...refineTimeDisplayOptions(options)) + const [nanoInc, roundingMode, showSecond, subsecDigits] = refineTimeDisplayOptions(options) + + return formatDurationInternals( + roundDurationToNano(internals, nanoInc, roundingMode), + showSecond, + subsecDigits, + ) }, valueOf: neverValueOf, diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index d49825b3..c536c6c3 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -4,12 +4,7 @@ import { createTemporalClass, neverValueOf } from './class' import { diffEpochNano } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' -import { - formatCalendar, - formatIsoDateTimeFields, - formatOffsetNanoseconds, - formatTimeZone, -} from './isoFormat' +import { formatIsoDateTimeFields, formatOffsetNano } from './isoFormat' import { epochGetters, epochMicroToNano, @@ -20,8 +15,14 @@ import { } from './isoMath' import { compareLargeInts } from './largeInt' import { moveEpochNano } from './move' -import { refineDiffOptions, refineRoundOptions, toEpochNano, toObject } from './options' -import { roundLargeNano } from './round' +import { + refineDiffOptions, + refineInstantDisplayOptions, + refineRoundOptions, + toEpochNano, + toObject, +} from './options' +import { computeNanoInc, roundByIncLarge } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { hourIndex, secondsIndex } from './units' import { noop } from './utils' @@ -109,12 +110,11 @@ export const [ return diffInstants(toInstantEpochNanoseconds(otherArg), epochNanoseconds, options, true) }, - round(epochNanoseconds, options) { + round(epochNano, options) { + const [smallestUnitI, roundingModeI, roundingInc] = refineRoundOptions(options, hourIndex) + return createInstant( - roundLargeNano( - epochNanoseconds, - ...refineRoundOptions(options, hourIndex), - ), + roundByIncLarge(epochNano, computeNanoInc(smallestUnitI, roundingInc), roundingModeI), ) }, @@ -125,24 +125,22 @@ export const [ ) }, - toString(epochNanoseconds, options) { // has rounding options too - const refinedOptions = toObject(options) // TODO: make optional - // ^important for destructuring options because used once for rounding, second for formatting - - const calendar = queryCalendarOps(refinedOptions.calendar || isoCalendarId) - const timeZone = queryTimeZoneOps(refinedOptions.timeZone || utcTimeZoneId) - - epochNanoseconds = roundLargeNano( - epochNanoseconds, - refinedOptions, // TODO: break apart options - ) - const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) - const isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) - - return formatIsoDateTimeFields(isoDateTimeFields, refinedOptions) + - formatOffsetNanoseconds(offsetNanoseconds) + - formatTimeZone(timeZone, options) + - formatCalendar(calendar, options) + toString(epochNano, options) { + const [ + timeZoneArg, + nanoInc, + roundingModeI, + showSecond, + subsecDigits, + ] = refineInstantDisplayOptions(options) + const timeZone = queryTimeZoneOps(timeZoneArg || utcTimeZoneId) + + epochNano = roundByIncLarge(epochNano, nanoInc, roundingModeI) + const offsetNano = timeZone.getOffsetNanosecondsFor(epochNano) + const isoFields = epochNanoToIso(epochNano.addNumber(offsetNano)) + + return formatIsoDateTimeFields(isoFields, showSecond, subsecDigits) + + formatOffsetNano(offsetNano) }, toLocaleString(epochNanoseconds, locales, options) { diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.js index e70bc58c..d980f066 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -1,77 +1,74 @@ import { isoCalendarId } from './calendarConfig' import { getObjId } from './class' -import { refineDateDisplayOptions } from './options' +import { alwaysI, autoI, criticalI, refineDateDisplayOptions } from './options' +/* +High-level. Refined options +*/ export function formatPossibleDate(internals, options, formatSimple) { - const calendarDisplay = refineDateDisplayOptions(options) + const calendarDisplayI = refineDateDisplayOptions(options) const showCalendar = - calendarDisplay === 'always' || // TODO: use indexes - calendarDisplay === 'critical' || + calendarDisplayI === alwaysI || // TODO: use math >=< comparisons? + calendarDisplayI === criticalI || getObjId(internals.calendar) !== isoCalendarId if (showCalendar) { - return formatIsoDateFields(internals) + - formatCalendarWithSingleOpt(internals.calendar, calendarDisplay) + return formatIsoDateFields(internals) + formatCalendar(internals.calendar, calendarDisplayI) } else { return formatSimple(internals) } } -export function formatIsoDateTimeFields( - isoDateTimeFields, - options, // TODO: use spread args -) { - return formatIsoDateFields(isoDateTimeFields) + - 'T' + formatIsoTimeFields(isoDateTimeFields, options) -} +/* +Rounding already happened with these... +*/ export function formatIsoDateFields(isoDateFields) { - } export function formatIsoYearMonthFields(isoDateFields) { - } export function formatIsoMonthDayFields(isoDateFields) { +} +export function formatIsoDateTimeFields( + isoDateTimeFields, + showSecond, + subsecDigits, +) { + return formatIsoDateFields(isoDateTimeFields) + + 'T' + formatIsoTimeFields(isoDateTimeFields, showSecond, subsecDigits) } export function formatIsoTimeFields( isoTimeFields, - options, // TODO: use spread args + showSecond, + subsecDigits, ) { - // smallestUnit will be <= MINUTE (meaning minute ALWAYS displayed) } -export function formatOffsetNanoseconds( - offsetNanoseconds, - options, // TODO: use spread args +export function formatDurationInternals( + durationInternals, + showSecond, + subsecDigits, ) { - } -export function formatTimeZone( - timeZoneProtocol, - options, // TODO: use spread args +export function formatOffsetNano( + offsetNanoseconds, + offsetDisplayI = autoI, // auto/never ) { - } -export function formatCalendar( - calendarProtocol, - options, // TODO: use spread args +export function formatTimeZone( + timeZoneOps, + timeZoneDisplayI, ) { - return formatCalendarWithSingleOpt(calendarProtocol, refineDateDisplayOptions(options)) } -function formatCalendarWithSingleOpt(calendarProtocol, calendarNameOptIndex) { - -} - -export function formatDurationInternals( - durationInternals, - options, // TODO: use spread args +export function formatCalendar( + calendarOps, + calendarDisplayI, ) { - } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 1d6b96e6..20e169cb 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,6 +1,6 @@ import { durationFieldIndexes } from './durationFields' import { bigIntToLargeInt } from './largeInt' -import { dayIndex, minuteIndex, nanoIndex, unitIndexes, yearIndex } from './units' +import { dayIndex, minuteIndex, nanoIndex, unitIndexToNano, unitIndexes, yearIndex } from './units' import { clamp, hasAnyMatchingProps, isObjectLike } from './utils' // TODO: ensure all callers use *INDEXES* @@ -48,12 +48,15 @@ export function refineDiffOptions( return [largestUnitI, smallestUnitI, roundingMode, roundingIncrement] } +/* +Always related to time +*/ export function refineRoundOptions(options, maxUnitI = dayIndex) { options = normalizeRequiredOptions(options, smallestUnitStr) const smallestUnitI = refineSmallestUnit(options, maxUnitI) // required return [ smallestUnitI, - refineRoundingMode(options, halfExpandI), + refineRoundingMode(options, halfExpandI), // TODO: switch order of mode/inc EVERYWHERE? refineRoundingInc(options, smallestUnitI), ] } @@ -71,7 +74,7 @@ export function refineDurationRoundOptions(options, defaultLargestUnitI) { export function refineTotalOptions(options) { options = normalizeRequiredOptions(options, totalUnitStr) return [ - refineTotalUnit(options), + refineTotalUnit(options), // required refineRelativeTo(options), ] } @@ -80,13 +83,21 @@ export function refineRelativeToOptions(options) { return refineRelativeTo(normalizeOptions(options)) } +export function refineInstantDisplayOptions(options) { + options = normalizeOptions(options) + return [ + options.timeZone, + ...refineTimeDisplayTuple(options), + ] +} + export function refineZonedDateTimeDisplayOptions(options) { options = normalizeOptions(options) return [ refineCalendarDisplay(options), refineTimeZoneDisplay(options), refineOffsetDisplay(options), - ...refineTimeDisplayTuple(options), // BAD: this is being misused + ...refineTimeDisplayTuple(options), ] } @@ -94,7 +105,7 @@ export function refineDateTimeDisplayOptions(options) { options = normalizeOptions(options) return [ refineCalendarDisplay(options), - ...refineTimeDisplayTuple(options), // BAD: this is being misused + ...refineTimeDisplayTuple(options), ] } @@ -103,20 +114,35 @@ export function refineDateDisplayOptions(options) { } export function refineTimeDisplayOptions(options) { - return refineTimeDisplayTuple(normalizeOptions(options)) // BAD: this is being misused + return refineTimeDisplayTuple(normalizeOptions(options)) } +/* +returns [ + nanoInc, + roundingMode, + showSecond, + subsecDigits, +] +*/ function refineTimeDisplayTuple(options) { + const smallestUnitI = refineSmallestUnit(options, minuteIndex, nanoIndex, -1) + if (smallestUnitI !== -1) { + return [ + unitIndexToNano[smallestUnitI], + refineRoundingMode(options), + smallestUnitI < minuteIndex, // showSecond + 9 - (smallestUnitI * 3), // subsecDigits (callers should guard for <0) + ] + } + + const subsecDigits = refineSubsecDigits(options) return [ - refineSubsecDigits(options), - refineSmallestUnit(options, minuteIndex), + Math.pow(10, 9 - subsecDigits), // TODO: use 10** notation? refineRoundingMode(options), + true, // showSecond + subsecDigits, ] - /* - smallestUnit takes precedence - (if smallestUnit not given, treat as nano) - will need to conver to an `inc` - search `Math.pow(10, 9` - */ } // Single Options @@ -243,10 +269,20 @@ function refineRoundingInc(options, validateWithSmallestUnitI) { */ } +const subsecDigitsName = 'fractionalSecondDigits' + function refineSubsecDigits(options) { - // 'fractionalSecondDigits' - // 'auto'/0-9 - // allow undefined + const subsecDigits = options[subsecDigitsName] + + if (typeof subsecDigits === 'number') { + return clamp(Math.floor(subsecDigits), 0, 9, 1, subsecDigitsName) // 1=throwOnError + } + + if (String(subsecDigits) !== 'auto') { + throw new RangeError('Must be auto or 0-9') + } + + return 9 } function refineRelativeTo(options) { @@ -258,6 +294,9 @@ function refineRelativeTo(options) { // Utils // ------------------------------------------------------------------------------------------------- +/* +If defaultUnitI is undefined, will throw error if not specified +*/ function refineUnitOption(optionName, options, maxUnitI, minUnitI = nanoIndex, defaultUnitI) { let unitName = options[optionName] if (unitName === undefined) { diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index 08193c1a..de4ed340 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -25,7 +25,7 @@ import { import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoDateTimeFields } from './isoMath' import { parsePlainDate } from './isoParse' -import { refineDiffOptions, refineOverflowOptions } from './options' +import { refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' import { zonedInternalsToIso } from './timeZoneOps' @@ -120,7 +120,7 @@ export const [ toString(internals, options) { return formatIsoDateFields(internals) + - formatCalendar(internals.calendar, options) + formatCalendar(internals.calendar, refineDateDisplayOptions(options)) }, toLocaleString: toLocaleStringMethod, diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index d36a404b..4ccb36b4 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -32,7 +32,7 @@ import { } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainTime, toPlainTimeInternals } from './plainTime' -import { roundIsoDateTimeFields } from './round' +import { roundDateTime, roundDateTimeToNano } from './round' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' import { dayIndex } from './units' import { createZonedDateTime } from './zonedDateTime' @@ -150,7 +150,7 @@ export const [ }, round(internals, options) { - const isoDateTimeFields = roundIsoDateTimeFields( + const isoDateTimeFields = roundDateTime( internals, ...refineRoundOptions(options), ) @@ -168,10 +168,17 @@ export const [ }, toString(internals, options) { - const [calendarDisplayI, ...timeDisplayTuple] = refineDateTimeDisplayOptions(options) - const roundedIsoFields = roundIsoDateTimeFields(internals, ...timeDisplayTuple) + const [ + calendarDisplayI, + nanoInc, + roundingMode, + showSecond, + subsecDigits, + ] = refineDateTimeDisplayOptions(options) - return formatIsoDateTimeFields(roundedIsoFields, ...timeDisplayTuple) + + const roundedIsoFields = roundDateTimeToNano(internals, nanoInc, roundingMode) + + return formatIsoDateTimeFields(roundedIsoFields, showSecond, subsecDigits) + formatCalendar(internals.calendar, calendarDisplayI) }, diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index d63e502b..410a5bd7 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -21,7 +21,7 @@ import { } from './options' import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' -import { roundIsoTimeFields } from './round' +import { roundTime, roundTimeToNano } from './round' import { zonedInternalsToIso } from './timeZoneOps' import { hourIndex } from './units' @@ -102,7 +102,7 @@ export const [ round(internals, options) { return createPlainTime( - roundIsoTimeFields(internals, ...refineRoundOptions(options, hourIndex)), + roundTime(internals, ...refineRoundOptions(options, hourIndex)), ) }, @@ -112,10 +112,12 @@ export const [ }, toString(internals, options) { - const timeDisplayTuple = refineTimeDisplayOptions(options) + const [nanoInc, roundingMode, showSecond, subsecDigits] = refineTimeDisplayOptions(options) + return formatIsoTimeFields( - roundIsoTimeFields(internals, ...timeDisplayTuple), - ...timeDisplayTuple, + roundTimeToNano(internals, nanoInc, roundingMode), + showSecond, + subsecDigits, ) }, diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 20210436..4a3750c4 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -21,56 +21,66 @@ export function roundToMinute(epochNano) { // Rounding Dates // ------------------------------------------------------------------------------------------------- -export function roundIsoDateTimeFields( - isoDateTimeFields, - smallestUnitIndex, // day/time +export function roundDateTime( + isoFields, + smallestUnitI, // day/time roundingMode, - roundingIncrement, + roundingInc, timeZoneOps = undefined, ) { - let isoTimeFields - let dayDelta - - if (smallestUnitIndex === dayIndex) { - const nanoInDay = timeZoneOps - ? computeNanosecondsInDay(timeZoneOps, isoDateTimeFields) - : nanoInUtcDay - - dayDelta = roundWithDivisor( - isoTimeFieldsToNano(isoDateTimeFields), - nanoInDay, - roundingMode, - ) - - isoTimeFields = isoTimeFieldDefaults - } else { - ([isoTimeFields, dayDelta] = roundIsoTimeFields( - isoDateTimeFields, - smallestUnitIndex, - roundingMode, - roundingIncrement, - )) + if (smallestUnitI === dayIndex) { + return roundDateTimeToDay(isoFields, timeZoneOps, roundingMode) } - return { - ...moveDateByDays(isoDateTimeFields, dayDelta), - ...isoTimeFields, - } + return roundDateTimeToNano( + isoFields, + computeNanoInc(smallestUnitI, roundingInc), + roundingMode, + ) } -export function roundIsoTimeFields( - isoTimeFields, - smallestUnitIndex, +export function roundTime( + isoFields, + smallestUnitI, roundingMode, - roundingIncrement, + roundingInc, ) { - const timeNano = roundNano( - isoTimeFieldsToNano(isoTimeFields), - smallestUnitIndex, + return roundTimeToNano( + isoFields, + computeNanoInc(smallestUnitI, roundingInc), roundingMode, - roundingIncrement, ) - return nanoToIsoTimeAndDay(timeNano) +} + +function roundDateTimeToDay(isoFields, timeZoneOps, roundingMode) { + const nanoInDay = timeZoneOps + ? computeNanosecondsInDay(timeZoneOps, isoFields) + : nanoInUtcDay + + const dayDelta = roundByInc( + isoTimeFieldsToNano(isoFields), + nanoInDay, + roundingMode, + ) + + return { + ...moveDateByDays(isoFields, dayDelta), + ...isoTimeFieldDefaults, + } +} + +export function roundDateTimeToNano(isoFields, nanoInc, roundingMode) { + const [roundedIsoFields, dayDelta] = roundTimeToNano(isoFields, nanoInc, roundingMode) + return { + ...moveDateByDays(roundedIsoFields, dayDelta), + ...roundedIsoFields, + } +} + +export function roundTimeToNano(isoFields, nanoInc, roundingMode) { + return nanoToIsoTimeAndDay( + roundByInc(isoTimeFieldsToNano(isoFields), nanoInc, roundingMode), + ) } // Rounding Duration @@ -78,16 +88,24 @@ export function roundIsoTimeFields( export function roundDayTimeDuration( durationFields, - smallestUnitIndex, + smallestUnitI, roundingMode, - roundingIncrement, + roundingInc, ) { + return roundDurationToNano( + durationFields, + computeNanoInc(smallestUnitI, roundingInc), + roundingMode, + ) +} + +export function roundDurationToNano(durationFields, nanoInc, roundingMode) { const largeNano = durationFieldsToNano(durationFields) - const r = roundLargeNano(largeNano, smallestUnitIndex, roundingMode, roundingIncrement) + const roundedLargeNano = roundByIncLarge(largeNano, nanoInc, roundingMode) return { ...durationFieldDefaults, - ...nanoToDurationFields(r), + ...nanoToDurationFields(roundedLargeNano), } } @@ -96,20 +114,20 @@ export function roundRelativeDuration( // ^has sign endEpochNanoseconds, largestUnitIndex, - smallestUnitIndex, + smallestUnitI, roundingMode, - roundingIncrement, + roundingInc, // marker system... marker, markerToEpochMilliseconds, moveMarker, ) { - if (smallestUnitIndex === nanoIndex && roundingIncrement === 1) { + if (smallestUnitI === nanoIndex && roundingInc === 1) { return durationFields } let [roundedDurationFields, roundedEpochNanoseconds, grew] = ( - smallestUnitIndex >= dayIndex + smallestUnitI >= dayIndex ? nudgeRelativeDuration : markerToEpochMilliseconds === identityFunc // marker is ZonedDateTime's epochNanoseconds? ? nudgeRelativeDurationTime @@ -117,9 +135,9 @@ export function roundRelativeDuration( )( durationFields, endEpochNanoseconds, - smallestUnitIndex, + smallestUnitI, roundingMode, - roundingIncrement, + roundingInc, // marker system only needed for nudgeRelativeDuration... marker, moveMarker, @@ -132,7 +150,7 @@ export function roundRelativeDuration( roundedDurationFields, roundedEpochNanoseconds, largestUnitIndex, - smallestUnitIndex, + smallestUnitI, // marker system... marker, moveMarker, @@ -146,22 +164,17 @@ export function roundRelativeDuration( // Rounding Numbers // ------------------------------------------------------------------------------------------------- -export function roundLargeNano(largeNano, smallestUnitIndex, roundingMode, roundingIncrement) { - const divisor = unitIndexToNano[smallestUnitIndex] * roundingIncrement - const [fullUnits, remainder] = largeNano.divTruncMod(divisor) - return fullUnits.mult(divisor).addNumber(roundWithMode(remainder / divisor, roundingMode)) +export function computeNanoInc(smallestUnitI, roundingInc) { + return unitIndexToNano[smallestUnitI] * roundingInc } -export function roundNano(nano, smallestUnitIndex, roundingMode, roundingIncrement) { - return roundWithDivisor( - nano, - unitIndexToNano[smallestUnitIndex] * roundingIncrement, - roundingMode, - ) +export function roundByInc(num, inc, roundingMode) { + return roundWithMode(num / inc, roundingMode) * inc } -function roundWithDivisor(num, divisor, roundingMode) { - return roundWithMode(num / divisor, roundingMode) * divisor +export function roundByIncLarge(largeInt, inc, roundingMode) { + const [whole, remainder] = largeInt.divTruncMod(inc) + return whole.mult(inc).addNumber(roundWithMode(remainder / inc, roundingMode)) } function roundWithMode(num, roundingMode) { @@ -218,12 +231,13 @@ and return the (day) delta. Also return the (potentially) unbalanced new duratio function nudgeDurationTime( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, // NOT NEEDED, just for adding result to - smallestUnitIndex, + smallestUnitI, roundingMode, - roundingIncrement, + roundingInc, ) { const timeNano = durationFieldsToTimeNano(durationFields) - const roundedTimeNano = roundNano(timeNano, smallestUnitIndex, roundingMode, roundingIncrement) + const nanoInc = computeNanoInc(smallestUnitI, roundByInc) + const roundedTimeNano = roundByInc(timeNano, nanoInc, roundingMode) const roundedFields = nanoToDurationFields(roundedTimeNano) const dayDelta = roundedFields.days const nudgedDurationFields = { // TODO: what about sign? @@ -242,9 +256,9 @@ function nudgeDurationTime( function nudgeRelativeDurationTime( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, // NOT NEEDED, just for conformance - smallestUnitIndex, + smallestUnitI, roundingMode, - roundingIncrement, + roundingInc, // marker system... marker, markerToEpochMilliseconds, @@ -252,7 +266,8 @@ function nudgeRelativeDurationTime( ) { const { sign } = durationFields const timeNano = durationFieldsToTimeNano(durationFields) - let roundedTimeNano = roundNano(timeNano, smallestUnitIndex, roundingMode, roundingIncrement) + const nanoInc = computeNanoInc(smallestUnitI, roundingInc) + let roundedTimeNano = roundByInc(timeNano, nanoInc, roundingMode) const [dayEpochNanoseconds0, dayEpochNanoseconds1] = clampRelativeDuration( { ...durationFields, ...durationTimeFieldDefaults }, @@ -270,7 +285,7 @@ function nudgeRelativeDurationTime( if (!beyondDay || Math.sign(beyondDay) === sign) { dayDelta++ - roundedTimeNano = roundNano(beyondDay, smallestUnitIndex, roundingMode, roundingIncrement) + roundedTimeNano = roundByInc(beyondDay, nanoInc, roundingMode) endEpochNanoseconds = dayEpochNanoseconds1.addNumber(roundedTimeNano) } else { endEpochNanoseconds = dayEpochNanoseconds0.addNumber(roundedTimeNano) @@ -289,9 +304,9 @@ function nudgeRelativeDurationTime( function nudgeRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, - smallestUnitIndex, + smallestUnitI, roundingMode, - roundingIncrement, + roundingInc, // marker system... marker, markerToEpochMilliseconds, @@ -302,17 +317,17 @@ function nudgeRelativeDuration( const baseDurationFields = clearDurationFields( durationFields, nanoIndex, - smallestUnitIndex - 1, + smallestUnitI - 1, ) - baseDurationFields[smallestUnitIndex] = Math.trunc( - durationFields[smallestUnitIndex] / roundingIncrement, + baseDurationFields[smallestUnitI] = Math.trunc( + durationFields[smallestUnitI] / roundingInc, ) const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( baseDurationFields, - smallestUnitIndex, - roundingIncrement * sign, + smallestUnitI, + roundingInc * sign, // marker system... marker, markerToEpochMilliseconds, @@ -326,7 +341,7 @@ function nudgeRelativeDuration( const roundedPortion = roundWithMode(portion * sign, roundingMode) // -1/0/1 if (roundedPortion) { // enlarged? - baseDurationFields[smallestUnitIndex] += roundingIncrement * sign + baseDurationFields[smallestUnitI] += roundingInc * sign return [baseDurationFields, epochNanoseconds1, roundedPortion] } else { @@ -341,7 +356,7 @@ function bubbleRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, largestUnitIndex, - smallestUnitIndex, + smallestUnitI, // marker system... marker, markerToEpochMilliseconds, @@ -350,7 +365,7 @@ function bubbleRelativeDuration( const { sign } = durationFields for ( - let currentUnitIndex = smallestUnitIndex + 1; + let currentUnitIndex = smallestUnitI + 1; currentUnitIndex < largestUnitIndex; currentUnitIndex++ ) { diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index f97de86c..b43aed54 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -4,7 +4,7 @@ import { queryCalendarOps } from './calendarOps' import { createTemporalClass, getObjId, idGetters } from './class' import { refineComplexBag } from './convert' import { createInstant, toInstantEpochNanoseconds } from './instant' -import { formatOffsetNanoseconds } from './isoFormat' +import { formatOffsetNano } from './isoFormat' import { parseTimeZoneId } from './isoParse' import { refineEpochDisambigOptions } from './options' import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' @@ -53,7 +53,7 @@ export const [TimeZone, createTimeZone] = createTemporalClass( ...timeZoneProtocolMethods, getOffsetStringFor(impl, instantArg) { - return formatOffsetNanoseconds(getImplOffsetNanosecondsFor(impl, instantArg)) + return formatOffsetNano(getImplOffsetNanosecondsFor(impl, instantArg)) }, getPlainDateTimeFor(impl, instantArg, calendarArg) { diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 8b3b04d8..dde6821d 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -22,7 +22,7 @@ import { import { formatCalendar, formatIsoDateTimeFields, - formatOffsetNanoseconds, + formatOffsetNano, formatTimeZone, } from './isoFormat' import { @@ -43,7 +43,7 @@ import { import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { createPlainTime, toPlainTimeInternals } from './plainTime' -import { roundIsoDateTimeFields } from './round' +import { roundDateTime, roundDateTimeToNano } from './round' import { computeNanosecondsInDay, getCommonTimeZoneOps, @@ -116,7 +116,7 @@ export const [ }, offset(internals) { - return formatOffsetNanoseconds( + return formatOffsetNano( // TODO: more DRY zonedInternalsToIso(internals).offsetNanoseconds, ) @@ -222,13 +222,16 @@ export const [ return diffZonedDateTimes(toZonedDateTimeInternals(otherArg), internals, options, true) }, + /* + Do param-list destructuring here and other methods! + */ round(internals, options) { let { epochNanoseconds, timeZone, calendar } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) let isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) - isoDateTimeFields = roundIsoDateTimeFields( + isoDateTimeFields = roundDateTime( isoDateTimeFields, ...refineRoundOptions(options), timeZone, @@ -289,17 +292,16 @@ export const [ calendarDisplayI, timeZoneDisplayI, offsetDisplayI, - ...timeDisplayTuple + nanoInc, + roundingMode, + showSecond, + subsecDigits, ] = refineZonedDateTimeDisplayOptions(options) let offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) let isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) - isoDateTimeFields = roundIsoDateTimeFields( - isoDateTimeFields, - ...timeDisplayTuple, - timeZone, - ) + isoDateTimeFields = roundDateTimeToNano(isoDateTimeFields, nanoInc, roundingMode) epochNanoseconds = getMatchingInstantFor( isoDateTimeFields, timeZone, @@ -314,8 +316,8 @@ export const [ offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) - return formatIsoDateTimeFields(isoDateTimeFields, ...timeDisplayTuple) + - formatOffsetNanoseconds(offsetNanoseconds, offsetDisplayI) + + return formatIsoDateTimeFields(isoDateTimeFields, showSecond, subsecDigits) + + formatOffsetNano(offsetNanoseconds, offsetDisplayI) + formatTimeZone(timeZone, timeZoneDisplayI) + formatCalendar(calendar, calendarDisplayI) }, @@ -356,7 +358,7 @@ export const [ // maintain alphabetical order calendar: getPublicIdOrObj(internals.calendar), ...pluckIsoDateTimeInternals(zonedInternalsToIso(internals)), - offset: formatOffsetNanoseconds( + offset: formatOffsetNano( // TODO: more DRY zonedInternalsToIso(internals).offsetNanoseconds, ), From 1a52bb7f4d8d0ac4f46ae273b7132b8cdc27e812 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 15 Jun 2023 15:33:52 -0400 Subject: [PATCH 108/805] more natural roundingMode/roundingInc order --- packages/temporal-polyfill/src/new/diff.js | 22 +++++++++---------- .../temporal-polyfill/src/new/duration.js | 4 ++-- packages/temporal-polyfill/src/new/instant.js | 2 +- packages/temporal-polyfill/src/new/options.js | 9 +++++--- packages/temporal-polyfill/src/new/round.js | 18 +++++++-------- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.js index 3a318da4..610db164 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.js @@ -32,8 +32,8 @@ export function diffDateTimes( endIsoFields, largestUnitIndex, smallestUnitIndex, // TODO: nanoDivisor - roundingMode, roundingIncrement, + roundingMode, ) { const startEpochNano = isoToEpochNano(startIsoFields) const endEpochNano = isoToEpochNano(endIsoFields) @@ -44,8 +44,8 @@ export function diffDateTimes( endEpochNano, largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, ) } @@ -73,8 +73,8 @@ export function diffDateTimes( endEpochNano, largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, startIsoFields, // marker isoToEpochNano, // markerToEpochNano moveDateTime.bind(undefined, calendar), // moveMarker @@ -87,8 +87,8 @@ export function diffDates( endIsoFields, largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, ) { if (largestUnitIndex < dayIndex) { return diffEpochNano( @@ -96,8 +96,8 @@ export function diffDates( isoToEpochNano(endIsoFields), largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, ) } @@ -108,8 +108,8 @@ export function diffDates( isoToEpochNano(endIsoFields), largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, startIsoFields, // marker isoToEpochNano, // markerToEpochNano calendar.dateAdd.bind(calendar), // moveMarker @@ -159,8 +159,8 @@ export function diffTimes( endIsoFields, largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, ) { const startTimeNano = isoTimeFieldsToNano(startIsoFields) const endTimeNano = isoTimeFieldsToNano(endIsoFields) @@ -183,8 +183,8 @@ export function diffZonedEpochNano( endEpochNano, largestUnitIndex, smallestUnitIndex, // optional. internally will default to 'nanoseconds' - roundingMode, // optional. internally will default to 'halfExpand' roundingIncrement, // optional. internally will default to 1 + roundingMode, // optional. internally will default to 'halfExpand' ) { if (largestUnitIndex < dayIndex) { return diffEpochNano( @@ -192,8 +192,8 @@ export function diffZonedEpochNano( endEpochNano, largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, ) } @@ -223,8 +223,8 @@ export function diffZonedEpochNano( endEpochNano, largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, startEpochNano, // marker identityFunc, // markerToEpochNano moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker @@ -236,8 +236,8 @@ export function diffEpochNano( endEpochNano, largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, ) { return { ...durationFieldDefaults, diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index a430ee02..1b591561 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -122,7 +122,7 @@ export const [ if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { // TODO: check internals doesn't have large fields return createDuration( - roundDayTimeDuration(internals, smallestUnitIndex, roundingMode, roundingIncrement), + roundDayTimeDuration(internals, smallestUnitIndex, roundingIncrement, roundingMode), ) } @@ -137,8 +137,8 @@ export const [ ...spanDuration(internals, largestUnitIndex, ...markerSystem), largestUnitIndex, smallestUnitIndex, - roundingMode, roundingIncrement, + roundingMode, ...markerSystem, ), ) diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index c536c6c3..ef4f84af 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -111,7 +111,7 @@ export const [ }, round(epochNano, options) { - const [smallestUnitI, roundingModeI, roundingInc] = refineRoundOptions(options, hourIndex) + const [smallestUnitI, roundingInc, roundingModeI] = refineRoundOptions(options, hourIndex) return createInstant( roundByIncLarge(epochNano, computeNanoInc(smallestUnitI, roundingInc), roundingModeI), diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 20e169cb..cfc58897 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -40,12 +40,15 @@ export function refineDiffOptions( Math.max(smallestUnitI, minUnitI), Math.max(smallestUnitI, defaultLargestUnitI), ) + + const roundingIncrement = refineRoundingInc(options, smallestUnitI) + let roundingMode = refineRoundingMode(options) if (roundingModeInvert) { roundingMode = invertRoundingMode(roundingMode) } - const roundingIncrement = refineRoundingInc(options, smallestUnitI) - return [largestUnitI, smallestUnitI, roundingMode, roundingIncrement] + + return [largestUnitI, smallestUnitI, roundingIncrement, roundingMode] } /* @@ -56,8 +59,8 @@ export function refineRoundOptions(options, maxUnitI = dayIndex) { const smallestUnitI = refineSmallestUnit(options, maxUnitI) // required return [ smallestUnitI, - refineRoundingMode(options, halfExpandI), // TODO: switch order of mode/inc EVERYWHERE? refineRoundingInc(options, smallestUnitI), + refineRoundingMode(options, halfExpandI), ] } diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 4a3750c4..3bff8354 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -24,8 +24,8 @@ export function roundToMinute(epochNano) { export function roundDateTime( isoFields, smallestUnitI, // day/time - roundingMode, roundingInc, + roundingMode, timeZoneOps = undefined, ) { if (smallestUnitI === dayIndex) { @@ -42,8 +42,8 @@ export function roundDateTime( export function roundTime( isoFields, smallestUnitI, - roundingMode, roundingInc, + roundingMode, ) { return roundTimeToNano( isoFields, @@ -89,8 +89,8 @@ export function roundTimeToNano(isoFields, nanoInc, roundingMode) { export function roundDayTimeDuration( durationFields, smallestUnitI, - roundingMode, roundingInc, + roundingMode, ) { return roundDurationToNano( durationFields, @@ -115,8 +115,8 @@ export function roundRelativeDuration( endEpochNanoseconds, largestUnitIndex, smallestUnitI, - roundingMode, roundingInc, + roundingMode, // marker system... marker, markerToEpochMilliseconds, @@ -136,8 +136,8 @@ export function roundRelativeDuration( durationFields, endEpochNanoseconds, smallestUnitI, - roundingMode, roundingInc, + roundingMode, // marker system only needed for nudgeRelativeDuration... marker, moveMarker, @@ -232,11 +232,11 @@ function nudgeDurationTime( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, // NOT NEEDED, just for adding result to smallestUnitI, - roundingMode, roundingInc, + roundingMode, ) { const timeNano = durationFieldsToTimeNano(durationFields) - const nanoInc = computeNanoInc(smallestUnitI, roundByInc) + const nanoInc = computeNanoInc(smallestUnitI, roundingInc) const roundedTimeNano = roundByInc(timeNano, nanoInc, roundingMode) const roundedFields = nanoToDurationFields(roundedTimeNano) const dayDelta = roundedFields.days @@ -257,8 +257,8 @@ function nudgeRelativeDurationTime( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, // NOT NEEDED, just for conformance smallestUnitI, - roundingMode, roundingInc, + roundingMode, // marker system... marker, markerToEpochMilliseconds, @@ -305,8 +305,8 @@ function nudgeRelativeDuration( durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNanoseconds, smallestUnitI, - roundingMode, roundingInc, + roundingMode, // marker system... marker, markerToEpochMilliseconds, From 0288c75684489051b71d415d95e3644703271adf Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 15 Jun 2023 16:38:47 -0400 Subject: [PATCH 109/805] correct rounding inversion --- packages/temporal-polyfill/src/new/options.js | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index cfc58897..868f3ac9 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -43,7 +43,7 @@ export function refineDiffOptions( const roundingIncrement = refineRoundingInc(options, smallestUnitI) - let roundingMode = refineRoundingMode(options) + let roundingMode = refineRoundingMode(options, truncI) if (roundingModeInvert) { roundingMode = invertRoundingMode(roundingMode) } @@ -133,7 +133,7 @@ function refineTimeDisplayTuple(options) { if (smallestUnitI !== -1) { return [ unitIndexToNano[smallestUnitI], - refineRoundingMode(options), + refineRoundingMode(options, truncI), smallestUnitI < minuteIndex, // showSecond 9 - (smallestUnitI * 3), // subsecDigits (callers should guard for <0) ] @@ -142,7 +142,7 @@ function refineTimeDisplayTuple(options) { const subsecDigits = refineSubsecDigits(options) return [ Math.pow(10, 9 - subsecDigits), // TODO: use 10** notation? - refineRoundingMode(options), + refineRoundingMode(options, truncI), true, // showSecond subsecDigits, ] @@ -215,31 +215,37 @@ const refineOffsetDisplay = refineChoiceOption.bind(undefined, 'offset', [ 'never', ]) -export const truncI = 0 -export const floorI = 1 +export const floorI = 0 +export const halfFloorI = 1 export const ceilI = 2 -export const expandI = 3 -export const halfCeilI = 4 -export const halfFloorI = 5 -export const halfExpandI = 6 -export const halfTruncI = 7 +export const halfCeilI = 3 +export const truncI = 4 +export const halfTruncI = 5 +export const expandI = 6 +export const halfExpandI = 7 export const halfEvenI = 8 +/* +Caller should always supply default +*/ const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', [ - 'trunc', - 'halfTrunc', - 'expand', - 'halfExpand', // round() should override this as default - 'halfEven', - // ones that invert from floor/ceil... + // modes that get inverted (see invertRoundingMode) 'floor', 'halfFloor', 'ceil', 'halfCeil', + // other modes + 'trunc', // default for most things + 'halfTrunc', + 'expand', + 'halfExpand', // default for date/time::round() + 'halfEven', ]) function invertRoundingMode(roundingModeI) { - // TODO - // use numbers? + if (roundingModeI < 4) { + return (roundingModeI + 2) % 4 + } + return roundingModeI } function refineRoundingInc(options, validateWithSmallestUnitI) { @@ -278,7 +284,7 @@ function refineSubsecDigits(options) { const subsecDigits = options[subsecDigitsName] if (typeof subsecDigits === 'number') { - return clamp(Math.floor(subsecDigits), 0, 9, 1, subsecDigitsName) // 1=throwOnError + return clamp(Math.floor(subsecDigits), 0, 9, 1, subsecDigitsName) // throwOnError=1 } if (String(subsecDigits) !== 'auto') { From e4dc3df52fda8ec49e6efad61a00b7ebb3d1161f Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 15 Jun 2023 17:42:44 -0400 Subject: [PATCH 110/805] implement roundingMode --- .../temporal-polyfill/src/new/largeInt.js | 12 +++++--- packages/temporal-polyfill/src/new/options.js | 23 ++++++++++++++- packages/temporal-polyfill/src/new/round.js | 8 ++++- packages/temporal-polyfill/src/new/utils.js | 29 +++++++++++++++++++ 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.js index c2bb8327..49f85574 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.js @@ -35,14 +35,18 @@ export class LargeInt { } divTruncMod(divisor) { - let [fullUnits, remainder] = this.divFloorMod(divisor) + let [whole, remainder] = this.divFloorMod(divisor) - if (fullUnits.computeSign() === -1 && remainder) { - fullUnits = fullUnits.addNumber(1) + if (whole.computeSign() === -1 && remainder) { + whole = whole.addNumber(1) remainder -= divisor } - return [fullUnits, remainder] + return [whole, remainder] + } + + mod2() { + return (this.low % 2) * this.computeSign() } /* diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 868f3ac9..3228e929 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,7 +1,16 @@ import { durationFieldIndexes } from './durationFields' import { bigIntToLargeInt } from './largeInt' import { dayIndex, minuteIndex, nanoIndex, unitIndexToNano, unitIndexes, yearIndex } from './units' -import { clamp, hasAnyMatchingProps, isObjectLike } from './utils' +import { + clamp, + hasAnyMatchingProps, + isObjectLike, + roundExpand, + roundHalfCeil, + roundHalfEven, + roundHalfFloor, + roundHalfTrunc, +} from './utils' // TODO: ensure all callers use *INDEXES* @@ -241,6 +250,18 @@ const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', [ 'halfEven', ]) +export const roundingModeFuncs = [ + Math.floor, + roundHalfFloor, + Math.ceil, + roundHalfCeil, + Math.trunc, + roundHalfTrunc, + roundExpand, + Math.round, + roundHalfEven, +] + function invertRoundingMode(roundingModeI) { if (roundingModeI < 4) { return (roundingModeI + 2) % 4 diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 3bff8354..9641a9f2 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -10,6 +10,7 @@ import { import { isoTimeFieldDefaults } from './isoFields' import { isoTimeFieldsToNano, nanoToIsoTimeAndDay } from './isoMath' import { moveDateByDays } from './move' +import { roundingModeFuncs } from './options' import { computeNanosecondsInDay } from './timeZoneOps' import { dayIndex, nanoInUtcDay, nanoIndex, unitIndexToNano, weekIndex } from './units' import { identityFunc } from './utils' @@ -174,10 +175,15 @@ export function roundByInc(num, inc, roundingMode) { export function roundByIncLarge(largeInt, inc, roundingMode) { const [whole, remainder] = largeInt.divTruncMod(inc) - return whole.mult(inc).addNumber(roundWithMode(remainder / inc, roundingMode)) + const mod2 = whole.mod2() // workaround for halfEven + + return whole.mult(inc).addNumber( + roundWithMode((remainder / inc) + mod2, roundingMode) - mod2, + ) } function roundWithMode(num, roundingMode) { + return roundingModeFuncs[roundingMode](num) } // Total Duration diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 2bfccb80..a4e9a537 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -125,3 +125,32 @@ Works with BigInt or Number (as long as the same) export function floorMod(n, divisor) { return (n % divisor + divisor) % divisor } + +// rounding +// -------- + +export function roundExpand(n) { + return n < 0 ? Math.floor(n) : Math.ceil(n) +} + +export function roundHalfFloor(n) { + return hasHalf(n) ? Math.floor(n) : Math.round(n) +} + +export function roundHalfCeil(n) { + return hasHalf(n) ? Math.ceil(n) : Math.round(n) +} + +export function roundHalfTrunc(n) { + return hasHalf(n) ? Math.trunc(n) : Math.round(n) +} + +export function roundHalfEven(n) { + return hasHalf(n) + ? Math.trunc(n) + (n % 2) + : Math.round(n) +} + +function hasHalf(n) { + return n % 1 === 0.5 +} From a4c4ae95086d5bead6a54572b0d271dff75a5ec1 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 12:50:23 -0400 Subject: [PATCH 111/805] input-processing fixes --- .../temporal-polyfill/src/new/duration.js | 3 +- packages/temporal-polyfill/src/new/instant.js | 3 +- packages/temporal-polyfill/src/new/options.js | 37 +++++++++++++------ .../src/new/plainDateTime.js | 3 +- .../temporal-polyfill/src/new/plainTime.js | 3 +- packages/temporal-polyfill/src/new/utils.js | 8 ++-- .../src/new/zonedDateTime.js | 3 +- 7 files changed, 35 insertions(+), 25 deletions(-) diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index 1b591561..cac0b60b 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -166,11 +166,10 @@ export const [ }, toString(internals, options) { - const [nanoInc, roundingMode, showSecond, subsecDigits] = refineTimeDisplayOptions(options) + const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatDurationInternals( roundDurationToNano(internals, nanoInc, roundingMode), - showSecond, subsecDigits, ) }, diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index ef4f84af..8531c82a 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -130,7 +130,6 @@ export const [ timeZoneArg, nanoInc, roundingModeI, - showSecond, subsecDigits, ] = refineInstantDisplayOptions(options) const timeZone = queryTimeZoneOps(timeZoneArg || utcTimeZoneId) @@ -139,7 +138,7 @@ export const [ const offsetNano = timeZone.getOffsetNanosecondsFor(epochNano) const isoFields = epochNanoToIso(epochNano.addNumber(offsetNano)) - return formatIsoDateTimeFields(isoFields, showSecond, subsecDigits) + + return formatIsoDateTimeFields(isoFields, subsecDigits) + formatOffsetNano(offsetNano) }, diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 3228e929..cf0b0b52 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -133,26 +133,25 @@ export function refineTimeDisplayOptions(options) { returns [ nanoInc, roundingMode, - showSecond, - subsecDigits, + subsecDigits, (undefined = auto-digits, -1 = hide-seconds, >=0 = #-of-digits) ] */ -function refineTimeDisplayTuple(options) { +function refineTimeDisplayTuple(options) { // trace callers of this, make sure using right const smallestUnitI = refineSmallestUnit(options, minuteIndex, nanoIndex, -1) if (smallestUnitI !== -1) { return [ unitIndexToNano[smallestUnitI], refineRoundingMode(options, truncI), - smallestUnitI < minuteIndex, // showSecond - 9 - (smallestUnitI * 3), // subsecDigits (callers should guard for <0) + (smallestUnitI < minuteIndex) + ? 9 - (smallestUnitI * 3) + : -1, // hide seconds ] } const subsecDigits = refineSubsecDigits(options) return [ - Math.pow(10, 9 - subsecDigits), // TODO: use 10** notation? + subsecDigits === undefined ? 1 : Math.pow(10, 9 - subsecDigits), // TODO: use 10** notation? refineRoundingMode(options, truncI), - true, // showSecond subsecDigits, ] } @@ -160,6 +159,23 @@ function refineTimeDisplayTuple(options) { // Single Options // ------------------------------------------------------------------------------------------------- +/* +TODO: leverage preserveConstEnums:false +https://www.typescriptlang.org/tsconfig#preserveConstEnums + +const enum Album { + JimmyEatWorldFutures, + TubRingZooHypothesis, + DogFashionDiscoAdultery, +} +console.log({ + JimmyEatWorldFutures: Album.JimmyEatWorldFutures, + TubRingZooHypothesis: Album.TubRingZooHypothesis, + DogFashionDiscoAdultery: Album.DogFashionDiscoAdultery, +}) +console.log(Album.JimmyEatWorldFutures) +*/ + const smallestUnitStr = 'smallestUnit' const largestUnitStr = 'largestUnit' const totalUnitStr = 'unit' @@ -312,7 +328,7 @@ function refineSubsecDigits(options) { throw new RangeError('Must be auto or 0-9') } - return 9 + // undefind means 'auto' } function refineRelativeTo(options) { @@ -349,12 +365,11 @@ function refineUnitOption(optionName, options, maxUnitI, minUnitI = nanoIndex, d return unitIndex } -// TODO: optimize by using map -// TODO: keep acceting string arrays. good for accepting default first element +// TODO: move to accepting maps function refineChoiceOption(optionName, choices, options, defaultChoice) { const optionValue = options[optionName] if (optionValue === undefined) { - return defaultChoice ?? choices[0] + return defaultChoice ?? 0 } const index = choices.indexOf(optionValue) if (index < 0) { diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 4ccb36b4..88dab316 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -172,13 +172,12 @@ export const [ calendarDisplayI, nanoInc, roundingMode, - showSecond, subsecDigits, ] = refineDateTimeDisplayOptions(options) const roundedIsoFields = roundDateTimeToNano(internals, nanoInc, roundingMode) - return formatIsoDateTimeFields(roundedIsoFields, showSecond, subsecDigits) + + return formatIsoDateTimeFields(roundedIsoFields, subsecDigits) + formatCalendar(internals.calendar, calendarDisplayI) }, diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index 410a5bd7..b72b3664 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -112,11 +112,10 @@ export const [ }, toString(internals, options) { - const [nanoInc, roundingMode, showSecond, subsecDigits] = refineTimeDisplayOptions(options) + const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatIsoTimeFields( roundTimeToNano(internals, nanoInc, roundingMode), - showSecond, subsecDigits, ) }, diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index a4e9a537..3fb60283 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -96,8 +96,8 @@ export function compareNumbers() { export function clamp( val, - min, - max, + min, // inclusive + max, // inclusive throwOnOverflow, // 0/1 (matched constrain/reject) noun, // for error message (required if throwOnOverflow given) ) { @@ -147,10 +147,10 @@ export function roundHalfTrunc(n) { export function roundHalfEven(n) { return hasHalf(n) - ? Math.trunc(n) + (n % 2) + ? (n = Math.trunc(n)) + (n % 2) : Math.round(n) } function hasHalf(n) { - return n % 1 === 0.5 + return Math.abs(n % 1) === 0.5 } diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index dde6821d..2ce8b451 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -294,7 +294,6 @@ export const [ offsetDisplayI, nanoInc, roundingMode, - showSecond, subsecDigits, ] = refineZonedDateTimeDisplayOptions(options) @@ -316,7 +315,7 @@ export const [ offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) - return formatIsoDateTimeFields(isoDateTimeFields, showSecond, subsecDigits) + + return formatIsoDateTimeFields(isoDateTimeFields, subsecDigits) + formatOffsetNano(offsetNanoseconds, offsetDisplayI) + formatTimeZone(timeZone, timeZoneDisplayI) + formatCalendar(calendar, calendarDisplayI) From 3becb35a5d09c29312518457181c08cdf8ff9500 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 14:13:58 -0400 Subject: [PATCH 112/805] fixes --- .../temporal-polyfill/src/new/isoParse.js | 62 +++++++++-------- packages/temporal-polyfill/src/new/options.js | 67 ++++++++++--------- 2 files changed, 69 insertions(+), 60 deletions(-) diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index 3eed6e78..4b6ec5a3 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -1,5 +1,4 @@ import { isoCalendarId } from './calendarConfig' -import { queryCalendarOps } from './calendarOps' import { pluckIsoDateInternals, pluckIsoDateTimeInternals, @@ -10,7 +9,7 @@ import { constrainIsoDateTimeInternals, constrainIsoTimeFields, } from './isoMath' -import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' +import { getMatchingInstantFor, utcTimeZoneId } from './timeZoneOps' // High-level // ------------------------------------------------------------------------------------------------- @@ -18,33 +17,33 @@ import { getMatchingInstantFor, queryTimeZoneOps, utcTimeZoneId } from './timeZo export function parseZonedDateTime(s) { const parsed = parseDateTime(s) // TODO: use just 'calendar' and 'timeZone' ? if (parsed) { - if (!parsed.timeZoneId) { + if (!parsed.timeZone) { throw new Error() } - - const calendar = queryCalendarOps(parsed.calendarId || isoCalendarId) - const timeZone = queryTimeZoneOps(parsed.timeZoneId) - - const epochNanoseconds = getMatchingInstantFor( - timeZone, - parsed, - parsed.offset !== undefined ? parseOffsetNano(parsed.offset) : undefined, - parsed.z, - 'reject', - 'compatible', - true, // fuzzy - ) - - return { - epochNanoseconds, - timeZone, - calendar, - } + return processZonedDateTimeParse(parsed) } throw new Error() } +export function processZonedDateTimeParse(parsed) { + const epochNanoseconds = getMatchingInstantFor( + parsed.timeZone, + parsed, + parsed.offset !== undefined ? parseOffsetNano(parsed.offset) : undefined, + parsed.z, + 'reject', + 'compatible', + true, // fuzzy + ) + + return { + epochNanoseconds, + timeZone: parsed.timeZone, + calendar: parsed.calendar, + } +} + export function parsePlainDateTime(s) { const parsed = parseDateTime(s) if (parsed) { @@ -110,7 +109,7 @@ export function parsePlainTime(s) { if (parsed.hasZ) { throw new Error() } - if (parsed.calendarId !== undefined && parsed.calendarId !== isoCalendarId) { + if (parsed.calendar !== undefined && parsed.calendar !== isoCalendarId) { throw new Error() } @@ -131,7 +130,7 @@ export function parseCalendarId(s) { if (s !== isoCalendarId) { s = ( parseDateTime(s) || parseYearMonth(s) || parseMonthDay(s) - )?.calendarId || isoCalendarId + )?.calendar.id || isoCalendarId } return s @@ -140,8 +139,8 @@ export function parseCalendarId(s) { export function parseTimeZoneId(s) { const parsed = parseDateTime(s) if (parsed !== undefined) { - if (parsed.timeZonedId) { - return parsed.timeZonedId // TODO: need to canonicalize (run through DateTimeFormat) + if (parsed.timeZone) { + return parsed.timeZone.id } if (parsed.hasZ) { return utcTimeZoneId @@ -163,20 +162,27 @@ function parseDateTime(s) { // isoHour, isMinute, isoSecond, etc... // hasTime, hasZ, offset, // calendar, timeZone } + // + // should use `queryCalendarOps(parsed.calendar || isoCalendarId)` + // should use `queryTimeZoneOps(parsed.timeZone)` }) } function parseYearMonth(s) { return constrainIsoDateInternals({ // { isYear, isoMonth, isoDay - // calendar, timeZone } + // calendar } + // + // should use `queryCalendarOps(parsed.calendar || isoCalendarId)` }) } function parseMonthDay(s) { return constrainIsoDateInternals({ // { isYear, isoMonth, isoDay - // calendar, timeZone } + // calendar } + // + // should use `queryCalendarOps(parsed.calendar || isoCalendarId)` }) } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index cf0b0b52..15f2bb7e 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,4 +1,7 @@ +import { parseDateTime } from '../dateUtils/parse' import { durationFieldIndexes } from './durationFields' +import { pluckIsoDateTimeInternals } from './isoFields' +import { processZonedDateTimeParse } from './isoParse' import { bigIntToLargeInt } from './largeInt' import { dayIndex, minuteIndex, nanoIndex, unitIndexToNano, unitIndexes, yearIndex } from './units' import { @@ -50,14 +53,14 @@ export function refineDiffOptions( Math.max(smallestUnitI, defaultLargestUnitI), ) - const roundingIncrement = refineRoundingInc(options, smallestUnitI) + const roundingInc = refineRoundingInc(options, smallestUnitI) let roundingMode = refineRoundingMode(options, truncI) if (roundingModeInvert) { roundingMode = invertRoundingMode(roundingMode) } - return [largestUnitI, smallestUnitI, roundingIncrement, roundingMode] + return [largestUnitI, smallestUnitI, roundingInc, roundingMode] } /* @@ -285,34 +288,29 @@ function invertRoundingMode(roundingModeI) { return roundingModeI } -function refineRoundingInc(options, validateWithSmallestUnitI) { - // default to 1 - // with smallestUnit... - /* - if (roundTo === undefined) throw new TypeError('options parameter is required'); - if (ES.Type(roundTo) === 'String') { - const stringParam = roundTo; - roundTo = ObjectCreate(null); - roundTo.smallestUnit = stringParam; - } else { - roundTo = ES.GetOptionsObject(roundTo); +const roundingIncName = 'roundingIncrement' + +function refineRoundingInc(options, smallestUnitI) { // smallestUnit is day/time + let roundingInc = options[roundingIncName] + if (roundingInc === undefined) { + return 1 + } + + const upUnitNano = unitIndexToNano[smallestUnitI + 1] + + if (upUnitNano) { + const unitNano = unitIndexToNano[smallestUnitI] + const maxRoundingInc = upUnitNano / unitNano + roundingInc = clamp(roundingInc, 1, maxRoundingInc - 1, roundingIncName) + + if (upUnitNano % (roundingInc * unitNano)) { + throw new RangeError('Must be even multiple') } - const roundingIncrement = ES.ToTemporalRoundingIncrement(roundTo); - const roundingMode = ES.ToTemporalRoundingMode(roundTo, 'halfExpand'); - const smallestUnit = ES.GetTemporalUnit(roundTo, 'smallestUnit', 'time', ES.REQUIRED, ['day']); - const maximumIncrements = { - day: 1, - hour: 24, - minute: 60, - second: 60, - millisecond: 1000, - microsecond: 1000, - nanosecond: 1000 - }; - const maximum = maximumIncrements[smallestUnit]; - const inclusive = maximum === 1; - ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive); - */ + } else { + roundingInc = clamp(roundingInc, 1, 1, roundingIncName) + } + + return roundingInc } const subsecDigitsName = 'fractionalSecondDigits' @@ -332,9 +330,13 @@ function refineSubsecDigits(options) { } function refineRelativeTo(options) { - // TODO - // should return ZoneDateTimeINTERNALS or PlainDateINTERNALS - // allow undefined + const parsed = parseDateTime(options) + + if (parsed.timeZone) { + return processZonedDateTimeParse(parsed) + } + + return pluckIsoDateTimeInternals(parsed) } // Utils @@ -450,6 +452,7 @@ export function toInteger(value) { export function toStringOrUndefined() { } +// used? export function toNumberOrUndefined() { } From 4586b01df09f857df53b748df22ef75417a757ea Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 15:17:48 -0400 Subject: [PATCH 113/805] smarter refining --- .../temporal-polyfill/src/new/calendar.js | 8 +- .../src/new/calendarFields.js | 38 +++---- .../temporal-polyfill/src/new/calendarOps.js | 6 +- packages/temporal-polyfill/src/new/class.js | 10 +- packages/temporal-polyfill/src/new/convert.js | 10 +- .../temporal-polyfill/src/new/duration.js | 2 - .../src/new/durationFields.js | 4 +- packages/temporal-polyfill/src/new/instant.js | 4 +- .../temporal-polyfill/src/new/isoFields.js | 24 ++-- packages/temporal-polyfill/src/new/options.js | 104 ++++++++---------- .../temporal-polyfill/src/new/timeZoneOps.js | 8 +- packages/temporal-polyfill/src/new/utils.js | 6 +- 12 files changed, 105 insertions(+), 119 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index f37686fa..c56bf5e8 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -10,7 +10,7 @@ import { import { createDuration, toDurationInternals } from './duration' import { isoDaysInWeek } from './isoMath' import { parseCalendarId } from './isoParse' -import { refineOverflowOptions, strictArray, toObject } from './options' +import { ensureArray, ensureObjectlike, ensureString, refineOverflowOptions } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' @@ -61,13 +61,13 @@ export const calendarProtocolMethods = { }, fields(impl, fieldNames) { - return impl.fields(strictArray(fieldNames).map(toString)) + return impl.fields(ensureArray(fieldNames).map(ensureString)) }, mergeFields(impl, fields0, fields1) { return impl.mergeFields( - removeUndefines(toObject(fields0)), - removeUndefines(toObject(fields1)), + removeUndefines(ensureObjectlike(fields0)), + removeUndefines(ensureObjectlike(fields1)), ) }, } diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index 061614b8..78c1930b 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -1,11 +1,11 @@ import { isoTimeFieldNames } from './isoFields' -import { toBoolean, toInteger, toIntegerThrowOnInfinity, toPositiveInteger } from './options' +import { ensureBoolean, ensureInteger, toInteger } from './options' import { mapArrayToProps, remapProps, zipSingleValue } from './utils' // Refiners // ------------------------------------------------------------------------------------------------- -const dayFieldRefiners = { day: toPositiveInteger } +const dayFieldRefiners = { day: toInteger } const monthCodeFieldRefiners = { monthCode: toString } // Ordered alphabetically @@ -17,9 +17,9 @@ export const eraYearFieldRefiners = { // Ordered alphabetically // Does not include era/eraYear const yearMonthFieldRefiners = { - month: toPositiveInteger, + month: toInteger, ...monthCodeFieldRefiners, - year: toIntegerThrowOnInfinity, + year: toInteger, } // Ordered alphabetically @@ -31,12 +31,12 @@ export const dateFieldRefiners = { // Ordered alphabetically const timeFieldRefiners = { - hour: toIntegerThrowOnInfinity, - microsecond: toIntegerThrowOnInfinity, - millisecond: toIntegerThrowOnInfinity, - minute: toIntegerThrowOnInfinity, - nanosecond: toIntegerThrowOnInfinity, - second: toIntegerThrowOnInfinity, + hour: toInteger, + microsecond: toInteger, + millisecond: toInteger, + minute: toInteger, + nanosecond: toInteger, + second: toInteger, } // Unordered @@ -48,25 +48,25 @@ export const dateTimeFieldRefiners = { // Ordered alphabetically, for predictable macros const yearStatRefiners = { - daysInYear: toPositiveInteger, - inLeapYear: toBoolean, - monthsInYear: toPositiveInteger, + daysInYear: ensureInteger, + inLeapYear: ensureBoolean, + monthsInYear: ensureInteger, } // Unordered export const yearMonthStatRefiners = { ...yearStatRefiners, - daysInMonth: toPositiveInteger, + daysInMonth: ensureInteger, } // Unordered export const dateStatRefiners = { ...yearMonthStatRefiners, - dayOfWeek: toPositiveInteger, - dayOfYear: toPositiveInteger, - weekOfYear: toPositiveInteger, - yearOfWeek: toPositiveInteger, - daysInWeek: toPositiveInteger, + dayOfWeek: ensureInteger, + dayOfYear: ensureInteger, + weekOfYear: ensureInteger, + yearOfWeek: ensureInteger, + daysInWeek: ensureInteger, } // Property Names diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index a6df275b..c2a2e4b2 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -10,7 +10,7 @@ import { idGettersStrict, } from './class' import { createDuration } from './duration' -import { strictArray, toObject, toString } from './options' +import { ensureArray, ensureObjectlike, ensureString, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' @@ -92,10 +92,10 @@ const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { }, fields(calendar, fieldNames) { - return strictArray(calendar.fields(fieldNames)).map(toString) + return ensureArray(calendar.fields(fieldNames)).map(ensureString) }, mergeFields(calendar, fields0, fields1) { - return toObject(calendar.mergeFields(fields0, fields1)) + return ensureObjectlike(calendar.mergeFields(fields0, fields1)) }, }) diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js index 1ae836da..e0a50ba3 100644 --- a/packages/temporal-polyfill/src/new/class.js +++ b/packages/temporal-polyfill/src/new/class.js @@ -1,11 +1,11 @@ import { DateTimeFormat } from './intlFormat' -import { strictInstanceOf, toString } from './options' +import { ensureInstanceOf, toString } from './options' import { createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, defineProps, hasAllMatchingProps, identityFunc, - isObjectLike, + isObjectlike, mapProps, noop, } from './utils' @@ -49,8 +49,8 @@ export function createWrapperClass( return InternalObj } -export function getStrictInternals(Class, res) { - return getInternals(strictInstanceOf(res, Class)) +export function getStrictInternals(Class, res) { // rename: getInternalsStrict? + return getInternals(ensureInstanceOf(Class, res)) } // Temporal Class @@ -101,7 +101,7 @@ export function createTemporalClass( argInternals = (internalsConversionMap[argTemporalName] || noop)(argInternals) } - return (!argInternals && isObjectLike(arg) && bagToInternals(arg, options)) || + return (!argInternals && isObjectlike(arg) && bagToInternals(arg, options)) || (handleUnusedOptions(options), argInternals || stringToInternals(toString(arg))) } diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index d31c1f10..68948b54 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -27,16 +27,16 @@ import { import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNano } from './isoParse' import { + ensureObjectlike, normalizeOptions, refineOverflowOptions, - refineZonedFieldOptions, - toObject, // TODO: shouldn't we use this all over the place? + refineZonedFieldOptions, // TODO: shouldn't we use this all over the place? } from './options' import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { isObjectLike, pluckProps, removeDuplicateStrings } from './utils' +import { isObjectlike, pluckProps, removeDuplicateStrings } from './utils' import { createZonedDateTime } from './zonedDateTime' /* @@ -237,7 +237,7 @@ export function mergePlainYearMonthBag(plainYearMonth, bag, options) { export function convertPlainYearMonthToDate(plainYearMonth, bag) { return createPlainDate( - convertToIso(plainYearMonth, yearMonthBasicNames, toObject(bag), ['day']), + convertToIso(plainYearMonth, yearMonthBasicNames, ensureObjectlike(bag), ['day']), ) } @@ -475,7 +475,7 @@ export function refineComplexBag(key, ForbiddenClass, bag) { forbidInstanceClass(bag, ForbiddenClass) - if (isObjectLike(bag) && !(key in bag)) { + if (isObjectlike(bag) && !(key in bag)) { return bag } } diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index cac0b60b..ab7df577 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -214,8 +214,6 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -// TODO: move to move.js? - function addToDuration(direction, internals, otherArg, options) { const otherFields = toDurationInternals(otherArg) const markerInternals = refineRelativeToOptions(options) // optional diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 8c868167..e01b761d 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -1,5 +1,5 @@ import { isoTimeFieldNames } from './isoFields' -import { toIntegerWithoutRounding } from './options' +import { toIntegerStrict } from './options' import { dayIndex, givenFieldsToLargeNano, @@ -31,7 +31,7 @@ export const durationTimeFieldDefaults = zipSingleValue(durationTimeFieldNames, // Refiners // ------------------------------------------------------------------------------------------------- -export const durationFieldRefiners = zipSingleValue(durationFieldNames, toIntegerWithoutRounding) +export const durationFieldRefiners = zipSingleValue(durationFieldNames, toIntegerStrict) // Getters // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 8531c82a..8fc72d21 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -16,11 +16,11 @@ import { import { compareLargeInts } from './largeInt' import { moveEpochNano } from './move' import { + ensureObjectlike, refineDiffOptions, refineInstantDisplayOptions, refineRoundOptions, toEpochNano, - toObject, } from './options' import { computeNanoInc, roundByIncLarge } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' @@ -75,7 +75,7 @@ export const [ }, toZonedDateTime(epochNanoseconds, options) { - const refinedObj = toObject(options) + const refinedObj = ensureObjectlike(options) return createZonedDateTime({ epochNanoseconds, diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 36212349..d945a1f0 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -5,11 +5,7 @@ import { constrainIsoDateTimeInternals, constrainIsoTimeFields, } from './isoMath' -import { - toIntegerThrowOnInfinity, - toIntegerWithoutRounding, - toPositiveInteger, -} from './options' +import { toInteger } from './options' import { mapRefiners, pluckProps, zipSingleValue } from './utils' // Refiners @@ -18,19 +14,19 @@ import { mapRefiners, pluckProps, zipSingleValue } from './utils' // Ordered alphabetically export const isoDateInternalRefiners = { calendar: queryCalendarOps, - isoDay: toPositiveInteger, - isoMonth: toPositiveInteger, - isoYear: toIntegerWithoutRounding, + isoDay: toInteger, + isoMonth: toInteger, + isoYear: toInteger, } // Ordered by ascending size export const isoTimeFieldRefiners = { - isoHour: toIntegerThrowOnInfinity, - isoMicrosecond: toIntegerThrowOnInfinity, - isoMillisecond: toIntegerThrowOnInfinity, - isoMinute: toIntegerThrowOnInfinity, - isoNanosecond: toPositiveInteger, // why different? - isoSecond: toPositiveInteger, // why different? + isoHour: toInteger, + isoMicrosecond: toInteger, + isoMillisecond: toInteger, + isoMinute: toInteger, + isoNanosecond: toInteger, + isoSecond: toInteger, } // Unordered diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 15f2bb7e..a3bfd582 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -7,7 +7,7 @@ import { dayIndex, minuteIndex, nanoIndex, unitIndexToNano, unitIndexes, yearInd import { clamp, hasAnyMatchingProps, - isObjectLike, + isObjectlike, roundExpand, roundHalfCeil, roundHalfEven, @@ -384,10 +384,7 @@ export function normalizeOptions(options) { if (options === undefined) { return {} } - if (!isObjectLike(options)) { - throw new TypeError('Must be object-like') - } - return options + return ensureObjectlike(options) } // will NOT check for atomicName in options @@ -395,10 +392,7 @@ function normalizeRequiredOptions(options, atomicName) { if (typeof options === 'string') { return { [atomicName]: options } } - if (!isObjectLike(options)) { - throw new TypeError('Must be object-like') - } - return options + return ensureObjectlike(options) } function mustHaveMatch(obj, propNames) { @@ -421,39 +415,41 @@ export function clampProp(props, propName, min, max, overflowI) { // Primitives // ------------------------------------------------------------------------------------------------- -export function strictNumber(input) { +export function ensureInstanceOf(Class, obj) { + if (!(obj instanceof Class)) { + throw new TypeError('Must be certain type') // TODO: show Class's symbol? + } + return obj } -export function strictInstanceOf(obj, Class) { +function ensureType(typeName, obj) { + // eslint-disable-next-line valid-typeof + if (typeof obj !== typeName) { + throw new TypeError(`Must be certain type ${typeName}`) + } + return obj } -export function strictArray() { -} +export const ensureBoolean = ensureType.bind(undefined, 'boolean') +export const ensureString = ensureType.bind(undefined, 'string') +export const ensureNumber = ensureType.bind(undefined, 'number') -export function toObject() { - // ensures a real object. throws error otherwise +export function ensureInteger(arg) { + return ensureNumberIsInteger(ensureNumber(arg)) } -export function toNumber(value) { - if (typeof value === 'bigint') { - throw new TypeError('Cannot convert BigInt to number') +export function ensureArray(arg) { + if (!Array.isArray(arg)) { + throw new TypeError('Must be array') } - return Number(value) -} - -export function toInteger(value) { - const num = toNumber(value) - if (isNaN(num)) return 0 - const integer = Math.trunc(num) - if (num === 0) return 0 - return integer + return arg } -export function toStringOrUndefined() { -} - -// used? -export function toNumberOrUndefined() { +export function ensureObjectlike(arg) { + if (!isObjectlike(arg)) { + throw new TypeError('Must be object-like') + } + return arg } export function toString(value) { @@ -463,39 +459,31 @@ export function toString(value) { return String(value) } -export function toIntegerThrowOnInfinity(value) { - const integer = toInteger(value) - if (!Number.isFinite(integer)) { - throw new RangeError('infinity is out of range') - } - return integer +export function toInteger(value) { // truncates floats + return Math.trunc(toNumber(value)) || 0 // ensure no -0 } -export function toBoolean() { +export function toIntegerStrict(value) { // throws error on floats + return ensureNumberIsInteger(toNumber(value)) } -export function toPositiveInteger(valueParam, property) { - const value = toInteger(valueParam) - if (!Number.isFinite(value)) { - throw new RangeError('infinity is out of range') +function ensureNumberIsInteger(n) { + if (!Number.isInteger(n)) { + throw new RangeError('must be integer') } - if (value < 1) { - if (property !== undefined) { - throw new RangeError(`property '${property}' cannot be a a number less than one`) - } - throw new RangeError('Cannot convert a number less than one to a positive integer') - } - return value + return n || 0 // ensure no -0 } -export function toIntegerWithoutRounding(valueParam) { - const value = toNumber(valueParam) - if (isNaN(value)) return 0 - if (!Number.isFinite(value)) { - throw new RangeError('infinity is out of range') +/* +Caller must ||0 to ensure no -0 +*/ +function toNumber(value) { + value = Number(value) + if (isNaN(value)) { + throw new RangeError('not a number') } - if (!Number.isInteger(value)) { - throw new RangeError(`unsupported fractional value ${value}`) + if (!Number.isFinite(value)) { + throw new RangeError('must be finite') } - return toInteger(value) // ℝ(value) in spec text; converts -0 to 0 + return value } diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index af10e33e..67e162d8 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -13,7 +13,7 @@ import { isoToEpochNano, } from './isoMath' import { moveDateByDays } from './move' -import { strictArray, strictNumber } from './options' +import { ensureArray } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' import { TimeZone, createTimeZone, timeZoneProtocolMethods } from './timeZone' @@ -202,13 +202,15 @@ export const TimeZoneOpsAdapter = createWrapperClass(idGettersStrict, { }, getPossibleInstantsFor(timeZone, isoDateTimeFields) { - return strictArray(timeZone.getPossibleInstantsFor(createPlainDateTime(isoDateTimeFields))) + return ensureArray(timeZone.getPossibleInstantsFor(createPlainDateTime(isoDateTimeFields))) .map(getInstantEpochNano) }, }) function validateOffsetNano(offsetNano) { - offsetNano = strictNumber(offsetNano) + if (!Number.isInteger(offsetNano)) { // will return false on non-number (good) + throw new RangeError('must be integer number') + } if (Math.abs(offsetNano) >= nanoInUtcDay) { throw new RangeError('out of range') diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 3fb60283..42327f41 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -1,5 +1,5 @@ -export function isObjectLike() { +export function isObjectlike() { } export function mapRefiners(input, refinerMap) { @@ -89,9 +89,11 @@ export function noop() { } export function twoDigit(num) { // as a string + // TODO } -export function compareNumbers() { +export function compareNumbers(a, b) { + return a - b } export function clamp( From 755b52c1f1a80594c15ae7cdd39552c541c94493 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 17:35:24 -0400 Subject: [PATCH 114/805] parseInstant --- packages/temporal-polyfill/src/new/instant.js | 7 +-- .../temporal-polyfill/src/new/isoParse.js | 50 ++++++++++++++----- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index 8fc72d21..f1a6f060 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -13,6 +13,7 @@ import { epochSecToNano, validateEpochNano, } from './isoMath' +import { parseInstant } from './isoParse' import { compareLargeInts } from './largeInt' import { moveEpochNano } from './move' import { @@ -52,7 +53,7 @@ export const [ noop, // stringToInternals - stringToEpochNanoseconds, + parseInstant, // handleUnusedOptions noop, @@ -167,10 +168,6 @@ export const [ }, ) -function stringToEpochNanoseconds(str) { - // TODO -} - function diffInstants(epochNano0, epochNano1, options, roundingModeInvert) { return createDuration( diffEpochNano( diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index 4b6ec5a3..ffdbc16c 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -8,29 +8,53 @@ import { constrainIsoDateInternals, constrainIsoDateTimeInternals, constrainIsoTimeFields, + isoToEpochNano, } from './isoMath' import { getMatchingInstantFor, utcTimeZoneId } from './timeZoneOps' +// TODO: finish isoParse + // High-level // ------------------------------------------------------------------------------------------------- +export function parseInstant(s) { + const parsed = parseDateTime(s) + + if (parsed) { + let offsetNano + + if (parsed.hasZ) { + offsetNano = 0 + } else if (parsed.offset) { + offsetNano = parseOffsetNano(parsed.offset) + } else { + return new RangeError() + } + + return isoToEpochNano(parsed).addNumber(offsetNano) + } + + throw new RangeError() +} + export function parseZonedDateTime(s) { const parsed = parseDateTime(s) // TODO: use just 'calendar' and 'timeZone' ? + if (parsed) { if (!parsed.timeZone) { - throw new Error() + throw new RangeError() } return processZonedDateTimeParse(parsed) } - throw new Error() + throw new RangeError() } export function processZonedDateTimeParse(parsed) { const epochNanoseconds = getMatchingInstantFor( parsed.timeZone, parsed, - parsed.offset !== undefined ? parseOffsetNano(parsed.offset) : undefined, + parsed.offset ? parseOffsetNano(parsed.offset) : undefined, parsed.z, 'reject', 'compatible', @@ -50,7 +74,7 @@ export function parsePlainDateTime(s) { return pluckIsoDateTimeInternals(parsed) } - throw new Error() + throw new RangeError() } export function parsePlainDate(s) { @@ -59,7 +83,7 @@ export function parsePlainDate(s) { return parsed } - throw new Error() + throw new RangeError() } export function parsePlainYearMonth(s) { @@ -75,7 +99,7 @@ export function parsePlainYearMonth(s) { return parsed } - throw new Error() + throw new RangeError() } export function parsePlainMonthDay(s) { @@ -91,7 +115,7 @@ export function parsePlainMonthDay(s) { return parsed } - throw new Error() + throw new RangeError() } export function parsePlainTime(s) { @@ -101,29 +125,29 @@ export function parsePlainTime(s) { parsed = parseDateTime(s) if (parsed && !parsed.hasTime) { - throw new Error() + throw new RangeError() } } if (parsed) { if (parsed.hasZ) { - throw new Error() + throw new RangeError() } if (parsed.calendar !== undefined && parsed.calendar !== isoCalendarId) { - throw new Error() + throw new RangeError() } if (parseMonthDay(s)) { - throw new Error() + throw new RangeError() } if (parseYearMonth(s)) { - throw new Error() + throw new RangeError() } return pluckIsoTimeFields(parsed) } - throw new Error() + throw new RangeError() } export function parseCalendarId(s) { From 149adb6f3a7baab477912895861462a460b7a018 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 17:42:58 -0400 Subject: [PATCH 115/805] roundToMinute implementation --- packages/temporal-polyfill/src/new/round.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 9641a9f2..517a6d86 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -10,13 +10,20 @@ import { import { isoTimeFieldDefaults } from './isoFields' import { isoTimeFieldsToNano, nanoToIsoTimeAndDay } from './isoMath' import { moveDateByDays } from './move' -import { roundingModeFuncs } from './options' +import { halfEvenI, roundingModeFuncs } from './options' import { computeNanosecondsInDay } from './timeZoneOps' -import { dayIndex, nanoInUtcDay, nanoIndex, unitIndexToNano, weekIndex } from './units' +import { + dayIndex, + nanoInMinute, + nanoInUtcDay, + nanoIndex, + unitIndexToNano, + weekIndex, +} from './units' import { identityFunc } from './utils' -export function roundToMinute(epochNano) { - +export function roundToMinute(offsetNano) { + return roundByInc(offsetNano, nanoInMinute, halfEvenI) } // Rounding Dates From a833873820bb86771b4108139a968f8c43629560 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 17:46:37 -0400 Subject: [PATCH 116/805] implement clearDurationFields --- packages/temporal-polyfill/src/new/round.js | 26 ++++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index 517a6d86..afae2251 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -18,6 +18,7 @@ import { nanoInUtcDay, nanoIndex, unitIndexToNano, + unitNamesAsc, weekIndex, } from './units' import { identityFunc } from './utils' @@ -218,7 +219,7 @@ export function totalRelativeDuration( const { sign } = durationFields const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( - clearDurationFields(durationFields, nanoIndex, totalUnitIndex - 1), + clearDurationFields(durationFields, totalUnitIndex - 1), totalUnitIndex, sign, // marker system... @@ -327,12 +328,7 @@ function nudgeRelativeDuration( ) { const { sign } = durationFields - const baseDurationFields = clearDurationFields( - durationFields, - nanoIndex, - smallestUnitI - 1, - ) - + const baseDurationFields = clearDurationFields(durationFields, smallestUnitI - 1) baseDurationFields[smallestUnitI] = Math.trunc( durationFields[smallestUnitI] / roundingInc, ) @@ -386,11 +382,7 @@ function bubbleRelativeDuration( continue } - const baseDurationFields = clearDurationFields( - durationFields, - nanoIndex, - currentUnitIndex - 1, - ) + const baseDurationFields = clearDurationFields(durationFields, currentUnitIndex - 1) baseDurationFields[durationFieldNamesAsc[currentUnitIndex]] += sign const thresholdEpochNanoseconds = markerToEpochMilliseconds( @@ -425,6 +417,12 @@ function clampRelativeDuration( return [epochNanoseconds0, epochNanoseconds1] } -function clearDurationFields(durationFields, firstUnitIndex, lastUnitIndex) { - // TODO: always assume `nanoIndex` as firstUnitIndex +function clearDurationFields(durationFields, lastUnitIndex) { + const copy = { ...durationFields } + + for (let unitIndex = nanoIndex; unitIndex <= lastUnitIndex; unitIndex++) { + copy[unitNamesAsc[unitIndex]] = 0 + } + + return copy } From 8b134eb24d6703407ed4dc8cd25f8c4271275027 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 19:32:29 -0400 Subject: [PATCH 117/805] smarter prop-related utils --- .../temporal-polyfill/src/new/calendar.js | 10 +- .../src/new/calendarFields.js | 24 ++-- .../temporal-polyfill/src/new/calendarImpl.js | 4 +- .../temporal-polyfill/src/new/calendarOps.js | 10 +- packages/temporal-polyfill/src/new/class.js | 8 +- packages/temporal-polyfill/src/new/convert.js | 4 +- .../src/new/durationFields.js | 30 +++-- .../temporal-polyfill/src/new/intlFormat.js | 15 ++- .../temporal-polyfill/src/new/isoFields.js | 10 +- packages/temporal-polyfill/src/new/options.js | 4 +- packages/temporal-polyfill/src/new/units.js | 4 +- packages/temporal-polyfill/src/new/utils.js | 120 ++++++++++++++---- .../src/new/zonedDateTime.js | 8 +- 13 files changed, 164 insertions(+), 87 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index c56bf5e8..63445859 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -15,14 +15,14 @@ import { createPlainDate, toPlainDateInternals } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' -import { mapArrayToProps, noop, removeUndefines } from './utils' +import { excludeUndefinedProps, mapPropNames, noop } from './utils' export const calendarProtocolMethods = { - ...mapArrayToProps(dateGetterNames, (propName) => { + ...mapPropNames((propName) => { return (impl, plainDateArg) => { return impl[propName](toPlainDateInternals(plainDateArg)) } - }), + }, dateGetterNames), daysInWeek() { return isoDaysInWeek @@ -66,8 +66,8 @@ export const calendarProtocolMethods = { mergeFields(impl, fields0, fields1) { return impl.mergeFields( - removeUndefines(ensureObjectlike(fields0)), - removeUndefines(ensureObjectlike(fields1)), + excludeUndefinedProps(ensureObjectlike(fields0)), + excludeUndefinedProps(ensureObjectlike(fields1)), ) }, } diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js index 78c1930b..eb8a353b 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ b/packages/temporal-polyfill/src/new/calendarFields.js @@ -1,6 +1,6 @@ import { isoTimeFieldNames } from './isoFields' import { ensureBoolean, ensureInteger, toInteger } from './options' -import { mapArrayToProps, remapProps, zipSingleValue } from './utils' +import { mapPropNames, mapPropNamesToConstant, remapProps } from './utils' // Refiners // ------------------------------------------------------------------------------------------------- @@ -101,23 +101,25 @@ export const dateGetters = createGetters(dateGetterNames) export const yearMonthGetters = createGetters(yearMonthGetterNames) export const monthDayGetters = createGetters(monthDayGetterNames) -export const timeGetters = mapArrayToProps(timeFieldNames, (timeFieldName, i) => { +export const timeGetters = mapPropNames((timeFieldName, i) => { return (isoTimeFieldsInternals) => { return isoTimeFieldsInternals[isoTimeFieldNames[i]] } -}) +}, timeFieldNames) export const dateTimeGetters = { ...dateGetters, ...timeGetters, } +function createGetter(propName) { + return (internals) => { + return internals.calendar[propName](internals) + } +} + function createGetters(getterNames) { - const getters = mapArrayToProps(getterNames, (propName) => { - return (internals) => { - return internals.calendar[propName](internals) - } - }) + const getters = mapPropNames(createGetter, getterNames) getters.calendarId = function(internals) { return internals.calendar.id // works for either CalendarOpsAdapter or CalendarImpl @@ -129,11 +131,9 @@ function createGetters(getterNames) { // Defaults // ------------------------------------------------------------------------------------------------- -export const timeFieldDefaults = zipSingleValue(timeFieldNames, 0) +export const timeFieldDefaults = mapPropNamesToConstant(timeFieldNames, 0) // Conversion // ------------------------------------------------------------------------------------------------- -export function timeFieldsToIso(timeFields) { - return remapProps(timeFields, timeFieldNames, isoTimeFieldNames) -} +export const timeFieldsToIso = remapProps.bind(undefined, timeFieldNames, isoTimeFieldNames) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 1680223a..12828fbc 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -41,7 +41,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { rejectI } from './options' import { milliInDay } from './units' -import { buildWeakMapCache, clamp, createLazyMap, mapArrayToProps, twoDigit } from './utils' +import { buildWeakMapCache, clamp, createLazyMap, mapPropNamesToIndex, twoDigit } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -648,7 +648,7 @@ function createIntlMonthCache(epochMilliToIntlFields) { return { monthEpochMilli: milliReversed.reverse(), - monthStrToIndex: mapArrayToProps(monthStrsReversed.reverse()), + monthStrToIndex: mapPropNamesToIndex(monthStrsReversed.reverse()), } } diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index c2a2e4b2..ac911d96 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -49,14 +49,14 @@ const getPlainYearMonthInternals = getStrictInternals.bind(undefined, PlainYearM const getPlainMonthDayInternals = getStrictInternals.bind(undefined, PlainMonthDay) const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { - ...mapProps({ - ...eraYearFieldRefiners, - ...dateFieldRefiners, - ...dateStatRefiners, - }, (refiner, propName) => { + ...mapProps((refiner, propName) => { return (calendar, isoDateFields) => { return refiner(calendar[propName](createPlainDate(isoDateFields))) } + }, { + ...eraYearFieldRefiners, + ...dateFieldRefiners, + ...dateStatRefiners, }), dateAdd(calendar, isoDateFields, durationInternals, overflow) { diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js index e0a50ba3..fc5d8ad7 100644 --- a/packages/temporal-polyfill/src/new/class.js +++ b/packages/temporal-polyfill/src/new/class.js @@ -3,7 +3,7 @@ import { ensureInstanceOf, toString } from './options' import { createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, defineProps, - hasAllMatchingProps, + hasAllPropsByName, identityFunc, isObjectlike, mapProps, @@ -39,8 +39,8 @@ export function createWrapperClass( } Object.defineProperties(InternalObj.prototype, { - ...createGetterDescriptors(mapProps(getters, curryMethod)), - ...createPropDescriptors(mapProps(methods, curryMethod)), + ...createGetterDescriptors(mapProps(curryMethod, getters)), + ...createPropDescriptors(mapProps(curryMethod, methods)), ...extraPrototypeDescriptors, }) @@ -137,7 +137,7 @@ export function createProtocolChecker(protocolMethods) { propNames.sort() // TODO: order matters? return (obj) => { - if (!hasAllMatchingProps(obj, propNames)) { + if (!hasAllPropsByName(obj, propNames)) { throw new TypeError('Invalid protocol') } } diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.js index 68948b54..6516bbba 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.js @@ -36,7 +36,7 @@ import { createPlainDate } from './plainDate' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { isObjectlike, pluckProps, removeDuplicateStrings } from './utils' +import { excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' import { createZonedDateTime } from './zonedDateTime' /* @@ -203,7 +203,7 @@ function convertToIso( extra = refineFields(extra, extraFieldNames, getRequiredDateFields(calendar)) let mergedFields = calendar.mergeFields(input, extra) - const mergedFieldNames = removeDuplicateStrings([...inputFieldNames, ...extraFieldNames]) + const mergedFieldNames = excludeArrayDuplicates([...inputFieldNames, ...extraFieldNames]) mergedFields = refineFields(mergedFields, mergedFieldNames, []) return calendar.dateFromFields(mergedFields) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index e01b761d..9b5e2935 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -8,13 +8,19 @@ import { unitIndexToNano, unitNamesAsc, } from './units' -import { mapArrayToProps, mapRefiners, remapProps, zipSingleValue } from './utils' +import { + mapPropNames, + mapPropNamesToConstant, + mapPropNamesToIndex, + mapPropsWithRefiners, + remapProps, +} from './utils' // Property Names // ------------------------------------------------------------------------------------------------- export const durationFieldNamesAsc = unitNamesAsc.map((unitName) => unitName + 's') // pluralize -export const durationFieldIndexes = mapArrayToProps(durationFieldNamesAsc) +export const durationFieldIndexes = mapPropNamesToIndex(durationFieldNamesAsc) export const durationFieldNames = durationFieldNamesAsc.sort() // unordered @@ -25,33 +31,35 @@ const durationInternalNames = [...durationFieldNames, 'sign'] // Defaults // ------------------------------------------------------------------------------------------------- -export const durationFieldDefaults = zipSingleValue(durationFieldNames, 0) -export const durationTimeFieldDefaults = zipSingleValue(durationTimeFieldNames, 0) +export const durationFieldDefaults = mapPropNamesToConstant(durationFieldNames, 0) +export const durationTimeFieldDefaults = mapPropNamesToConstant(durationTimeFieldNames, 0) // Refiners // ------------------------------------------------------------------------------------------------- -export const durationFieldRefiners = zipSingleValue(durationFieldNames, toIntegerStrict) +export const durationFieldRefiners = mapPropNamesToConstant(durationFieldNames, toIntegerStrict) // Getters // ------------------------------------------------------------------------------------------------- -export const durationGetters = mapArrayToProps(durationInternalNames, (propName) => { +export const durationGetters = mapPropNames((propName) => { return (durationInternals) => { return durationInternals[propName] } -}) +}, durationInternalNames) // Field <-> Field Conversion // ------------------------------------------------------------------------------------------------- export function refineDurationInternals(rawDurationFields) { - return updateDurationFieldsSign(mapRefiners(rawDurationFields, durationFieldRefiners)) + return updateDurationFieldsSign(mapPropsWithRefiners(rawDurationFields, durationFieldRefiners)) } -export function durationTimeFieldsToIso(durationTimeFields) { - return remapProps(durationTimeFields, durationTimeFieldNames, isoTimeFieldNames) -} +export const durationTimeFieldsToIso = remapProps.bind( + undefined, + durationTimeFieldNames, + isoTimeFieldNames, +) export function durationTimeFieldsToIsoStrict(durationFields) { if (durationHasDateParts(durationFields)) { diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index 8825f66a..759d400e 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -5,10 +5,10 @@ import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createLazyMap, - excludeProps, - hasAnyMatchingProps, + excludePropsByName, + hasAnyPropsByName, identityFunc, - zipSingleValue, + mapPropNamesToConstant, } from './utils' export const standardCalendarId = 'en-GB' // gives 24-hour clock @@ -114,7 +114,7 @@ export function resolveZonedFormattable( if ( options.timeZoneName === undefined && - !hasAnyMatchingProps(options, dateTimeOptionNames) + !hasAnyPropsByName(options, dateTimeOptionNames) ) { // The rest of the defaults will be filled in by formatting the Instant options.timeZoneName = 'short' @@ -208,12 +208,13 @@ const optionTransformers = { } function createTransformer(optionNames, basicNames, exclusionNames) { - const defaults = zipSingleValue(basicNames, 'numeric') + const defaults = mapPropNamesToConstant(basicNames, 'numeric') + const exclusionNamesSet = new Set(exclusionNames) return (options) => { - options = excludeProps(options, exclusionNames) + options = excludePropsByName(options, exclusionNamesSet) - if (!hasAnyMatchingProps(options, optionNames)) { + if (!hasAnyPropsByName(options, optionNames)) { Object.assign(options, defaults) } diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index d945a1f0..1374ed88 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -6,7 +6,7 @@ import { constrainIsoTimeFields, } from './isoMath' import { toInteger } from './options' -import { mapRefiners, pluckProps, zipSingleValue } from './utils' +import { mapPropNamesToConstant, mapPropsWithRefiners, pluckProps } from './utils' // Refiners // ------------------------------------------------------------------------------------------------- @@ -49,26 +49,26 @@ export const isoTimeFieldNames = isoTimeFieldNamesAsc.sort() // Defaults // ------------------------------------------------------------------------------------------------- -export const isoTimeFieldDefaults = zipSingleValue(isoTimeFieldNames, 0) +export const isoTimeFieldDefaults = mapPropNamesToConstant(isoTimeFieldNames, 0) // Refining // ------------------------------------------------------------------------------------------------- export function refineIsoTimeInternals(rawIsoTimeInternals) { return constrainIsoTimeFields( - mapRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), + mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), ) } export function refineIsoDateInternals(rawIsoDateInternals) { return constrainIsoDateInternals( - mapRefiners(rawIsoDateInternals, isoDateInternalRefiners), + mapPropsWithRefiners(rawIsoDateInternals, isoDateInternalRefiners), ) } export function refineIsoDateTimeInternals(rawIsoDateTimeInternals) { return constrainIsoDateTimeInternals( - mapRefiners(rawIsoDateTimeInternals, isoDateTimeInternalRefiners), + mapPropsWithRefiners(rawIsoDateTimeInternals, isoDateTimeInternalRefiners), ) } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index a3bfd582..d1117e92 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -6,7 +6,7 @@ import { bigIntToLargeInt } from './largeInt' import { dayIndex, minuteIndex, nanoIndex, unitIndexToNano, unitIndexes, yearIndex } from './units' import { clamp, - hasAnyMatchingProps, + hasAnyPropsByName, isObjectlike, roundExpand, roundHalfCeil, @@ -396,7 +396,7 @@ function normalizeRequiredOptions(options, atomicName) { } function mustHaveMatch(obj, propNames) { - if (!hasAnyMatchingProps(obj, propNames)) { + if (!hasAnyPropsByName(obj, propNames)) { throw new TypeError('Need one: ' + JSON.stringify(propNames)) } } diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js index 054aab0c..8b1a343e 100644 --- a/packages/temporal-polyfill/src/new/units.js +++ b/packages/temporal-polyfill/src/new/units.js @@ -1,5 +1,5 @@ import { LargeInt, numberToLargeInt } from './largeInt' -import { mapArrayToProps } from './utils' +import { mapPropNamesToIndex } from './utils' export const nanoIndex = 0 export const microIndex = 1 @@ -25,7 +25,7 @@ export const unitNamesAsc = [ 'year', ] -export const unitIndexes = mapArrayToProps(unitNamesAsc) +export const unitIndexes = mapPropNamesToIndex(unitNamesAsc) // Nanoseconds // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 42327f41..3ffd3863 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -1,59 +1,127 @@ -export function isObjectlike() { -} +// TODO: auto these utils -export function mapRefiners(input, refinerMap) { - // loops get driven props of input -} +const objectlikeRE = /object|function/ -export function mapProps(input, refinerMap) { - // loops get driven my refinerMap +export function isObjectlike(arg) { + return arg !== null && objectlikeRE.test(typeof arg) } -export function mapArrayToProps() { // propNameToProps - // TODO: auto uses of this because often a {key:value} will take up same minification space - // as defining an array of strings and running it through this function -} +export function mapProps(transformer, props, extraArg) { + const res = {} -export function remapProps(obj, oldKeys, newKeys) { - // TODO: put key args in front so can use bind? -} + for (const propName in props) { + res[propName] = transformer(props[propName], propName, extraArg) + } -export function pluckProps(propNames, obj) { + return res } -export function removeDuplicateStrings(a0, a1) { - // if we use a Set(), can be generalized away from just strings!!! +export const mapPropsWithRefiners = mapProps.bind( + undefined, + (propValue, propName, refinerMap) => refinerMap[propName](propValue, propName), +) + +export function mapPropNames(generator, propNames, extraArg) { + const res = {} + + for (let i = 0; i < propNames.length; i++) { + const propName = propNames[i] + res[propName] = generator(propName, i, extraArg) + } + + return res } -export function removeUndefines(obj) { // and copy +export const mapPropNamesToIndex = mapPropNames.bind( + undefined, + (propName, index) => index, +) + +export const mapPropNamesToConstant = mapPropNames.bind( + undefined, + (propName, index, extraArg) => extraArg, +) + +export function remapProps(oldKeys, newKeys, props) { + const res = {} + + for (let i = 0; i < oldKeys.length; i++) { + res[newKeys[i]] = props[oldKeys[i]] + } + + return res } -export function buildWeakMapCache() { +export function pluckProps(propNames, props) { + const res = {} + + for (const propName of propNames) { + res[propName] = props[propName] + } + + return res } -export function createLazyMap() { +export function excludeArrayDuplicates(a) { + return [...new Set(a)] } -export function excludeProps(options, propNames) { +function filterProps(filterFunc, props, extraArg) { + const res = {} + + for (const propName in props) { + const propValue = props[propName] + + if (filterFunc(propValue, propName, extraArg)) { + res[propName] = propValue + } + } + + return res } -export function hasAnyMatchingProps(props, propNames) { +export const excludeUndefinedProps = filterProps.bind( + undefined, + (propValue) => propValue !== undefined, +) + +export const excludePropsByName = filterProps.bind( + undefined, + (propValue, propName, nameSet) => !nameSet.has(propName), +) + +export function hasAnyPropsByName(props, names) { + for (const name of names) { + if (props[name] !== undefined) { + return true + } + } + return false } -export function hasAllMatchingProps(props, propNames) { +export function hasAllPropsByName(props, names) { + for (const name of names) { + if (props[name] === undefined) { + return false + } + } + return true } -export function zipSingleValue() { +export function buildWeakMapCache() { } -export function defineProps(target, propVals) { - return Object.defineProperties(target, createPropDescriptors(propVals)) +export function createLazyMap() { } // descriptor stuff // ---------------- +export function defineProps(target, propVals) { + return Object.defineProperties(target, createPropDescriptors(propVals)) +} + export function createPropDescriptors(props) { return mapProps(props, (value) => ({ value, diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 2ce8b451..5fc7321e 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -90,17 +90,17 @@ export const [ // ----------------------------------------------------------------------------------------------- { - ...mapProps(epochGetters, (getter) => { + ...mapProps((getter) => { return function(internals) { return getter(internals.epochNanoseconds) } - }), + }, epochGetters), - ...mapProps(dateTimeGetters, (getter) => { + ...mapProps((getter) => { return function(internals) { return getter(zonedInternalsToIso(internals)) } - }), + }, dateTimeGetters), hoursInDay(internals) { return computeNanosecondsInDay( From a6c98dcf7752305dfcc1983d8f85456686862990 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 19:37:49 -0400 Subject: [PATCH 118/805] implement createLazyMap --- .../temporal-polyfill/src/new/calendarImpl.js | 10 +++++----- packages/temporal-polyfill/src/new/utils.js | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 12828fbc..938c233b 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -41,7 +41,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { rejectI } from './options' import { milliInDay } from './units' -import { buildWeakMapCache, clamp, createLazyMap, mapPropNamesToIndex, twoDigit } from './utils' +import { clamp, createLazyMap, mapPropNamesToIndex, twoDigit } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -541,17 +541,17 @@ interface IntlFields { */ function createIntlFieldCache(epochMilliToIntlFields) { - return buildWeakMapCache((isoDateFields) => { + return createLazyMap((isoDateFields) => { const epochMilli = isoToEpochMilli(isoDateFields) return epochMilliToIntlFields(epochMilli) - }) + }, WeakMap) } function createJapaneseFieldCache() { const epochMilliToIntlFields = createEpochMilliToIntlFields(japaneseCalendarId) const primaryEraMilli = isoArgsToEpochMilli(1868, 9, 8) - return buildWeakMapCache((isoDateFields) => { + return createLazyMap((isoDateFields) => { const epochMilli = isoToEpochMilli(isoDateFields) const intlFields = epochMilliToIntlFields(epochMilli) @@ -561,7 +561,7 @@ function createJapaneseFieldCache() { } return intlFields - }) + }, WeakMap) } function createEpochMilliToIntlFields(calendarId) { diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 3ffd3863..c067594e 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -109,10 +109,18 @@ export function hasAllPropsByName(props, names) { return true } -export function buildWeakMapCache() { -} - -export function createLazyMap() { +export function createLazyMap(generator, MapClass = Map) { + const map = new MapClass() + + return (key, ...otherArgs) => { + if (map.has(key)) { + return map.get(key) + } else { + const val = generator(key, ...otherArgs) + map.set(key, val) + return val + } + } } // descriptor stuff From fb43013abd3033b82b0f1fae6dc945bd14c4fe30 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 19:43:00 -0400 Subject: [PATCH 119/805] createLazyGenerator --- packages/temporal-polyfill/src/new/calendarImpl.js | 10 +++++----- packages/temporal-polyfill/src/new/intlFormat.js | 4 ++-- packages/temporal-polyfill/src/new/timeZoneImpl.js | 6 +++--- packages/temporal-polyfill/src/new/timeZoneOps.js | 4 ++-- packages/temporal-polyfill/src/new/utils.js | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 938c233b..39cca84c 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -41,7 +41,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { rejectI } from './options' import { milliInDay } from './units' -import { clamp, createLazyMap, mapPropNamesToIndex, twoDigit } from './utils' +import { clamp, createLazyGenerator, mapPropNamesToIndex, twoDigit } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -512,7 +512,7 @@ const calendarImplClasses = { [japaneseCalendarId]: JapaneseCalendarImpl, } -const queryCalendarImplWithClass = createLazyMap((calendarId, CalendarImplClass) => { +const queryCalendarImplWithClass = createLazyGenerator((calendarId, CalendarImplClass) => { return new CalendarImplClass(calendarId) }) @@ -541,7 +541,7 @@ interface IntlFields { */ function createIntlFieldCache(epochMilliToIntlFields) { - return createLazyMap((isoDateFields) => { + return createLazyGenerator((isoDateFields) => { const epochMilli = isoToEpochMilli(isoDateFields) return epochMilliToIntlFields(epochMilli) }, WeakMap) @@ -551,7 +551,7 @@ function createJapaneseFieldCache() { const epochMilliToIntlFields = createEpochMilliToIntlFields(japaneseCalendarId) const primaryEraMilli = isoArgsToEpochMilli(1868, 9, 8) - return createLazyMap((isoDateFields) => { + return createLazyGenerator((isoDateFields) => { const epochMilli = isoToEpochMilli(isoDateFields) const intlFields = epochMilliToIntlFields(epochMilli) @@ -619,7 +619,7 @@ function buildIntlFormat(calendarId) { function createIntlMonthCache(epochMilliToIntlFields) { const yearAtEpoch = epochMilliToIntlFields(0).year const yearCorrection = yearAtEpoch - isoEpochOriginYear - const queryYear = createLazyMap(buildYear) + const queryYear = createLazyGenerator(buildYear) function buildYear(year) { let epochMilli = isoArgsToEpochMilli(year - yearCorrection) diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.js index 759d400e..38165097 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.js @@ -4,7 +4,7 @@ import { getInternals, getTemporalName } from './class' import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { - createLazyMap, + createLazyGenerator, excludePropsByName, hasAnyPropsByName, identityFunc, @@ -65,7 +65,7 @@ export class DateTimeFormat extends IntlDateTimeFormat { // DateTimeFormat Helpers // ------------------------------------------------------------------------------------------------- -const getGetSpecificFormat = createLazyMap(() => createLazyMap(createSpecificFormat), WeakMap) +const getGetSpecificFormat = createLazyGenerator(() => createLazyGenerator(createSpecificFormat), WeakMap) function createSpecificFormat(transformOptions, resolvedOptions) { return new IntlDateTimeFormat(resolvedOptions.locale, transformOptions(resolvedOptions)) diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.js index 828af7f7..8317e108 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.js @@ -12,7 +12,7 @@ import { } from './isoMath' import { parseOffsetNano } from './isoParse' import { milliInSec, nanoInSec, secInDay } from './units' -import { clamp, compareNumbers, createLazyMap } from './utils' +import { clamp, compareNumbers, createLazyGenerator } from './utils' const periodDur = secInDay * 60 const minPossibleTransition = isoArgsToEpochSec(1847) @@ -88,8 +88,8 @@ export class IntlTimeZoneImpl { } function createIntlTimeZoneStore(computeOffsetSec) { - const getSample = createLazyMap(computeOffsetSec) // always given startEpochSec/endEpochSec - const getSplit = createLazyMap((startEpochSec, endEpochSec) => [startEpochSec, endEpochSec]) + const getSample = createLazyGenerator(computeOffsetSec) // always given startEpochSec/endEpochSec + const getSplit = createLazyGenerator((startEpochSec, endEpochSec) => [startEpochSec, endEpochSec]) let minTransition = minPossibleTransition let maxTransition = maxPossibleTransition diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.js index 67e162d8..45d3d245 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.js @@ -19,7 +19,7 @@ import { roundToMinute } from './round' import { TimeZone, createTimeZone, timeZoneProtocolMethods } from './timeZone' import { queryTimeZoneImpl } from './timeZoneImpl' import { nanoInUtcDay } from './units' -import { createLazyMap } from './utils' +import { createLazyGenerator } from './utils' export const utcTimeZoneId = 'UTC' @@ -175,7 +175,7 @@ function computeGapNear(timeZoneOps, zonedEpochNano) { return endOffsetNano - startOffsetNano } -export const zonedInternalsToIso = createLazyMap((internals) => { +export const zonedInternalsToIso = createLazyGenerator((internals) => { const { timeZone, epochNanoseconds } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) const isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index c067594e..c852f819 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -109,7 +109,7 @@ export function hasAllPropsByName(props, names) { return true } -export function createLazyMap(generator, MapClass = Map) { +export function createLazyGenerator(generator, MapClass = Map) { const map = new MapClass() return (key, ...otherArgs) => { From 2afb245e40baa145fe1c80180e7ccc5c8e8c96fe Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 3 Jul 2023 23:38:06 -0400 Subject: [PATCH 120/805] some stuff --- packages/temporal-polyfill/src/new/calendarImpl.js | 5 +++-- packages/temporal-polyfill/src/new/options.js | 2 +- packages/temporal-polyfill/src/new/utils.js | 6 ++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 39cca84c..3d06b4ed 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -41,7 +41,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { rejectI } from './options' import { milliInDay } from './units' -import { clamp, createLazyGenerator, mapPropNamesToIndex, twoDigit } from './utils' +import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -702,12 +702,13 @@ function refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) { } function formatMonthCode(month, leapMonth) { - return 'M' + twoDigit( + return 'M' + padNumber( month - ( (leapMonth && month >= leapMonth) ? 1 : 0 ), + 2, ) + ((month === leapMonth) ? 'L' : '') } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index d1117e92..7e1d5ee5 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -153,7 +153,7 @@ function refineTimeDisplayTuple(options) { // trace callers of this, make sure u const subsecDigits = refineSubsecDigits(options) return [ - subsecDigits === undefined ? 1 : Math.pow(10, 9 - subsecDigits), // TODO: use 10** notation? + subsecDigits === undefined ? 1 : 10 ** (9 - subsecDigits), refineRoundingMode(options, truncI), subsecDigits, ] diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index c852f819..f29a756e 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -1,6 +1,4 @@ -// TODO: auto these utils - const objectlikeRE = /object|function/ export function isObjectlike(arg) { @@ -164,8 +162,8 @@ export function identityFunc(thing) { export function noop() { } -export function twoDigit(num) { // as a string - // TODO +export function padNumber(num, digits) { + return num.padStart(digits, '0') } export function compareNumbers(a, b) { From 887b2c64d7576c092add338a0739acee75346fb4 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 12:36:01 -0400 Subject: [PATCH 121/805] finish isoMath --- .../temporal-polyfill/src/new/isoFields.js | 6 +- packages/temporal-polyfill/src/new/isoMath.js | 108 ++++++++++++------ packages/temporal-polyfill/src/new/utils.js | 12 +- 3 files changed, 88 insertions(+), 38 deletions(-) diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 1374ed88..7822189b 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -29,7 +29,7 @@ export const isoTimeFieldRefiners = { isoSecond: toInteger, } -// Unordered +// Ordered by ascending size export const isoDateTimeInternalRefiners = { ...isoDateInternalRefiners, ...isoTimeFieldRefiners, @@ -42,7 +42,7 @@ const isoDateInternalNames = Object.keys(isoDateInternalRefiners) export const isoDateTimeInternalNames = Object.keys(isoDateTimeInternalRefiners).sort() export const isoDateFieldNames = isoDateInternalNames.slice(1) // no calendar -const isoDateTimeFieldNames = isoDateTimeInternalRefiners.slice(1) // no calendar +export const isoDateTimeFieldNamesAsc = isoDateTimeInternalRefiners.slice(1) // no calendar export const isoTimeFieldNamesAsc = Object.keys(isoTimeFieldRefiners) export const isoTimeFieldNames = isoTimeFieldNamesAsc.sort() @@ -77,7 +77,7 @@ export function refineIsoDateTimeInternals(rawIsoDateTimeInternals) { export const pluckIsoDateInternals = pluckProps.bind(undefined, isoDateInternalNames) export const pluckIsoDateTimeInternals = pluckProps.bind(undefined, isoDateTimeInternalNames) -export const pluckIsoDateTimeFields = pluckProps.bind(undefined, isoDateTimeFieldNames) +export const pluckIsoDateTimeFields = pluckProps.bind(undefined, isoDateTimeFieldNamesAsc) export const pluckIsoTimeFields = pluckProps.bind(undefined, isoTimeFieldNames) export const generatePublicIsoDateFields = diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 8ef2b8b0..98f2974c 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,4 +1,4 @@ -import { isoTimeFieldNamesAsc, pluckIsoDateTimeFields } from './isoFields' +import { isoDateTimeFieldNamesAsc, isoTimeFieldNamesAsc, pluckIsoDateTimeFields } from './isoFields' import { compareLargeInts, numberToLargeInt } from './largeInt' import { clampProp, rejectI } from './options' // use 1 instead of rejectI? import { @@ -11,7 +11,7 @@ import { nanoInUtcDay, nanoToGivenFields, } from './units' -import { divFloorMod } from './utils' +import { compareProps, divFloorMod } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -47,7 +47,11 @@ export function computeIsoIsLeapYear(isoYear) { } export function computeIsoDayOfWeek(isoDateFields) { - return isoToLegacyDate(isoDateFields).getDay() + 1 + return isoToLegacyDate( + isoDateFields.isoYear, + isoDateFields.isoMonth, + isoDateFields.isoDay, + ).getDay() + 1 } export function computeIsoWeekOfYear(isoDateFields) { @@ -194,68 +198,104 @@ export function validateEpochNano(epochNano) { // ------------------------------------------------------------------------------------------------- // ISO Fields -> Epoch -// (could be out-of-bounds, return undefined!) export function isoToEpochSec(isoDateTimeFields) { - const epochSec = isoArgsToEpochSec( - isoDateTimeFields.year, - isoDateTimeFields.month, - isoDateTimeFields.day, - isoDateTimeFields.hour, - isoDateTimeFields.minute, - isoDateTimeFields.second, - ) + const epochSec = isoArgsToEpochSec(...pluckIsoDateTimeFields(isoDateTimeFields)) + // ^assume valid + const subsecNano = - isoDateTimeFields.millisecond * nanoInMilli + - isoDateTimeFields.microsecond * nanoInMicro + - isoDateTimeFields.nanosecond + isoDateTimeFields.isoMillisecond * nanoInMilli + + isoDateTimeFields.isoMicrosecond * nanoInMicro + + isoDateTimeFields.isoNanosecond return [epochSec, subsecNano] } +/* +If out-of-bounds, returns undefined +*/ export function isoToEpochMilli(isoDateTimeFields) { return isoArgsToEpochMilli(...pluckIsoDateTimeFields(isoDateTimeFields)) } +/* +If out-of-bounds, returns undefined +*/ export function isoToEpochNano(isoDateTimeFields) { - // if invalid, should return undefined + const epochMilli = isoToEpochMilli(isoDateTimeFields) + + if (epochMilli !== undefined) { + return numberToLargeInt(epochMilli) + .mult(nanoInMilli) + .addNumber( + isoDateTimeFields.isoMicrosecond * nanoInMicro + + isoDateTimeFields.isoNanosecond, + ) + } } // ISO Arguments -> Epoch -// (could be out-of-bounds, return undefined!) -export function isoArgsToEpochSec(...args) { // doesn't accept beyond sec - return isoArgsToEpochMilli(...args) / milliInSec // no need for rounding +export function isoArgsToEpochSec(...args) { + return isoArgsToEpochMilli(...args) / milliInSec // assume valid +} + +/* +If out-of-bounds, returns undefined +*/ +export function isoArgsToEpochMilli(...args) { + const legacyDate = isoToLegacyDate(...args) + const epochMilli = legacyDate.getTime() + + if (!isNaN(epochMilli)) { + return epochMilli + } } -export function isoArgsToEpochMilli( +function isoToLegacyDate( isoYear, - isoMonth = 1, - isoDate, // rest are optional... + isoMonth = 1, // rest are optional... + isoDate, isoHour, - isMinute, + isoMinute, isoSec, isoMilli, ) { -} - -function isoToLegacyDate(isoDateTimeFields) { + // Note: Date.UTC() interprets one and two-digit years as being in the + // 20th century, so don't use it + const legacyDate = new Date() + legacyDate.setUTCHours(isoHour, isoMinute, isoSec, isoMilli) + legacyDate.setUTCFullYear(isoYear, isoMonth - 1, isoDate) + return legacyDate } // Epoch -> ISO Fields -export function epochNanoToIso() { +export function epochNanoToIso(epochNano) { + const [epochMilli, nanoRemainder] = epochNano.divFloorMod(nanoInMilli) + const [isoMicrosecond, isoNanosecond] = divFloorMod(nanoRemainder, nanoInMicro) + return { + ...epochMilliToIso(epochMilli), + isoMicrosecond, + isoNanosecond, + } } -export function epochMilliToIso() { +export function epochMilliToIso(epochMilli) { + const legacyDate = new Date(epochMilli) + return { + isoYear: legacyDate.getUTCFullYear(), + isoMonth: legacyDate.getUTCMonth() + 1, + isoDay: legacyDate.getUTCDate(), + isoHour: legacyDate.getUTCHours(), + isoMinute: legacyDate.getUTCMinutes(), + isoSecond: legacyDate.getUTCSeconds(), + isoMillisecond: legacyDate.getUTCMilliseconds(), + } } // Comparison // ------------------------------------------------------------------------------------------------- -export function compareIsoDateTimeFields() { - // TODO: (use Math.sign technique?) -} - -export function compareIsoTimeFields() { -} +export const compareIsoDateTimeFields = compareProps.bind(undefined, isoDateTimeFieldNamesAsc) +export const compareIsoTimeFields = compareProps.bind(undefined, isoTimeFieldNamesAsc) diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index f29a756e..57d89dc7 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -167,7 +167,17 @@ export function padNumber(num, digits) { } export function compareNumbers(a, b) { - return a - b + return Math.sign(a - b) +} + +export function compareProps(propNames, props0, props1) { + for (const propName of propNames) { + const cmp = compareNumbers(props0[propName], props1[propName]) + if (cmp) { + return cmp + } + } + return 0 } export function clamp( From 18bd6fe9629fb7ce0182cde2682c969c75deda1a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 12:42:17 -0400 Subject: [PATCH 122/805] some formatting improvements --- packages/temporal-polyfill/src/new/isoFormat.js | 14 +++++--------- .../temporal-polyfill/src/new/plainMonthDay.js | 4 +--- .../temporal-polyfill/src/new/plainYearMonth.js | 4 +--- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.js index d980f066..9b5c2cf8 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -1,16 +1,15 @@ import { isoCalendarId } from './calendarConfig' -import { getObjId } from './class' import { alwaysI, autoI, criticalI, refineDateDisplayOptions } from './options' /* High-level. Refined options */ -export function formatPossibleDate(internals, options, formatSimple) { +export function formatPossibleDate(formatSimple, internals, options) { const calendarDisplayI = refineDateDisplayOptions(options) const showCalendar = calendarDisplayI === alwaysI || // TODO: use math >=< comparisons? calendarDisplayI === criticalI || - getObjId(internals.calendar) !== isoCalendarId + internals.calendar.id !== isoCalendarId if (showCalendar) { return formatIsoDateFields(internals) + formatCalendar(internals.calendar, calendarDisplayI) @@ -34,24 +33,21 @@ export function formatIsoMonthDayFields(isoDateFields) { export function formatIsoDateTimeFields( isoDateTimeFields, - showSecond, subsecDigits, ) { return formatIsoDateFields(isoDateTimeFields) + - 'T' + formatIsoTimeFields(isoDateTimeFields, showSecond, subsecDigits) + 'T' + formatIsoTimeFields(isoDateTimeFields, subsecDigits) } export function formatIsoTimeFields( isoTimeFields, - showSecond, - subsecDigits, + subsecDigits, // undefined/-1/# ) { } export function formatDurationInternals( durationInternals, - showSecond, - subsecDigits, + subsecDigits, // undefined/-1/# ) { } diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 09346acc..3232f3c8 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -64,9 +64,7 @@ export const [ isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals, options) { - return formatPossibleDate(internals, options, formatIsoMonthDayFields) - }, + toString: formatPossibleDate.bind(undefined, formatIsoMonthDayFields), toLocaleString: toLocaleStringMethod, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index 94d82a64..e4461230 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -93,9 +93,7 @@ export const [ isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals, options) { - return formatPossibleDate(internals, options, formatIsoYearMonthFields) - }, + toString: formatPossibleDate.bind(undefined, formatIsoYearMonthFields), toLocaleString: toLocaleStringMethod, From 17ba2b1e7e04875ef579aa84fcc0ea40b2b55f26 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 14:59:18 -0400 Subject: [PATCH 123/805] finish parsing --- .../temporal-polyfill/src/new/calendarImpl.js | 5 +- .../temporal-polyfill/src/new/isoFields.js | 18 +- .../temporal-polyfill/src/new/isoFormat.js | 183 ++++++++++++++++-- packages/temporal-polyfill/src/new/round.js | 9 +- packages/temporal-polyfill/src/new/utils.js | 4 +- 5 files changed, 188 insertions(+), 31 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 3d06b4ed..2d02d1a8 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -41,7 +41,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { rejectI } from './options' import { milliInDay } from './units' -import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber } from './utils' +import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber, padNumber2 } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -702,13 +702,12 @@ function refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) { } function formatMonthCode(month, leapMonth) { - return 'M' + padNumber( + return 'M' + padNumber2( month - ( (leapMonth && month >= leapMonth) ? 1 : 0 ), - 2, ) + ((month === leapMonth) ? 'L' : '') } diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 7822189b..398e344d 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -14,22 +14,22 @@ import { mapPropNamesToConstant, mapPropsWithRefiners, pluckProps } from './util // Ordered alphabetically export const isoDateInternalRefiners = { calendar: queryCalendarOps, - isoDay: toInteger, - isoMonth: toInteger, - isoYear: toInteger, + isoDay: toInteger, // happens to be ascending + isoMonth: toInteger, // " + isoYear: toInteger, // " } // Ordered by ascending size export const isoTimeFieldRefiners = { - isoHour: toInteger, + isoNanosecond: toInteger, isoMicrosecond: toInteger, isoMillisecond: toInteger, - isoMinute: toInteger, - isoNanosecond: toInteger, isoSecond: toInteger, + isoMinute: toInteger, + isoHour: toInteger, } -// Ordered by ascending size +// Unordered export const isoDateTimeInternalRefiners = { ...isoDateInternalRefiners, ...isoTimeFieldRefiners, @@ -41,10 +41,10 @@ export const isoDateTimeInternalRefiners = { const isoDateInternalNames = Object.keys(isoDateInternalRefiners) export const isoDateTimeInternalNames = Object.keys(isoDateTimeInternalRefiners).sort() -export const isoDateFieldNames = isoDateInternalNames.slice(1) // no calendar -export const isoDateTimeFieldNamesAsc = isoDateTimeInternalRefiners.slice(1) // no calendar +export const isoDateFieldNames = isoDateInternalNames.slice(1) // no calendar. ascending export const isoTimeFieldNamesAsc = Object.keys(isoTimeFieldRefiners) export const isoTimeFieldNames = isoTimeFieldNamesAsc.sort() +export const isoDateTimeFieldNamesAsc = [...isoDateFieldNames, ...isoTimeFieldNamesAsc] // Defaults // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.js index 9b5c2cf8..97891c3d 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -1,5 +1,15 @@ import { isoCalendarId } from './calendarConfig' -import { alwaysI, autoI, criticalI, refineDateDisplayOptions } from './options' +import { absDurationInternals, durationFieldsToNano } from './durationFields' +import { autoI, criticalI, neverI, refineDateDisplayOptions } from './options' +import { + nanoInHour, + nanoInMicro, + nanoInMilli, + nanoInMinute, + nanoInSec, + secondsIndex, +} from './units' +import { divFloorMod, padNumber, padNumber2 } from './utils' /* High-level. Refined options @@ -7,9 +17,8 @@ High-level. Refined options export function formatPossibleDate(formatSimple, internals, options) { const calendarDisplayI = refineDateDisplayOptions(options) const showCalendar = - calendarDisplayI === alwaysI || // TODO: use math >=< comparisons? - calendarDisplayI === criticalI || - internals.calendar.id !== isoCalendarId + calendarDisplayI > neverI || // critical or always + (calendarDisplayI === autoI && internals.calendar.id !== isoCalendarId) if (showCalendar) { return formatIsoDateFields(internals) + formatCalendar(internals.calendar, calendarDisplayI) @@ -22,49 +31,191 @@ export function formatPossibleDate(formatSimple, internals, options) { Rounding already happened with these... */ +export function formatIsoDateTimeFields( + isoDateTimeFields, + subsecDigits, +) { + return formatIsoDateFields(isoDateTimeFields) + + 'T' + formatIsoTimeFields(isoDateTimeFields, subsecDigits) +} + export function formatIsoDateFields(isoDateFields) { + return formatIsoYearMonthFields(isoDateFields) + '-' + padNumber2(isoDateFields.isoDay) } export function formatIsoYearMonthFields(isoDateFields) { + const { isoYear } = isoDateFields + return ( + (isoYear < 0 || isoYear > 9999) + ? getSignStr(isoYear) + padNumber(6, Math.abs(isoYear)) + : padNumber(4, isoYear) + ) + '-' + padNumber2(isoDateFields.isoMonth) } export function formatIsoMonthDayFields(isoDateFields) { -} - -export function formatIsoDateTimeFields( - isoDateTimeFields, - subsecDigits, -) { - return formatIsoDateFields(isoDateTimeFields) + - 'T' + formatIsoTimeFields(isoDateTimeFields, subsecDigits) + return padNumber2(isoDateFields.isoMonth) + '-' + padNumber2(isoDateFields.isoDay) } export function formatIsoTimeFields( isoTimeFields, subsecDigits, // undefined/-1/# ) { + const parts = [ + padNumber2(isoTimeFields.isoHour), + padNumber2(isoTimeFields.isoMinute), + ] + + if (subsecDigits !== -1) { // show seconds? + parts.push( + padNumber2(isoTimeFields.isoSecond) + + formatSubsec( + isoTimeFields.isoMillisecond, + isoTimeFields.isoMicrosecond, + isoTimeFields.isoNanosecond, + subsecDigits, + ), + ) + } + + return parts.join(':') +} + +export function formatOffsetNano( + offsetNano, + offsetDisplayI = autoI, // auto/never +) { + if (offsetDisplayI === neverI) { + return '' + } + + const [hour, nanoRemainder0] = divFloorMod(Math.abs(offsetNano), nanoInHour) + const [minute, nanoRemainder1] = divFloorMod(nanoRemainder0, nanoInMinute) + const [second, nanoRemainder2] = divFloorMod(nanoRemainder1, nanoInSec) + + return getSignStr(offsetNano) + + padNumber2(hour) + + padNumber2(minute) + + ((second || nanoRemainder2) + ? ':' + padNumber2(second) + formatSubsecNano(nanoRemainder2) + : '') } export function formatDurationInternals( durationInternals, subsecDigits, // undefined/-1/# ) { + const { sign } = durationInternals + const abs = absDurationInternals(durationInternals) + const { hours, minutes } = abs + const secondsNano = durationFieldsToNano(abs, secondsIndex) + const [wholeSeconds, subsecNano] = divFloorMod(secondsNano, nanoInSec) + const forceSeconds = + subsecDigits > 0 || // # of subsecond digits being forced? + !sign // completely empty? display 'PT0S' + + return (sign < 0 ? '-' : '') + 'P' + formatDurationFragments({ + Y: abs.years, + M: abs.months, + W: abs.weeks, + D: abs.days, + }) + ( + (hours || minutes || wholeSeconds || subsecNano || forceSeconds) + ? 'T' + formatDurationFragments({ + H: hours, + M: minutes, + S: wholeSeconds + ( + formatSubsecNano(subsecNano, subsecDigits) || + (forceSeconds ? '' : 0) // string concatenation will force truthiness + ), + }) + : '' + ) } -export function formatOffsetNano( - offsetNanoseconds, - offsetDisplayI = autoI, // auto/never -) { +/* +Values are guaranteed to be non-negative +*/ +function formatDurationFragments(fragObj) { + const parts = [] + + for (const fragName in fragObj) { + const fragVal = fragObj[fragName] + if (fragVal) { + parts.push(formatNumberNoSciNot(fragVal) + fragName) + } + } + + return parts.join('') } +// +// complex objs +// + export function formatTimeZone( timeZoneOps, timeZoneDisplayI, ) { + if (timeZoneDisplayI !== neverI) { + return '[' + + (timeZoneDisplayI === criticalI ? '!' : '') + + timeZoneOps.id + + ']' + } + return '' } export function formatCalendar( calendarOps, calendarDisplayI, ) { + if ( + calendarDisplayI > neverI || // critical or always + (calendarDisplayI === autoI && calendarOps.id !== isoCalendarId) + ) { + return '[' + + (calendarDisplayI === criticalI ? '!' : '') + + calendarOps.id + + ']' + } + return '' +} + +// +// utils +// + +function formatSubsec( + isoMillisecond, + isoMicrosecond, + isoNanosecond, + subsecDigits, // undefined/# +) { + return formatSubsecNano( + isoMillisecond * nanoInMilli + + isoMicrosecond * nanoInMicro + + isoNanosecond, + subsecDigits, + ) +} + +const trailingZerosRE = /0+$/ + +function formatSubsecNano(totalNano, subsecDigits) { // subsecDigits can be undefined + let s = padNumber(9, totalNano) + s = subsecDigits === undefined + ? s.replace(trailingZerosRE, '') + : s.substring(0, subsecDigits) + + return s ? '.' + s : '' +} + +function getSignStr(num) { + return num < 0 ? '-' : '+' +} + +function formatNumberNoSciNot(n) { + // avoid outputting scientific notation + // https://stackoverflow.com/a/50978675/96342 + return n.toLocaleString('fullwide', { useGrouping: false }) } diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index afae2251..d4e8c18b 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -108,13 +108,18 @@ export function roundDayTimeDuration( ) } +/* +Only does day-time rounding +*/ export function roundDurationToNano(durationFields, nanoInc, roundingMode) { const largeNano = durationFieldsToNano(durationFields) const roundedLargeNano = roundByIncLarge(largeNano, nanoInc, roundingMode) + const dayTimeFields = nanoToDurationFields(roundedLargeNano) return { - ...durationFieldDefaults, - ...nanoToDurationFields(roundedLargeNano), + ...durationFields, + ...dayTimeFields, + days: durationFields.days + dayTimeFields.days, } } diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 57d89dc7..03aeb3e0 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -162,10 +162,12 @@ export function identityFunc(thing) { export function noop() { } -export function padNumber(num, digits) { +export function padNumber(digits, num) { return num.padStart(digits, '0') } +export const padNumber2 = padNumber.bind(undefined, 2) + export function compareNumbers(a, b) { return Math.sign(a - b) } From dadfe33c00486c564e3605251dc0f91356ce7d7b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 15:51:19 -0400 Subject: [PATCH 124/805] parsing for datetimes --- .../temporal-polyfill/src/new/isoParse.js | 307 ++++++++++++------ 1 file changed, 205 insertions(+), 102 deletions(-) diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index ffdbc16c..20663924 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -1,4 +1,6 @@ +import { nanoInSecond } from '../dateUtils/units' import { isoCalendarId } from './calendarConfig' +import { queryCalendarImpl } from './calendarImpl' import { pluckIsoDateInternals, pluckIsoDateTimeInternals, @@ -9,45 +11,40 @@ import { constrainIsoDateTimeInternals, constrainIsoTimeFields, isoToEpochNano, + nanoToIsoTimeAndDay, } from './isoMath' +import { queryTimeZoneImpl } from './timeZoneImpl' import { getMatchingInstantFor, utcTimeZoneId } from './timeZoneOps' - -// TODO: finish isoParse +import { nanoInHour, nanoInMinute } from './units' // High-level // ------------------------------------------------------------------------------------------------- export function parseInstant(s) { const parsed = parseDateTime(s) + if (!parsed) { + throw new RangeError() + } - if (parsed) { - let offsetNano - - if (parsed.hasZ) { - offsetNano = 0 - } else if (parsed.offset) { - offsetNano = parseOffsetNano(parsed.offset) - } else { - return new RangeError() - } + let offsetNano - return isoToEpochNano(parsed).addNumber(offsetNano) + if (parsed.hasZ) { + offsetNano = 0 + } else if (parsed.offset) { + offsetNano = parseOffsetNano(parsed.offset) + } else { + return new RangeError() } - throw new RangeError() + return isoToEpochNano(parsed).addNumber(offsetNano) } export function parseZonedDateTime(s) { - const parsed = parseDateTime(s) // TODO: use just 'calendar' and 'timeZone' ? - - if (parsed) { - if (!parsed.timeZone) { - throw new RangeError() - } - return processZonedDateTimeParse(parsed) + const parsed = parseDateTime(s) + if (!parsed || !parsed.timeZone) { + throw new RangeError() } - - throw new RangeError() + return processZonedDateTimeParse(parsed) } export function processZonedDateTimeParse(parsed) { @@ -60,7 +57,6 @@ export function processZonedDateTimeParse(parsed) { 'compatible', true, // fuzzy ) - return { epochNanoseconds, timeZone: parsed.timeZone, @@ -70,52 +66,26 @@ export function processZonedDateTimeParse(parsed) { export function parsePlainDateTime(s) { const parsed = parseDateTime(s) - if (parsed) { - return pluckIsoDateTimeInternals(parsed) + if (!parsed) { + throw new RangeError() } - - throw new RangeError() + return pluckIsoDateTimeInternals(parsed) } export function parsePlainDate(s) { const parsed = parseDateTime(s) - if (parsed) { - return parsed + if (!parsed) { + throw new RangeError() } - - throw new RangeError() + return pluckIsoDateInternals(parsed) } export function parsePlainYearMonth(s) { - let parsed = parseYearMonth(s) - if (!parsed) { - parsed = parseDateTime(s) - if (parsed) { - parsed = pluckIsoDateInternals(parsed) - } - } - - if (parsed) { - return parsed - } - - throw new RangeError() + return parseYearMonth(s) || parsePlainDate(s) // parsePlainDate will throw error } export function parsePlainMonthDay(s) { - let parsed = parseMonthDay(s) - if (!parsed) { - parsed = parseDateTime(s) - if (parsed) { - parsed = pluckIsoDateInternals(parsed) - } - } - - if (parsed) { - return parsed - } - - throw new RangeError() + return parseMonthDay(s) || parsePlainDate(s) // parsePlainDate will throw error } export function parsePlainTime(s) { @@ -123,31 +93,28 @@ export function parsePlainTime(s) { if (!parsed) { parsed = parseDateTime(s) - if (parsed && !parsed.hasTime) { throw new RangeError() } } - if (parsed) { - if (parsed.hasZ) { - throw new RangeError() - } - if (parsed.calendar !== undefined && parsed.calendar !== isoCalendarId) { - throw new RangeError() - } - - if (parseMonthDay(s)) { - throw new RangeError() - } - if (parseYearMonth(s)) { - throw new RangeError() - } - - return pluckIsoTimeFields(parsed) + if (!parsed) { + throw new RangeError() + } + if (parsed.hasZ) { + throw new RangeError() + } + if (parsed.calendar !== undefined && parsed.calendar.id !== isoCalendarId) { + throw new RangeError() + } + if (parseMonthDay(s)) { + throw new RangeError() + } + if (parseYearMonth(s)) { + throw new RangeError() } - throw new RangeError() + return pluckIsoTimeFields(parsed) } export function parseCalendarId(s) { @@ -156,7 +123,6 @@ export function parseCalendarId(s) { parseDateTime(s) || parseYearMonth(s) || parseMonthDay(s) )?.calendar.id || isoCalendarId } - return s } @@ -177,49 +143,186 @@ export function parseTimeZoneId(s) { return s } +export function parseOffsetNano(s) { + const parts = numericOffsetRegExp.exec(normalizeDashes(s)) + return parts && parseOffsetParts(parts.slice(1)) +} + +export function parseDuration(s) { + // includes sign +} + // Low-level // ------------------------------------------------------------------------------------------------- +const yearMonthRegExpStr = + '([+-]\\d{6}|\\d{4})' + // 0:year + '-?(\\d{2})' // 1:month + // 2:annotations + +const dateRegExpStr = + yearMonthRegExpStr + // 0:year, 1:month + '-?(\\d{2})' // 2:day + // 3:annotations + +const monthDayRegExpStr = + '(--)?(\\d{2})' + // 1:month + '-?(\\d{2})' // 2:day + // 3:annotations + +const numericTimeRegExpStr = + '(\\d{2})' + // 0:hour + '(:?(\\d{2})' + // 2:minute (NOTE: ':?' means optional ':') + '(:?(\\d{2})' + // 4:second + '([.,](\\d{1,9}))?' + // 6:afterDecimal + ')?)?' + +const numericOffsetRegExpStr = + '([+-])' + // 0:plusOrMinus + numericTimeRegExpStr // 1:hour, 3:minute, 5:second, 7:afterDecimal + +const offsetRegExpStr = + '(Z|' + // 0:zOrOffset + numericOffsetRegExpStr + // 1:plusOrMinus, 2:hour, 4:minute, 6:second, 8:afterDecimal + ')?' + +const timeRegExpStr = + numericTimeRegExpStr + // 0:hour, 2:minute, 4:second, 6:afterDecimal + offsetRegExpStr // 7:zOrOffset, 8:plusOrMinus, 9:hour, 11:minute, 13:second, 15:afterDecimal + // 16:annotations + +const dateTimeRegExpStr = + dateRegExpStr + // 0:year, 1:month, 2:day + '([T ]' + // 3:timeEverything + timeRegExpStr + + // 4:hour, 6:minute, 8:second, 10:afterDecimal + // 11:zOrOffset, 12:plusOrMinus, 13:hour, 15:minute, 17:second, 19:afterDecimal + ')?' + // 20:annotations + +const annotationRegExpStr = '((\\[[^\\]]*\\])*)' + +const yearMonthRegExp = createRegExp(yearMonthRegExpStr + annotationRegExpStr) +const monthDayRegExp = createRegExp(monthDayRegExpStr + annotationRegExpStr) +const dateTimeRegExp = createRegExp(dateTimeRegExpStr + annotationRegExpStr) +const timeRegExp = createRegExp('T?' + timeRegExpStr + annotationRegExpStr) +const numericOffsetRegExp = createRegExp(numericOffsetRegExpStr) // annotations not allowed + function parseDateTime(s) { - return constrainIsoDateTimeInternals({ - // { isYear, isoMonth, isoDay, - // isoHour, isMinute, isoSecond, etc... - // hasTime, hasZ, offset, - // calendar, timeZone } - // - // should use `queryCalendarOps(parsed.calendar || isoCalendarId)` - // should use `queryTimeZoneOps(parsed.timeZone)` + const parts = dateTimeRegExp.exec(normalizeDashes(s)) // 0 is whole-match + return parts && constrainIsoDateTimeInternals({ + isoYear: parseInt1(parts[1]), + isoMonth: parseInt1(parts[2]), + isoDay: parseInt1(parts[3]), + ...parseTimeParts(parts.slice(5)), // parses annotations }) } function parseYearMonth(s) { - return constrainIsoDateInternals({ - // { isYear, isoMonth, isoDay - // calendar } - // - // should use `queryCalendarOps(parsed.calendar || isoCalendarId)` + const parts = yearMonthRegExp.exec(normalizeDashes(s)) // 0 is whole-match + return parts && constrainIsoDateInternals({ + isoYear: parseInt1(parts[1]), + isoMonth: parseInt1(parts[2]), + isoDay: 1, + ...parseAnnotations(parts[3]), }) } function parseMonthDay(s) { - return constrainIsoDateInternals({ - // { isYear, isoMonth, isoDay - // calendar } - // - // should use `queryCalendarOps(parsed.calendar || isoCalendarId)` + const parts = monthDayRegExp.exec(normalizeDashes(s)) // 0 is whole-match + return parts && constrainIsoDateInternals({ + isoYear: parseInt1(parts[0]), + isoMonth: parseInt1(parts[1]), + isoDay: 1, + ...parseAnnotations(parts[2]), }) } function parseTime(s) { - return constrainIsoTimeFields({ - // { isoHour, isoMinute, isoSecond, etc... } - }) + const parts = timeRegExp.exec(normalizeDashes(s)) // 0 is whole-match + return constrainIsoTimeFields(parseTimeParts(parts.slice(1))) } -export function parseOffsetNano(s) { - // number +function parseTimeParts(parts) { // parses annotations + const isoSecond = parseInt0(parts[4]) + return { + ...nanoToIsoTimeAndDay(parseNanoAfterDecimal(parts[6] || ''))[0], + isoHour: parseInt0(parts[0]), + isoMinute: parseInt0(parts[2]), + isoSecond: isoSecond === 60 ? 59 : isoSecond, // massage leap-second + ...parseAnnotations(parts[16]), + } } -export function parseDuration(s) { - // includes sign +function parseOffsetParts(parts) { + return (parts[0] === '+' ? 1 : -1) * ( + parseInt0(parts[0]) * nanoInHour + + parseInt0(parts[2]) * nanoInMinute + + parseInt0(parts[4]) * nanoInSecond + + parseNanoAfterDecimal(parts[6] || '') + ) +} + +function parseNanoAfterDecimal(str) { + return parseInt(str.padEnd(9, '0')) +} + +function parseAnnotations(s) { + let calendarId + let timeZoneId + + for (const chunk of s.split(']')) { + if (chunk) { // not the empty end chunk + let annotation = chunk.slice(1) // remove leading '[' + let isCritical = false + + if (annotation.charAt(0) === '!') { + isCritical = true + annotation = annotation.slice(1) + } + + const annotationParts = annotation.split('=') + if (annotationParts.length === 1) { + if (timeZoneId !== undefined) { + throw new RangeError('Cannot specify timeZone multiple times') + } + timeZoneId = annotation + } else if (annotationParts[0] === 'u-ca') { + if (calendarId === undefined) { // ignore subsequent calendar annotations + calendarId = annotationParts[1] + } + } else if (isCritical) { + throw new RangeError(`Critical annotation '${annotationParts[0]}' not used`) + } + } + } + + return { + calendar: queryCalendarImpl(calendarId || isoCalendarId), + timeZone: timeZoneId ? queryTimeZoneImpl(timeZoneId) : undefined, + } } + +const unicodeDashRegExp = /\u2212/g + +function normalizeDashes(str) { + return str.replace(unicodeDashRegExp, '-') +} + +function createRegExp(meat) { + return new RegExp(`^${meat}$`, 'i') +} + +function parseIntWithDefault(defaultInt, s) { + if (s === undefined) { + return defaultInt + } + const n = parseInt(s) + if (Object.is(n, -0)) { + throw RangeError('no negative zero') + } + return n +} + +const parseInt0 = parseIntWithDefault.bind(undefined, 0) +const parseInt1 = parseIntWithDefault.bind(undefined, 1) From 44c72fc621b46d6da77d391fcacdccbd1ec7d578 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 17:12:55 -0400 Subject: [PATCH 125/805] improvements to datetime parsing --- .../temporal-polyfill/src/new/isoParse.js | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index 20663924..60151118 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -144,61 +144,54 @@ export function parseTimeZoneId(s) { } export function parseOffsetNano(s) { - const parts = numericOffsetRegExp.exec(normalizeDashes(s)) + const parts = offsetRegExp.exec(s) return parts && parseOffsetParts(parts.slice(1)) } export function parseDuration(s) { - // includes sign + const parts = durationRegExp.exec(s) + console.log(parts) } // Low-level // ------------------------------------------------------------------------------------------------- +const plusOrMinusRegExpStr = '([+-\u2212])' +const fractionRegExpStr = '([.,](\\d{1,9}))?' + const yearMonthRegExpStr = - '([+-]\\d{6}|\\d{4})' + // 0:year - '-?(\\d{2})' // 1:month - // 2:annotations + `(${plusOrMinusRegExpStr}?\\d{6}|\\d{4})` + // 0:yearSign, 1:year + '-?(\\d{2})' // 2:month + // 3:annotations const dateRegExpStr = - yearMonthRegExpStr + // 0:year, 1:month - '-?(\\d{2})' // 2:day - // 3:annotations + yearMonthRegExpStr + // 0:yearSign, 1:year, 2:month + '-?(\\d{2})' // 3:day + // 4:annotations const monthDayRegExpStr = '(--)?(\\d{2})' + // 1:month '-?(\\d{2})' // 2:day // 3:annotations -const numericTimeRegExpStr = +const timeRegExpStr = '(\\d{2})' + // 0:hour '(:?(\\d{2})' + // 2:minute (NOTE: ':?' means optional ':') '(:?(\\d{2})' + // 4:second - '([.,](\\d{1,9}))?' + // 6:afterDecimal + fractionRegExpStr + // 6:afterDecimal ')?)?' -const numericOffsetRegExpStr = - '([+-])' + // 0:plusOrMinus - numericTimeRegExpStr // 1:hour, 3:minute, 5:second, 7:afterDecimal - const offsetRegExpStr = - '(Z|' + // 0:zOrOffset - numericOffsetRegExpStr + // 1:plusOrMinus, 2:hour, 4:minute, 6:second, 8:afterDecimal - ')?' - -const timeRegExpStr = - numericTimeRegExpStr + // 0:hour, 2:minute, 4:second, 6:afterDecimal - offsetRegExpStr // 7:zOrOffset, 8:plusOrMinus, 9:hour, 11:minute, 13:second, 15:afterDecimal - // 16:annotations + plusOrMinusRegExpStr + // 0:plusOrMinus + timeRegExpStr // 1:hour, 3:minute, 5:second, 7:afterDecimal const dateTimeRegExpStr = - dateRegExpStr + // 0:year, 1:month, 2:day - '([T ]' + // 3:timeEverything - timeRegExpStr + - // 4:hour, 6:minute, 8:second, 10:afterDecimal - // 11:zOrOffset, 12:plusOrMinus, 13:hour, 15:minute, 17:second, 19:afterDecimal - ')?' - // 20:annotations + dateRegExpStr + // 0:yearSign, 1:year, 2:month, 3:day + '([T ]' + // 4:timeEverything + timeRegExpStr + // 5:hour, 7:minute, 9:second, 11:afterDecimal + '(Z|' + // 12:zOrOffset + offsetRegExpStr + // 13:plusOrMinus, 14:hour, 16:minute, 18:second, 20:afterDecimal + ')?)?' const annotationRegExpStr = '((\\[[^\\]]*\\])*)' @@ -206,40 +199,59 @@ const yearMonthRegExp = createRegExp(yearMonthRegExpStr + annotationRegExpStr) const monthDayRegExp = createRegExp(monthDayRegExpStr + annotationRegExpStr) const dateTimeRegExp = createRegExp(dateTimeRegExpStr + annotationRegExpStr) const timeRegExp = createRegExp('T?' + timeRegExpStr + annotationRegExpStr) -const numericOffsetRegExp = createRegExp(numericOffsetRegExpStr) // annotations not allowed +const offsetRegExp = createRegExp(offsetRegExpStr) // annotations not allowed + +const durationRegExp = createRegExp( + `${plusOrMinusRegExpStr}?P` + + '(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?' + + '(T' + + `((\\d+)${fractionRegExpStr}H)?` + + `((\\d+)${fractionRegExpStr}M)?` + + `((\\d+)${fractionRegExpStr}S)?` + + ')?', +) function parseDateTime(s) { - const parts = dateTimeRegExp.exec(normalizeDashes(s)) // 0 is whole-match + const parts = dateTimeRegExp.exec(s) // 0 is whole-match return parts && constrainIsoDateTimeInternals({ - isoYear: parseInt1(parts[1]), - isoMonth: parseInt1(parts[2]), - isoDay: parseInt1(parts[3]), - ...parseTimeParts(parts.slice(5)), // parses annotations + isoYear: parseIsoYearParts(parts), + isoMonth: parseInt(parts[3]), + isoDay: parseInt(parts[4]), + ...parseTimeParts(parts.slice(6)), // parses annotations }) } function parseYearMonth(s) { - const parts = yearMonthRegExp.exec(normalizeDashes(s)) // 0 is whole-match - return parts && constrainIsoDateInternals({ - isoYear: parseInt1(parts[1]), - isoMonth: parseInt1(parts[2]), + const parts = yearMonthRegExp.exec(s) // 0 is whole-match + return { + isoYear: parseIsoYearParts(parts), + isoMonth: parseInt(parts[3]), isoDay: 1, ...parseAnnotations(parts[3]), - }) + } +} + +function parseIsoYearParts(parts) { // 0 is whole-match + const yearSign = parseSign(parts[1]) + const year = parseInt(parts[2]) + if (yearSign < 0 && !year) { + throw new RangeError('Negative zero not allowed') + } + return yearSign * year } function parseMonthDay(s) { - const parts = monthDayRegExp.exec(normalizeDashes(s)) // 0 is whole-match + const parts = monthDayRegExp.exec(s) // 0 is whole-match return parts && constrainIsoDateInternals({ - isoYear: parseInt1(parts[0]), - isoMonth: parseInt1(parts[1]), + isoYear: parseInt(parts[1]), + isoMonth: parseInt(parts[2]), isoDay: 1, - ...parseAnnotations(parts[2]), + ...parseAnnotations(parts[3]), }) } function parseTime(s) { - const parts = timeRegExp.exec(normalizeDashes(s)) // 0 is whole-match + const parts = timeRegExp.exec(s) // 0 is whole-match return constrainIsoTimeFields(parseTimeParts(parts.slice(1))) } @@ -255,7 +267,7 @@ function parseTimeParts(parts) { // parses annotations } function parseOffsetParts(parts) { - return (parts[0] === '+' ? 1 : -1) * ( + return parseSign(parts[0]) * ( parseInt0(parts[0]) * nanoInHour + parseInt0(parts[2]) * nanoInMinute + parseInt0(parts[4]) * nanoInSecond + @@ -303,26 +315,14 @@ function parseAnnotations(s) { } } -const unicodeDashRegExp = /\u2212/g - -function normalizeDashes(str) { - return str.replace(unicodeDashRegExp, '-') -} - function createRegExp(meat) { return new RegExp(`^${meat}$`, 'i') } -function parseIntWithDefault(defaultInt, s) { - if (s === undefined) { - return defaultInt - } - const n = parseInt(s) - if (Object.is(n, -0)) { - throw RangeError('no negative zero') - } - return n +function parseSign(s) { + return !s || s === '+' ? 1 : -1 } -const parseInt0 = parseIntWithDefault.bind(undefined, 0) -const parseInt1 = parseIntWithDefault.bind(undefined, 1) +function parseInt0(s) { + return s === undefined ? 0 : parseInt(s) +} From 41be4ec802ef45ecd8c5703ba1201c0005bb43b7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 20:44:55 -0400 Subject: [PATCH 126/805] tame validating/checking/refining/parsing --- packages/temporal-polyfill/src/new/instant.js | 4 +- .../temporal-polyfill/src/new/isoFields.js | 28 +-- packages/temporal-polyfill/src/new/isoMath.js | 135 ++++++++----- .../temporal-polyfill/src/new/isoParse.js | 179 +++++++++++------- packages/temporal-polyfill/src/new/options.js | 30 ++- .../temporal-polyfill/src/new/plainDate.js | 3 +- .../src/new/plainDateTime.js | 3 +- .../src/new/plainMonthDay.js | 4 +- .../temporal-polyfill/src/new/plainTime.js | 4 +- .../src/new/plainYearMonth.js | 4 +- packages/temporal-polyfill/src/new/utils.js | 10 +- .../src/new/zonedDateTime.js | 4 +- 12 files changed, 246 insertions(+), 162 deletions(-) diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.js index f1a6f060..afcacc8b 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.js @@ -11,7 +11,7 @@ import { epochMilliToNano, epochNanoToIso, epochSecToNano, - validateEpochNano, + checkEpochNano, } from './isoMath' import { parseInstant } from './isoParse' import { compareLargeInts } from './largeInt' @@ -41,7 +41,7 @@ export const [ // constructorToInternals (epochNanoseconds) => { - return validateEpochNano(toEpochNano(epochNanoseconds)) + return checkEpochNano(toEpochNano(epochNanoseconds)) }, // internalsConversionMap diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js index 398e344d..3f8d9ce4 100644 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ b/packages/temporal-polyfill/src/new/isoFields.js @@ -1,12 +1,7 @@ import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' -import { - constrainIsoDateInternals, - constrainIsoDateTimeInternals, - constrainIsoTimeFields, -} from './isoMath' import { toInteger } from './options' -import { mapPropNamesToConstant, mapPropsWithRefiners, pluckProps } from './utils' +import { mapPropNamesToConstant, pluckProps } from './utils' // Refiners // ------------------------------------------------------------------------------------------------- @@ -51,27 +46,6 @@ export const isoDateTimeFieldNamesAsc = [...isoDateFieldNames, ...isoTimeFieldNa export const isoTimeFieldDefaults = mapPropNamesToConstant(isoTimeFieldNames, 0) -// Refining -// ------------------------------------------------------------------------------------------------- - -export function refineIsoTimeInternals(rawIsoTimeInternals) { - return constrainIsoTimeFields( - mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), - ) -} - -export function refineIsoDateInternals(rawIsoDateInternals) { - return constrainIsoDateInternals( - mapPropsWithRefiners(rawIsoDateInternals, isoDateInternalRefiners), - ) -} - -export function refineIsoDateTimeInternals(rawIsoDateTimeInternals) { - return constrainIsoDateTimeInternals( - mapPropsWithRefiners(rawIsoDateTimeInternals, isoDateTimeInternalRefiners), - ) -} - // Conversion // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 98f2974c..80bc3e13 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,4 +1,11 @@ -import { isoDateTimeFieldNamesAsc, isoTimeFieldNamesAsc, pluckIsoDateTimeFields } from './isoFields' +import { + isoDateInternalRefiners, + isoDateTimeFieldNamesAsc, + isoDateTimeInternalRefiners, + isoTimeFieldNamesAsc, + isoTimeFieldRefiners, + pluckIsoDateTimeFields, +} from './isoFields' import { compareLargeInts, numberToLargeInt } from './largeInt' import { clampProp, rejectI } from './options' // use 1 instead of rejectI? import { @@ -11,7 +18,7 @@ import { nanoInUtcDay, nanoToGivenFields, } from './units' -import { compareProps, divFloorMod } from './utils' +import { compareProps, divFloorMod, mapPropsWithRefiners } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -55,29 +62,65 @@ export function computeIsoDayOfWeek(isoDateFields) { } export function computeIsoWeekOfYear(isoDateFields) { + // TODO } export function computeIsoYearOfWeek(isoDateFields) { + // TODO +} + +// Refining +// ------------------------------------------------------------------------------------------------- + +export function refineIsoDateTimeInternals(rawIsoDateTimeInternals) { + return checkIsoDateTimeInternals( + constrainIsoDateTimeInternals( + mapPropsWithRefiners(rawIsoDateTimeInternals, isoDateTimeInternalRefiners), + ), + ) +} + +export function refineIsoDateInternals(rawIsoDateInternals) { + return checkIsoDateTimeInternals( + constrainIsoDateInternals( + mapPropsWithRefiners(rawIsoDateInternals, isoDateInternalRefiners), + ), + ) +} + +export function refineIsoTimeInternals(rawIsoTimeInternals) { + return constrainIsoTimeFields( + mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), + ) } // Constraining // ------------------------------------------------------------------------------------------------- -export function constrainIsoDateTimeInternals(isoDateTimeInternals) { - return validateIsoDateTimeInternals({ - ...constrainIsoDateInternals(isoDateTimeInternals), - ...constrainIsoTimeFields(isoDateTimeInternals), - }) +export function constrainIsoDateTimeInternals(isoDateTimeFields) { + return { + ...constrainIsoDateInternals(isoDateTimeFields), + ...constrainIsoTimeFields(isoDateTimeFields), + } } -export function constrainIsoDateInternals(isoDateInternals) { - const daysInMonth = computeIsoDaysInMonth(isoDateInternals.isoYear, isoDateInternals.isoMonth) - return validateIsoDateTimeInternals({ - calendar: isoDateInternals.calendar, - isoYear: isoDateInternals.isoYear, - isoMonth: clampProp(isoDateInternals, 'isoMonth', 1, isoMonthsInYear, rejectI), - isoDay: clampProp(isoDateInternals, 'isoDay', 1, daysInMonth, rejectI), - }) +/* +accepts iso-date-like fields and will pass all through +accepts returnUndefinedI +*/ +export function constrainIsoDateInternals(isoDateFields, overflowI = rejectI) { + const isoMonth = clampProp(isoDateFields, 'isoMonth', 1, isoMonthsInYear, overflowI) + if (isoMonth) { + const daysInMonth = computeIsoDaysInMonth(isoDateFields.isoYear, isoMonth) + const isoDay = clampProp(isoDateFields, 'isoDay', 1, daysInMonth, overflowI) + if (isoDay) { + return { + ...isoDateFields, // calendar,(timeZone),isoYear + isoMonth, + isoDay, + } + } + } } export function constrainIsoTimeFields(isoTimeFields, overflowI = rejectI) { @@ -93,6 +136,37 @@ export function constrainIsoTimeFields(isoTimeFields, overflowI = rejectI) { } } +// Epoch-checking +// ------------------------------------------------------------------------------------------------- + +const epochNanoMax = numberToLargeInt(nanoInUtcDay).mult(100000000) // inclusive +const epochNanoMin = epochNanoMax.mult(-1) // inclusive +const isoYearMax = 275760 // optimization. isoYear at epochNanoMax +const isoYearMin = -271821 // optimization. isoYear at epochNanoMin + +export function checkIsoDateTimeInternals(isoDateTimeInternals) { + const isoYear = clampProp(isoDateTimeInternals, 'isoYear', isoYearMin, isoYearMax, rejectI) + const nudge = isoYear === isoYearMin ? 1 : isoYear === isoYearMax ? -1 : 0 + + if (nudge) { + const epochNano = isoToEpochNano(isoDateTimeInternals) + checkEpochNano(epochNano && epochNano.addNumber((nanoInUtcDay - 1) * nudge)) + } + + return isoDateTimeInternals +} + +export function checkEpochNano(epochNano) { + if ( + epochNano === undefined || + compareLargeInts(epochNano, epochNanoMin) === 1 || // epochNano < epochNanoMin + compareLargeInts(epochNanoMax, epochNano) === 1 // epochNanoMax < epochNano + ) { + throw new RangeError('aahh') + } + return epochNano +} + // Field <-> Nanosecond Conversion // ------------------------------------------------------------------------------------------------- @@ -163,37 +237,6 @@ export const epochGetters = { }, } -// Validation -// ------------------------------------------------------------------------------------------------- - -const epochNanoMax = numberToLargeInt(nanoInUtcDay).mult(100000000) // inclusive -const epochNanoMin = epochNanoMax.mult(-1) // inclusive -const isoYearMax = 275760 // optimization. isoYear at epochNanoMax -const isoYearMin = -271821 // optimization. isoYear at epochNanoMin - -function validateIsoDateTimeInternals(isoDateTimeInternals) { // validateIsoInternals? - const isoYear = clampProp(isoDateTimeInternals, 'isoYear', isoYearMin, isoYearMax, rejectI) - const nudge = isoYear === isoYearMin ? 1 : isoYear === isoYearMax ? -1 : 0 - - if (nudge) { - const epochNano = isoToEpochNano(isoDateTimeInternals) - validateEpochNano(epochNano && epochNano.addNumber((nanoInUtcDay - 1) * nudge)) - } - - return isoDateTimeInternals -} - -export function validateEpochNano(epochNano) { - if ( - epochNano === undefined || - compareLargeInts(epochNano, epochNanoMin) === 1 || // epochNano < epochNanoMin - compareLargeInts(epochNanoMax, epochNano) === 1 // epochNanoMax < epochNano - ) { - throw new RangeError('aahh') - } - return epochNano -} - // ISO <-> Epoch Conversion // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index 60151118..d8aa9c11 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -1,18 +1,16 @@ import { nanoInSecond } from '../dateUtils/units' import { isoCalendarId } from './calendarConfig' import { queryCalendarImpl } from './calendarImpl' +import { isoTimeFieldDefaults } from './isoFields' import { - pluckIsoDateInternals, - pluckIsoDateTimeInternals, - pluckIsoTimeFields, -} from './isoFields' -import { + checkIsoDateTimeInternals, constrainIsoDateInternals, constrainIsoDateTimeInternals, constrainIsoTimeFields, isoToEpochNano, nanoToIsoTimeAndDay, } from './isoMath' +import { returnUndefinedI } from './options' import { queryTimeZoneImpl } from './timeZoneImpl' import { getMatchingInstantFor, utcTimeZoneId } from './timeZoneOps' import { nanoInHour, nanoInMinute } from './units' @@ -39,29 +37,23 @@ export function parseInstant(s) { return isoToEpochNano(parsed).addNumber(offsetNano) } -export function parseZonedDateTime(s) { +export function parseMaybeZonedDateTime(s) { const parsed = parseDateTime(s) - if (!parsed || !parsed.timeZone) { + if (!parsed) { throw new RangeError() } - return processZonedDateTimeParse(parsed) + if (parsed.timeZone) { + return processZonedDateTimeParse(parsed) + } + return processDatelikeParse(parsed) // unnecessarily checks for undefined } -export function processZonedDateTimeParse(parsed) { - const epochNanoseconds = getMatchingInstantFor( - parsed.timeZone, - parsed, - parsed.offset ? parseOffsetNano(parsed.offset) : undefined, - parsed.z, - 'reject', - 'compatible', - true, // fuzzy - ) - return { - epochNanoseconds, - timeZone: parsed.timeZone, - calendar: parsed.calendar, +export function parseZonedDateTime(s) { + const parsed = parseDateTime(s) + if (!parsed || !parsed.timeZone) { + throw new RangeError() } + return processZonedDateTimeParse(parsed) } export function parsePlainDateTime(s) { @@ -69,23 +61,19 @@ export function parsePlainDateTime(s) { if (!parsed) { throw new RangeError() } - return pluckIsoDateTimeInternals(parsed) + return processDateTimeParse(parsed) } export function parsePlainDate(s) { - const parsed = parseDateTime(s) - if (!parsed) { - throw new RangeError() - } - return pluckIsoDateInternals(parsed) + return processDatelikeParse(parseDateTime(s)) } export function parsePlainYearMonth(s) { - return parseYearMonth(s) || parsePlainDate(s) // parsePlainDate will throw error + return processDatelikeParse(parseYearMonth(s) || parseDateTime(s)) } export function parsePlainMonthDay(s) { - return parseMonthDay(s) || parsePlainDate(s) // parsePlainDate will throw error + return processDatelikeParse(parseMonthDay(s) || parseDateTime(s)) } export function parsePlainTime(s) { @@ -104,17 +92,19 @@ export function parsePlainTime(s) { if (parsed.hasZ) { throw new RangeError() } - if (parsed.calendar !== undefined && parsed.calendar.id !== isoCalendarId) { + if (parsed.calendar && parsed.calendar.id !== isoCalendarId) { throw new RangeError() } - if (parseMonthDay(s)) { + + let altParsed + if ((altParsed = parseYearMonth(s)) && constrainIsoDateInternals(altParsed, returnUndefinedI)) { throw new RangeError() } - if (parseYearMonth(s)) { + if ((altParsed = parseMonthDay(s)) && constrainIsoDateInternals(altParsed, returnUndefinedI)) { throw new RangeError() } - return pluckIsoTimeFields(parsed) + return constrainIsoTimeFields(parsed) } export function parseCalendarId(s) { @@ -128,6 +118,7 @@ export function parseCalendarId(s) { export function parseTimeZoneId(s) { const parsed = parseDateTime(s) + if (parsed !== undefined) { if (parsed.timeZone) { return parsed.timeZone.id @@ -143,17 +134,74 @@ export function parseTimeZoneId(s) { return s } +// Intermediate +// ------------------------------------------------------------------------------------------------- + +function processZonedDateTimeParse(parsed) { + const epochNanoseconds = getMatchingInstantFor( + parsed.timeZone, + parsed, + parsed.offset ? parseOffsetNano(parsed.offset) : undefined, + parsed.z, + 'reject', + 'compatible', + true, // fuzzy + ) + return { + epochNanoseconds, + timeZone: parsed.timeZone, + calendar: parsed.calendar, + } +} + +function processDateTimeParse(parsed) { + return checkIsoDateTimeInternals(constrainIsoDateTimeInternals(parsed)) +} + +/* +Unlike others, throws an error +*/ +function processDatelikeParse(parsed) { + if (!parsed) { + throw new RangeError() + } + return checkIsoDateTimeInternals(constrainIsoDateInternals(parsed)) +} + +// Low-level +// ------------------------------------------------------------------------------------------------- + +export function parseDuration(s) { + const parts = durationRegExp.exec(s) + console.log(parts) // TODO +} + export function parseOffsetNano(s) { const parts = offsetRegExp.exec(s) return parts && parseOffsetParts(parts.slice(1)) } -export function parseDuration(s) { - const parts = durationRegExp.exec(s) - console.log(parts) +function parseDateTime(s) { + const parts = dateTimeRegExp.exec(s) + return parts && parseDateTimeParts(parts) } -// Low-level +function parseYearMonth(s) { + const parts = yearMonthRegExp.exec(s) + return parts && parseYearMonthParts(parts) +} + +function parseMonthDay(s) { + const parts = monthDayRegExp.exec(s) + return parts && parseMonthDayParts(parts) +} + +function parseTime(s) { + const parts = timeRegExp.exec(s) + return parts && parseTimeParts(parts.slice(1)) +} + +// RegExp & Parts // ------------------------------------------------------------------------------------------------- const plusOrMinusRegExpStr = '([+-\u2212])' @@ -167,7 +215,6 @@ const yearMonthRegExpStr = const dateRegExpStr = yearMonthRegExpStr + // 0:yearSign, 1:year, 2:month '-?(\\d{2})' // 3:day - // 4:annotations const monthDayRegExpStr = '(--)?(\\d{2})' + // 1:month @@ -180,6 +227,7 @@ const timeRegExpStr = '(:?(\\d{2})' + // 4:second fractionRegExpStr + // 6:afterDecimal ')?)?' + // 7:annotations const offsetRegExpStr = plusOrMinusRegExpStr + // 0:plusOrMinus @@ -192,6 +240,7 @@ const dateTimeRegExpStr = '(Z|' + // 12:zOrOffset offsetRegExpStr + // 13:plusOrMinus, 14:hour, 16:minute, 18:second, 20:afterDecimal ')?)?' + // 21:annotations const annotationRegExpStr = '((\\[[^\\]]*\\])*)' @@ -211,22 +260,36 @@ const durationRegExp = createRegExp( ')?', ) -function parseDateTime(s) { - const parts = dateTimeRegExp.exec(s) // 0 is whole-match - return parts && constrainIsoDateTimeInternals({ +function parseDateTimeParts(parts) { // 0 is whole-match + const hasTime = Boolean(parts[5]) + const hasZ = Boolean(parts[13]) + return { isoYear: parseIsoYearParts(parts), isoMonth: parseInt(parts[3]), isoDay: parseInt(parts[4]), - ...parseTimeParts(parts.slice(6)), // parses annotations - }) + ...(hasTime + ? parseTimeParts(parts.slice(6)) // parses annotations + : { ...isoTimeFieldDefaults, ...parseAnnotations(parts[22]) } + ), + hasTime, + hasZ, + } } -function parseYearMonth(s) { - const parts = yearMonthRegExp.exec(s) // 0 is whole-match +function parseYearMonthParts(parts) { // 0 is whole-match return { isoYear: parseIsoYearParts(parts), isoMonth: parseInt(parts[3]), isoDay: 1, + ...parseAnnotations(parts[4]), + } +} + +function parseMonthDayParts(parts) { // 0 is whole-match + return { + isoYear: parseInt(parts[1]), + isoMonth: parseInt(parts[2]), + isoDay: 1, ...parseAnnotations(parts[3]), } } @@ -240,21 +303,6 @@ function parseIsoYearParts(parts) { // 0 is whole-match return yearSign * year } -function parseMonthDay(s) { - const parts = monthDayRegExp.exec(s) // 0 is whole-match - return parts && constrainIsoDateInternals({ - isoYear: parseInt(parts[1]), - isoMonth: parseInt(parts[2]), - isoDay: 1, - ...parseAnnotations(parts[3]), - }) -} - -function parseTime(s) { - const parts = timeRegExp.exec(s) // 0 is whole-match - return constrainIsoTimeFields(parseTimeParts(parts.slice(1))) -} - function parseTimeParts(parts) { // parses annotations const isoSecond = parseInt0(parts[4]) return { @@ -275,8 +323,8 @@ function parseOffsetParts(parts) { ) } -function parseNanoAfterDecimal(str) { - return parseInt(str.padEnd(9, '0')) +function parseNanoAfterDecimal(s) { + return parseInt(s.padEnd(9, '0')) } function parseAnnotations(s) { @@ -311,10 +359,13 @@ function parseAnnotations(s) { return { calendar: queryCalendarImpl(calendarId || isoCalendarId), - timeZone: timeZoneId ? queryTimeZoneImpl(timeZoneId) : undefined, + timeZone: timeZoneId && queryTimeZoneImpl(timeZoneId), } } +// Utils +// ------------------------------------------------------------------------------------------------- + function createRegExp(meat) { return new RegExp(`^${meat}$`, 'i') } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 7e1d5ee5..27b7ee93 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -1,8 +1,10 @@ -import { parseDateTime } from '../dateUtils/parse' +import { getInternals } from './class' import { durationFieldIndexes } from './durationFields' -import { pluckIsoDateTimeInternals } from './isoFields' -import { processZonedDateTimeParse } from './isoParse' +import { pluckIsoDateInternals } from './isoFields' +import { parseMaybeZonedDateTime } from './isoParse' import { bigIntToLargeInt } from './largeInt' +import { PlainDate } from './plainDate' +import { PlainDateTime } from './plainDateTime' import { dayIndex, minuteIndex, nanoIndex, unitIndexToNano, unitIndexes, yearIndex } from './units' import { clamp, @@ -14,6 +16,7 @@ import { roundHalfFloor, roundHalfTrunc, } from './utils' +import { ZonedDateTime } from './zonedDateTime' // TODO: ensure all callers use *INDEXES* @@ -189,6 +192,7 @@ const refineTotalUnit = refineUnitOption.bind(undefined, totalUnitStr) export const constrainI = 0 export const rejectI = 1 // must be truthy for clamp's throwOnOverflow param +export const returnUndefinedI = 2 // non-standard const refineOverflow = refineChoiceOption.bind(undefined, 'overflow', [ 'constrain', 'reject', @@ -330,13 +334,23 @@ function refineSubsecDigits(options) { } function refineRelativeTo(options) { - const parsed = parseDateTime(options) + const { relativeTo } = options + + if (relativeTo) { + if (isObjectlike(relativeTo)) { + if ( + relativeTo instanceof ZonedDateTime || + relativeTo instanceof PlainDate + ) { + return getInternals(relativeTo) + } else if (relativeTo instanceof PlainDateTime) { + return pluckIsoDateInternals(getInternals(relativeTo)) + } + throw new TypeError() + } - if (parsed.timeZone) { - return processZonedDateTimeParse(parsed) + return parseMaybeZonedDateTime(toString(relativeTo)) } - - return pluckIsoDateTimeInternals(parsed) } // Utils diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.js index de4ed340..af505837 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.js @@ -20,10 +20,9 @@ import { generatePublicIsoDateFields, isoTimeFieldDefaults, pluckIsoDateInternals, - refineIsoDateInternals, } from './isoFields' import { formatCalendar, formatIsoDateFields } from './isoFormat' -import { compareIsoDateTimeFields } from './isoMath' +import { compareIsoDateTimeFields, refineIsoDateInternals } from './isoMath' import { parsePlainDate } from './isoParse' import { refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' import { createPlainDateTime } from './plainDateTime' diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.js index 88dab316..b245b835 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.js @@ -17,10 +17,9 @@ import { pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields, - refineIsoDateTimeInternals, } from './isoFields' import { formatCalendar, formatIsoDateTimeFields } from './isoFormat' -import { compareIsoDateTimeFields } from './isoMath' +import { compareIsoDateTimeFields, refineIsoDateTimeInternals } from './isoMath' import { parsePlainDateTime } from './isoParse' import { moveDateTime } from './move' import { diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.js index 3232f3c8..aa34b064 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.js @@ -7,9 +7,9 @@ import { mergePlainMonthDayBag, refinePlainMonthDayBag, } from './convert' -import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' +import { generatePublicIsoDateFields } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' -import { compareIsoDateTimeFields, isoEpochFirstLeapYear } from './isoMath' +import { compareIsoDateTimeFields, isoEpochFirstLeapYear, refineIsoDateInternals } from './isoMath' import { parsePlainMonthDay } from './isoParse' import { refineOverflowOptions } from './options' diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.js index b72b3664..3c6a1275 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.js @@ -8,9 +8,9 @@ import { import { diffTimes } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' -import { pluckIsoTimeFields, refineIsoTimeInternals } from './isoFields' +import { pluckIsoTimeFields } from './isoFields' import { formatIsoTimeFields } from './isoFormat' -import { compareIsoTimeFields } from './isoMath' +import { compareIsoTimeFields, refineIsoTimeInternals } from './isoMath' import { parsePlainTime } from './isoParse' import { moveTime } from './move' import { diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.js index e4461230..78b5ad0f 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.js @@ -10,9 +10,9 @@ import { import { diffDates } from './diff' import { createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' -import { generatePublicIsoDateFields, refineIsoDateInternals } from './isoFields' +import { generatePublicIsoDateFields } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' -import { compareIsoDateTimeFields } from './isoMath' +import { compareIsoDateTimeFields, refineIsoDateInternals } from './isoMath' import { parsePlainYearMonth } from './isoParse' import { moveDateByDays } from './move' import { refineDiffOptions, refineOverflowOptions } from './options' diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js index 03aeb3e0..ad5d5b8a 100644 --- a/packages/temporal-polyfill/src/new/utils.js +++ b/packages/temporal-polyfill/src/new/utils.js @@ -1,3 +1,4 @@ +import { returnUndefinedI } from './options' const objectlikeRE = /object|function/ @@ -186,12 +187,15 @@ export function clamp( val, min, // inclusive max, // inclusive - throwOnOverflow, // 0/1 (matched constrain/reject) - noun, // for error message (required if throwOnOverflow given) + overflowBehavior, // 0/1/2 --- overflow enum + noun, // for error message (required if overflowBehavior given) ) { const clamped = Math.min(Math.max(val, min), max) - if (throwOnOverflow && val !== clamped) { + if (overflowBehavior && val !== clamped) { + if (overflowBehavior === returnUndefinedI) { + return undefined + } throw new RangeError(`${noun} must be between ${min}-${max}`) } diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 5fc7321e..1c38acd8 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -28,7 +28,7 @@ import { import { epochGetters, epochNanoToIso, - validateEpochNano, + checkEpochNano, } from './isoMath' import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' @@ -68,7 +68,7 @@ export const [ // constructorToInternals (epochNanoseconds, timeZoneArg, calendarArg) => { return { - epochNanoseconds: validateEpochNano(toEpochNano(epochNanoseconds)), + epochNanoseconds: checkEpochNano(toEpochNano(epochNanoseconds)), timeZone: queryTimeZoneOps(timeZoneArg), // TODO: validate string/object somehow? calendar: queryCalendarOps(calendarArg), } From 2b8b61dbd73192a241ae4115dd697887057d2093 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 21:36:20 -0400 Subject: [PATCH 127/805] week calculations --- .../temporal-polyfill/src/new/calendarImpl.js | 2 +- packages/temporal-polyfill/src/new/isoMath.js | 44 +++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.js index 2d02d1a8..3a762024 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.js @@ -41,7 +41,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { rejectI } from './options' import { milliInDay } from './units' -import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber, padNumber2 } from './utils' +import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './utils' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.js index 80bc3e13..63a9421d 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.js @@ -1,3 +1,5 @@ +import { isoFieldsToEpochMilli } from '../dateUtils/epoch' +import { diffEpochMilliByDay } from './diff' import { isoDateInternalRefiners, isoDateTimeFieldNamesAsc, @@ -53,6 +55,13 @@ export function computeIsoIsLeapYear(isoYear) { return isoYear % 4 === 0 && (isoYear % 100 !== 0 || isoYear % 400 === 0) } +export function computeIsoDayOfYear(isoDateFields) { + return diffEpochMilliByDay( + isoFieldsToEpochMilli(isoDateMonthStart(isoDateFields)), + isoFieldsToEpochMilli(isoDateFields), + ) +} + export function computeIsoDayOfWeek(isoDateFields) { return isoToLegacyDate( isoDateFields.isoYear, @@ -61,12 +70,41 @@ export function computeIsoDayOfWeek(isoDateFields) { ).getDay() + 1 } +export function computeIsoYearOfWeek(isoDateFields) { + return computeIsoWeekInfo(isoDateFields).isoYear +} + export function computeIsoWeekOfYear(isoDateFields) { - // TODO + return computeIsoWeekInfo(isoDateFields).isoWeek } -export function computeIsoYearOfWeek(isoDateFields) { - // TODO +function computeIsoWeekInfo(isoDateFields) { + const doy = computeIsoDayOfYear(isoDateFields) + const dow = computeIsoDayOfWeek(isoDateFields) + const doj = computeIsoDayOfWeek(isoDateMonthStart(isoDateFields)) + const isoWeek = Math.floor((doy - dow + 10) / isoDaysInWeek) + const { isoYear } = isoDateFields + + if (isoWeek < 1) { + return { + isoYear: isoYear - 1, + isoWeek: (doj === 5 || (doj === 6 && computeIsoIsLeapYear(isoYear - 1))) ? 53 : 52, + } + } + if (isoWeek === 53) { + if (computeIsoDaysInYear(isoYear) - doy < 4 - dow) { + return { + isoYear: isoYear + 1, + isoWeek: 1, + } + } + } + + return { isoYear, isoWeek } +} + +function isoDateMonthStart(isoDateFields) { + return { ...isoDateFields, isoMonth: 1, isoDay: 1 } } // Refining From f2bbb48133054eedc494b80058a6aba71027b29a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 23:15:45 -0400 Subject: [PATCH 128/805] parsing duration --- .../src/new/durationFields.js | 7 +- .../temporal-polyfill/src/new/isoParse.js | 117 ++++++++++++++---- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js index 9b5e2935..13a4723c 100644 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ b/packages/temporal-polyfill/src/new/durationFields.js @@ -112,13 +112,18 @@ export function addDurationFields(a, b, sign) { // TODO: make version that updat } export function negateDurationInternals(internals) { + const res = negateDurationFields(internals) + res.sign = -internals.sign || 0 + return res +} + +export function negateDurationFields(internals) { const res = {} for (const fieldName in durationFieldNames) { res[fieldName] = internals[fieldName] * -1 || 0 } - res.sign = -internals.sign || 0 return res } diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index d8aa9c11..f11f83ae 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -1,6 +1,11 @@ -import { nanoInSecond } from '../dateUtils/units' +import { nanoIn, nanoInSecond } from '../dateUtils/units' import { isoCalendarId } from './calendarConfig' import { queryCalendarImpl } from './calendarImpl' +import { + durationFieldNamesAsc, + negateDurationFields, + updateDurationFieldsSign, +} from './durationFields' import { isoTimeFieldDefaults } from './isoFields' import { checkIsoDateTimeInternals, @@ -13,7 +18,16 @@ import { import { returnUndefinedI } from './options' import { queryTimeZoneImpl } from './timeZoneImpl' import { getMatchingInstantFor, utcTimeZoneId } from './timeZoneOps' -import { nanoInHour, nanoInMinute } from './units' +import { + hourIndex, + milliIndex, + minuteIndex, + nanoInHour, + nanoInMinute, + nanoToGivenFields, + secondsIndex, +} from './units' +import { divFloorMod } from './utils' // High-level // ------------------------------------------------------------------------------------------------- @@ -171,16 +185,6 @@ function processDatelikeParse(parsed) { // Low-level // ------------------------------------------------------------------------------------------------- -export function parseDuration(s) { - const parts = durationRegExp.exec(s) - console.log(parts) // TODO -} - -export function parseOffsetNano(s) { - const parts = offsetRegExp.exec(s) - return parts && parseOffsetParts(parts.slice(1)) -} - function parseDateTime(s) { const parts = dateTimeRegExp.exec(s) return parts && parseDateTimeParts(parts) @@ -201,6 +205,16 @@ function parseTime(s) { return parts && parseTimeParts(parts.slice(1)) } +export function parseOffsetNano(s) { + const parts = offsetRegExp.exec(s) + return parts && parseOffsetParts(parts.slice(1)) +} + +export function parseDuration(s) { + const parts = durationRegExp.exec(s) + return parts && parseDurationParts(parts) +} + // RegExp & Parts // ------------------------------------------------------------------------------------------------- @@ -251,12 +265,15 @@ const timeRegExp = createRegExp('T?' + timeRegExpStr + annotationRegExpStr) const offsetRegExp = createRegExp(offsetRegExpStr) // annotations not allowed const durationRegExp = createRegExp( - `${plusOrMinusRegExpStr}?P` + - '(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?' + - '(T' + - `((\\d+)${fractionRegExpStr}H)?` + - `((\\d+)${fractionRegExpStr}M)?` + - `((\\d+)${fractionRegExpStr}S)?` + + `${plusOrMinusRegExpStr}?P` + // 0:sign + '(\\d+Y)?' + // 1:years + '(\\d+M)?' + // 2:months + '(\\d+W)?' + // 3:weeks + '(\\d+D)?' + // 4:days + '(T' + // 5:hasTimes + `((\\d+)${fractionRegExpStr}H)?` + // 6:hours, 7:partialHour + `((\\d+)${fractionRegExpStr}M)?` + // 8:minutes, 9:partialMinute + `((\\d+)${fractionRegExpStr}S)?` + // 10:seconds, 11:partialSecond ')?', ) @@ -306,7 +323,7 @@ function parseIsoYearParts(parts) { // 0 is whole-match function parseTimeParts(parts) { // parses annotations const isoSecond = parseInt0(parts[4]) return { - ...nanoToIsoTimeAndDay(parseNanoAfterDecimal(parts[6] || ''))[0], + ...nanoToIsoTimeAndDay(parseSubsecNano(parts[6] || ''))[0], isoHour: parseInt0(parts[0]), isoMinute: parseInt0(parts[2]), isoSecond: isoSecond === 60 ? 59 : isoSecond, // massage leap-second @@ -319,14 +336,10 @@ function parseOffsetParts(parts) { parseInt0(parts[0]) * nanoInHour + parseInt0(parts[2]) * nanoInMinute + parseInt0(parts[4]) * nanoInSecond + - parseNanoAfterDecimal(parts[6] || '') + parseSubsecNano(parts[6] || '') ) } -function parseNanoAfterDecimal(s) { - return parseInt(s.padEnd(9, '0')) -} - function parseAnnotations(s) { let calendarId let timeZoneId @@ -363,6 +376,62 @@ function parseAnnotations(s) { } } +function parseDurationParts(parts) { + let hasAny = false + let hasAnyFrac = false + let leftoverNano = 0 + let durationFields = { + years: parseUnit(parts[2]), + months: parseUnit(parts[3]), + weeks: parseUnit(parts[4]), + days: parseUnit(parts[5]), + hours: parseUnit(parts[7], parts[8], hourIndex), + minutes: parseUnit(parts[9], parts[10], minuteIndex), + seconds: parseUnit(parts[11], parts[12], secondsIndex), + ...nanoToGivenFields(leftoverNano, milliIndex, durationFieldNamesAsc), + } + + if (!hasAny) { + throw new RangeError('Duration string must have at least one field') + } + + if (parseSign(parts[1]) < 0) { + durationFields = negateDurationFields(durationFields) + } + + return updateDurationFieldsSign(durationFields) + + function parseUnit(wholeStr, fracStr, timeUnitI) { + let wholeUnits = 0 + let leftoverUnits = 0 // from previous round + + if (timeUnitI) { + [leftoverUnits, leftoverNano] = divFloorMod(leftoverNano, nanoIn[timeUnitI]) + } + + if (wholeStr !== undefined) { + if (hasAnyFrac) { + throw new RangeError('Fraction must be last one') + } + + wholeUnits = parseInt(wholeStr) + hasAny = true + + if (fracStr) { + // convert seconds to other units, abusing parseSubsecNano + leftoverNano = parseSubsecNano(fracStr) * (nanoIn[timeUnitI] / nanoInSecond) + hasAnyFrac = true + } + } + + return wholeUnits + leftoverUnits + } +} + +function parseSubsecNano(fracStr) { + return parseInt(fracStr.padEnd(9, '0')) +} + // Utils // ------------------------------------------------------------------------------------------------- From bcb2f34c610da4465c8130123292528b05a3a122 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 23:22:11 -0400 Subject: [PATCH 129/805] cleanup --- .../temporal-polyfill/src/new/isoFormat.js | 2 +- .../temporal-polyfill/src/new/isoParse.js | 83 ++++++++++--------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.js index 97891c3d..60f296b0 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.js @@ -205,7 +205,7 @@ function formatSubsecNano(totalNano, subsecDigits) { // subsecDigits can be unde let s = padNumber(9, totalNano) s = subsecDigits === undefined ? s.replace(trailingZerosRE, '') - : s.substring(0, subsecDigits) + : s.slice(0, subsecDigits) return s ? '.' + s : '' } diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index f11f83ae..20a5bead 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -278,8 +278,9 @@ const durationRegExp = createRegExp( ) function parseDateTimeParts(parts) { // 0 is whole-match - const hasTime = Boolean(parts[5]) - const hasZ = Boolean(parts[13]) + const hasTime = parts[5] // boolean-like + const hasZ = parts[13] // " + return { isoYear: parseIsoYearParts(parts), isoMonth: parseInt(parts[3]), @@ -340,42 +341,6 @@ function parseOffsetParts(parts) { ) } -function parseAnnotations(s) { - let calendarId - let timeZoneId - - for (const chunk of s.split(']')) { - if (chunk) { // not the empty end chunk - let annotation = chunk.slice(1) // remove leading '[' - let isCritical = false - - if (annotation.charAt(0) === '!') { - isCritical = true - annotation = annotation.slice(1) - } - - const annotationParts = annotation.split('=') - if (annotationParts.length === 1) { - if (timeZoneId !== undefined) { - throw new RangeError('Cannot specify timeZone multiple times') - } - timeZoneId = annotation - } else if (annotationParts[0] === 'u-ca') { - if (calendarId === undefined) { // ignore subsequent calendar annotations - calendarId = annotationParts[1] - } - } else if (isCritical) { - throw new RangeError(`Critical annotation '${annotationParts[0]}' not used`) - } - } - } - - return { - calendar: queryCalendarImpl(calendarId || isoCalendarId), - timeZone: timeZoneId && queryTimeZoneImpl(timeZoneId), - } -} - function parseDurationParts(parts) { let hasAny = false let hasAnyFrac = false @@ -428,13 +393,49 @@ function parseDurationParts(parts) { } } +// Utils +// ------------------------------------------------------------------------------------------------- + +function parseAnnotations(s) { + let calendarId + let timeZoneId + + for (const chunk of s.split(']')) { + if (chunk) { // not the empty end chunk + let annotation = chunk.slice(1) // remove leading '[' + let isCritical = false + + if (annotation.charAt(0) === '!') { + isCritical = true + annotation = annotation.slice(1) + } + + const annotationParts = annotation.split('=') + if (annotationParts.length === 1) { + if (timeZoneId !== undefined) { + throw new RangeError('Cannot specify timeZone multiple times') + } + timeZoneId = annotation + } else if (annotationParts[0] === 'u-ca') { + if (calendarId === undefined) { // ignore subsequent calendar annotations + calendarId = annotationParts[1] + } + } else if (isCritical) { + throw new RangeError(`Critical annotation '${annotationParts[0]}' not used`) + } + } + } + + return { + calendar: queryCalendarImpl(calendarId || isoCalendarId), + timeZone: timeZoneId && queryTimeZoneImpl(timeZoneId), + } +} + function parseSubsecNano(fracStr) { return parseInt(fracStr.padEnd(9, '0')) } -// Utils -// ------------------------------------------------------------------------------------------------- - function createRegExp(meat) { return new RegExp(`^${meat}$`, 'i') } From 9b9de516e2460dc28e816bfe88e2badb2d54f47c Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 6 Jul 2023 23:27:20 -0400 Subject: [PATCH 130/805] a little more clean --- packages/temporal-polyfill/src/new/isoParse.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.js index 20a5bead..6b094665 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.js @@ -367,8 +367,8 @@ function parseDurationParts(parts) { return updateDurationFieldsSign(durationFields) function parseUnit(wholeStr, fracStr, timeUnitI) { - let wholeUnits = 0 let leftoverUnits = 0 // from previous round + let wholeUnits = 0 if (timeUnitI) { [leftoverUnits, leftoverNano] = divFloorMod(leftoverNano, nanoIn[timeUnitI]) @@ -389,7 +389,7 @@ function parseDurationParts(parts) { } } - return wholeUnits + leftoverUnits + return leftoverUnits + wholeUnits } } From 0d8760e5ad8889946543f09e39d3638d721530a3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 10 Jul 2023 18:48:29 -0400 Subject: [PATCH 131/805] convert some core file to typescript --- .../src/new/calendarFields.js | 139 -------- .../src/new/calendarFields.ts | 283 +++++++++++++++ .../temporal-polyfill/src/new/calendarOps.js | 1 + .../temporal-polyfill/src/new/isoFields.js | 73 ---- .../temporal-polyfill/src/new/isoFields.ts | 130 +++++++ packages/temporal-polyfill/src/new/utils.js | 248 ------------- packages/temporal-polyfill/src/new/utils.ts | 333 ++++++++++++++++++ .../src/new/zonedDateTime.js | 2 +- packages/temporal-polyfill/tsconfig.json | 3 +- 9 files changed, 749 insertions(+), 463 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/calendarFields.js create mode 100644 packages/temporal-polyfill/src/new/calendarFields.ts delete mode 100644 packages/temporal-polyfill/src/new/isoFields.js create mode 100644 packages/temporal-polyfill/src/new/isoFields.ts delete mode 100644 packages/temporal-polyfill/src/new/utils.js create mode 100644 packages/temporal-polyfill/src/new/utils.ts diff --git a/packages/temporal-polyfill/src/new/calendarFields.js b/packages/temporal-polyfill/src/new/calendarFields.js deleted file mode 100644 index eb8a353b..00000000 --- a/packages/temporal-polyfill/src/new/calendarFields.js +++ /dev/null @@ -1,139 +0,0 @@ -import { isoTimeFieldNames } from './isoFields' -import { ensureBoolean, ensureInteger, toInteger } from './options' -import { mapPropNames, mapPropNamesToConstant, remapProps } from './utils' - -// Refiners -// ------------------------------------------------------------------------------------------------- - -const dayFieldRefiners = { day: toInteger } -const monthCodeFieldRefiners = { monthCode: toString } - -// Ordered alphabetically -export const eraYearFieldRefiners = { - era: toString, - eraYear: toInteger, -} - -// Ordered alphabetically -// Does not include era/eraYear -const yearMonthFieldRefiners = { - month: toInteger, - ...monthCodeFieldRefiners, - year: toInteger, -} - -// Ordered alphabetically -// Does not include era/eraYear -export const dateFieldRefiners = { - ...dayFieldRefiners, - ...yearMonthFieldRefiners, -} - -// Ordered alphabetically -const timeFieldRefiners = { - hour: toInteger, - microsecond: toInteger, - millisecond: toInteger, - minute: toInteger, - nanosecond: toInteger, - second: toInteger, -} - -// Unordered -// Does not include era/eraYear -export const dateTimeFieldRefiners = { - ...dateFieldRefiners, - ...timeFieldRefiners, -} - -// Ordered alphabetically, for predictable macros -const yearStatRefiners = { - daysInYear: ensureInteger, - inLeapYear: ensureBoolean, - monthsInYear: ensureInteger, -} - -// Unordered -export const yearMonthStatRefiners = { - ...yearStatRefiners, - daysInMonth: ensureInteger, -} - -// Unordered -export const dateStatRefiners = { - ...yearMonthStatRefiners, - dayOfWeek: ensureInteger, - dayOfYear: ensureInteger, - weekOfYear: ensureInteger, - yearOfWeek: ensureInteger, - daysInWeek: ensureInteger, -} - -// Property Names -// ------------------------------------------------------------------------------------------------- - -export const eraYearFieldNames = Object.keys(eraYearFieldRefiners) -export const allYearFieldNames = [...eraYearFieldNames, 'year'] - -export const dateFieldNames = Object.keys(dateFieldRefiners) -export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) // month/monthCode/year -export const monthDayFieldNames = dateFieldNames.slice(0, 3) // day/month/monthCode -export const monthFieldNames = monthDayFieldNames.slice(1) // month/monthCode -export const dateTimeFieldNames = Object.keys(dateTimeFieldRefiners).sort() -export const timeFieldNames = Object.keys(timeFieldRefiners) - -export const dateBasicNames = ['day', 'month', 'year'] -export const yearMonthBasicNames = yearMonthFieldNames.slice(1) // monthCode/year -export const monthDayBasicNames = ['day', 'monthCode'] - -export const yearStatNames = Object.keys(yearStatRefiners) -export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) // unordered -export const dateStatNames = Object.keys(dateStatRefiners) // unordered - -export const dateGetterNames = [...dateFieldNames, ...dateStatNames] // unordered -export const yearMonthGetterNames = [...yearMonthFieldNames, ...yearMonthStatNames] // unordered -export const monthDayGetterNames = monthDayFieldNames // unordered - -// Getters -// ------------------------------------------------------------------------------------------------- - -export const dateGetters = createGetters(dateGetterNames) -export const yearMonthGetters = createGetters(yearMonthGetterNames) -export const monthDayGetters = createGetters(monthDayGetterNames) - -export const timeGetters = mapPropNames((timeFieldName, i) => { - return (isoTimeFieldsInternals) => { - return isoTimeFieldsInternals[isoTimeFieldNames[i]] - } -}, timeFieldNames) - -export const dateTimeGetters = { - ...dateGetters, - ...timeGetters, -} - -function createGetter(propName) { - return (internals) => { - return internals.calendar[propName](internals) - } -} - -function createGetters(getterNames) { - const getters = mapPropNames(createGetter, getterNames) - - getters.calendarId = function(internals) { - return internals.calendar.id // works for either CalendarOpsAdapter or CalendarImpl - } - - return getters -} - -// Defaults -// ------------------------------------------------------------------------------------------------- - -export const timeFieldDefaults = mapPropNamesToConstant(timeFieldNames, 0) - -// Conversion -// ------------------------------------------------------------------------------------------------- - -export const timeFieldsToIso = remapProps.bind(undefined, timeFieldNames, isoTimeFieldNames) diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts new file mode 100644 index 00000000..e89087ce --- /dev/null +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -0,0 +1,283 @@ +import { IsoDateFields, IsoTimeFields, isoTimeFieldNames } from './isoFields' +import { ensureBoolean, ensureInteger, toInteger, toString } from './options' +import { mapPropNames, mapPropNamesToConstant, remapProps } from './utils' + +interface EraYearFields { + era: string + eraYear: number +} + +interface AllYearFields extends EraYearFields { + year: number +} + +interface MonthFields { + monthCode: string + month: number +} + +type YearMonthFields = { year: number } & MonthFields +type DateFields = YearMonthFields & { day: number } +type MonthDayFields = MonthFields & { day: number } + +interface TimeFields { + hour: number + microsecond: number + millisecond: number + minute: number + nanosecond: number + second: number +} + +type DateTimeFields = DateFields & TimeFields + +interface DateBasics { + year: number + month: number + day: number +} + +interface YearMonthBasics { + year: number + month: number +} + +interface MonthDayBasics { + monthCode: string + day: number +} + +interface YearStats { + daysInYear: number + inLeapYear: boolean + monthsInYear: number +} +interface YearMonthStats extends YearStats { + daysInMonth: number +} +interface DateStats extends YearMonthStats { + dayOfWeek: number + dayOfYear: number + weekOfYear: number + yearOfWeek: number + daysInWeek: number +} + +// TODO: move +type FilterPropValues = { + [K in keyof P as P[K] extends F ? K : never]: P[K] +} + +// TODO: temporary +interface CalendarOps { + id: string + era(isoFields: IsoDateFields): string | undefined + eraYear(isoFields: IsoDateFields): number | undefined + year(isoFields: IsoDateFields): number + monthCode(isoFields: IsoDateFields): string + month(isoFields: IsoDateFields): number + day(isoFields: IsoDateFields): number + daysInYear(isoFields: IsoDateFields): number + inLeapYear(isoFields: IsoDateFields): number + monthsInYear(isoFields: IsoDateFields): number + daysInMonth(isoFields: IsoDateFields): number + dayOfWeek(isoFields: IsoDateFields): number + dayOfYear(isoFields: IsoDateFields): number + weekOfYear(isoFields: IsoDateFields): number + yearOfWeek(isoFields: IsoDateFields): number + daysInWeek(isoFields: IsoDateFields): number +} + +type DateMethods = FilterPropValues any> + +type DateGetters = { + [K in keyof DateMethods]: ( + internals: IsoDateFields & { calendar: CalendarOps } + ) => ReturnType +} + +type TimeGetters = { + [K in keyof TimeFields]: (isoFields: IsoTimeFields) => number +} + +type CalendarIdGetters = { + calendarId: (internals: { calendar: CalendarOps }) => string +} + +// Refiners +// ------------------------------------------------------------------------------------------------- + +const dayFieldRefiners = { day: toInteger } +const monthCodeFieldRefiners = { monthCode: toString } + +// Ordered alphabetically +export const eraYearFieldRefiners = { + era: toString, + eraYear: toInteger, +} + +// Ordered alphabetically +// Does not include era/eraYear +const yearMonthFieldRefiners = { + month: toInteger, + ...monthCodeFieldRefiners, + year: toInteger, +} + +// Ordered alphabetically +// Does not include era/eraYear +export const dateFieldRefiners = { + ...dayFieldRefiners, + ...yearMonthFieldRefiners, +} + +// Ordered alphabetically +const timeFieldRefiners = { + hour: toInteger, + microsecond: toInteger, + millisecond: toInteger, + minute: toInteger, + nanosecond: toInteger, + second: toInteger, +} + +// Unordered +// Does not include era/eraYear +export const dateTimeFieldRefiners = { + ...dateFieldRefiners, + ...timeFieldRefiners, +} + +// Ordered alphabetically, for predictable macros +const yearStatRefiners = { + daysInYear: ensureInteger, + inLeapYear: ensureBoolean, + monthsInYear: ensureInteger, +} + +// Unordered +export const yearMonthStatRefiners = { + ...yearStatRefiners, + daysInMonth: ensureInteger, +} + +// Unordered +export const dateStatRefiners = { + ...yearMonthStatRefiners, + dayOfWeek: ensureInteger, + dayOfYear: ensureInteger, + weekOfYear: ensureInteger, + yearOfWeek: ensureInteger, + daysInWeek: ensureInteger, +} + +// Property Names +// ------------------------------------------------------------------------------------------------- + +export const eraYearFieldNames = Object.keys(eraYearFieldRefiners) as + (keyof EraYearFields)[] + +export const allYearFieldNames = [...eraYearFieldNames, 'year'] as + (keyof AllYearFields)[] + +export const dateFieldNames = Object.keys(dateFieldRefiners) as + (keyof DateFields)[] + +export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) as // month/monthCode/year + (keyof YearMonthFields)[] + +export const monthDayFieldNames = dateFieldNames.slice(0, 3) as // day/month/monthCode + (keyof MonthDayFields)[] + +export const monthFieldNames = monthDayFieldNames.slice(1) as // month/monthCode + (keyof MonthDayFields)[] + +export const dateTimeFieldNames = Object.keys(dateTimeFieldRefiners).sort() as + (keyof DateTimeFields)[] + +export const timeFieldNames = Object.keys(timeFieldRefiners) as + (keyof TimeFields)[] + +export const dateBasicNames = ['day', 'month', 'year'] as + (keyof DateBasics)[] + +export const yearMonthBasicNames = yearMonthFieldNames.slice(1) as // monthCode/year + (keyof YearMonthBasics)[] + +export const monthDayBasicNames = ['day', 'monthCode'] as + (keyof MonthDayBasics)[] + +export const yearStatNames = Object.keys(yearStatRefiners) as + (keyof YearStats)[] + +export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) as // unordered + (keyof YearMonthStats)[] + +export const dateStatNames = Object.keys(dateStatRefiners) as // unordered + (keyof DateStats)[] + +export const dateGetterNames = [ // unordered + ...eraYearFieldNames, + ...dateFieldNames, + ...dateStatNames, +] + +export const yearMonthGetterNames = [ // unordered + ...eraYearFieldNames, + ...yearMonthFieldNames, + ...yearMonthStatNames, +] + +export const monthDayGetterNames = monthDayFieldNames // unordered + +// Getters +// ------------------------------------------------------------------------------------------------- + +function createCalendarGetter( + propName: K, +) { + return (internals: IsoDateFields & { calendar: CalendarOps }) => { + return internals.calendar[propName](internals) as ReturnType + } +} + +function createCalendarGetters( + propNames: K[], +) { + const getters = mapPropNames( + createCalendarGetter as any, // trouble merging prop-vals into single type + propNames, + ) as (Pick & CalendarIdGetters) + + getters.calendarId = function(internals) { + return internals.calendar.id + } + + return getters +} + +export const dateGetters = createCalendarGetters(dateGetterNames) +export const yearMonthGetters = createCalendarGetters(yearMonthGetterNames) +export const monthDayGetters = createCalendarGetters(monthDayGetterNames) + +export const timeGetters = mapPropNames((fieldName, i) => { + return (isoTimeFields: IsoTimeFields) => { + return isoTimeFields[isoTimeFieldNames[i]] + } +}, timeFieldNames) + +export const dateTimeGetters = { + ...dateGetters, + ...timeGetters, +} + +// Conversion +// ------------------------------------------------------------------------------------------------- + +export const timeFieldsToIso: (fields: TimeFields) => IsoTimeFields = + (remapProps as any).bind(undefined, timeFieldNames, isoTimeFieldNames) + +// Defaults +// ------------------------------------------------------------------------------------------------- + +export const timeFieldDefaults = mapPropNamesToConstant(timeFieldNames, 0) diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.js index ac911d96..eee69294 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.js @@ -54,6 +54,7 @@ const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { return refiner(calendar[propName](createPlainDate(isoDateFields))) } }, { + // TODO: more DRY with DateGetters or something? ...eraYearFieldRefiners, ...dateFieldRefiners, ...dateStatRefiners, diff --git a/packages/temporal-polyfill/src/new/isoFields.js b/packages/temporal-polyfill/src/new/isoFields.js deleted file mode 100644 index 3f8d9ce4..00000000 --- a/packages/temporal-polyfill/src/new/isoFields.js +++ /dev/null @@ -1,73 +0,0 @@ -import { queryCalendarOps } from './calendarOps' -import { getInternals } from './class' -import { toInteger } from './options' -import { mapPropNamesToConstant, pluckProps } from './utils' - -// Refiners -// ------------------------------------------------------------------------------------------------- - -// Ordered alphabetically -export const isoDateInternalRefiners = { - calendar: queryCalendarOps, - isoDay: toInteger, // happens to be ascending - isoMonth: toInteger, // " - isoYear: toInteger, // " -} - -// Ordered by ascending size -export const isoTimeFieldRefiners = { - isoNanosecond: toInteger, - isoMicrosecond: toInteger, - isoMillisecond: toInteger, - isoSecond: toInteger, - isoMinute: toInteger, - isoHour: toInteger, -} - -// Unordered -export const isoDateTimeInternalRefiners = { - ...isoDateInternalRefiners, - ...isoTimeFieldRefiners, -} - -// Property Names -// ------------------------------------------------------------------------------------------------- - -const isoDateInternalNames = Object.keys(isoDateInternalRefiners) -export const isoDateTimeInternalNames = Object.keys(isoDateTimeInternalRefiners).sort() - -export const isoDateFieldNames = isoDateInternalNames.slice(1) // no calendar. ascending -export const isoTimeFieldNamesAsc = Object.keys(isoTimeFieldRefiners) -export const isoTimeFieldNames = isoTimeFieldNamesAsc.sort() -export const isoDateTimeFieldNamesAsc = [...isoDateFieldNames, ...isoTimeFieldNamesAsc] - -// Defaults -// ------------------------------------------------------------------------------------------------- - -export const isoTimeFieldDefaults = mapPropNamesToConstant(isoTimeFieldNames, 0) - -// Conversion -// ------------------------------------------------------------------------------------------------- - -export const pluckIsoDateInternals = pluckProps.bind(undefined, isoDateInternalNames) -export const pluckIsoDateTimeInternals = pluckProps.bind(undefined, isoDateTimeInternalNames) -export const pluckIsoDateTimeFields = pluckProps.bind(undefined, isoDateTimeFieldNamesAsc) -export const pluckIsoTimeFields = pluckProps.bind(undefined, isoTimeFieldNames) - -export const generatePublicIsoDateFields = - generatePublicIsoFields.bind(undefined, pluckIsoDateInternals) - -export const generatePublicIsoDateTimeFields = - generatePublicIsoFields.bind(undefined, pluckIsoDateTimeInternals) - -function generatePublicIsoFields(pluckFunc, internals) { - const publicFields = pluckFunc(internals) - publicFields.calendar = getPublicIdOrObj(internals.calendar) - return publicFields -} - -// Similar to getPublicCalendar and getPublicTimeZone -export function getPublicIdOrObj(ops) { - return getInternals(ops) || // adapter (return internal object) - ops.id // impl (return id) -} diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts new file mode 100644 index 00000000..2424eddd --- /dev/null +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -0,0 +1,130 @@ +import { queryCalendarOps } from './calendarOps' +import { getInternals } from './class' +import { toInteger } from './options' +import { mapPropNamesToConstant, pluckProps } from './utils' + +export interface IsoDateFields { + isoDay: number + isoMonth: number + isoYear: number +} + +export interface IsoTimeFields { + isoNanosecond: number, + isoMicrosecond: number, + isoMillisecond: number, + isoSecond: number, + isoMinute: number, + isoHour: number, +} + +// TODO: move +interface CalendarOps { + id: string +} + +// TODO: move +type CalendarIdOrObj = string | CalendarOps + +interface IsoDateInternals extends IsoDateFields { + calendar: CalendarOps +} + +type IsoDateTimeFields = IsoDateFields & IsoTimeFields +type IsoDateTimeInternals = IsoDateInternals & IsoTimeFields + +// Refiners +// ------------------------------------------------------------------------------------------------- + +// Ordered alphabetically +export const isoDateInternalRefiners = { + calendar: queryCalendarOps, + isoDay: toInteger, // happens to be ascending + isoMonth: toInteger, // " + isoYear: toInteger, // " +} + +// Ordered by ascending size +export const isoTimeFieldRefiners = { + isoNanosecond: toInteger, + isoMicrosecond: toInteger, + isoMillisecond: toInteger, + isoSecond: toInteger, + isoMinute: toInteger, + isoHour: toInteger, +} + +// Unordered +export const isoDateTimeInternalRefiners = { + ...isoDateInternalRefiners, + ...isoTimeFieldRefiners, +} + +// Property Names +// ------------------------------------------------------------------------------------------------- + +const isoDateInternalNames = Object.keys(isoDateInternalRefiners) as + (keyof IsoDateInternals)[] + +export const isoDateTimeInternalNames = Object.keys(isoDateTimeInternalRefiners).sort() as + (keyof IsoDateTimeInternals)[] + +export const isoDateFieldNames = isoDateInternalNames.slice(1) as + (keyof IsoDateTimeFields)[] + +export const isoTimeFieldNamesAsc = Object.keys(isoTimeFieldRefiners) as + (keyof IsoTimeFields)[] + +export const isoTimeFieldNames = isoTimeFieldNamesAsc.sort() +export const isoDateTimeFieldNamesAsc = [...isoDateFieldNames, ...isoTimeFieldNamesAsc] + +// Defaults +// ------------------------------------------------------------------------------------------------- + +export const isoTimeFieldDefaults = mapPropNamesToConstant(isoTimeFieldNames, 0) + +// Conversion +// ------------------------------------------------------------------------------------------------- + +export const pluckIsoDateInternals: (internals: IsoDateInternals) => IsoDateFields = + (pluckProps as any).bind(undefined, isoDateInternalNames) + +export const pluckIsoDateTimeInternals: (internals: IsoDateTimeInternals) => IsoDateTimeInternals = + (pluckProps as any).bind(undefined, isoDateTimeInternalNames) + +export const pluckIsoDateTimeFields: (fields: IsoDateTimeFields) => IsoDateTimeFields = + (pluckProps as any).bind(undefined, isoDateTimeFieldNamesAsc) + +export const pluckIsoTimeFields: (fields: IsoTimeFields) => IsoTimeFields = + (pluckProps as any).bind(undefined, isoTimeFieldNames) + +function generatePublicIsoFields( + pluckFunc: (internals: I) => I, + internals: I, +): I & { calendar: CalendarIdOrObj } { + const publicFields = pluckFunc(internals) as (I & { calendar: CalendarIdOrObj }) + publicFields.calendar = getPublicIdOrObj(internals.calendar) + return publicFields +} + +export const generatePublicIsoDateFields: ( + isoDateFields: IsoDateFields +) => ( + IsoDateFields & { calendar: CalendarIdOrObj } +) = (generatePublicIsoFields as any).bind(undefined, pluckIsoDateInternals) + +export const generatePublicIsoDateTimeFields: ( + isoDateTimeFields: IsoDateTimeFields +) => ( + IsoDateTimeFields & { calendar: CalendarIdOrObj } +) = (generatePublicIsoFields as any).bind(undefined, pluckIsoDateTimeInternals) + +/* +Similar to getPublicCalendar and getPublicTimeZone +*/ +export function getPublicIdOrObj( + ops: { id: string }, +): { id: string } | any { + return getInternals(ops) || // adapter (return internal object) + ops.id // impl (return id) +} diff --git a/packages/temporal-polyfill/src/new/utils.js b/packages/temporal-polyfill/src/new/utils.js deleted file mode 100644 index ad5d5b8a..00000000 --- a/packages/temporal-polyfill/src/new/utils.js +++ /dev/null @@ -1,248 +0,0 @@ -import { returnUndefinedI } from './options' - -const objectlikeRE = /object|function/ - -export function isObjectlike(arg) { - return arg !== null && objectlikeRE.test(typeof arg) -} - -export function mapProps(transformer, props, extraArg) { - const res = {} - - for (const propName in props) { - res[propName] = transformer(props[propName], propName, extraArg) - } - - return res -} - -export const mapPropsWithRefiners = mapProps.bind( - undefined, - (propValue, propName, refinerMap) => refinerMap[propName](propValue, propName), -) - -export function mapPropNames(generator, propNames, extraArg) { - const res = {} - - for (let i = 0; i < propNames.length; i++) { - const propName = propNames[i] - res[propName] = generator(propName, i, extraArg) - } - - return res -} - -export const mapPropNamesToIndex = mapPropNames.bind( - undefined, - (propName, index) => index, -) - -export const mapPropNamesToConstant = mapPropNames.bind( - undefined, - (propName, index, extraArg) => extraArg, -) - -export function remapProps(oldKeys, newKeys, props) { - const res = {} - - for (let i = 0; i < oldKeys.length; i++) { - res[newKeys[i]] = props[oldKeys[i]] - } - - return res -} - -export function pluckProps(propNames, props) { - const res = {} - - for (const propName of propNames) { - res[propName] = props[propName] - } - - return res -} - -export function excludeArrayDuplicates(a) { - return [...new Set(a)] -} - -function filterProps(filterFunc, props, extraArg) { - const res = {} - - for (const propName in props) { - const propValue = props[propName] - - if (filterFunc(propValue, propName, extraArg)) { - res[propName] = propValue - } - } - - return res -} - -export const excludeUndefinedProps = filterProps.bind( - undefined, - (propValue) => propValue !== undefined, -) - -export const excludePropsByName = filterProps.bind( - undefined, - (propValue, propName, nameSet) => !nameSet.has(propName), -) - -export function hasAnyPropsByName(props, names) { - for (const name of names) { - if (props[name] !== undefined) { - return true - } - } - return false -} - -export function hasAllPropsByName(props, names) { - for (const name of names) { - if (props[name] === undefined) { - return false - } - } - return true -} - -export function createLazyGenerator(generator, MapClass = Map) { - const map = new MapClass() - - return (key, ...otherArgs) => { - if (map.has(key)) { - return map.get(key) - } else { - const val = generator(key, ...otherArgs) - map.set(key, val) - return val - } - } -} - -// descriptor stuff -// ---------------- - -export function defineProps(target, propVals) { - return Object.defineProperties(target, createPropDescriptors(propVals)) -} - -export function createPropDescriptors(props) { - return mapProps(props, (value) => ({ - value, - configurable: true, - writable: true, - })) -} - -export function createGetterDescriptors(getters) { - return mapProps(getters, (getter) => ({ - get: getter, - configurable: true, - })) -} - -export function createTemporalNameDescriptors(temporalName) { - return { - [Symbol.toStringTag]: { - value: 'Temporal.' + temporalName, - configurable: true, - }, - } -} - -// former lang -// ----------- - -export function identityFunc(thing) { - return thing -} - -export function noop() { -} - -export function padNumber(digits, num) { - return num.padStart(digits, '0') -} - -export const padNumber2 = padNumber.bind(undefined, 2) - -export function compareNumbers(a, b) { - return Math.sign(a - b) -} - -export function compareProps(propNames, props0, props1) { - for (const propName of propNames) { - const cmp = compareNumbers(props0[propName], props1[propName]) - if (cmp) { - return cmp - } - } - return 0 -} - -export function clamp( - val, - min, // inclusive - max, // inclusive - overflowBehavior, // 0/1/2 --- overflow enum - noun, // for error message (required if overflowBehavior given) -) { - const clamped = Math.min(Math.max(val, min), max) - - if (overflowBehavior && val !== clamped) { - if (overflowBehavior === returnUndefinedI) { - return undefined - } - throw new RangeError(`${noun} must be between ${min}-${max}`) - } - - return clamped -} - -/* -Works with BigInt or Number (as long as the same) -*/ -export function divFloorMod(n, divisor) { - const remainder = floorMod(n, divisor) - const quotient = (n - remainder) / divisor - return [quotient, remainder] -} - -/* -Works with BigInt or Number (as long as the same) -*/ -export function floorMod(n, divisor) { - return (n % divisor + divisor) % divisor -} - -// rounding -// -------- - -export function roundExpand(n) { - return n < 0 ? Math.floor(n) : Math.ceil(n) -} - -export function roundHalfFloor(n) { - return hasHalf(n) ? Math.floor(n) : Math.round(n) -} - -export function roundHalfCeil(n) { - return hasHalf(n) ? Math.ceil(n) : Math.round(n) -} - -export function roundHalfTrunc(n) { - return hasHalf(n) ? Math.trunc(n) : Math.round(n) -} - -export function roundHalfEven(n) { - return hasHalf(n) - ? (n = Math.trunc(n)) + (n % 2) - : Math.round(n) -} - -function hasHalf(n) { - return Math.abs(n % 1) === 0.5 -} diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts new file mode 100644 index 00000000..56c92b56 --- /dev/null +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -0,0 +1,333 @@ +const objectlikeRE = /object|function/ + +export function isObjectlike(arg: unknown): boolean { + return arg !== null && objectlikeRE.test(typeof arg) +} + +export function mapProps( + transformer: (propVal: P[keyof P], propName: keyof P, extraArg?: E) => V, + props: P, + extraArg?: E, +): { [PropName in keyof P]: V } { + const res = {} as { [PropName in keyof P]: V } + + for (const propName in props) { + res[propName] = transformer(props[propName], propName, extraArg) + } + + return res +} + +export type PropsRefinerMap = { + [K in keyof P]: (propVal: P[K], propName: K) => V +} + +export const mapPropsWithRefiners: ( + props: P, + refinerMap: PropsRefinerMap +) => { + [K in keyof P]: V +} = (mapProps as any).bind(undefined, ( + propVal: P[keyof P], + propName: keyof P, + refinerMap: PropsRefinerMap, +) => { + return refinerMap[propName](propVal, propName) +}) + +export function mapPropNames( + generator: (propName: keyof P, i: number, extraArg?: E) => P[keyof P], + propNames: (keyof P)[], + extraArg?: E, +): P { + const props = {} as P + + for (let i = 0; i < propNames.length; i++) { + const propName = propNames[i] + props[propName] = generator(propName, i, extraArg) + } + + return props +} + +export const mapPropNamesToIndex:

( + propNames: (keyof P)[], +) => { + [K in keyof P]: number +} = (mapProps as any).bind(undefined,

( + propName: keyof P, + i: number, +) => i) + +export const mapPropNamesToConstant: ( + propNames: (keyof P)[], + val: V +) => { + [K in keyof P]: V +} = (mapProps as any).bind(undefined, ( + propName: keyof P, + i: number, + val: V, +) => val) + +export function remapProps( + oldPropNames: (keyof OldProps)[], + newPropNames: (keyof NewProps)[], + oldProps: OldProps, +): NewProps { + const newProps = {} as NewProps + + for (let i = 0; i < oldPropNames.length; i++) { + newProps[newPropNames[i]] = oldProps[oldPropNames[i]] as any + } + + return newProps +} + +export function pluckProps( + propNames: PropName[], + props: Props, +): Pick { + const res = {} as Pick + + for (const propName of propNames) { + res[propName] = props[propName] + } + + return res +} + +export function excludeArrayDuplicates(a: Item[]): Item[] { + return [...new Set(a)] +} + +function filterProps( + filterFunc: ( + propVal: Props[keyof Props], + propName: keyof Props, + extraArg: ExtraArg + ) => boolean, + props: Props, + extraArg?: ExtraArg, +) { + const filteredProps = {} as Props + + for (const propName in props) { + const propVal = props[propName] + + if (filterFunc(propVal, propName, extraArg as ExtraArg)) { + filteredProps[propName] = propVal + } + } + + return filteredProps +} + +export const excludePropsByName = filterProps.bind( + undefined, + (propVal, propName, nameSet: any) => !nameSet.has(propName), +) as ( + props: Props, + propNames: Set, +) => Omit + +export const excludeUndefinedProps = filterProps.bind( + undefined, + (propVal) => propVal !== undefined, +) as (props: Props) => Partial + +export function hasAnyPropsByName( + props: Props, + names: (keyof Props)[], +): boolean { + for (const name of names) { + if (props[name] !== undefined) { + return true + } + } + return false +} + +export function hasAllPropsByName( + props: Props, + names: (keyof Props)[], +): boolean { + for (const name of names) { + if (props[name] === undefined) { + return false + } + } + return true +} + +export function createLazyGenerator( + generator: (key: Key, ...otherArgs: OtherArgs) => Val, + MapClass: { new(): Map } = Map, +): (key: Key, ...otherArgs: OtherArgs) => Val { + const map = new MapClass() + + return (key: Key, ...otherArgs: OtherArgs) => { + if (map.has(key)) { + return map.get(key)! + } else { + const val = generator(key, ...otherArgs) + map.set(key, val) + return val + } + } +} + +// descriptor stuff +// ---------------- + +export function defineProps( + target: Target, + propVals: Record, +): Target & PropVals { + return Object.defineProperties(target, createPropDescriptors(propVals)) as (Target & PropVals) +} + +export function createPropDescriptors( + propVals: Record, +): PropertyDescriptorMap { + return mapProps((value) => ({ + value, + configurable: true, + writable: true, + }), propVals) +} + +export function createGetterDescriptors( + getters: Record unknown>, +): PropertyDescriptorMap { + return mapProps((getter) => ({ + get: getter, + configurable: true, + }), getters) +} + +export function createTemporalNameDescriptors(temporalName: string): PropertyDescriptorMap { + return { + [Symbol.toStringTag]: { + value: 'Temporal.' + temporalName, + configurable: true, + }, + } +} + +// former lang +// ----------- + +export function identityFunc(arg: T): T { + return arg +} + +export function noop(): void { + // return undefined +} + +export function padNumber(digits: number, num: number): string { // TODO: rename `padNum` + return String(num).padStart(digits, '0') +} + +export const padNumber2 = padNumber.bind(undefined, 2) + +export type NumSign = -1 | 0 | 1 + +export function compareNumbers(a: number, b: number): NumSign { // TODO: rename `compareNums` + return Math.sign(a - b) as NumSign +} + +export function compareProps>( + propNames: (keyof Props)[], + props0: Props, + props1: Props, +): NumSign { + for (const propName of propNames) { + const cmp = compareNumbers(props0[propName], props1[propName]) + if (cmp) { + return cmp + } + } + return 0 +} + +export function clamp( + num: number, + min: number, + max: number, +): number +export function clamp( + num: number, + min: number, + max: number, + overflowBehavior: 1, + noun: string, +): number +export function clamp( + num: number, + min: number, + max: number, + overflowBehavior: 2, +): number | undefined +export function clamp( + num: number, + min: number, // inclusive + max: number, // inclusive + overflowBehavior: (0 | 1 | 2) = 0, // TODO: better enum - 0/1/2 --- overflow enum + noun?: string, +): number | undefined { + const clamped = Math.min(Math.max(num, min), max) + + if (overflowBehavior && num !== clamped) { + if (overflowBehavior === 2) { + return undefined + } + throw new RangeError(`${noun!} must be between ${min}-${max}`) + } + + return clamped +} + +export function divFloorMod(num: number, divisor: number): [number, number] +export function divFloorMod(num: bigint, divisor: bigint): [bigint, bigint] +export function divFloorMod(num: any, divisor: any): [any, any] { + const remainder = floorMod(num, divisor) + const quotient = (num - remainder) / divisor + return [quotient, remainder] +} + +export function floorMod(num: number, divisor: number): number +export function floorMod(num: bigint, divisor: bigint): bigint +export function floorMod(num: any, divisor: any): any { + return (num % divisor + divisor) % divisor +} + +// rounding +// -------- + +export function roundExpand(num: number): number { + return num < 0 ? Math.floor(num) : Math.ceil(num) +} + +export function roundHalfFloor(num: number): number { + return hasHalf(num) ? Math.floor(num) : Math.round(num) +} + +export function roundHalfCeil(num: number): number { + return hasHalf(num) ? Math.ceil(num) : Math.round(num) +} + +export function roundHalfTrunc(num: number): number { + return hasHalf(num) ? Math.trunc(num) : Math.round(num) +} + +export function roundHalfEven(num: number): number { + return hasHalf(num) + ? (num = Math.trunc(num)) + (num % 2) + : Math.round(num) +} + +function hasHalf(num: number): boolean { + return Math.abs(num % 1) === 0.5 +} diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.js index 1c38acd8..6141edcd 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.js @@ -26,9 +26,9 @@ import { formatTimeZone, } from './isoFormat' import { + checkEpochNano, epochGetters, epochNanoToIso, - checkEpochNano, } from './isoMath' import { parseZonedDateTime } from './isoParse' import { compareLargeInts } from './largeInt' diff --git a/packages/temporal-polyfill/tsconfig.json b/packages/temporal-polyfill/tsconfig.json index df8d62e5..5005d809 100644 --- a/packages/temporal-polyfill/tsconfig.json +++ b/packages/temporal-polyfill/tsconfig.json @@ -6,8 +6,7 @@ "types": [], "target": "ES2018", "lib": [ - "ES2015", - "ES2017.Intl", + "ES2017", "ES2020.Intl", "ES2020.BigInt" ] From ea4f115c9c852265775a3443e7d36d71208632dd Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 11 Jul 2023 00:14:50 -0400 Subject: [PATCH 132/805] more ts conversion --- .../src/new/calendarFields.ts | 44 ++-- .../temporal-polyfill/src/new/duration.js | 4 +- .../src/new/durationFields.js | 156 ------------- .../src/new/durationFields.ts | 219 ++++++++++++++++++ .../temporal-polyfill/src/new/isoFields.ts | 22 +- .../src/new/{largeInt.js => largeInt.ts} | 48 ++-- packages/temporal-polyfill/src/new/options.js | 10 +- packages/temporal-polyfill/src/new/round.js | 6 +- packages/temporal-polyfill/src/new/units.js | 96 -------- packages/temporal-polyfill/src/new/units.ts | 122 ++++++++++ packages/temporal-polyfill/src/new/utils.ts | 5 +- 11 files changed, 413 insertions(+), 319 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/durationFields.js create mode 100644 packages/temporal-polyfill/src/new/durationFields.ts rename packages/temporal-polyfill/src/new/{largeInt.js => largeInt.ts} (52%) delete mode 100644 packages/temporal-polyfill/src/new/units.js create mode 100644 packages/temporal-polyfill/src/new/units.ts diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index e89087ce..4b6dccdc 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -1,4 +1,10 @@ -import { IsoDateFields, IsoTimeFields, isoTimeFieldNames } from './isoFields' +import { + CalendarOps, + IsoDateFields, + IsoDateInternals, + IsoTimeFields, + isoTimeFieldNames, +} from './isoFields' import { ensureBoolean, ensureInteger, toInteger, toString } from './options' import { mapPropNames, mapPropNamesToConstant, remapProps } from './utils' @@ -52,9 +58,11 @@ interface YearStats { inLeapYear: boolean monthsInYear: number } + interface YearMonthStats extends YearStats { daysInMonth: number } + interface DateStats extends YearMonthStats { dayOfWeek: number dayOfYear: number @@ -68,32 +76,10 @@ type FilterPropValues = { [K in keyof P as P[K] extends F ? K : never]: P[K] } -// TODO: temporary -interface CalendarOps { - id: string - era(isoFields: IsoDateFields): string | undefined - eraYear(isoFields: IsoDateFields): number | undefined - year(isoFields: IsoDateFields): number - monthCode(isoFields: IsoDateFields): string - month(isoFields: IsoDateFields): number - day(isoFields: IsoDateFields): number - daysInYear(isoFields: IsoDateFields): number - inLeapYear(isoFields: IsoDateFields): number - monthsInYear(isoFields: IsoDateFields): number - daysInMonth(isoFields: IsoDateFields): number - dayOfWeek(isoFields: IsoDateFields): number - dayOfYear(isoFields: IsoDateFields): number - weekOfYear(isoFields: IsoDateFields): number - yearOfWeek(isoFields: IsoDateFields): number - daysInWeek(isoFields: IsoDateFields): number -} - type DateMethods = FilterPropValues any> type DateGetters = { - [K in keyof DateMethods]: ( - internals: IsoDateFields & { calendar: CalendarOps } - ) => ReturnType + [K in keyof DateMethods]: (internals: IsoDateInternals) => ReturnType } type TimeGetters = { @@ -236,7 +222,7 @@ export const monthDayGetterNames = monthDayFieldNames // unordered function createCalendarGetter( propName: K, ) { - return (internals: IsoDateFields & { calendar: CalendarOps }) => { + return (internals: IsoDateInternals) => { return internals.calendar[propName](internals) as ReturnType } } @@ -244,12 +230,12 @@ function createCalendarGetter( function createCalendarGetters( propNames: K[], ) { - const getters = mapPropNames( - createCalendarGetter as any, // trouble merging prop-vals into single type + const getters = mapPropNames>( + createCalendarGetter as ((propName: K) => any), propNames, - ) as (Pick & CalendarIdGetters) + ) as Pick & CalendarIdGetters - getters.calendarId = function(internals) { + getters.calendarId = (internals: { calendar: CalendarOps }) => { return internals.calendar.id } diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.js index ab7df577..6a5a6834 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.js @@ -7,7 +7,7 @@ import { durationFieldsToNano, durationGetters, negateDurationInternals, - refineDurationInternals, + refineDurationFields, } from './durationFields' import { formatDurationInternals } from './isoFormat' import { isoToEpochNano } from './isoMath' @@ -53,7 +53,7 @@ export const [ microseconds = 0, nanoseconds = 0, ) => { - return refineDurationInternals({ + return refineDurationFields({ years, months, weeks, diff --git a/packages/temporal-polyfill/src/new/durationFields.js b/packages/temporal-polyfill/src/new/durationFields.js deleted file mode 100644 index 13a4723c..00000000 --- a/packages/temporal-polyfill/src/new/durationFields.js +++ /dev/null @@ -1,156 +0,0 @@ -import { isoTimeFieldNames } from './isoFields' -import { toIntegerStrict } from './options' -import { - dayIndex, - givenFieldsToLargeNano, - hourIndex, - nanoToGivenFields, - unitIndexToNano, - unitNamesAsc, -} from './units' -import { - mapPropNames, - mapPropNamesToConstant, - mapPropNamesToIndex, - mapPropsWithRefiners, - remapProps, -} from './utils' - -// Property Names -// ------------------------------------------------------------------------------------------------- - -export const durationFieldNamesAsc = unitNamesAsc.map((unitName) => unitName + 's') // pluralize -export const durationFieldIndexes = mapPropNamesToIndex(durationFieldNamesAsc) -export const durationFieldNames = durationFieldNamesAsc.sort() - -// unordered -const durationTimeFieldNames = durationFieldNamesAsc.slice(0, dayIndex) -const durationDateFieldNames = durationFieldNamesAsc.slice(dayIndex) -const durationInternalNames = [...durationFieldNames, 'sign'] - -// Defaults -// ------------------------------------------------------------------------------------------------- - -export const durationFieldDefaults = mapPropNamesToConstant(durationFieldNames, 0) -export const durationTimeFieldDefaults = mapPropNamesToConstant(durationTimeFieldNames, 0) - -// Refiners -// ------------------------------------------------------------------------------------------------- - -export const durationFieldRefiners = mapPropNamesToConstant(durationFieldNames, toIntegerStrict) - -// Getters -// ------------------------------------------------------------------------------------------------- - -export const durationGetters = mapPropNames((propName) => { - return (durationInternals) => { - return durationInternals[propName] - } -}, durationInternalNames) - -// Field <-> Field Conversion -// ------------------------------------------------------------------------------------------------- - -export function refineDurationInternals(rawDurationFields) { - return updateDurationFieldsSign(mapPropsWithRefiners(rawDurationFields, durationFieldRefiners)) -} - -export const durationTimeFieldsToIso = remapProps.bind( - undefined, - durationTimeFieldNames, - isoTimeFieldNames, -) - -export function durationTimeFieldsToIsoStrict(durationFields) { - if (durationHasDateParts(durationFields)) { - throw new RangeError('Operation not allowed') - } - return durationTimeFieldsToIso(durationFields) -} - -// Field <-> Nanosecond Conversion -// ------------------------------------------------------------------------------------------------- - -export function durationFieldsToNano(durationFields, largestUnitIndex = dayIndex) { - return givenFieldsToLargeNano(durationFields, largestUnitIndex, durationFieldNamesAsc) -} - -export function durationFieldsToTimeNano(durationFields) { - return durationFieldsToNano(durationFields, hourIndex).toNumber() -} - -export function nanoToDurationFields(largeNano, largestUnitIndex = dayIndex) { - const divisor = unitIndexToNano[largestUnitIndex] - const [largeUnitNum, remainder] = largeNano.divTruncMod(divisor) - - return { - [durationFieldNamesAsc[largestUnitIndex]]: largeUnitNum.toNumber(), - ...nanoToGivenFields(remainder, largestUnitIndex - 1, durationFieldNamesAsc), - } -} - -export function timeNanoToDurationFields(nano) { - return nanoToGivenFields(nano, hourIndex, durationFieldNamesAsc) -} - -// Field Math -// ------------------------------------------------------------------------------------------------- - -export function updateDurationFieldsSign(fields) { - fields.sign = computeDurationFieldsSign(fields) - return fields // returns 'internals' -} - -export function addDurationFields(a, b, sign) { // TODO: make version that updates sign? - const res = {} - - for (const fieldName in durationFieldNames) { - res[fieldName] = a[fieldName] + b[fieldName] * sign - } - - return res -} - -export function negateDurationInternals(internals) { - const res = negateDurationFields(internals) - res.sign = -internals.sign || 0 - return res -} - -export function negateDurationFields(internals) { - const res = {} - - for (const fieldName in durationFieldNames) { - res[fieldName] = internals[fieldName] * -1 || 0 - } - - return res -} - -export function absDurationInternals(internals) { - if (internals.sign === -1) { - return negateDurationInternals(internals) - } - return internals -} - -export function durationHasDateParts(internals) { - return Boolean(computeDurationFieldsSign(internals, durationDateFieldNames)) -} - -function computeDurationFieldsSign(internals, fieldNames = durationFieldNames) { - let sign = 0 - - for (const fieldName in durationFieldNames) { - const fieldSign = Math.sign(internals[fieldName]) - - if (fieldSign) { - if (sign && sign !== fieldSign) { - throw new RangeError('Cant have mixed signs') - } - sign = fieldSign - } - } - - return sign -} diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts new file mode 100644 index 00000000..6f351ffb --- /dev/null +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -0,0 +1,219 @@ +import { IsoTimeFields, isoTimeFieldNames } from './isoFields' +import { LargeInt } from './largeInt' +import { toIntegerStrict } from './options' +import { + DayTimeUnit, + Unit, + givenFieldsToLargeNano, + nanoToGivenFields, + unitNamesAsc, + unitNanoMap, +} from './units' +import { + NumSign, + mapPropNames, + mapPropNamesToConstant, + mapPropNamesToIndex, + mapProps, + remapProps, +} from './utils' + +interface DurationDateFields { + days: number + weeks: number + months: number + years: number +} + +interface DurationTimeFields { + nanoseconds: number + microseconds: number + milliseconds: number + seconds: number + minutes: number + hours: number +} + +type DurationFields = DurationDateFields & DurationTimeFields + +interface DurationInternals extends DurationFields { + sign: NumSign +} + +type DurationGetters = { + [K in keyof DurationInternals]: (internals: DurationInternals) => DurationInternals[K] +} + +// Property Names +// ------------------------------------------------------------------------------------------------- + +// pluralized +export const durationFieldNamesAsc = unitNamesAsc.map((unitName) => unitName + 's') as + (keyof DurationFields)[] + +export const durationFieldIndexes = mapPropNamesToIndex(durationFieldNamesAsc) + +export const durationFieldNames = durationFieldNamesAsc.sort() + +// unordered +const durationTimeFieldNames = durationFieldNamesAsc.slice(0, Unit.Day) as + (keyof DurationTimeFields)[] + +// unordered +const durationDateFieldNames = durationFieldNamesAsc.slice(Unit.Day) as + (keyof DurationDateFields)[] + +// unordered +const durationInternalNames = [...durationFieldNames, 'sign'] as + (keyof DurationInternals)[] + +// Defaults +// ------------------------------------------------------------------------------------------------- + +export const durationFieldDefaults = mapPropNamesToConstant(durationFieldNames, 0) +export const durationTimeFieldDefaults = mapPropNamesToConstant(durationTimeFieldNames, 0) + +// Refiners +// ------------------------------------------------------------------------------------------------- + +export const durationFieldRefiners = mapPropNamesToConstant(durationFieldNames, toIntegerStrict) + +// Getters +// ------------------------------------------------------------------------------------------------- + +export const durationGetters = mapPropNames((propName) => { + return (internals: DurationInternals) => { + return internals[propName] + } +}, durationInternalNames) + +// Field <-> Field Conversion +// ------------------------------------------------------------------------------------------------- + +export function refineDurationFields( + rawFields: DurationFields, +): DurationFields { + return updateDurationFieldsSign( + mapProps(toIntegerStrict, rawFields), + ) +} + +export const durationTimeFieldsToIso: ( + fields: DurationTimeFields +) => ( + IsoTimeFields +) = (remapProps as any).bind(undefined, durationTimeFieldNames, isoTimeFieldNames) + +export function durationTimeFieldsToIsoStrict(fields: DurationFields): IsoTimeFields { + if (durationHasDateParts(fields)) { + throw new RangeError('Operation not allowed') // correct error? + } + return durationTimeFieldsToIso(fields) +} + +// Field <-> Nanosecond Conversion +// ------------------------------------------------------------------------------------------------- + +export function durationFieldsToNano( + fields: DurationFields, + largestUnit: DayTimeUnit = Unit.Day, +): LargeInt { + return givenFieldsToLargeNano(fields, largestUnit, durationFieldNamesAsc) +} + +export function durationFieldsToTimeNano(fields: DurationFields): number { + return durationFieldsToNano(fields, Unit.Hour).toNumber() +} + +export function nanoToDurationFields( + largeNano: LargeInt, + largestUnit: DayTimeUnit = Unit.Day, +): DurationFields { + const divisor = unitNanoMap[largestUnit] + const [largeUnitNum, remainder] = largeNano.divTruncMod(divisor) + + return { + [durationFieldNamesAsc[largestUnit]]: largeUnitNum.toNumber(), + ...nanoToGivenFields(remainder, largestUnit - 1, durationFieldNamesAsc), + } +} + +export function timeNanoToDurationFields(nano: number): DurationFields { + return nanoToGivenFields( + nano, + Unit.Hour, + durationFieldNamesAsc, + ) +} + +// Field Math +// ------------------------------------------------------------------------------------------------- + +/* +Mutates `fields` +*/ +export function updateDurationFieldsSign(fields: DurationFields): DurationInternals { + (fields as DurationInternals).sign = computeDurationFieldsSign(fields) + return (fields as DurationInternals) +} + +export function addDurationFields( + a: DurationFields, + b: DurationFields, + sign: NumSign, +): DurationFields { + const res = {} as DurationFields + + for (const fieldName of durationFieldNames) { + res[fieldName] = a[fieldName] + b[fieldName] * sign + } + + return res +} + +export function negateDurationInternals(internals: DurationInternals): DurationInternals { + const res = negateDurationFields(internals) + ;(res as DurationInternals).sign = (-internals.sign || 0) as NumSign + return (res as DurationInternals) +} + +export function negateDurationFields(fields: DurationFields): DurationFields { + const res = {} as DurationFields + + for (const fieldName of durationFieldNames) { + res[fieldName] = fields[fieldName] * -1 || 0 + } + + return res +} + +export function absDurationInternals(internals: DurationInternals): DurationInternals { + if (internals.sign === -1) { + return negateDurationInternals(internals) + } + return internals +} + +export function durationHasDateParts(fields: DurationFields): boolean { + return Boolean(computeDurationFieldsSign(fields, durationDateFieldNames)) +} + +function computeDurationFieldsSign( + fields: DurationFields, + fieldNames = durationFieldNames, +): NumSign { + let sign: NumSign = 0 + + for (const fieldName of fieldNames) { + const fieldSign = Math.sign(fields[fieldName]) as NumSign + + if (fieldSign) { + if (sign && sign !== fieldSign) { + throw new RangeError('Cant have mixed signs') + } + sign = fieldSign + } + } + + return sign +} diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts index 2424eddd..7d8e5e28 100644 --- a/packages/temporal-polyfill/src/new/isoFields.ts +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -18,18 +18,34 @@ export interface IsoTimeFields { isoHour: number, } -// TODO: move -interface CalendarOps { +// TODO: temporary +export interface CalendarOps { id: string + era(isoFields: IsoDateFields): string | undefined + eraYear(isoFields: IsoDateFields): number | undefined + year(isoFields: IsoDateFields): number + monthCode(isoFields: IsoDateFields): string + month(isoFields: IsoDateFields): number + day(isoFields: IsoDateFields): number + daysInYear(isoFields: IsoDateFields): number + inLeapYear(isoFields: IsoDateFields): number + monthsInYear(isoFields: IsoDateFields): number + daysInMonth(isoFields: IsoDateFields): number + dayOfWeek(isoFields: IsoDateFields): number + dayOfYear(isoFields: IsoDateFields): number + weekOfYear(isoFields: IsoDateFields): number + yearOfWeek(isoFields: IsoDateFields): number + daysInWeek(isoFields: IsoDateFields): number } // TODO: move type CalendarIdOrObj = string | CalendarOps -interface IsoDateInternals extends IsoDateFields { +export interface CalendarInternals { calendar: CalendarOps } +export type IsoDateInternals = IsoDateFields & CalendarInternals type IsoDateTimeFields = IsoDateFields & IsoTimeFields type IsoDateTimeInternals = IsoDateInternals & IsoTimeFields diff --git a/packages/temporal-polyfill/src/new/largeInt.js b/packages/temporal-polyfill/src/new/largeInt.ts similarity index 52% rename from packages/temporal-polyfill/src/new/largeInt.js rename to packages/temporal-polyfill/src/new/largeInt.ts index 49f85574..0d2fc61c 100644 --- a/packages/temporal-polyfill/src/new/largeInt.js +++ b/packages/temporal-polyfill/src/new/largeInt.ts @@ -1,29 +1,29 @@ -import { compareNumbers, divFloorMod } from './utils' +import { NumSign, compareNumbers, divFloorMod } from './utils' const maxLow = 1e8 // exclusive // TODO: explain why export class LargeInt { - constructor(high, low) { - this.high = high - this.low = low - } + constructor( + public high: number, + public low: number, + ) {} - addLargeInt(n, sign = 1) { - return balanceAndCreate(this.high + n.high * sign, this.low + n.low * sign) + addLargeInt(num: LargeInt, sign = 1 | -1): LargeInt { + return balanceAndCreate(this.high + num.high * sign, this.low + num.low * sign) } /* different than PlainTime/Duration::add, for minification */ - addNumber(n) { - return balanceAndCreate(this.high, this.low + n) + addNumber(num: number): LargeInt { + return balanceAndCreate(this.high, this.low + num) } - mult(multiplier) { + mult(multiplier: number): LargeInt { return balanceAndCreate(this.high * multiplier, this.low * multiplier) } - divFloorMod(divisor) { + divFloorMod(divisor: number): [LargeInt, number] { const { high, low } = this const [newHigh, highRemainder] = divFloorMod(high, divisor) const [newLow, remainder] = divFloorMod(highRemainder * maxLow + low, divisor) @@ -34,7 +34,7 @@ export class LargeInt { ] } - divTruncMod(divisor) { + divTruncMod(divisor: number): [LargeInt, number] { let [whole, remainder] = this.divFloorMod(divisor) if (whole.computeSign() === -1 && remainder) { @@ -45,40 +45,42 @@ export class LargeInt { return [whole, remainder] } - mod2() { + mod2(): number { return (this.low % 2) * this.computeSign() } /* different than Duration::sign, for minification */ - computeSign() { - return Math.sign(this.high) || Math.sign(this.low) + computeSign(): NumSign { + return (Math.sign(this.high) || Math.sign(this.low)) as NumSign } - toNumber() { + toNumber(): number { return this.high * maxLow + this.low } - toBigInt() { + toBigInt(): bigint { return BigInt(this.high) * BigInt(maxLow) + BigInt(this.low) } } -function balanceAndCreate(high, low) { +function balanceAndCreate(high: number, low: number) { const [extraHigh, newLow] = divFloorMod(low, maxLow) return new LargeInt(high + extraHigh, newLow) } -export function numberToLargeInt(n) { - return new LargeInt(...divFloorMod(n, maxLow)) +export function numberToLargeInt(num: number): LargeInt { + return new LargeInt(...divFloorMod(num, maxLow)) } -export function bigIntToLargeInt(n) { +export function bigIntToLargeInt(num: bigint): LargeInt { // must create BigInt lazily for if browser lacks support - return new LargeInt(...divFloorMod(n, BigInt(maxLow)).map(Number)) + return new LargeInt( + ...(divFloorMod(num, BigInt(maxLow)).map(Number) as [number, number]), + ) } -export function compareLargeInts(a, b) { +export function compareLargeInts(a: LargeInt, b: LargeInt): NumSign { return compareNumbers(a.high, b.high) || compareNumbers(a.low, b.low) } diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js index 27b7ee93..03799407 100644 --- a/packages/temporal-polyfill/src/new/options.js +++ b/packages/temporal-polyfill/src/new/options.js @@ -5,7 +5,7 @@ import { parseMaybeZonedDateTime } from './isoParse' import { bigIntToLargeInt } from './largeInt' import { PlainDate } from './plainDate' import { PlainDateTime } from './plainDateTime' -import { dayIndex, minuteIndex, nanoIndex, unitIndexToNano, unitIndexes, yearIndex } from './units' +import { dayIndex, minuteIndex, nanoIndex, unitNanoMap, unitNameMap, yearIndex } from './units' import { clamp, hasAnyPropsByName, @@ -146,7 +146,7 @@ function refineTimeDisplayTuple(options) { // trace callers of this, make sure u const smallestUnitI = refineSmallestUnit(options, minuteIndex, nanoIndex, -1) if (smallestUnitI !== -1) { return [ - unitIndexToNano[smallestUnitI], + unitNanoMap[smallestUnitI], refineRoundingMode(options, truncI), (smallestUnitI < minuteIndex) ? 9 - (smallestUnitI * 3) @@ -300,10 +300,10 @@ function refineRoundingInc(options, smallestUnitI) { // smallestUnit is day/time return 1 } - const upUnitNano = unitIndexToNano[smallestUnitI + 1] + const upUnitNano = unitNanoMap[smallestUnitI + 1] if (upUnitNano) { - const unitNano = unitIndexToNano[smallestUnitI] + const unitNano = unitNanoMap[smallestUnitI] const maxRoundingInc = upUnitNano / unitNano roundingInc = clamp(roundingInc, 1, maxRoundingInc - 1, roundingIncName) @@ -369,7 +369,7 @@ function refineUnitOption(optionName, options, maxUnitI, minUnitI = nanoIndex, d } unitName = toString(unitName) - const unitIndex = unitIndexes[unitName] ?? durationFieldIndexes[unitName] + const unitIndex = unitNameMap[unitName] ?? durationFieldIndexes[unitName] if (unitIndex === undefined) { throw new RangeError('Invalid unit ' + optionName) // correct error? diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js index d4e8c18b..3f43542b 100644 --- a/packages/temporal-polyfill/src/new/round.js +++ b/packages/temporal-polyfill/src/new/round.js @@ -17,7 +17,7 @@ import { nanoInMinute, nanoInUtcDay, nanoIndex, - unitIndexToNano, + unitNanoMap, unitNamesAsc, weekIndex, } from './units' @@ -179,7 +179,7 @@ export function roundRelativeDuration( // ------------------------------------------------------------------------------------------------- export function computeNanoInc(smallestUnitI, roundingInc) { - return unitIndexToNano[smallestUnitI] * roundingInc + return unitNanoMap[smallestUnitI] * roundingInc } export function roundByInc(num, inc, roundingMode) { @@ -207,7 +207,7 @@ export function totalDayTimeDuration( // assumes iso-length days totalUnitIndex, ) { const largeNano = durationFieldsToNano(durationFields) - const divisor = unitIndexToNano[totalUnitIndex] + const divisor = unitNanoMap[totalUnitIndex] const [fullUnits, remainder] = largeNano.divTruncMod(divisor) return fullUnits.toNumber() + (remainder / divisor) } diff --git a/packages/temporal-polyfill/src/new/units.js b/packages/temporal-polyfill/src/new/units.js deleted file mode 100644 index 8b1a343e..00000000 --- a/packages/temporal-polyfill/src/new/units.js +++ /dev/null @@ -1,96 +0,0 @@ -import { LargeInt, numberToLargeInt } from './largeInt' -import { mapPropNamesToIndex } from './utils' - -export const nanoIndex = 0 -export const microIndex = 1 -export const milliIndex = 2 -export const secondsIndex = 3 // secondIndex -export const minuteIndex = 4 -export const hourIndex = 5 -export const dayIndex = 6 -export const weekIndex = 7 -export const monthIndex = 8 -export const yearIndex = 9 - -export const unitNamesAsc = [ - 'nanosecond', - 'microsecond', - 'millisecond', - 'second', - 'minute', - 'hour', - 'day', - 'week', - 'month', - 'year', -] - -export const unitIndexes = mapPropNamesToIndex(unitNamesAsc) - -// Nanoseconds -// ------------------------------------------------------------------------------------------------- - -export const secInDay = 86400 -export const milliInDay = 86400000 // TODO: not DRY -export const milliInSec = 1000 - -export const nanoInMicro = 1000 // consolidate with other 1000 units -export const nanoInMilli = 1_000_000 -export const nanoInSec = 1_000_000_000 -export const nanoInMinute = 60_000_000_000 -export const nanoInHour = 3_600_000_000_000 -export const nanoInUtcDay = 86_400_000_000_000 - -export const unitIndexToNano = [ - 1, // nano-in-nano - nanoInMicro, - nanoInMilli, - nanoInSec, - nanoInMinute, - nanoInHour, - nanoInUtcDay, -] - -// Utils -// ------------------------------------------------------------------------------------------------- - -export function givenFieldsToLargeNano(fields, unitIndex, fieldNames) { - let largeNano = new LargeInt(0, 0) - - for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = unitIndexToNano[unitIndex] - const fieldValue = fields[fieldNames[unitIndex]] - - if (fieldValue) { - largeNano = largeNano.addLargeInt(numberToLargeInt(fieldValue).mult(divisor)) - } - } - - return largeNano -} - -export function givenFieldsToNano(fields, unitIndex, fieldNames) { - let nano = 0 - - for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = unitIndexToNano[unitIndex] - const fieldValue = fields[fieldNames[unitIndex]] - - nano += fieldValue * divisor - } - - return nano -} - -export function nanoToGivenFields(nano, unitIndex, fieldNames) { - const fields = {} - - for (; unitIndex >= nanoIndex; unitIndex--) { - const divisor = unitIndexToNano[unitIndex] - - fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) - nano %= divisor - } - - return fields -} diff --git a/packages/temporal-polyfill/src/new/units.ts b/packages/temporal-polyfill/src/new/units.ts new file mode 100644 index 00000000..1e91071e --- /dev/null +++ b/packages/temporal-polyfill/src/new/units.ts @@ -0,0 +1,122 @@ +import { LargeInt, numberToLargeInt } from './largeInt' + +/* +TODO: use short names? +*/ +export enum Unit { + Nanosecond, + Microsecond, + Millisecond, + Second, + Minute, + Hour, + Day, + Week, + Month, + Year, +} + +export const unitNameMap = { + nanosecond: Unit.Nanosecond, + microsecond: Unit.Microsecond, + millisecond: Unit.Millisecond, + second: Unit.Second, + minute: Unit.Minute, + hour: Unit.Hour, + day: Unit.Day, + week: Unit.Week, + month: Unit.Month, + year: Unit.Year, +} + +type TimeUnit = + Unit.Nanosecond | + Unit.Microsecond | + Unit.Millisecond | + Unit.Second | + Unit.Minute | + Unit.Hour + +export type DayTimeUnit = Unit.Day | TimeUnit + +export const unitNamesAsc = Object.keys(unitNameMap) as (keyof typeof unitNameMap)[] + +// Nanoseconds +// ------------------------------------------------------------------------------------------------- + +export const secInDay = 86400 +export const milliInDay = 86400000 // TODO: not DRY +export const milliInSec = 1000 + +export const nanoInMicro = 1000 // consolidate with other 1000 units +export const nanoInMilli = 1_000_000 +export const nanoInSec = 1_000_000_000 +export const nanoInMinute = 60_000_000_000 +export const nanoInHour = 3_600_000_000_000 +export const nanoInUtcDay = 86_400_000_000_000 + +export const unitNanoMap = [ + 1, // nano-in-nano + nanoInMicro, + nanoInMilli, + nanoInSec, + nanoInMinute, + nanoInHour, + nanoInUtcDay, +] + +// Utils +// ------------------------------------------------------------------------------------------------- + +export function givenFieldsToLargeNano( + fields: Record, + unit: DayTimeUnit, + fieldNames: K[], +): LargeInt { + let largeNano = new LargeInt(0, 0) + + for (; unit >= Unit.Nanosecond; unit--) { + const divisor = unitNanoMap[unit] + const fieldVal = fields[fieldNames[unit]] + + if (fieldVal) { + largeNano = largeNano.addLargeInt(numberToLargeInt(fieldVal).mult(divisor)) + } + } + + return largeNano +} + +export function givenFieldsToNano( + fields: Record, + unit: DayTimeUnit, + fieldNames: K[], +): number { + let nano = 0 + + for (; unit >= Unit.Nanosecond; unit--) { + const divisor = unitNanoMap[unit] + const fieldVal = fields[fieldNames[unit]] + + nano += fieldVal * divisor + } + + return nano +} + +export function nanoToGivenFields( + nano: number, + unitIndex: DayTimeUnit, + fieldNames: (keyof F)[], +): { [Key in keyof F]: number } { + const fields = {} as { [Key in keyof F]: number } + + for (; unitIndex >= Unit.Nanosecond; unitIndex--) { + const divisor = unitNanoMap[unitIndex] + + fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) as any + nano %= divisor + } + + return fields +} diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index 56c92b56..9646a12c 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -8,8 +8,8 @@ export function mapProps( transformer: (propVal: P[keyof P], propName: keyof P, extraArg?: E) => V, props: P, extraArg?: E, -): { [PropName in keyof P]: V } { - const res = {} as { [PropName in keyof P]: V } +): { [K in keyof P]: V } { + const res = {} as { [K in keyof P]: V } for (const propName in props) { res[propName] = transformer(props[propName], propName, extraArg) @@ -50,6 +50,7 @@ export function mapPropNames( return props } +// TODO: used? export const mapPropNamesToIndex:

( propNames: (keyof P)[], ) => { From aa33e750e90e2620a26c5bbf9827329030ac6a83 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 11 Jul 2023 23:28:22 -0400 Subject: [PATCH 133/805] improved typing --- package.json | 2 +- .../src/new/calendarFields.ts | 53 +- .../src/new/durationFields.ts | 15 +- .../temporal-polyfill/src/new/isoFields.ts | 68 +- packages/temporal-polyfill/src/new/options.js | 503 ----- packages/temporal-polyfill/src/new/options.ts | 540 +++++ packages/temporal-polyfill/src/new/units.ts | 4 +- packages/temporal-polyfill/src/new/utils.ts | 169 +- pnpm-lock.yaml | 1894 +++++++++-------- 9 files changed, 1677 insertions(+), 1571 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/options.js create mode 100644 packages/temporal-polyfill/src/new/options.ts diff --git a/package.json b/package.json index c0e0afbc..9ac92918 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "rollup-plugin-dts": "^3.0.2", "rollup-plugin-esbuild": "^4.9.1", "rollup-plugin-terser": "^7.0.2", - "typescript": "^4.3.5", + "typescript": "^5.1.6", "yargs": "^17.0.1" }, "pnpm": { diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index 4b6dccdc..113f9880 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -169,13 +169,16 @@ export const allYearFieldNames = [...eraYearFieldNames, 'year'] as export const dateFieldNames = Object.keys(dateFieldRefiners) as (keyof DateFields)[] -export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) as // month/monthCode/year +// month/monthCode/year +export const yearMonthFieldNames = Object.keys(yearMonthFieldRefiners) as (keyof YearMonthFields)[] -export const monthDayFieldNames = dateFieldNames.slice(0, 3) as // day/month/monthCode +// day/month/monthCode +export const monthDayFieldNames = dateFieldNames.slice(0, 3) as (keyof MonthDayFields)[] -export const monthFieldNames = monthDayFieldNames.slice(1) as // month/monthCode +// month/monthCode +export const monthFieldNames = monthDayFieldNames.slice(1) as (keyof MonthDayFields)[] export const dateTimeFieldNames = Object.keys(dateTimeFieldRefiners).sort() as @@ -187,7 +190,8 @@ export const timeFieldNames = Object.keys(timeFieldRefiners) as export const dateBasicNames = ['day', 'month', 'year'] as (keyof DateBasics)[] -export const yearMonthBasicNames = yearMonthFieldNames.slice(1) as // monthCode/year +// monthCode/year +export const yearMonthBasicNames = yearMonthFieldNames.slice(1) as (keyof YearMonthBasics)[] export const monthDayBasicNames = ['day', 'monthCode'] as @@ -196,57 +200,59 @@ export const monthDayBasicNames = ['day', 'monthCode'] as export const yearStatNames = Object.keys(yearStatRefiners) as (keyof YearStats)[] -export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) as // unordered +// unordered +export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) as (keyof YearMonthStats)[] -export const dateStatNames = Object.keys(dateStatRefiners) as // unordered +// unordered +export const dateStatNames = Object.keys(dateStatRefiners) as (keyof DateStats)[] -export const dateGetterNames = [ // unordered +// unordered +export const dateGetterNames = [ ...eraYearFieldNames, ...dateFieldNames, ...dateStatNames, ] -export const yearMonthGetterNames = [ // unordered +// unordered +export const yearMonthGetterNames = [ ...eraYearFieldNames, ...yearMonthFieldNames, ...yearMonthStatNames, ] -export const monthDayGetterNames = monthDayFieldNames // unordered +// unordered +export const monthDayGetterNames = monthDayFieldNames // Getters // ------------------------------------------------------------------------------------------------- -function createCalendarGetter( - propName: K, -) { +function createCalendarGetter(propName: K) { return (internals: IsoDateInternals) => { return internals.calendar[propName](internals) as ReturnType } } +type CalendarGetters = Pick & CalendarIdGetters + function createCalendarGetters( propNames: K[], -) { - const getters = mapPropNames>( - createCalendarGetter as ((propName: K) => any), - propNames, - ) as Pick & CalendarIdGetters +): CalendarGetters { + const getters = mapPropNames(createCalendarGetter, propNames) - getters.calendarId = (internals: { calendar: CalendarOps }) => { + ;(getters as any).calendarId = (internals: { calendar: CalendarOps }) => { return internals.calendar.id } - return getters + return getters as unknown as CalendarGetters } export const dateGetters = createCalendarGetters(dateGetterNames) export const yearMonthGetters = createCalendarGetters(yearMonthGetterNames) export const monthDayGetters = createCalendarGetters(monthDayGetterNames) -export const timeGetters = mapPropNames((fieldName, i) => { +export const timeGetters = mapPropNames((fieldName, i) => { return (isoTimeFields: IsoTimeFields) => { return isoTimeFields[isoTimeFieldNames[i]] } @@ -260,8 +266,11 @@ export const dateTimeGetters = { // Conversion // ------------------------------------------------------------------------------------------------- -export const timeFieldsToIso: (fields: TimeFields) => IsoTimeFields = - (remapProps as any).bind(undefined, timeFieldNames, isoTimeFieldNames) +export const timeFieldsToIso = remapProps.bind< + any, [any, any], // bound + [IsoTimeFields], // unbound + IsoTimeFields // return +>(undefined, timeFieldNames, isoTimeFieldNames) // Defaults // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts index 6f351ffb..25e1b8a3 100644 --- a/packages/temporal-polyfill/src/new/durationFields.ts +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -34,7 +34,7 @@ interface DurationTimeFields { hours: number } -type DurationFields = DurationDateFields & DurationTimeFields +export type DurationFields = DurationDateFields & DurationTimeFields interface DurationInternals extends DurationFields { sign: NumSign @@ -71,6 +71,7 @@ const durationInternalNames = [...durationFieldNames, 'sign'] as // ------------------------------------------------------------------------------------------------- export const durationFieldDefaults = mapPropNamesToConstant(durationFieldNames, 0) + export const durationTimeFieldDefaults = mapPropNamesToConstant(durationTimeFieldNames, 0) // Refiners @@ -81,7 +82,7 @@ export const durationFieldRefiners = mapPropNamesToConstant(durationFieldNames, // Getters // ------------------------------------------------------------------------------------------------- -export const durationGetters = mapPropNames((propName) => { +export const durationGetters = mapPropNames((propName: keyof DurationInternals) => { return (internals: DurationInternals) => { return internals[propName] } @@ -98,11 +99,11 @@ export function refineDurationFields( ) } -export const durationTimeFieldsToIso: ( - fields: DurationTimeFields -) => ( - IsoTimeFields -) = (remapProps as any).bind(undefined, durationTimeFieldNames, isoTimeFieldNames) +export const durationTimeFieldsToIso = remapProps.bind< + any, [any, any], // bound + [DurationTimeFields], // unbound + IsoTimeFields // return +>(undefined, durationTimeFieldNames, isoTimeFieldNames) export function durationTimeFieldsToIsoStrict(fields: DurationFields): IsoTimeFields { if (durationHasDateParts(fields)) { diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts index 7d8e5e28..440f71a1 100644 --- a/packages/temporal-polyfill/src/new/isoFields.ts +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -102,38 +102,50 @@ export const isoTimeFieldDefaults = mapPropNamesToConstant(isoTimeFieldNames, 0) // Conversion // ------------------------------------------------------------------------------------------------- -export const pluckIsoDateInternals: (internals: IsoDateInternals) => IsoDateFields = - (pluckProps as any).bind(undefined, isoDateInternalNames) - -export const pluckIsoDateTimeInternals: (internals: IsoDateTimeInternals) => IsoDateTimeInternals = - (pluckProps as any).bind(undefined, isoDateTimeInternalNames) - -export const pluckIsoDateTimeFields: (fields: IsoDateTimeFields) => IsoDateTimeFields = - (pluckProps as any).bind(undefined, isoDateTimeFieldNamesAsc) - -export const pluckIsoTimeFields: (fields: IsoTimeFields) => IsoTimeFields = - (pluckProps as any).bind(undefined, isoTimeFieldNames) - -function generatePublicIsoFields( - pluckFunc: (internals: I) => I, - internals: I, -): I & { calendar: CalendarIdOrObj } { - const publicFields = pluckFunc(internals) as (I & { calendar: CalendarIdOrObj }) +export const pluckIsoDateInternals = pluckProps.bind< + any, [any], // bound + [IsoDateInternals], // unbound + IsoDateInternals // return +>(undefined, isoDateInternalNames) // bound + +export const pluckIsoDateTimeInternals = pluckProps.bind< + any, [any], // bound + [IsoDateTimeInternals], // unbound + IsoDateTimeInternals // return +>(undefined, isoDateTimeInternalNames) + +export const pluckIsoDateTimeFields = pluckProps.bind< + any, [any], // bound + [IsoDateTimeFields], // unbound + IsoDateTimeFields // return +>(undefined, isoDateTimeFieldNamesAsc) + +export const pluckIsoTimeFields = pluckProps.bind< + any, [any], // bound + [IsoTimeFields], // unbound + IsoTimeFields // return +>(undefined, isoTimeFieldNames) + +function generatePublicIsoFields

( + pluckFunc: (internals: P) => P, + internals: P & { calendar: CalendarOps }, +): P & { calendar: CalendarIdOrObj } { + const publicFields = pluckFunc(internals) as P & { calendar: CalendarIdOrObj } publicFields.calendar = getPublicIdOrObj(internals.calendar) return publicFields } -export const generatePublicIsoDateFields: ( - isoDateFields: IsoDateFields -) => ( - IsoDateFields & { calendar: CalendarIdOrObj } -) = (generatePublicIsoFields as any).bind(undefined, pluckIsoDateInternals) - -export const generatePublicIsoDateTimeFields: ( - isoDateTimeFields: IsoDateTimeFields -) => ( - IsoDateTimeFields & { calendar: CalendarIdOrObj } -) = (generatePublicIsoFields as any).bind(undefined, pluckIsoDateTimeInternals) +export const generatePublicIsoDateFields = generatePublicIsoFields.bind< + any, [any], // bound + [IsoDateFields & { calendar: CalendarOps }], // unbound + IsoDateFields & { calendar: CalendarIdOrObj } // return +>(undefined, pluckIsoDateInternals) + +export const generatePublicIsoDateTimeFields = generatePublicIsoFields.bind< + any, [any], // bound + [IsoDateTimeFields & { calendar: CalendarOps }], // unbound + IsoDateTimeFields & { calendar: CalendarIdOrObj } // return +>(undefined, pluckIsoDateTimeInternals) /* Similar to getPublicCalendar and getPublicTimeZone diff --git a/packages/temporal-polyfill/src/new/options.js b/packages/temporal-polyfill/src/new/options.js deleted file mode 100644 index 03799407..00000000 --- a/packages/temporal-polyfill/src/new/options.js +++ /dev/null @@ -1,503 +0,0 @@ -import { getInternals } from './class' -import { durationFieldIndexes } from './durationFields' -import { pluckIsoDateInternals } from './isoFields' -import { parseMaybeZonedDateTime } from './isoParse' -import { bigIntToLargeInt } from './largeInt' -import { PlainDate } from './plainDate' -import { PlainDateTime } from './plainDateTime' -import { dayIndex, minuteIndex, nanoIndex, unitNanoMap, unitNameMap, yearIndex } from './units' -import { - clamp, - hasAnyPropsByName, - isObjectlike, - roundExpand, - roundHalfCeil, - roundHalfEven, - roundHalfFloor, - roundHalfTrunc, -} from './utils' -import { ZonedDateTime } from './zonedDateTime' - -// TODO: ensure all callers use *INDEXES* - -// Compound Options -// ------------------------------------------------------------------------------------------------- - -export function refineOverflowOptions(options) { - return refineOverflow(normalizeOptions(options)) -} - -export function refineZonedFieldOptions(options) { - options = normalizeOptions(options) - return [ - refineOverflow(options), - refineEpochDisambig(options), - refineOffsetDisambig(options), - ] -} - -export function refineEpochDisambigOptions(options) { - return refineEpochDisambig(normalizeOptions(options)) -} - -export function refineDiffOptions( - roundingModeInvert, - options, - defaultLargestUnitI, - maxUnitI = yearIndex, - minUnitI = nanoIndex, -) { - options = normalizeOptions(options) - const smallestUnitI = refineSmallestUnit(options, maxUnitI, minUnitI, minUnitI) - const largestUnitI = refineLargestUnit( - options, - maxUnitI, - Math.max(smallestUnitI, minUnitI), - Math.max(smallestUnitI, defaultLargestUnitI), - ) - - const roundingInc = refineRoundingInc(options, smallestUnitI) - - let roundingMode = refineRoundingMode(options, truncI) - if (roundingModeInvert) { - roundingMode = invertRoundingMode(roundingMode) - } - - return [largestUnitI, smallestUnitI, roundingInc, roundingMode] -} - -/* -Always related to time -*/ -export function refineRoundOptions(options, maxUnitI = dayIndex) { - options = normalizeRequiredOptions(options, smallestUnitStr) - const smallestUnitI = refineSmallestUnit(options, maxUnitI) // required - return [ - smallestUnitI, - refineRoundingInc(options, smallestUnitI), - refineRoundingMode(options, halfExpandI), - ] -} - -export function refineDurationRoundOptions(options, defaultLargestUnitI) { - options = normalizeRequiredOptions(options, smallestUnitStr) - mustHaveMatch(options, [largestUnitStr, smallestUnitStr]) // will register unwanted read? - // ^do a whitelist filter that copies instead? - return [ - ...refineDiffOptions(options, defaultLargestUnitI), // double-refined. oh well - refineRelativeTo(options), - ] -} - -export function refineTotalOptions(options) { - options = normalizeRequiredOptions(options, totalUnitStr) - return [ - refineTotalUnit(options), // required - refineRelativeTo(options), - ] -} - -export function refineRelativeToOptions(options) { - return refineRelativeTo(normalizeOptions(options)) -} - -export function refineInstantDisplayOptions(options) { - options = normalizeOptions(options) - return [ - options.timeZone, - ...refineTimeDisplayTuple(options), - ] -} - -export function refineZonedDateTimeDisplayOptions(options) { - options = normalizeOptions(options) - return [ - refineCalendarDisplay(options), - refineTimeZoneDisplay(options), - refineOffsetDisplay(options), - ...refineTimeDisplayTuple(options), - ] -} - -export function refineDateTimeDisplayOptions(options) { - options = normalizeOptions(options) - return [ - refineCalendarDisplay(options), - ...refineTimeDisplayTuple(options), - ] -} - -export function refineDateDisplayOptions(options) { - return refineCalendarDisplay(normalizeOptions(options)) -} - -export function refineTimeDisplayOptions(options) { - return refineTimeDisplayTuple(normalizeOptions(options)) -} - -/* -returns [ - nanoInc, - roundingMode, - subsecDigits, (undefined = auto-digits, -1 = hide-seconds, >=0 = #-of-digits) -] -*/ -function refineTimeDisplayTuple(options) { // trace callers of this, make sure using right - const smallestUnitI = refineSmallestUnit(options, minuteIndex, nanoIndex, -1) - if (smallestUnitI !== -1) { - return [ - unitNanoMap[smallestUnitI], - refineRoundingMode(options, truncI), - (smallestUnitI < minuteIndex) - ? 9 - (smallestUnitI * 3) - : -1, // hide seconds - ] - } - - const subsecDigits = refineSubsecDigits(options) - return [ - subsecDigits === undefined ? 1 : 10 ** (9 - subsecDigits), - refineRoundingMode(options, truncI), - subsecDigits, - ] -} - -// Single Options -// ------------------------------------------------------------------------------------------------- - -/* -TODO: leverage preserveConstEnums:false -https://www.typescriptlang.org/tsconfig#preserveConstEnums - -const enum Album { - JimmyEatWorldFutures, - TubRingZooHypothesis, - DogFashionDiscoAdultery, -} -console.log({ - JimmyEatWorldFutures: Album.JimmyEatWorldFutures, - TubRingZooHypothesis: Album.TubRingZooHypothesis, - DogFashionDiscoAdultery: Album.DogFashionDiscoAdultery, -}) -console.log(Album.JimmyEatWorldFutures) -*/ - -const smallestUnitStr = 'smallestUnit' -const largestUnitStr = 'largestUnit' -const totalUnitStr = 'unit' - -const refineSmallestUnit = refineUnitOption.bind(undefined, smallestUnitStr) -const refineLargestUnit = refineUnitOption.bind(undefined, largestUnitStr) -const refineTotalUnit = refineUnitOption.bind(undefined, totalUnitStr) - -export const constrainI = 0 -export const rejectI = 1 // must be truthy for clamp's throwOnOverflow param -export const returnUndefinedI = 2 // non-standard -const refineOverflow = refineChoiceOption.bind(undefined, 'overflow', [ - 'constrain', - 'reject', -]) - -export const compatibleI = 0 -/* export const rejectI = 1 */ -export const earlierI = 2 -export const laterI = 3 -const refineEpochDisambig = refineChoiceOption.bind(undefined, 'disambiguation', [ - 'compatible', - 'reject', - 'earlier', - 'later', -]) - -export const useI = 0 -/* export const rejectI = 1 */ -export const preferI = 2 -export const ignoreI = 3 -const refineOffsetDisambig = refineChoiceOption.bind(undefined, 'offset', [ - 'use', - 'reject', - 'prefer', - 'ignore', -]) - -export const autoI = 0 -export const neverI = 1 -export const criticalI = 2 -export const alwaysI = 3 -const refineCalendarDisplay = refineChoiceOption.bind(undefined, 'calendarName', [ - 'auto', - 'never', - 'critical', - 'always', -]) - -/* export const autoI = 0 */ -/* export const neverI = 1 */ -/* export const criticalI = 2 */ -const refineTimeZoneDisplay = refineChoiceOption.bind(undefined, 'timeZoneName', [ - 'auto', - 'never', - 'critical', -]) - -/* export const autoI = 0 */ -/* export const neverI = 1 */ -const refineOffsetDisplay = refineChoiceOption.bind(undefined, 'offset', [ - 'auto', - 'never', -]) - -export const floorI = 0 -export const halfFloorI = 1 -export const ceilI = 2 -export const halfCeilI = 3 -export const truncI = 4 -export const halfTruncI = 5 -export const expandI = 6 -export const halfExpandI = 7 -export const halfEvenI = 8 -/* -Caller should always supply default -*/ -const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', [ - // modes that get inverted (see invertRoundingMode) - 'floor', - 'halfFloor', - 'ceil', - 'halfCeil', - // other modes - 'trunc', // default for most things - 'halfTrunc', - 'expand', - 'halfExpand', // default for date/time::round() - 'halfEven', -]) - -export const roundingModeFuncs = [ - Math.floor, - roundHalfFloor, - Math.ceil, - roundHalfCeil, - Math.trunc, - roundHalfTrunc, - roundExpand, - Math.round, - roundHalfEven, -] - -function invertRoundingMode(roundingModeI) { - if (roundingModeI < 4) { - return (roundingModeI + 2) % 4 - } - return roundingModeI -} - -const roundingIncName = 'roundingIncrement' - -function refineRoundingInc(options, smallestUnitI) { // smallestUnit is day/time - let roundingInc = options[roundingIncName] - if (roundingInc === undefined) { - return 1 - } - - const upUnitNano = unitNanoMap[smallestUnitI + 1] - - if (upUnitNano) { - const unitNano = unitNanoMap[smallestUnitI] - const maxRoundingInc = upUnitNano / unitNano - roundingInc = clamp(roundingInc, 1, maxRoundingInc - 1, roundingIncName) - - if (upUnitNano % (roundingInc * unitNano)) { - throw new RangeError('Must be even multiple') - } - } else { - roundingInc = clamp(roundingInc, 1, 1, roundingIncName) - } - - return roundingInc -} - -const subsecDigitsName = 'fractionalSecondDigits' - -function refineSubsecDigits(options) { - const subsecDigits = options[subsecDigitsName] - - if (typeof subsecDigits === 'number') { - return clamp(Math.floor(subsecDigits), 0, 9, 1, subsecDigitsName) // throwOnError=1 - } - - if (String(subsecDigits) !== 'auto') { - throw new RangeError('Must be auto or 0-9') - } - - // undefind means 'auto' -} - -function refineRelativeTo(options) { - const { relativeTo } = options - - if (relativeTo) { - if (isObjectlike(relativeTo)) { - if ( - relativeTo instanceof ZonedDateTime || - relativeTo instanceof PlainDate - ) { - return getInternals(relativeTo) - } else if (relativeTo instanceof PlainDateTime) { - return pluckIsoDateInternals(getInternals(relativeTo)) - } - throw new TypeError() - } - - return parseMaybeZonedDateTime(toString(relativeTo)) - } -} - -// Utils -// ------------------------------------------------------------------------------------------------- - -/* -If defaultUnitI is undefined, will throw error if not specified -*/ -function refineUnitOption(optionName, options, maxUnitI, minUnitI = nanoIndex, defaultUnitI) { - let unitName = options[optionName] - if (unitName === undefined) { - if (defaultUnitI === undefined) { - throw new RangeError('Must specify' + optionName) // best error? - } - return defaultUnitI - } - - unitName = toString(unitName) - const unitIndex = unitNameMap[unitName] ?? durationFieldIndexes[unitName] - - if (unitIndex === undefined) { - throw new RangeError('Invalid unit ' + optionName) // correct error? - } - if (unitIndex < minUnitI || unitIndex > maxUnitI) { // TODO: use clamp? - throw new RangeError('Out of bounds' + optionName) - } - - return unitIndex -} - -// TODO: move to accepting maps -function refineChoiceOption(optionName, choices, options, defaultChoice) { - const optionValue = options[optionName] - if (optionValue === undefined) { - return defaultChoice ?? 0 - } - const index = choices.indexOf(optionValue) - if (index < 0) { - throw new RangeError('Must be one of the choices') - } - return index -} - -export function normalizeOptions(options) { - if (options === undefined) { - return {} - } - return ensureObjectlike(options) -} - -// will NOT check for atomicName in options -function normalizeRequiredOptions(options, atomicName) { - if (typeof options === 'string') { - return { [atomicName]: options } - } - return ensureObjectlike(options) -} - -function mustHaveMatch(obj, propNames) { - if (!hasAnyPropsByName(obj, propNames)) { - throw new TypeError('Need one: ' + JSON.stringify(propNames)) - } -} - -export function toEpochNano(input) { - if (typeof input !== 'bigint') { - throw new TypeError('Needs bigint') - } - return bigIntToLargeInt(input) -} - -export function clampProp(props, propName, min, max, overflowI) { - return clamp(props[propName], min, max, overflowI, propName) -} - -// Primitives -// ------------------------------------------------------------------------------------------------- - -export function ensureInstanceOf(Class, obj) { - if (!(obj instanceof Class)) { - throw new TypeError('Must be certain type') // TODO: show Class's symbol? - } - return obj -} - -function ensureType(typeName, obj) { - // eslint-disable-next-line valid-typeof - if (typeof obj !== typeName) { - throw new TypeError(`Must be certain type ${typeName}`) - } - return obj -} - -export const ensureBoolean = ensureType.bind(undefined, 'boolean') -export const ensureString = ensureType.bind(undefined, 'string') -export const ensureNumber = ensureType.bind(undefined, 'number') - -export function ensureInteger(arg) { - return ensureNumberIsInteger(ensureNumber(arg)) -} - -export function ensureArray(arg) { - if (!Array.isArray(arg)) { - throw new TypeError('Must be array') - } - return arg -} - -export function ensureObjectlike(arg) { - if (!isObjectlike(arg)) { - throw new TypeError('Must be object-like') - } - return arg -} - -export function toString(value) { - if (typeof value === 'symbol') { - throw new TypeError('Cannot convert a Symbol value to a String') - } - return String(value) -} - -export function toInteger(value) { // truncates floats - return Math.trunc(toNumber(value)) || 0 // ensure no -0 -} - -export function toIntegerStrict(value) { // throws error on floats - return ensureNumberIsInteger(toNumber(value)) -} - -function ensureNumberIsInteger(n) { - if (!Number.isInteger(n)) { - throw new RangeError('must be integer') - } - return n || 0 // ensure no -0 -} - -/* -Caller must ||0 to ensure no -0 -*/ -function toNumber(value) { - value = Number(value) - if (isNaN(value)) { - throw new RangeError('not a number') - } - if (!Number.isFinite(value)) { - throw new RangeError('must be finite') - } - return value -} diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts new file mode 100644 index 00000000..6e6f74af --- /dev/null +++ b/packages/temporal-polyfill/src/new/options.ts @@ -0,0 +1,540 @@ +import { getInternals } from './class' +import { DurationFields, durationFieldIndexes } from './durationFields' +import { pluckIsoDateInternals } from './isoFields' +import { parseMaybeZonedDateTime } from './isoParse' +import { LargeInt, bigIntToLargeInt } from './largeInt' +import { PlainDate } from './plainDate' +import { PlainDateTime } from './plainDateTime' +import { DayTimeUnit, Unit, UnitName, unitNameMap, unitNanoMap } from './units' +import { + clamp, + hasAnyPropsByName, + isObjectlike, + roundExpand, + roundHalfCeil, + roundHalfEven, + roundHalfFloor, + roundHalfTrunc, + Reused, +} from './utils' +import { ZonedDateTime } from './zonedDateTime' + +type Options = Record + +// Compound Options +// ------------------------------------------------------------------------------------------------- + +export function refineOverflowOptions(options: Options | undefined) { + return refineOverflow(normalizeOptions(options)) +} + +export function refineZonedFieldOptions(options: Options | undefined) { + options = normalizeOptions(options) + return [ + refineOverflow(options), + refineEpochDisambig(options), + refineOffsetDisambig(options), + ] +} + +export function refineEpochDisambigOptions(options: Options | undefined) { + return refineEpochDisambig(normalizeOptions(options)) +} + +export function refineDiffOptions( + roundingModeInvert: boolean, + options: Options | undefined, + defaultLargestUnit: Unit, + maxUnit = Unit.Year, + minUnit = Unit.Nanosecond, +) { + options = normalizeOptions(options) + const smallestUnit = refineSmallestUnit(options, maxUnit, minUnit, minUnit) + const largestUnit = refineLargestUnit( + options, + maxUnit, + Math.max(smallestUnit, minUnit), + Math.max(smallestUnit, defaultLargestUnit), + ) + + const roundingInc = refineRoundingInc(options, smallestUnit as DayTimeUnit) + + let roundingMode = refineRoundingMode(options, RoundingMode.Trunc) + if (roundingModeInvert) { + roundingMode = invertRoundingMode(roundingMode) + } + + return [largestUnit, smallestUnit, roundingInc, roundingMode] +} + +/* +Always related to time +*/ +export function refineRoundOptions( + options: Options | undefined | Reused, + maxUnit: DayTimeUnit = Unit.Day, +) { + options = normalizeUnitNameOptions(options, smallestUnitStr) + const smallestUnit = refineSmallestUnit(options, maxUnit) as DayTimeUnit + return [ + smallestUnit, + refineRoundingInc(options, smallestUnit), + refineRoundingMode(options, RoundingMode.HalfExpand), + ] +} + +export function refineDurationRoundOptions( + options: Options | undefined | Reused, + defaultLargestUnit: Unit +) { + options = normalizeUnitNameOptions(options, smallestUnitStr) + mustHaveMatch(options, [largestUnitStr, smallestUnitStr]) // will register unwanted read? + // ^do a whitelist filter that copies instead? + + return [ + ...refineDiffOptions(false, options, defaultLargestUnit), // double-refined. oh well + refineRelativeTo(options), + ] +} + +export function refineTotalOptions( + options: Options | undefined | Reused +) { + options = normalizeUnitNameOptions(options, totalUnitStr) + return [ + refineTotalUnit(options), // required + refineRelativeTo(options), + ] +} + +export function refineRelativeToOptions(options: Options | undefined) { + return refineRelativeTo(normalizeOptions(options)) +} + +export function refineInstantDisplayOptions( + options: Options | undefined | Reused +) { + options = normalizeOptions(options) + return [ + options.timeZone, + ...refineTimeDisplayTuple(options), + ] +} + +export function refineZonedDateTimeDisplayOptions(options: Options | undefined) { + options = normalizeOptions(options) + return [ + refineCalendarDisplay(options), + refineTimeZoneDisplay(options), + refineOffsetDisplay(options), + ...refineTimeDisplayTuple(options), + ] +} + +export function refineDateTimeDisplayOptions(options: Options | undefined) { + options = normalizeOptions(options) + return [ + refineCalendarDisplay(options), + ...refineTimeDisplayTuple(options), + ] +} + +export function refineDateDisplayOptions(options: Options | undefined): CalendarDisplay { + return refineCalendarDisplay(normalizeOptions(options)) +} + +export function refineTimeDisplayOptions(options: Options | undefined): TimeDisplayTuple { + return refineTimeDisplayTuple(normalizeOptions(options)) +} + +export type TimeDisplayTuple = [ + nanoInc: number, + roundingMode: RoundingMode, + subsecDigits: number | undefined // (undefined = auto-digits, -1 = hide-seconds, >=0 = #-of-digits) +] + +function refineTimeDisplayTuple(options: Options): TimeDisplayTuple { + const smallestUnitI = refineSmallestUnit(options, Unit.Minute, Unit.Nanosecond, -1) + if (smallestUnitI !== -1) { + return [ + unitNanoMap[smallestUnitI], + refineRoundingMode(options, RoundingMode.Trunc), + (smallestUnitI < Unit.Minute) + ? 9 - (smallestUnitI * 3) + : -1, // hide seconds + ] + } + + const subsecDigits = refineSubsecDigits(options) + return [ + subsecDigits === undefined ? 1 : 10 ** (9 - subsecDigits), + refineRoundingMode(options, RoundingMode.Trunc), + subsecDigits, + ] +} + +// Single Options +// ------------------------------------------------------------------------------------------------- + +const smallestUnitStr = 'smallestUnit' +const largestUnitStr = 'largestUnit' +const totalUnitStr = 'unit' + +const refineSmallestUnit = refineUnitOption.bind(undefined, smallestUnitStr) +const refineLargestUnit = refineUnitOption.bind(undefined, largestUnitStr) +const refineTotalUnit = refineUnitOption.bind(undefined, totalUnitStr) + +export enum Overflow { + Constrain, + Reject, +} +const refineOverflow = refineChoiceOption.bind(undefined, 'overflow', { + constrain: Overflow.Constrain, + reject: Overflow.Reject, +}) as (options: Options) => Overflow + +export enum EpochDisambig { + Compat, + Reject, + Earlier, + Later, +} +const refineEpochDisambig = refineChoiceOption.bind(undefined, 'disambiguation', { + compatible: EpochDisambig.Compat, + reject: EpochDisambig.Reject, + earlier: EpochDisambig.Earlier, + later: EpochDisambig.Later, +}) as (options: Options) => EpochDisambig + +export enum OffsetDisambig { + Use, + Reject, + Prefer, + Ignore, +} +const refineOffsetDisambig = refineChoiceOption.bind(undefined, 'offset', { + use: OffsetDisambig.Use, + reject: OffsetDisambig.Reject, + prefer: OffsetDisambig.Prefer, + ignore: OffsetDisambig.Ignore, +}) as (options: Options) => OffsetDisambig + +export enum CalendarDisplay { + Auto, + Never, + Critical, + Always, +} +const refineCalendarDisplay = refineChoiceOption.bind(undefined, 'calendarName', { + auto: CalendarDisplay.Auto, + never: CalendarDisplay.Never, + critical: CalendarDisplay.Critical, + always: CalendarDisplay.Always, +}) as (options: Options) => CalendarDisplay + +export enum TimeZoneDisplay { + Auto, + Never, + Critical, +} +const refineTimeZoneDisplay = refineChoiceOption.bind(undefined, 'timeZoneName', { + auto: TimeZoneDisplay.Auto, + never: TimeZoneDisplay.Never, + critical: TimeZoneDisplay.Critical, +}) as (options: Options) => TimeZoneDisplay + +export enum OffsetDisplay { + Auto, + Never, +} +const refineOffsetDisplay = refineChoiceOption.bind(undefined, 'offset', { + auto: OffsetDisplay.Auto, + never: OffsetDisplay.Never, +}) as (options: Options) => OffsetDisplay + +export enum RoundingMode { + // modes that get inverted (see invertRoundingMode) + Floor, + HalfFloor, + Ceil, + HalfCeil, + // other modes + Trunc, // default for most things + HalfTrunc, + Expand, + HalfExpand, // default for date/time::round() + HalfEven, +} +// Caller should always supply default +const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', { + floor: RoundingMode.Floor, + halfFloor: RoundingMode.HalfFloor, + ceil: RoundingMode.Ceil, + halfCeil: RoundingMode.HalfCeil, + trunc: RoundingMode.Trunc, + halfTrunc: RoundingMode.HalfTrunc, + expand: RoundingMode.Expand, + halfExpand: RoundingMode.HalfExpand, + halfEven: RoundingMode.HalfEven, +}) +export const roundingModeFuncs = [ + Math.floor, + roundHalfFloor, + Math.ceil, + roundHalfCeil, + Math.trunc, + roundHalfTrunc, + roundExpand, + Math.round, + roundHalfEven, +] + +function invertRoundingMode(roundingMode: RoundingMode): RoundingMode { + if (roundingMode < 4) { + return (roundingMode + 2) % 4 + } + return roundingMode +} + +const roundingIncName = 'roundingIncrement' + +function refineRoundingInc(options: Options, smallestUnit: DayTimeUnit) { + let roundingInc = options[roundingIncName] as Reused + if (roundingInc === undefined) { + return 1 + } + + roundingInc = toNumber(roundingInc) + const upUnitNano = unitNanoMap[smallestUnit + 1] + + if (upUnitNano) { + const unitNano = unitNanoMap[smallestUnit] + const maxRoundingInc = upUnitNano / unitNano + roundingInc = clamp(roundingInc, 1, maxRoundingInc - 1, Overflow.Reject, roundingIncName) + + if (upUnitNano % (roundingInc * unitNano)) { + throw new RangeError('Must be even multiple') + } + } else { + roundingInc = clamp(roundingInc, 1, 1, Overflow.Reject, roundingIncName) + } + + return roundingInc +} + +const subsecDigitsName = 'fractionalSecondDigits' + +function refineSubsecDigits(options: Options): number | undefined { + const subsecDigits = options[subsecDigitsName] + + if (typeof subsecDigits === 'number') { + return clamp(Math.floor(subsecDigits), 0, 9, Overflow.Reject, subsecDigitsName) + } + + if (String(subsecDigits) !== 'auto') { + throw new RangeError('Must be auto or 0-9') + } + + // undefind means 'auto' +} + +function refineRelativeTo(options: Options) { + const { relativeTo } = options + + if (relativeTo) { + if (isObjectlike(relativeTo)) { + if ( + relativeTo instanceof ZonedDateTime || + relativeTo instanceof PlainDate + ) { + return getInternals(relativeTo) + } else if (relativeTo instanceof PlainDateTime) { + return pluckIsoDateInternals(getInternals(relativeTo)) + } + throw new TypeError() + } + + return parseMaybeZonedDateTime(toString(relativeTo)) + } +} + +// Utils +// ------------------------------------------------------------------------------------------------- + +/* +If defaultUnit is undefined, will throw error if not specified +*/ +function refineUnitOption( + optionName: string, + options: Options, + maxUnit: Unit = Unit.Year, + minUnit: Unit = Unit.Nanosecond, + defaultUnit?: Unit | -1, +): Unit | -1 { + let unitName = options[optionName] + if (unitName === undefined) { + if (defaultUnit === undefined) { + throw new RangeError('Must specify' + optionName) // best error? + } + return defaultUnit + } + + unitName = toString(unitName) + const unit = unitNameMap[unitName as UnitName] ?? + durationFieldIndexes[unitName as (keyof DurationFields)] + + if (unit === undefined) { + throw new RangeError('Invalid unit ' + optionName) // correct error? + } + if (unit < minUnit || unit > maxUnit) { // TODO: use clamp? + throw new RangeError('Out of bounds' + optionName) + } + + return unit +} + +function refineChoiceOption( + optionName: string, + enumNameMap: Record, + options: Options, + defaultChoice = 0, +) { + const enumName = options[optionName] as Reused + if (enumName === undefined) { + return defaultChoice + } + const enumNum = enumNameMap[enumName] + if (enumNum < 0) { + throw new RangeError('Must be one of the choices') + } + return enumNum +} + +export function normalizeOptions(options: Options | undefined) { + if (options === undefined) { + return {} + } + return ensureObjectlike(options) +} + +function normalizeUnitNameOptions( + options: Options | undefined, + optionName: string, +) { + if (typeof options === 'string') { + return { [optionName]: options } + } + return ensureObjectlike(options as Options) +} + +function mustHaveMatch( + props: Options, + propNames: string[], +) { + if (!hasAnyPropsByName(props, propNames)) { + throw new TypeError('Need one: ' + JSON.stringify(propNames)) + } +} + +export function toEpochNano(arg: any): LargeInt { + if (typeof arg !== 'bigint') { + throw new TypeError('Needs bigint') + } + return bigIntToLargeInt(arg) +} + +export function clampProp( + props: Record, + propName: string, + min: number, + max: number, + overflow: Overflow, +): number { + return clamp(props[propName], min, max, overflow, propName) +} + +// Primitives +// ------------------------------------------------------------------------------------------------- + +export function ensureInstanceOf(Class: any, obj: O): O { + if (!(obj instanceof Class)) { + throw new TypeError('Must be certain type') // TODO: show Class's symbol? + } + return obj +} + +function ensureType(typeName: string, arg: A): A { + if (typeof arg !== typeName) { + throw new TypeError(`Must be certain type ${typeName}`) + } + return arg +} + +export const ensureString = ensureType.bind(undefined, 'string') as + (arg: unknown) => string + +export const ensureNumber = ensureType.bind(undefined, 'number') as + (arg: unknown) => number + +export const ensureBoolean = ensureType.bind(undefined, 'boolean') as + (arg: unknown) => boolean + +export function ensureInteger(arg: number): number { + return ensureNumberIsInteger(ensureNumber(arg)) +} + +export function ensureArray(arg: A): A { + if (!Array.isArray(arg)) { + throw new TypeError('Must be array') + } + return arg +} + +export function ensureObjectlike(arg: O): O { + if (!isObjectlike(arg)) { + throw new TypeError('Must be object-like') + } + return arg +} + +export function toString(arg: any): string { + if (typeof arg === 'symbol') { + throw new TypeError('Cannot convert a Symbol to a String') + } + return String(arg) +} + +/* +truncates floats +*/ +export function toInteger(arg: any): number { + return Math.trunc(toNumber(arg)) || 0 // ensure no -0 +} + +/* +throws error on floats +*/ +export function toIntegerStrict(arg: any): number { + return ensureNumberIsInteger(toNumber(arg)) +} + +function ensureNumberIsInteger(num: number): number { + if (!Number.isInteger(num)) { + throw new RangeError('must be integer') + } + return num || 0 // ensure no -0 +} + +/* +Caller must do ||0 to ensure no -0 +*/ +function toNumber(arg: any): number { + arg = Number(arg) + if (isNaN(arg)) { + throw new RangeError('not a number') + } + if (!Number.isFinite(arg)) { + throw new RangeError('must be finite') + } + return arg +} diff --git a/packages/temporal-polyfill/src/new/units.ts b/packages/temporal-polyfill/src/new/units.ts index 1e91071e..17764e8a 100644 --- a/packages/temporal-polyfill/src/new/units.ts +++ b/packages/temporal-polyfill/src/new/units.ts @@ -29,6 +29,8 @@ export const unitNameMap = { year: Unit.Year, } +export type UnitName = keyof typeof unitNameMap + type TimeUnit = Unit.Nanosecond | Unit.Microsecond | @@ -114,7 +116,7 @@ export function nanoToGivenFields( for (; unitIndex >= Unit.Nanosecond; unitIndex--) { const divisor = unitNanoMap[unitIndex] - fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) as any + fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) nano %= divisor } diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index 9646a12c..42ee0ae3 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -1,15 +1,19 @@ +import { Overflow } from './options' + +export type Reused = any + const objectlikeRE = /object|function/ export function isObjectlike(arg: unknown): boolean { return arg !== null && objectlikeRE.test(typeof arg) } -export function mapProps( - transformer: (propVal: P[keyof P], propName: keyof P, extraArg?: E) => V, +export function mapProps( + transformer: (propVal: P[keyof P], propName: keyof P, extraArg?: E) => R, props: P, - extraArg?: E, -): { [K in keyof P]: V } { - const res = {} as { [K in keyof P]: V } + extraArg?: E +): { [K in keyof P]: R } { + const res = {} as { [K in keyof P]: R } for (const propName in props) { res[propName] = transformer(props[propName], propName, extraArg) @@ -22,25 +26,19 @@ export type PropsRefinerMap = { [K in keyof P]: (propVal: P[K], propName: K) => V } -export const mapPropsWithRefiners: ( - props: P, - refinerMap: PropsRefinerMap -) => { - [K in keyof P]: V -} = (mapProps as any).bind(undefined, ( - propVal: P[keyof P], - propName: keyof P, - refinerMap: PropsRefinerMap, -) => { - return refinerMap[propName](propVal, propName) -}) - -export function mapPropNames( - generator: (propName: keyof P, i: number, extraArg?: E) => P[keyof P], +export const mapPropsWithRefiners = mapProps.bind( + undefined, + (propVal: any, propName: string, refinerMap: any) => refinerMap[propName](propVal, propName), +) as ( + (props: P, refinerMap: PropsRefinerMap) => { [K in keyof P]: V } +) + +export function mapPropNames( + generator: (propName: keyof P, i: number, extraArg?: E) => R, propNames: (keyof P)[], - extraArg?: E, -): P { - const props = {} as P + extraArg?: E +): { [K in keyof P]: R } { + const props = {} as { [K in keyof P]: R } for (let i = 0; i < propNames.length; i++) { const propName = propNames[i] @@ -50,46 +48,36 @@ export function mapPropNames( return props } -// TODO: used? -export const mapPropNamesToIndex:

( - propNames: (keyof P)[], -) => { - [K in keyof P]: number -} = (mapProps as any).bind(undefined,

( - propName: keyof P, - i: number, -) => i) - -export const mapPropNamesToConstant: ( - propNames: (keyof P)[], - val: V -) => { - [K in keyof P]: V -} = (mapProps as any).bind(undefined, ( - propName: keyof P, - i: number, - val: V, -) => val) - -export function remapProps( - oldPropNames: (keyof OldProps)[], - newPropNames: (keyof NewProps)[], - oldProps: OldProps, -): NewProps { - const newProps = {} as NewProps - - for (let i = 0; i < oldPropNames.length; i++) { - newProps[newPropNames[i]] = oldProps[oldPropNames[i]] as any +export const mapPropNamesToIndex = mapPropNames.bind( + undefined, + (propVal: any, i: number) => i, +) as ( +

(propNames: (keyof P)[]) => { [K in keyof P]: number } +) + +export const mapPropNamesToConstant = mapPropNames.bind( + undefined, + (propVal: any, i: number, extra: any) => extra, +) as ( + (propNames: (keyof P)[], c: C) => { [K in keyof P]: C } +) + +export function remapProps( + oldNames: (keyof O)[], + newNames: (keyof N)[], + oldProps: O +): N { + const newProps = {} as N + + for (let i = 0; i < oldNames.length; i++) { + newProps[newNames[i]] = oldProps[oldNames[i]] as any } return newProps } -export function pluckProps( - propNames: PropName[], - props: Props, -): Pick { - const res = {} as Pick +export function pluckProps

(propNames: (keyof P)[], props: P): P { + const res = {} as P for (const propName of propNames) { res[propName] = props[propName] @@ -98,25 +86,21 @@ export function pluckProps( return res } -export function excludeArrayDuplicates(a: Item[]): Item[] { +export function excludeArrayDuplicates(a: V[]): V[] { return [...new Set(a)] } -function filterProps( - filterFunc: ( - propVal: Props[keyof Props], - propName: keyof Props, - extraArg: ExtraArg - ) => boolean, - props: Props, - extraArg?: ExtraArg, -) { - const filteredProps = {} as Props +function filterProps( + filterFunc: (propVal: P[keyof P], propName: keyof P, extraArg: E) => boolean, + props: P, + extraArg?: any, +): Partial

{ + const filteredProps = {} as Partial

for (const propName in props) { const propVal = props[propName] - if (filterFunc(propVal, propName, extraArg as ExtraArg)) { + if (filterFunc(propVal, propName, extraArg)) { filteredProps[propName] = propVal } } @@ -126,20 +110,21 @@ function filterProps( export const excludePropsByName = filterProps.bind( undefined, - (propVal, propName, nameSet: any) => !nameSet.has(propName), -) as ( - props: Props, - propNames: Set, -) => Omit + (propVal: any, propName: string, nameSet: any) => !nameSet.has(propName) +) as ( + (props: P, propNames: K[]) => Pick +) export const excludeUndefinedProps = filterProps.bind( undefined, - (propVal) => propVal !== undefined, -) as (props: Props) => Partial + (propVal: any) => propVal !== undefined, +) as ( +

(props: P) => Partial

+) -export function hasAnyPropsByName( - props: Props, - names: (keyof Props)[], +export function hasAnyPropsByName

( + props: P, + names: (keyof P)[] ): boolean { for (const name of names) { if (props[name] !== undefined) { @@ -149,9 +134,9 @@ export function hasAnyPropsByName( return false } -export function hasAllPropsByName( - props: Props, - names: (keyof Props)[], +export function hasAllPropsByName

( + props: P, + names: (keyof P)[] ): boolean { for (const name of names) { if (props[name] === undefined) { @@ -253,35 +238,39 @@ export function compareProps>( return 0 } +/* +min/max are inclusive +*/ export function clamp( num: number, min: number, max: number, + overflow?: Overflow.Constrain, ): number export function clamp( num: number, min: number, max: number, - overflowBehavior: 1, + overflow: Overflow | Overflow.Reject, noun: string, ): number export function clamp( num: number, min: number, max: number, - overflowBehavior: 2, + overflow: -1, // for returning undefined ): number | undefined export function clamp( num: number, - min: number, // inclusive - max: number, // inclusive - overflowBehavior: (0 | 1 | 2) = 0, // TODO: better enum - 0/1/2 --- overflow enum + min: number, + max: number, + overflow?: Overflow | -1, noun?: string, ): number | undefined { const clamped = Math.min(Math.max(num, min), max) - if (overflowBehavior && num !== clamped) { - if (overflowBehavior === 2) { + if (overflow && num !== clamped) { + if (overflow === -1) { return undefined } throw new RangeError(`${noun!} must be between ${min}-${max}`) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 595f4f94..a1979f85 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,8 @@ -lockfileVersion: 5.4 +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false patchedDependencies: '@js-temporal/temporal-test262-runner@0.9.0': @@ -8,142 +12,187 @@ patchedDependencies: importers: .: - specifiers: - '@babel/core': ^7.14.6 - '@babel/preset-env': ^7.14.5 - '@babel/preset-typescript': ^7.15.0 - '@rollup/plugin-node-resolve': ^13.3.0 - '@types/jest': ^26.0.23 - '@typescript-eslint/eslint-plugin': ^4.22.1 - '@typescript-eslint/parser': ^4.22.1 - colors: ^1.4.0 - deepmerge: ^4.2.2 - esbuild: ^0.14.38 - eslint: ^7.25.0 - eslint-config-standard: ^16.0.3 - eslint-import-resolver-node: ^0.3.6 - eslint-plugin-import: ^2.24.2 - eslint-plugin-node: ^11.1.0 - eslint-plugin-promise: ^5.1.0 - jest: ^27.0.4 - minimatch: ^5.0.1 - rollup: ^2.55.1 - rollup-plugin-dts: ^3.0.2 - rollup-plugin-esbuild: ^4.9.1 - rollup-plugin-terser: ^7.0.2 - typescript: ^4.3.5 - yargs: ^17.0.1 devDependencies: - '@babel/core': 7.21.0 - '@babel/preset-env': 7.20.2_@babel+core@7.21.0 - '@babel/preset-typescript': 7.21.0_@babel+core@7.21.0 - '@rollup/plugin-node-resolve': 13.3.0_rollup@2.79.1 - '@types/jest': 26.0.24 - '@typescript-eslint/eslint-plugin': 4.33.0_s2qqtxhzmb7vugvfoyripfgp7i - '@typescript-eslint/parser': 4.33.0_jofidmxrjzhj7l6vknpw5ecvfe - colors: 1.4.0 - deepmerge: 4.3.0 - esbuild: 0.14.54 - eslint: 7.32.0 - eslint-config-standard: 16.0.3_s3p4dyzitdtgac5nictnavtxa4 - eslint-import-resolver-node: 0.3.7 - eslint-plugin-import: 2.27.5_ffi3uiz42rv3jyhs6cr7p7qqry - eslint-plugin-node: 11.1.0_eslint@7.32.0 - eslint-plugin-promise: 5.2.0_eslint@7.32.0 - jest: 27.5.1 - minimatch: 5.1.6 - rollup: 2.79.1 - rollup-plugin-dts: 3.0.2_zptcx3kz3uwp66hzhyyt545weq - rollup-plugin-esbuild: 4.10.3_gkkadhp4kuvg7lmep2ttfihjii - rollup-plugin-terser: 7.0.2_rollup@2.79.1 - typescript: 4.9.5 - yargs: 17.7.1 + '@babel/core': + specifier: ^7.14.6 + version: 7.21.0 + '@babel/preset-env': + specifier: ^7.14.5 + version: 7.20.2(@babel/core@7.21.0) + '@babel/preset-typescript': + specifier: ^7.15.0 + version: 7.21.0(@babel/core@7.21.0) + '@rollup/plugin-node-resolve': + specifier: ^13.3.0 + version: 13.3.0(rollup@2.79.1) + '@types/jest': + specifier: ^26.0.23 + version: 26.0.24 + '@typescript-eslint/eslint-plugin': + specifier: ^4.22.1 + version: 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6) + '@typescript-eslint/parser': + specifier: ^4.22.1 + version: 4.33.0(eslint@7.32.0)(typescript@5.1.6) + colors: + specifier: ^1.4.0 + version: 1.4.0 + deepmerge: + specifier: ^4.2.2 + version: 4.3.0 + esbuild: + specifier: ^0.14.38 + version: 0.14.54 + eslint: + specifier: ^7.25.0 + version: 7.32.0 + eslint-config-standard: + specifier: ^16.0.3 + version: 16.0.3(eslint-plugin-import@2.27.5)(eslint-plugin-node@11.1.0)(eslint-plugin-promise@5.2.0)(eslint@7.32.0) + eslint-import-resolver-node: + specifier: ^0.3.6 + version: 0.3.7 + eslint-plugin-import: + specifier: ^2.24.2 + version: 2.27.5(@typescript-eslint/parser@4.33.0)(eslint@7.32.0) + eslint-plugin-node: + specifier: ^11.1.0 + version: 11.1.0(eslint@7.32.0) + eslint-plugin-promise: + specifier: ^5.1.0 + version: 5.2.0(eslint@7.32.0) + jest: + specifier: ^27.0.4 + version: 27.5.1 + minimatch: + specifier: ^5.0.1 + version: 5.1.6 + rollup: + specifier: ^2.55.1 + version: 2.79.1 + rollup-plugin-dts: + specifier: ^3.0.2 + version: 3.0.2(rollup@2.79.1)(typescript@5.1.6) + rollup-plugin-esbuild: + specifier: ^4.9.1 + version: 4.10.3(esbuild@0.14.54)(rollup@2.79.1) + rollup-plugin-terser: + specifier: ^7.0.2 + version: 7.0.2(rollup@2.79.1) + typescript: + specifier: ^5.1.6 + version: 5.1.6 + yargs: + specifier: ^17.0.1 + version: 17.7.1 packages/datetimeformat-tokens: - specifiers: - '@types/jest': ^26.0.23 - jest: ^27.0.4 - temporal-polyfill: workspace:* - temporal-spec: workspace:* dependencies: - temporal-spec: link:../temporal-spec + temporal-spec: + specifier: workspace:* + version: link:../temporal-spec devDependencies: - '@types/jest': 26.0.24 - jest: 27.5.1 - temporal-polyfill: link:../temporal-polyfill + '@types/jest': + specifier: ^26.0.23 + version: 26.0.24 + jest: + specifier: ^27.0.4 + version: 27.5.1 + temporal-polyfill: + specifier: workspace:* + version: link:../temporal-polyfill packages/durationformat-polyfill: - specifiers: - '@types/jest': ^26.0.23 - jest: ^27.0.4 - temporal-polyfill: workspace:* - temporal-spec: workspace:* dependencies: - temporal-spec: link:../temporal-spec + temporal-spec: + specifier: workspace:* + version: link:../temporal-spec devDependencies: - '@types/jest': 26.0.24 - jest: 27.5.1 - temporal-polyfill: link:../temporal-polyfill + '@types/jest': + specifier: ^26.0.23 + version: 26.0.24 + jest: + specifier: ^27.0.4 + version: 27.5.1 + temporal-polyfill: + specifier: workspace:* + version: link:../temporal-polyfill packages/locale-textinfo: - specifiers: - '@types/jest': ^26.0.23 - jest: ^27.0.4 devDependencies: - '@types/jest': 26.0.24 - jest: 27.5.1 + '@types/jest': + specifier: ^26.0.23 + version: 26.0.24 + jest: + specifier: ^27.0.4 + version: 27.5.1 packages/locale-weekinfo: - specifiers: - '@types/jest': ^26.0.23 - jest: ^27.0.4 devDependencies: - '@types/jest': 26.0.24 - jest: 27.5.1 + '@types/jest': + specifier: ^26.0.23 + version: 26.0.24 + jest: + specifier: ^27.0.4 + version: 27.5.1 packages/temporal-polyfill: - specifiers: - '@js-temporal/temporal-test262-runner': ^0.9.0 - '@types/chai': ^4.2.22 - '@types/jest': ^26.0.24 - '@types/node': ^16.9.1 - ansi-colors: ^4.1.3 - chai: ^4.3.4 - concurrently: ^7.6.0 - eslint: ^7.25.0 - jest: ^27.0.6 - jest-date-mock: ^1.0.8 - js-yaml: ^4.1.0 - progress: ^2.0.3 - rollup: ^2.55.1 - temporal-spec: ~0.1.0 - tiny-glob: ^0.2.9 - typescript: ^4.3.5 - dependencies: - temporal-spec: link:../temporal-spec + dependencies: + temporal-spec: + specifier: ~0.1.0 + version: link:../temporal-spec devDependencies: - '@js-temporal/temporal-test262-runner': 0.9.0 - '@types/chai': 4.3.4 - '@types/jest': 26.0.24 - '@types/node': 16.18.14 - ansi-colors: 4.1.3 - chai: 4.3.7 - concurrently: 7.6.0 - eslint: 7.32.0 - jest: 27.5.1 - jest-date-mock: 1.0.8 - js-yaml: 4.1.0 - progress: 2.0.3 - rollup: 2.79.1 - tiny-glob: 0.2.9 - typescript: 4.9.5 + '@js-temporal/temporal-test262-runner': + specifier: ^0.9.0 + version: 0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza) + '@types/chai': + specifier: ^4.2.22 + version: 4.3.4 + '@types/jest': + specifier: ^26.0.24 + version: 26.0.24 + '@types/node': + specifier: ^16.9.1 + version: 16.18.14 + ansi-colors: + specifier: ^4.1.3 + version: 4.1.3 + chai: + specifier: ^4.3.4 + version: 4.3.7 + concurrently: + specifier: ^7.6.0 + version: 7.6.0 + eslint: + specifier: ^7.25.0 + version: 7.32.0 + jest: + specifier: ^27.0.6 + version: 27.5.1 + jest-date-mock: + specifier: ^1.0.8 + version: 1.0.8 + js-yaml: + specifier: ^4.1.0 + version: 4.1.0 + progress: + specifier: ^2.0.3 + version: 2.0.3 + rollup: + specifier: ^2.55.1 + version: 2.79.1 + tiny-glob: + specifier: ^0.2.9 + version: 0.2.9 + typescript: + specifier: ^4.3.5 + version: 4.9.5 - packages/temporal-spec: - specifiers: {} + packages/temporal-spec: {} packages: - /@ampproject/remapping/2.2.0: + /@ampproject/remapping@2.2.0: resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} dependencies: @@ -151,32 +200,32 @@ packages: '@jridgewell/trace-mapping': 0.3.17 dev: true - /@babel/code-frame/7.12.11: + /@babel/code-frame@7.12.11: resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} dependencies: '@babel/highlight': 7.18.6 dev: true - /@babel/code-frame/7.18.6: + /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data/7.21.0: + /@babel/compat-data@7.21.0: resolution: {integrity: sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.21.0: + /@babel/core@7.21.0: resolution: {integrity: sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 '@babel/generator': 7.21.1 - '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.21.0 + '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) '@babel/helper-module-transforms': 7.21.2 '@babel/helpers': 7.21.0 '@babel/parser': 7.21.2 @@ -192,7 +241,7 @@ packages: - supports-color dev: true - /@babel/generator/7.21.1: + /@babel/generator@7.21.1: resolution: {integrity: sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==} engines: {node: '>=6.9.0'} dependencies: @@ -202,14 +251,14 @@ packages: jsesc: 2.5.2 dev: true - /@babel/helper-annotate-as-pure/7.18.6: + /@babel/helper-annotate-as-pure@7.18.6: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-builder-binary-assignment-operator-visitor/7.18.9: + /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==} engines: {node: '>=6.9.0'} dependencies: @@ -217,7 +266,7 @@ packages: '@babel/types': 7.21.2 dev: true - /@babel/helper-compilation-targets/7.20.7_@babel+core@7.21.0: + /@babel/helper-compilation-targets@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -231,7 +280,7 @@ packages: semver: 6.3.0 dev: true - /@babel/helper-create-class-features-plugin/7.21.0_@babel+core@7.21.0: + /@babel/helper-create-class-features-plugin@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -250,7 +299,7 @@ packages: - supports-color dev: true - /@babel/helper-create-regexp-features-plugin/7.21.0_@babel+core@7.21.0: + /@babel/helper-create-regexp-features-plugin@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg==} engines: {node: '>=6.9.0'} peerDependencies: @@ -261,13 +310,13 @@ packages: regexpu-core: 5.3.1 dev: true - /@babel/helper-define-polyfill-provider/0.3.3_@babel+core@7.21.0: + /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.21.0): resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} peerDependencies: '@babel/core': ^7.4.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.21.0 + '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 debug: 4.3.4 lodash.debounce: 4.0.8 @@ -277,19 +326,19 @@ packages: - supports-color dev: true - /@babel/helper-environment-visitor/7.18.9: + /@babel/helper-environment-visitor@7.18.9: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-explode-assignable-expression/7.18.6: + /@babel/helper-explode-assignable-expression@7.18.6: resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-function-name/7.21.0: + /@babel/helper-function-name@7.21.0: resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} engines: {node: '>=6.9.0'} dependencies: @@ -297,28 +346,28 @@ packages: '@babel/types': 7.21.2 dev: true - /@babel/helper-hoist-variables/7.18.6: + /@babel/helper-hoist-variables@7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-member-expression-to-functions/7.21.0: + /@babel/helper-member-expression-to-functions@7.21.0: resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-module-imports/7.18.6: + /@babel/helper-module-imports@7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-module-transforms/7.21.2: + /@babel/helper-module-transforms@7.21.2: resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} engines: {node: '>=6.9.0'} dependencies: @@ -334,19 +383,19 @@ packages: - supports-color dev: true - /@babel/helper-optimise-call-expression/7.18.6: + /@babel/helper-optimise-call-expression@7.18.6: resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-plugin-utils/7.20.2: + /@babel/helper-plugin-utils@7.20.2: resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-remap-async-to-generator/7.18.9_@babel+core@7.21.0: + /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.21.0): resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -361,7 +410,7 @@ packages: - supports-color dev: true - /@babel/helper-replace-supers/7.20.7: + /@babel/helper-replace-supers@7.20.7: resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} engines: {node: '>=6.9.0'} dependencies: @@ -375,43 +424,43 @@ packages: - supports-color dev: true - /@babel/helper-simple-access/7.20.2: + /@babel/helper-simple-access@7.20.2: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-skip-transparent-expression-wrappers/7.20.0: + /@babel/helper-skip-transparent-expression-wrappers@7.20.0: resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-split-export-declaration/7.18.6: + /@babel/helper-split-export-declaration@7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.21.2 dev: true - /@babel/helper-string-parser/7.19.4: + /@babel/helper-string-parser@7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-identifier/7.19.1: + /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-option/7.21.0: + /@babel/helper-validator-option@7.21.0: resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-wrap-function/7.20.5: + /@babel/helper-wrap-function@7.20.5: resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==} engines: {node: '>=6.9.0'} dependencies: @@ -423,7 +472,7 @@ packages: - supports-color dev: true - /@babel/helpers/7.21.0: + /@babel/helpers@7.21.0: resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==} engines: {node: '>=6.9.0'} dependencies: @@ -434,7 +483,7 @@ packages: - supports-color dev: true - /@babel/highlight/7.18.6: + /@babel/highlight@7.18.6: resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} engines: {node: '>=6.9.0'} dependencies: @@ -443,7 +492,7 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.21.2: + /@babel/parser@7.21.2: resolution: {integrity: sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -451,7 +500,7 @@ packages: '@babel/types': 7.21.2 dev: true - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.18.6_@babel+core@7.21.0: + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -461,7 +510,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/7.20.7_@babel+core@7.21.0: + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -470,10 +519,10 @@ packages: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-proposal-optional-chaining': 7.21.0_@babel+core@7.21.0 + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-async-generator-functions/7.20.7_@babel+core@7.21.0: + /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -482,40 +531,40 @@ packages: '@babel/core': 7.21.0 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-remap-async-to-generator': 7.18.9_@babel+core@7.21.0 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.21.0 + '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.0) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-proposal-class-properties/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-proposal-class-static-block/7.21.0_@babel+core@7.21.0: + /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-class-static-block': 7.14.5_@babel+core@7.21.0 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.21.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-proposal-dynamic-import/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -523,10 +572,10 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.21.0 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-export-namespace-from/7.18.9_@babel+core@7.21.0: + /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.21.0): resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -534,10 +583,10 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-export-namespace-from': 7.8.3_@babel+core@7.21.0 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-json-strings/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -545,10 +594,10 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.21.0 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-logical-assignment-operators/7.20.7_@babel+core@7.21.0: + /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} engines: {node: '>=6.9.0'} peerDependencies: @@ -556,10 +605,10 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.21.0 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-nullish-coalescing-operator/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -567,10 +616,10 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.21.0 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-numeric-separator/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} engines: {node: '>=6.9.0'} peerDependencies: @@ -578,10 +627,10 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.21.0 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-object-rest-spread/7.20.7_@babel+core@7.21.0: + /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} engines: {node: '>=6.9.0'} peerDependencies: @@ -589,13 +638,13 @@ packages: dependencies: '@babel/compat-data': 7.21.0 '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.21.0 + '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-transform-parameters': 7.20.7_@babel+core@7.21.0 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-transform-parameters': 7.20.7(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-optional-catch-binding/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -603,10 +652,10 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.21.0 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-optional-chaining/7.21.0_@babel+core@7.21.0: + /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -615,23 +664,23 @@ packages: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.21.0 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.0) dev: true - /@babel/plugin-proposal-private-methods/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-proposal-private-property-in-object/7.21.0_@babel+core@7.21.0: + /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -639,25 +688,25 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-private-property-in-object': 7.14.5_@babel+core@7.21.0 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-proposal-unicode-property-regex/7.18.6_@babel+core@7.21.0: + /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} engines: {node: '>=4'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.21.0: + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.21.0): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -666,7 +715,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -675,7 +724,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.21.0: + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.21.0): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -684,7 +733,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-class-static-block/7.14.5_@babel+core@7.21.0: + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.21.0): resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -694,7 +743,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-dynamic-import/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -703,7 +752,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-export-namespace-from/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -712,7 +761,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-import-assertions/7.20.0_@babel+core@7.21.0: + /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.21.0): resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -722,7 +771,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.21.0: + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.21.0): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -731,7 +780,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -740,7 +789,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.21.0: + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.21.0): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -749,7 +798,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -758,7 +807,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.21.0: + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.21.0): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -767,7 +816,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -776,7 +825,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -785,7 +834,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.21.0: + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.21.0): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 @@ -794,7 +843,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-private-property-in-object/7.14.5_@babel+core@7.21.0: + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.21.0): resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: @@ -804,7 +853,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.21.0: + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.21.0): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -814,7 +863,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-typescript/7.20.0_@babel+core@7.21.0: + /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.21.0): resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -824,7 +873,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-arrow-functions/7.20.7_@babel+core@7.21.0: + /@babel/plugin-transform-arrow-functions@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -834,7 +883,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-async-to-generator/7.20.7_@babel+core@7.21.0: + /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} engines: {node: '>=6.9.0'} peerDependencies: @@ -843,12 +892,12 @@ packages: '@babel/core': 7.21.0 '@babel/helper-module-imports': 7.18.6 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-remap-async-to-generator': 7.18.9_@babel+core@7.21.0 + '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-block-scoped-functions/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -858,7 +907,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-block-scoping/7.21.0_@babel+core@7.21.0: + /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -868,7 +917,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-classes/7.21.0_@babel+core@7.21.0: + /@babel/plugin-transform-classes@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -876,7 +925,7 @@ packages: dependencies: '@babel/core': 7.21.0 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.21.0 + '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.21.0 '@babel/helper-optimise-call-expression': 7.18.6 @@ -888,7 +937,7 @@ packages: - supports-color dev: true - /@babel/plugin-transform-computed-properties/7.20.7_@babel+core@7.21.0: + /@babel/plugin-transform-computed-properties@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -899,7 +948,7 @@ packages: '@babel/template': 7.20.7 dev: true - /@babel/plugin-transform-destructuring/7.20.7_@babel+core@7.21.0: + /@babel/plugin-transform-destructuring@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -909,18 +958,18 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-dotall-regex/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-duplicate-keys/7.18.9_@babel+core@7.21.0: + /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.21.0): resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -930,7 +979,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-exponentiation-operator/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -941,7 +990,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-for-of/7.21.0_@babel+core@7.21.0: + /@babel/plugin-transform-for-of@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -951,19 +1000,19 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-function-name/7.18.9_@babel+core@7.21.0: + /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.21.0): resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.21.0 + '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) '@babel/helper-function-name': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-literals/7.18.9_@babel+core@7.21.0: + /@babel/plugin-transform-literals@7.18.9(@babel/core@7.21.0): resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} engines: {node: '>=6.9.0'} peerDependencies: @@ -973,7 +1022,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-member-expression-literals/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -983,7 +1032,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-modules-amd/7.20.11_@babel+core@7.21.0: + /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.21.0): resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} engines: {node: '>=6.9.0'} peerDependencies: @@ -996,7 +1045,7 @@ packages: - supports-color dev: true - /@babel/plugin-transform-modules-commonjs/7.21.2_@babel+core@7.21.0: + /@babel/plugin-transform-modules-commonjs@7.21.2(@babel/core@7.21.0): resolution: {integrity: sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1010,7 +1059,7 @@ packages: - supports-color dev: true - /@babel/plugin-transform-modules-systemjs/7.20.11_@babel+core@7.21.0: + /@babel/plugin-transform-modules-systemjs@7.20.11(@babel/core@7.21.0): resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1025,7 +1074,7 @@ packages: - supports-color dev: true - /@babel/plugin-transform-modules-umd/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1038,18 +1087,18 @@ packages: - supports-color dev: true - /@babel/plugin-transform-named-capturing-groups-regex/7.20.5_@babel+core@7.21.0: + /@babel/plugin-transform-named-capturing-groups-regex@7.20.5(@babel/core@7.21.0): resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-new-target/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1059,7 +1108,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-object-super/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1072,7 +1121,7 @@ packages: - supports-color dev: true - /@babel/plugin-transform-parameters/7.20.7_@babel+core@7.21.0: + /@babel/plugin-transform-parameters@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1082,7 +1131,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-property-literals/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1092,7 +1141,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-regenerator/7.20.5_@babel+core@7.21.0: + /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.21.0): resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1103,7 +1152,7 @@ packages: regenerator-transform: 0.15.1 dev: true - /@babel/plugin-transform-reserved-words/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1113,7 +1162,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-shorthand-properties/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1123,7 +1172,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-spread/7.20.7_@babel+core@7.21.0: + /@babel/plugin-transform-spread@7.20.7(@babel/core@7.21.0): resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1134,7 +1183,7 @@ packages: '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 dev: true - /@babel/plugin-transform-sticky-regex/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1144,7 +1193,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-template-literals/7.18.9_@babel+core@7.21.0: + /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.21.0): resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1154,7 +1203,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-typeof-symbol/7.18.9_@babel+core@7.21.0: + /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.21.0): resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1164,21 +1213,21 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-typescript/7.21.0_@babel+core@7.21.0: + /@babel/plugin-transform-typescript@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-xo///XTPp3mDzTtrqXoBlK9eiAYW3wv9JXglcn/u1bi60RW11dEUxIgA8cbnDhutS1zacjMRmAwxE0gMklLnZg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.21.0 + '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.21.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-unicode-escapes/7.18.10_@babel+core@7.21.0: + /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.21.0): resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1188,18 +1237,18 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-unicode-regex/7.18.6_@babel+core@7.21.0: + /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.21.0): resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0_@babel+core@7.21.0 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/preset-env/7.20.2_@babel+core@7.21.0: + /@babel/preset-env@7.20.2(@babel/core@7.21.0): resolution: {integrity: sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1207,98 +1256,98 @@ packages: dependencies: '@babel/compat-data': 7.21.0 '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.21.0 + '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-proposal-async-generator-functions': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-proposal-class-properties': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-proposal-class-static-block': 7.21.0_@babel+core@7.21.0 - '@babel/plugin-proposal-dynamic-import': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-proposal-export-namespace-from': 7.18.9_@babel+core@7.21.0 - '@babel/plugin-proposal-json-strings': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-proposal-logical-assignment-operators': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-proposal-numeric-separator': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-proposal-object-rest-spread': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-proposal-optional-catch-binding': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-proposal-optional-chaining': 7.21.0_@babel+core@7.21.0 - '@babel/plugin-proposal-private-methods': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-proposal-private-property-in-object': 7.21.0_@babel+core@7.21.0 - '@babel/plugin-proposal-unicode-property-regex': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.21.0 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.21.0 - '@babel/plugin-syntax-class-static-block': 7.14.5_@babel+core@7.21.0 - '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-export-namespace-from': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-import-assertions': 7.20.0_@babel+core@7.21.0 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.21.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.21.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-private-property-in-object': 7.14.5_@babel+core@7.21.0 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.21.0 - '@babel/plugin-transform-arrow-functions': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-transform-async-to-generator': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-transform-block-scoped-functions': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-block-scoping': 7.21.0_@babel+core@7.21.0 - '@babel/plugin-transform-classes': 7.21.0_@babel+core@7.21.0 - '@babel/plugin-transform-computed-properties': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-transform-destructuring': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-transform-dotall-regex': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-duplicate-keys': 7.18.9_@babel+core@7.21.0 - '@babel/plugin-transform-exponentiation-operator': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-for-of': 7.21.0_@babel+core@7.21.0 - '@babel/plugin-transform-function-name': 7.18.9_@babel+core@7.21.0 - '@babel/plugin-transform-literals': 7.18.9_@babel+core@7.21.0 - '@babel/plugin-transform-member-expression-literals': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-modules-amd': 7.20.11_@babel+core@7.21.0 - '@babel/plugin-transform-modules-commonjs': 7.21.2_@babel+core@7.21.0 - '@babel/plugin-transform-modules-systemjs': 7.20.11_@babel+core@7.21.0 - '@babel/plugin-transform-modules-umd': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5_@babel+core@7.21.0 - '@babel/plugin-transform-new-target': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-object-super': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-parameters': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-transform-property-literals': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-regenerator': 7.20.5_@babel+core@7.21.0 - '@babel/plugin-transform-reserved-words': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-shorthand-properties': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-spread': 7.20.7_@babel+core@7.21.0 - '@babel/plugin-transform-sticky-regex': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-template-literals': 7.18.9_@babel+core@7.21.0 - '@babel/plugin-transform-typeof-symbol': 7.18.9_@babel+core@7.21.0 - '@babel/plugin-transform-unicode-escapes': 7.18.10_@babel+core@7.21.0 - '@babel/plugin-transform-unicode-regex': 7.18.6_@babel+core@7.21.0 - '@babel/preset-modules': 0.1.5_@babel+core@7.21.0 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-proposal-class-static-block': 7.21.0(@babel/core@7.21.0) + '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.21.0) + '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.0) + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0(@babel/core@7.21.0) + '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.21.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.21.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.21.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.21.0) + '@babel/plugin-transform-arrow-functions': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-block-scoping': 7.21.0(@babel/core@7.21.0) + '@babel/plugin-transform-classes': 7.21.0(@babel/core@7.21.0) + '@babel/plugin-transform-computed-properties': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-transform-destructuring': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.21.0) + '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-for-of': 7.21.0(@babel/core@7.21.0) + '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.21.0) + '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.21.0) + '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.21.0) + '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.21.0) + '@babel/plugin-transform-modules-systemjs': 7.20.11(@babel/core@7.21.0) + '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5(@babel/core@7.21.0) + '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-parameters': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-regenerator': 7.20.5(@babel/core@7.21.0) + '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.21.0) + '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.21.0) + '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.21.0) + '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.21.0) + '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.21.0) + '@babel/preset-modules': 0.1.5(@babel/core@7.21.0) '@babel/types': 7.21.2 - babel-plugin-polyfill-corejs2: 0.3.3_@babel+core@7.21.0 - babel-plugin-polyfill-corejs3: 0.6.0_@babel+core@7.21.0 - babel-plugin-polyfill-regenerator: 0.4.1_@babel+core@7.21.0 + babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.21.0) + babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.21.0) + babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.21.0) core-js-compat: 3.29.0 semver: 6.3.0 transitivePeerDependencies: - supports-color dev: true - /@babel/preset-modules/0.1.5_@babel+core@7.21.0: + /@babel/preset-modules@0.1.5(@babel/core@7.21.0): resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-proposal-unicode-property-regex': 7.18.6_@babel+core@7.21.0 - '@babel/plugin-transform-dotall-regex': 7.18.6_@babel+core@7.21.0 + '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.0) + '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.0) '@babel/types': 7.21.2 esutils: 2.0.3 dev: true - /@babel/preset-typescript/7.21.0_@babel+core@7.21.0: + /@babel/preset-typescript@7.21.0(@babel/core@7.21.0): resolution: {integrity: sha512-myc9mpoVA5m1rF8K8DgLEatOYFDpwC+RkMkjZ0Du6uI62YvDe8uxIEYVs/VCdSJ097nlALiU/yBC7//3nI+hNg==} engines: {node: '>=6.9.0'} peerDependencies: @@ -1307,23 +1356,23 @@ packages: '@babel/core': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-transform-typescript': 7.21.0_@babel+core@7.21.0 + '@babel/plugin-transform-typescript': 7.21.0(@babel/core@7.21.0) transitivePeerDependencies: - supports-color dev: true - /@babel/regjsgen/0.8.0: + /@babel/regjsgen@0.8.0: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} dev: true - /@babel/runtime/7.21.0: + /@babel/runtime@7.21.0: resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 dev: true - /@babel/template/7.20.7: + /@babel/template@7.20.7: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} dependencies: @@ -1332,7 +1381,7 @@ packages: '@babel/types': 7.21.2 dev: true - /@babel/traverse/7.21.2: + /@babel/traverse@7.21.2: resolution: {integrity: sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==} engines: {node: '>=6.9.0'} dependencies: @@ -1350,7 +1399,7 @@ packages: - supports-color dev: true - /@babel/types/7.21.2: + /@babel/types@7.21.2: resolution: {integrity: sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==} engines: {node: '>=6.9.0'} dependencies: @@ -1359,11 +1408,11 @@ packages: to-fast-properties: 2.0.0 dev: true - /@bcoe/v8-coverage/0.2.3: + /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@esbuild/linux-loong64/0.14.54: + /@esbuild/linux-loong64@0.14.54: resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} engines: {node: '>=12'} cpu: [loong64] @@ -1372,7 +1421,7 @@ packages: dev: true optional: true - /@eslint/eslintrc/0.4.3: + /@eslint/eslintrc@0.4.3: resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: @@ -1389,7 +1438,7 @@ packages: - supports-color dev: true - /@humanwhocodes/config-array/0.5.0: + /@humanwhocodes/config-array@0.5.0: resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} engines: {node: '>=10.10.0'} dependencies: @@ -1400,11 +1449,11 @@ packages: - supports-color dev: true - /@humanwhocodes/object-schema/1.2.1: + /@humanwhocodes/object-schema@1.2.1: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@istanbuljs/load-nyc-config/1.1.0: + /@istanbuljs/load-nyc-config@1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} dependencies: @@ -1415,12 +1464,12 @@ packages: resolve-from: 5.0.0 dev: true - /@istanbuljs/schema/0.1.3: + /@istanbuljs/schema@0.1.3: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} dev: true - /@jest/console/27.5.1: + /@jest/console@27.5.1: resolution: {integrity: sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1432,7 +1481,7 @@ packages: slash: 3.0.0 dev: true - /@jest/core/27.5.1: + /@jest/core@27.5.1: resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: @@ -1477,7 +1526,7 @@ packages: - utf-8-validate dev: true - /@jest/environment/27.5.1: + /@jest/environment@27.5.1: resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1487,7 +1536,7 @@ packages: jest-mock: 27.5.1 dev: true - /@jest/fake-timers/27.5.1: + /@jest/fake-timers@27.5.1: resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1499,7 +1548,7 @@ packages: jest-util: 27.5.1 dev: true - /@jest/globals/27.5.1: + /@jest/globals@27.5.1: resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1508,7 +1557,7 @@ packages: expect: 27.5.1 dev: true - /@jest/reporters/27.5.1: + /@jest/reporters@27.5.1: resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: @@ -1546,7 +1595,7 @@ packages: - supports-color dev: true - /@jest/source-map/27.5.1: + /@jest/source-map@27.5.1: resolution: {integrity: sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1555,7 +1604,7 @@ packages: source-map: 0.6.1 dev: true - /@jest/test-result/27.5.1: + /@jest/test-result@27.5.1: resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1565,7 +1614,7 @@ packages: collect-v8-coverage: 1.0.1 dev: true - /@jest/test-sequencer/27.5.1: + /@jest/test-sequencer@27.5.1: resolution: {integrity: sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1577,7 +1626,7 @@ packages: - supports-color dev: true - /@jest/transform/27.5.1: + /@jest/transform@27.5.1: resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1600,7 +1649,7 @@ packages: - supports-color dev: true - /@jest/types/26.6.2: + /@jest/types@26.6.2: resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} engines: {node: '>= 10.14.2'} dependencies: @@ -1611,7 +1660,7 @@ packages: chalk: 4.1.2 dev: true - /@jest/types/27.5.1: + /@jest/types@27.5.1: resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -1622,7 +1671,7 @@ packages: chalk: 4.1.2 dev: true - /@jridgewell/gen-mapping/0.1.1: + /@jridgewell/gen-mapping@0.1.1: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} dependencies: @@ -1630,7 +1679,7 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@jridgewell/gen-mapping/0.3.2: + /@jridgewell/gen-mapping@0.3.2: resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} engines: {node: '>=6.0.0'} dependencies: @@ -1639,35 +1688,35 @@ packages: '@jridgewell/trace-mapping': 0.3.17 dev: true - /@jridgewell/resolve-uri/3.1.0: + /@jridgewell/resolve-uri@3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array/1.1.2: + /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/source-map/0.3.2: + /@jridgewell/source-map@0.3.2: resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} dependencies: '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 dev: true - /@jridgewell/sourcemap-codec/1.4.14: + /@jridgewell/sourcemap-codec@1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} dev: true - /@jridgewell/trace-mapping/0.3.17: + /@jridgewell/trace-mapping@0.3.17: resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@js-temporal/temporal-test262-runner/0.9.0: + /@js-temporal/temporal-test262-runner@0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza): resolution: {integrity: sha512-+DbfZ6oyuFyHbfe77HOuYEPfIkSNlYvFfS7hA+o9n1MxTqjdTN1xxQ0IOkGloVblIsl5Ceu1yzG4RNVzZHWL9Q==} dependencies: ansi-colors: 4.1.3 @@ -1675,8 +1724,9 @@ packages: progress: 2.0.3 tiny-glob: 0.2.9 dev: true + patched: true - /@nodelib/fs.scandir/2.1.5: + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} dependencies: @@ -1684,12 +1734,12 @@ packages: run-parallel: 1.2.0 dev: true - /@nodelib/fs.stat/2.0.5: + /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} dev: true - /@nodelib/fs.walk/1.2.8: + /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} dependencies: @@ -1697,13 +1747,13 @@ packages: fastq: 1.15.0 dev: true - /@rollup/plugin-node-resolve/13.3.0_rollup@2.79.1: + /@rollup/plugin-node-resolve@13.3.0(rollup@2.79.1): resolution: {integrity: sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==} engines: {node: '>= 10.0.0'} peerDependencies: rollup: ^2.42.0 dependencies: - '@rollup/pluginutils': 3.1.0_rollup@2.79.1 + '@rollup/pluginutils': 3.1.0(rollup@2.79.1) '@types/resolve': 1.17.1 deepmerge: 4.3.0 is-builtin-module: 3.2.1 @@ -1712,7 +1762,7 @@ packages: rollup: 2.79.1 dev: true - /@rollup/pluginutils/3.1.0_rollup@2.79.1: + /@rollup/pluginutils@3.1.0(rollup@2.79.1): resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} peerDependencies: @@ -1724,7 +1774,7 @@ packages: rollup: 2.79.1 dev: true - /@rollup/pluginutils/4.2.1: + /@rollup/pluginutils@4.2.1: resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} dependencies: @@ -1732,24 +1782,24 @@ packages: picomatch: 2.3.1 dev: true - /@sinonjs/commons/1.8.6: + /@sinonjs/commons@1.8.6: resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} dependencies: type-detect: 4.0.8 dev: true - /@sinonjs/fake-timers/8.1.0: + /@sinonjs/fake-timers@8.1.0: resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} dependencies: '@sinonjs/commons': 1.8.6 dev: true - /@tootallnate/once/1.1.2: + /@tootallnate/once@1.1.2: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} dev: true - /@types/babel__core/7.20.0: + /@types/babel__core@7.20.0: resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==} dependencies: '@babel/parser': 7.21.2 @@ -1759,109 +1809,109 @@ packages: '@types/babel__traverse': 7.18.3 dev: true - /@types/babel__generator/7.6.4: + /@types/babel__generator@7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: '@babel/types': 7.21.2 dev: true - /@types/babel__template/7.4.1: + /@types/babel__template@7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: '@babel/parser': 7.21.2 '@babel/types': 7.21.2 dev: true - /@types/babel__traverse/7.18.3: + /@types/babel__traverse@7.18.3: resolution: {integrity: sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==} dependencies: '@babel/types': 7.21.2 dev: true - /@types/chai/4.3.4: + /@types/chai@4.3.4: resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} dev: true - /@types/estree/0.0.39: + /@types/estree@0.0.39: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: true - /@types/graceful-fs/4.1.6: + /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: '@types/node': 18.14.5 dev: true - /@types/istanbul-lib-coverage/2.0.4: + /@types/istanbul-lib-coverage@2.0.4: resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} dev: true - /@types/istanbul-lib-report/3.0.0: + /@types/istanbul-lib-report@3.0.0: resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} dependencies: '@types/istanbul-lib-coverage': 2.0.4 dev: true - /@types/istanbul-reports/3.0.1: + /@types/istanbul-reports@3.0.1: resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} dependencies: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/jest/26.0.24: + /@types/jest@26.0.24: resolution: {integrity: sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==} dependencies: jest-diff: 26.6.2 pretty-format: 26.6.2 dev: true - /@types/json-schema/7.0.11: + /@types/json-schema@7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true - /@types/json5/0.0.29: + /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/node/16.18.14: + /@types/node@16.18.14: resolution: {integrity: sha512-wvzClDGQXOCVNU4APPopC2KtMYukaF1MN/W3xAmslx22Z4/IF1/izDMekuyoUlwfnDHYCIZGaj7jMwnJKBTxKw==} dev: true - /@types/node/18.14.5: + /@types/node@18.14.5: resolution: {integrity: sha512-CRT4tMK/DHYhw1fcCEBwME9CSaZNclxfzVMe7GsO6ULSwsttbj70wSiX6rZdIjGblu93sTJxLdhNIT85KKI7Qw==} dev: true - /@types/prettier/2.7.2: + /@types/prettier@2.7.2: resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} dev: true - /@types/resolve/1.17.1: + /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: '@types/node': 18.14.5 dev: true - /@types/stack-utils/2.0.1: + /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true - /@types/yargs-parser/21.0.0: + /@types/yargs-parser@21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} dev: true - /@types/yargs/15.0.15: + /@types/yargs@15.0.15: resolution: {integrity: sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==} dependencies: '@types/yargs-parser': 21.0.0 dev: true - /@types/yargs/16.0.5: + /@types/yargs@16.0.5: resolution: {integrity: sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==} dependencies: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin/4.33.0_s2qqtxhzmb7vugvfoyripfgp7i: + /@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6): resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -1872,8 +1922,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 4.33.0_jofidmxrjzhj7l6vknpw5ecvfe - '@typescript-eslint/parser': 4.33.0_jofidmxrjzhj7l6vknpw5ecvfe + '@typescript-eslint/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.1.6) + '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) '@typescript-eslint/scope-manager': 4.33.0 debug: 4.3.4 eslint: 7.32.0 @@ -1881,13 +1931,13 @@ packages: ignore: 5.2.4 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.5 - typescript: 4.9.5 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils/4.33.0_jofidmxrjzhj7l6vknpw5ecvfe: + /@typescript-eslint/experimental-utils@4.33.0(eslint@7.32.0)(typescript@5.1.6): resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -1896,16 +1946,16 @@ packages: '@types/json-schema': 7.0.11 '@typescript-eslint/scope-manager': 4.33.0 '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.9.5 + '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.6) eslint: 7.32.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@7.32.0 + eslint-utils: 3.0.0(eslint@7.32.0) transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/parser/4.33.0_jofidmxrjzhj7l6vknpw5ecvfe: + /@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.1.6): resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -1917,15 +1967,15 @@ packages: dependencies: '@typescript-eslint/scope-manager': 4.33.0 '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.9.5 + '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.6) debug: 4.3.4 eslint: 7.32.0 - typescript: 4.9.5 + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager/4.33.0: + /@typescript-eslint/scope-manager@4.33.0: resolution: {integrity: sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==} engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dependencies: @@ -1933,12 +1983,12 @@ packages: '@typescript-eslint/visitor-keys': 4.33.0 dev: true - /@typescript-eslint/types/4.33.0: + /@typescript-eslint/types@4.33.0: resolution: {integrity: sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==} engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dev: true - /@typescript-eslint/typescript-estree/4.33.0_typescript@4.9.5: + /@typescript-eslint/typescript-estree@4.33.0(typescript@5.1.6): resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -1953,13 +2003,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.5 - typescript: 4.9.5 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/visitor-keys/4.33.0: + /@typescript-eslint/visitor-keys@4.33.0: resolution: {integrity: sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==} engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dependencies: @@ -1967,18 +2017,18 @@ packages: eslint-visitor-keys: 2.1.0 dev: true - /abab/2.0.6: + /abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} dev: true - /acorn-globals/6.0.0: + /acorn-globals@6.0.0: resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==} dependencies: acorn: 7.4.1 acorn-walk: 7.2.0 dev: true - /acorn-jsx/5.3.2_acorn@7.4.1: + /acorn-jsx@5.3.2(acorn@7.4.1): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1986,24 +2036,24 @@ packages: acorn: 7.4.1 dev: true - /acorn-walk/7.2.0: + /acorn-walk@7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} dev: true - /acorn/7.4.1: + /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} hasBin: true dev: true - /acorn/8.8.2: + /acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} hasBin: true dev: true - /agent-base/6.0.2: + /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: @@ -2012,7 +2062,7 @@ packages: - supports-color dev: true - /ajv/6.12.6: + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: fast-deep-equal: 3.1.3 @@ -2021,7 +2071,7 @@ packages: uri-js: 4.4.1 dev: true - /ajv/8.12.0: + /ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} dependencies: fast-deep-equal: 3.1.3 @@ -2030,43 +2080,43 @@ packages: uri-js: 4.4.1 dev: true - /ansi-colors/4.1.3: + /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} dev: true - /ansi-escapes/4.3.2: + /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} dependencies: type-fest: 0.21.3 dev: true - /ansi-regex/5.0.1: + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} dev: true - /ansi-styles/3.2.1: + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} dependencies: color-convert: 1.9.3 dev: true - /ansi-styles/4.3.0: + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 dev: true - /ansi-styles/5.2.0: + /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} dev: true - /anymatch/3.1.3: + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} dependencies: @@ -2074,17 +2124,17 @@ packages: picomatch: 2.3.1 dev: true - /argparse/1.0.10: + /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: sprintf-js: 1.0.3 dev: true - /argparse/2.0.1: + /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /array-includes/3.1.6: + /array-includes@3.1.6: resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} dependencies: @@ -2095,12 +2145,12 @@ packages: is-string: 1.0.7 dev: true - /array-union/2.1.0: + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true - /array.prototype.flat/1.3.1: + /array.prototype.flat@1.3.1: resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} engines: {node: '>= 0.4'} dependencies: @@ -2110,7 +2160,7 @@ packages: es-shim-unscopables: 1.0.0 dev: true - /array.prototype.flatmap/1.3.1: + /array.prototype.flatmap@1.3.1: resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} engines: {node: '>= 0.4'} dependencies: @@ -2120,25 +2170,25 @@ packages: es-shim-unscopables: 1.0.0 dev: true - /assertion-error/1.1.0: + /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true - /astral-regex/2.0.0: + /astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} dev: true - /asynckit/0.4.0: + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true - /available-typed-arrays/1.0.5: + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} dev: true - /babel-jest/27.5.1_@babel+core@7.21.0: + /babel-jest@27.5.1(@babel/core@7.21.0): resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: @@ -2149,7 +2199,7 @@ packages: '@jest/types': 27.5.1 '@types/babel__core': 7.20.0 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1_@babel+core@7.21.0 + babel-preset-jest: 27.5.1(@babel/core@7.21.0) chalk: 4.1.2 graceful-fs: 4.2.10 slash: 3.0.0 @@ -2157,7 +2207,7 @@ packages: - supports-color dev: true - /babel-plugin-istanbul/6.1.1: + /babel-plugin-istanbul@6.1.1: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} dependencies: @@ -2170,7 +2220,7 @@ packages: - supports-color dev: true - /babel-plugin-jest-hoist/27.5.1: + /babel-plugin-jest-hoist@27.5.1: resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -2180,63 +2230,63 @@ packages: '@types/babel__traverse': 7.18.3 dev: true - /babel-plugin-polyfill-corejs2/0.3.3_@babel+core@7.21.0: + /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.21.0): resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/compat-data': 7.21.0 '@babel/core': 7.21.0 - '@babel/helper-define-polyfill-provider': 0.3.3_@babel+core@7.21.0 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.0) semver: 6.3.0 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs3/0.6.0_@babel+core@7.21.0: + /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.21.0): resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-define-polyfill-provider': 0.3.3_@babel+core@7.21.0 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.0) core-js-compat: 3.29.0 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-regenerator/0.4.1_@babel+core@7.21.0: + /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.21.0): resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.0 - '@babel/helper-define-polyfill-provider': 0.3.3_@babel+core@7.21.0 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.0) transitivePeerDependencies: - supports-color dev: true - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.21.0: + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.21.0): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.21.0 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.21.0 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.21.0 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.21.0 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.21.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.21.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.21.0 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.21.0 - dev: true - - /babel-preset-jest/27.5.1_@babel+core@7.21.0: + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.21.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.21.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.21.0) + dev: true + + /babel-preset-jest@27.5.1(@babel/core@7.21.0): resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: @@ -2244,38 +2294,38 @@ packages: dependencies: '@babel/core': 7.21.0 babel-plugin-jest-hoist: 27.5.1 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.21.0 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.21.0) dev: true - /balanced-match/1.0.2: + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /brace-expansion/1.1.11: + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 dev: true - /brace-expansion/2.0.1: + /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 dev: true - /braces/3.0.2: + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} dependencies: fill-range: 7.0.1 dev: true - /browser-process-hrtime/1.0.0: + /browser-process-hrtime@1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} dev: true - /browserslist/4.21.5: + /browserslist@4.21.5: resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2283,51 +2333,51 @@ packages: caniuse-lite: 1.0.30001460 electron-to-chromium: 1.4.319 node-releases: 2.0.10 - update-browserslist-db: 1.0.10_browserslist@4.21.5 + update-browserslist-db: 1.0.10(browserslist@4.21.5) dev: true - /bser/2.1.1: + /bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} dependencies: node-int64: 0.4.0 dev: true - /buffer-from/1.1.2: + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true - /builtin-modules/3.3.0: + /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} dev: true - /call-bind/1.0.2: + /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: function-bind: 1.1.1 get-intrinsic: 1.2.0 dev: true - /callsites/3.1.0: + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} dev: true - /camelcase/5.3.1: + /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} dev: true - /camelcase/6.3.0: + /camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001460: + /caniuse-lite@1.0.30001460: resolution: {integrity: sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==} dev: true - /chai/4.3.7: + /chai@4.3.7: resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} engines: {node: '>=4'} dependencies: @@ -2340,7 +2390,7 @@ packages: type-detect: 4.0.8 dev: true - /chalk/2.4.2: + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} dependencies: @@ -2349,7 +2399,7 @@ packages: supports-color: 5.5.0 dev: true - /chalk/4.1.2: + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} dependencies: @@ -2357,25 +2407,25 @@ packages: supports-color: 7.2.0 dev: true - /char-regex/1.0.2: + /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} dev: true - /check-error/1.0.2: + /check-error@1.0.2: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true - /ci-info/3.8.0: + /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} dev: true - /cjs-module-lexer/1.2.2: + /cjs-module-lexer@1.2.2: resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} dev: true - /cliui/7.0.4: + /cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: string-width: 4.2.3 @@ -2383,7 +2433,7 @@ packages: wrap-ansi: 7.0.0 dev: true - /cliui/8.0.1: + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} dependencies: @@ -2392,57 +2442,57 @@ packages: wrap-ansi: 7.0.0 dev: true - /co/4.6.0: + /co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} dev: true - /collect-v8-coverage/1.0.1: + /collect-v8-coverage@1.0.1: resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} dev: true - /color-convert/1.9.3: + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 dev: true - /color-convert/2.0.1: + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 dev: true - /color-name/1.1.3: + /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} dev: true - /color-name/1.1.4: + /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true - /colors/1.4.0: + /colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} dev: true - /combined-stream/1.0.8: + /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} dependencies: delayed-stream: 1.0.0 dev: true - /commander/2.20.3: + /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true - /concat-map/0.0.1: + /concat-map@0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true - /concurrently/7.6.0: + /concurrently@7.6.0: resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==} engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} hasBin: true @@ -2458,17 +2508,17 @@ packages: yargs: 17.7.1 dev: true - /convert-source-map/1.9.0: + /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true - /core-js-compat/3.29.0: + /core-js-compat@3.29.0: resolution: {integrity: sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ==} dependencies: browserslist: 4.21.5 dev: true - /cross-spawn/7.0.3: + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} dependencies: @@ -2477,22 +2527,22 @@ packages: which: 2.0.2 dev: true - /cssom/0.3.8: + /cssom@0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} dev: true - /cssom/0.4.4: + /cssom@0.4.4: resolution: {integrity: sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==} dev: true - /cssstyle/2.3.0: + /cssstyle@2.3.0: resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} engines: {node: '>=8'} dependencies: cssom: 0.3.8 dev: true - /data-urls/2.0.0: + /data-urls@2.0.0: resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} engines: {node: '>=10'} dependencies: @@ -2501,12 +2551,12 @@ packages: whatwg-url: 8.7.0 dev: true - /date-fns/2.29.3: + /date-fns@2.29.3: resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} engines: {node: '>=0.11'} dev: true - /debug/3.2.7: + /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: supports-color: '*' @@ -2517,7 +2567,7 @@ packages: ms: 2.1.3 dev: true - /debug/4.3.4: + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: @@ -2529,31 +2579,31 @@ packages: ms: 2.1.2 dev: true - /decimal.js/10.4.3: + /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} dev: true - /dedent/0.7.0: + /dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} dev: true - /deep-eql/4.1.3: + /deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} dependencies: type-detect: 4.0.8 dev: true - /deep-is/0.1.4: + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /deepmerge/4.3.0: + /deepmerge@4.3.0: resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==} engines: {node: '>=0.10.0'} dev: true - /define-properties/1.2.0: + /define-properties@1.2.0: resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} engines: {node: '>= 0.4'} dependencies: @@ -2561,81 +2611,81 @@ packages: object-keys: 1.1.1 dev: true - /delayed-stream/1.0.0: + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} dev: true - /detect-newline/3.1.0: + /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} dev: true - /diff-sequences/26.6.2: + /diff-sequences@26.6.2: resolution: {integrity: sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==} engines: {node: '>= 10.14.2'} dev: true - /diff-sequences/27.5.1: + /diff-sequences@27.5.1: resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: true - /dir-glob/3.0.1: + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} dependencies: path-type: 4.0.0 dev: true - /doctrine/2.1.0: + /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} dependencies: esutils: 2.0.3 dev: true - /doctrine/3.0.0: + /doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} dependencies: esutils: 2.0.3 dev: true - /domexception/2.0.1: + /domexception@2.0.1: resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} engines: {node: '>=8'} dependencies: webidl-conversions: 5.0.0 dev: true - /electron-to-chromium/1.4.319: + /electron-to-chromium@1.4.319: resolution: {integrity: sha512-WeoI6NwZUgteKB+Wmn692S35QycwwNxwgTomNnoCJ79znBAjtBi6C/cIW62JkXmpJRX5rKNYSLDBdAM8l5fH0w==} dev: true - /emittery/0.8.1: + /emittery@0.8.1: resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} engines: {node: '>=10'} dev: true - /emoji-regex/8.0.0: + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true - /enquirer/2.3.6: + /enquirer@2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} dependencies: ansi-colors: 4.1.3 dev: true - /error-ex/1.3.2: + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 dev: true - /es-abstract/1.21.1: + /es-abstract@1.21.1: resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} engines: {node: '>= 0.4'} dependencies: @@ -2674,11 +2724,11 @@ packages: which-typed-array: 1.1.9 dev: true - /es-module-lexer/0.9.3: + /es-module-lexer@0.9.3: resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} dev: true - /es-set-tostringtag/2.0.1: + /es-set-tostringtag@2.0.1: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} engines: {node: '>= 0.4'} dependencies: @@ -2687,13 +2737,13 @@ packages: has-tostringtag: 1.0.0 dev: true - /es-shim-unscopables/1.0.0: + /es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: has: 1.0.3 dev: true - /es-to-primitive/1.2.1: + /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} dependencies: @@ -2702,7 +2752,7 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild-android-64/0.14.54: + /esbuild-android-64@0.14.54: resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} engines: {node: '>=12'} cpu: [x64] @@ -2711,7 +2761,7 @@ packages: dev: true optional: true - /esbuild-android-arm64/0.14.54: + /esbuild-android-arm64@0.14.54: resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} engines: {node: '>=12'} cpu: [arm64] @@ -2720,7 +2770,7 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.14.54: + /esbuild-darwin-64@0.14.54: resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} engines: {node: '>=12'} cpu: [x64] @@ -2729,7 +2779,7 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.14.54: + /esbuild-darwin-arm64@0.14.54: resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} engines: {node: '>=12'} cpu: [arm64] @@ -2738,7 +2788,7 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.14.54: + /esbuild-freebsd-64@0.14.54: resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} engines: {node: '>=12'} cpu: [x64] @@ -2747,7 +2797,7 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.14.54: + /esbuild-freebsd-arm64@0.14.54: resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} engines: {node: '>=12'} cpu: [arm64] @@ -2756,7 +2806,7 @@ packages: dev: true optional: true - /esbuild-linux-32/0.14.54: + /esbuild-linux-32@0.14.54: resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} engines: {node: '>=12'} cpu: [ia32] @@ -2765,7 +2815,7 @@ packages: dev: true optional: true - /esbuild-linux-64/0.14.54: + /esbuild-linux-64@0.14.54: resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} engines: {node: '>=12'} cpu: [x64] @@ -2774,25 +2824,25 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} + /esbuild-linux-arm64@0.14.54: + resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} engines: {node: '>=12'} - cpu: [arm] + cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-arm64/0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} + /esbuild-linux-arm@0.14.54: + resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} engines: {node: '>=12'} - cpu: [arm64] + cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-mips64le/0.14.54: + /esbuild-linux-mips64le@0.14.54: resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} engines: {node: '>=12'} cpu: [mips64el] @@ -2801,7 +2851,7 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.14.54: + /esbuild-linux-ppc64le@0.14.54: resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} engines: {node: '>=12'} cpu: [ppc64] @@ -2810,7 +2860,7 @@ packages: dev: true optional: true - /esbuild-linux-riscv64/0.14.54: + /esbuild-linux-riscv64@0.14.54: resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} engines: {node: '>=12'} cpu: [riscv64] @@ -2819,7 +2869,7 @@ packages: dev: true optional: true - /esbuild-linux-s390x/0.14.54: + /esbuild-linux-s390x@0.14.54: resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} engines: {node: '>=12'} cpu: [s390x] @@ -2828,7 +2878,7 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.14.54: + /esbuild-netbsd-64@0.14.54: resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} engines: {node: '>=12'} cpu: [x64] @@ -2837,7 +2887,7 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.14.54: + /esbuild-openbsd-64@0.14.54: resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} engines: {node: '>=12'} cpu: [x64] @@ -2846,7 +2896,7 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.14.54: + /esbuild-sunos-64@0.14.54: resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} engines: {node: '>=12'} cpu: [x64] @@ -2855,7 +2905,7 @@ packages: dev: true optional: true - /esbuild-windows-32/0.14.54: + /esbuild-windows-32@0.14.54: resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} engines: {node: '>=12'} cpu: [ia32] @@ -2864,7 +2914,7 @@ packages: dev: true optional: true - /esbuild-windows-64/0.14.54: + /esbuild-windows-64@0.14.54: resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} engines: {node: '>=12'} cpu: [x64] @@ -2873,7 +2923,7 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.14.54: + /esbuild-windows-arm64@0.14.54: resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} engines: {node: '>=12'} cpu: [arm64] @@ -2882,7 +2932,7 @@ packages: dev: true optional: true - /esbuild/0.14.54: + /esbuild@0.14.54: resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} engines: {node: '>=12'} hasBin: true @@ -2911,27 +2961,27 @@ packages: esbuild-windows-arm64: 0.14.54 dev: true - /escalade/3.1.1: + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} dev: true - /escape-string-regexp/1.0.5: + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} dev: true - /escape-string-regexp/2.0.0: + /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} dev: true - /escape-string-regexp/4.0.0: + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} dev: true - /escodegen/2.0.0: + /escodegen@2.0.0: resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} engines: {node: '>=6.0'} hasBin: true @@ -2944,7 +2994,7 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-standard/16.0.3_s3p4dyzitdtgac5nictnavtxa4: + /eslint-config-standard@16.0.3(eslint-plugin-import@2.27.5)(eslint-plugin-node@11.1.0)(eslint-plugin-promise@5.2.0)(eslint@7.32.0): resolution: {integrity: sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==} peerDependencies: eslint: ^7.12.1 @@ -2953,12 +3003,12 @@ packages: eslint-plugin-promise: ^4.2.1 || ^5.0.0 dependencies: eslint: 7.32.0 - eslint-plugin-import: 2.27.5_ffi3uiz42rv3jyhs6cr7p7qqry - eslint-plugin-node: 11.1.0_eslint@7.32.0 - eslint-plugin-promise: 5.2.0_eslint@7.32.0 + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@4.33.0)(eslint@7.32.0) + eslint-plugin-node: 11.1.0(eslint@7.32.0) + eslint-plugin-promise: 5.2.0(eslint@7.32.0) dev: true - /eslint-import-resolver-node/0.3.7: + /eslint-import-resolver-node@0.3.7: resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} dependencies: debug: 3.2.7 @@ -2968,7 +3018,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_n7wmpe4hfzj47xhbzj4etqyjdi: + /eslint-module-utils@2.7.4(@typescript-eslint/parser@4.33.0)(eslint-import-resolver-node@0.3.7)(eslint@7.32.0): resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -2989,7 +3039,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 4.33.0_jofidmxrjzhj7l6vknpw5ecvfe + '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) debug: 3.2.7 eslint: 7.32.0 eslint-import-resolver-node: 0.3.7 @@ -2997,7 +3047,7 @@ packages: - supports-color dev: true - /eslint-plugin-es/3.0.1_eslint@7.32.0: + /eslint-plugin-es@3.0.1(eslint@7.32.0): resolution: {integrity: sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==} engines: {node: '>=8.10.0'} peerDependencies: @@ -3008,7 +3058,7 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-import/2.27.5_ffi3uiz42rv3jyhs6cr7p7qqry: + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@4.33.0)(eslint@7.32.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} peerDependencies: @@ -3018,7 +3068,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 4.33.0_jofidmxrjzhj7l6vknpw5ecvfe + '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 @@ -3026,7 +3076,7 @@ packages: doctrine: 2.1.0 eslint: 7.32.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4_n7wmpe4hfzj47xhbzj4etqyjdi + eslint-module-utils: 2.7.4(@typescript-eslint/parser@4.33.0)(eslint-import-resolver-node@0.3.7)(eslint@7.32.0) has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -3041,14 +3091,14 @@ packages: - supports-color dev: true - /eslint-plugin-node/11.1.0_eslint@7.32.0: + /eslint-plugin-node@11.1.0(eslint@7.32.0): resolution: {integrity: sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==} engines: {node: '>=8.10.0'} peerDependencies: eslint: '>=5.16.0' dependencies: eslint: 7.32.0 - eslint-plugin-es: 3.0.1_eslint@7.32.0 + eslint-plugin-es: 3.0.1(eslint@7.32.0) eslint-utils: 2.1.0 ignore: 5.2.4 minimatch: 3.1.2 @@ -3056,7 +3106,7 @@ packages: semver: 6.3.0 dev: true - /eslint-plugin-promise/5.2.0_eslint@7.32.0: + /eslint-plugin-promise@5.2.0(eslint@7.32.0): resolution: {integrity: sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -3065,7 +3115,7 @@ packages: eslint: 7.32.0 dev: true - /eslint-scope/5.1.1: + /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} dependencies: @@ -3073,14 +3123,14 @@ packages: estraverse: 4.3.0 dev: true - /eslint-utils/2.1.0: + /eslint-utils@2.1.0: resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} engines: {node: '>=6'} dependencies: eslint-visitor-keys: 1.3.0 dev: true - /eslint-utils/3.0.0_eslint@7.32.0: + /eslint-utils@3.0.0(eslint@7.32.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: @@ -3090,17 +3140,17 @@ packages: eslint-visitor-keys: 2.1.0 dev: true - /eslint-visitor-keys/1.3.0: + /eslint-visitor-keys@1.3.0: resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} engines: {node: '>=4'} dev: true - /eslint-visitor-keys/2.1.0: + /eslint-visitor-keys@2.1.0: resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} engines: {node: '>=10'} dev: true - /eslint/7.32.0: + /eslint@7.32.0: resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==} engines: {node: ^10.12.0 || >=12.0.0} hasBin: true @@ -3149,59 +3199,59 @@ packages: - supports-color dev: true - /espree/7.3.1: + /espree@7.3.1: resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: acorn: 7.4.1 - acorn-jsx: 5.3.2_acorn@7.4.1 + acorn-jsx: 5.3.2(acorn@7.4.1) eslint-visitor-keys: 1.3.0 dev: true - /esprima/4.0.1: + /esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true dev: true - /esquery/1.5.0: + /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 dev: true - /esrecurse/4.3.0: + /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} dependencies: estraverse: 5.3.0 dev: true - /estraverse/4.3.0: + /estraverse@4.3.0: resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} engines: {node: '>=4.0'} dev: true - /estraverse/5.3.0: + /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} dev: true - /estree-walker/1.0.1: + /estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} dev: true - /estree-walker/2.0.2: + /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true - /esutils/2.0.3: + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} dev: true - /execa/5.1.1: + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} dependencies: @@ -3216,12 +3266,12 @@ packages: strip-final-newline: 2.0.0 dev: true - /exit/0.1.2: + /exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} dev: true - /expect/27.5.1: + /expect@27.5.1: resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -3231,11 +3281,11 @@ packages: jest-message-util: 27.5.1 dev: true - /fast-deep-equal/3.1.3: + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /fast-glob/3.2.12: + /fast-glob@3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} engines: {node: '>=8.6.0'} dependencies: @@ -3246,41 +3296,41 @@ packages: micromatch: 4.0.5 dev: true - /fast-json-stable-stringify/2.1.0: + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true - /fast-levenshtein/2.0.6: + /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true - /fastq/1.15.0: + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 dev: true - /fb-watchman/2.0.2: + /fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} dependencies: bser: 2.1.1 dev: true - /file-entry-cache/6.0.1: + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: flat-cache: 3.0.4 dev: true - /fill-range/7.0.1: + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 dev: true - /find-up/4.1.0: + /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} dependencies: @@ -3288,7 +3338,7 @@ packages: path-exists: 4.0.0 dev: true - /flat-cache/3.0.4: + /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: @@ -3296,17 +3346,17 @@ packages: rimraf: 3.0.2 dev: true - /flatted/3.2.7: + /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /for-each/0.3.3: + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 dev: true - /form-data/3.0.1: + /form-data@3.0.1: resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} dependencies: @@ -3315,11 +3365,11 @@ packages: mime-types: 2.1.35 dev: true - /fs.realpath/1.0.0: + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /fsevents/2.3.2: + /fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] @@ -3327,11 +3377,11 @@ packages: dev: true optional: true - /function-bind/1.1.1: + /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true - /function.prototype.name/1.1.5: + /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} engines: {node: '>= 0.4'} dependencies: @@ -3341,29 +3391,29 @@ packages: functions-have-names: 1.2.3 dev: true - /functional-red-black-tree/1.0.1: + /functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true - /functions-have-names/1.2.3: + /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true - /gensync/1.0.0-beta.2: + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} dev: true - /get-caller-file/2.0.5: + /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} dev: true - /get-func-name/2.0.0: + /get-func-name@2.0.0: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true - /get-intrinsic/1.2.0: + /get-intrinsic@1.2.0: resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} dependencies: function-bind: 1.1.1 @@ -3371,17 +3421,17 @@ packages: has-symbols: 1.0.3 dev: true - /get-package-type/0.1.0: + /get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} dev: true - /get-stream/6.0.1: + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} dev: true - /get-symbol-description/1.0.0: + /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} dependencies: @@ -3389,14 +3439,14 @@ packages: get-intrinsic: 1.2.0 dev: true - /glob-parent/5.1.2: + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 dev: true - /glob/7.2.3: + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: fs.realpath: 1.0.0 @@ -3407,30 +3457,30 @@ packages: path-is-absolute: 1.0.1 dev: true - /globals/11.12.0: + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} dev: true - /globals/13.20.0: + /globals@13.20.0: resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 dev: true - /globalthis/1.0.3: + /globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.0 dev: true - /globalyzer/0.1.0: + /globalyzer@0.1.0: resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} dev: true - /globby/11.1.0: + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} dependencies: @@ -3442,76 +3492,76 @@ packages: slash: 3.0.0 dev: true - /globrex/0.1.2: + /globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true - /gopd/1.0.1: + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.0 dev: true - /graceful-fs/4.2.10: + /graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} dev: true - /has-bigints/1.0.2: + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true - /has-flag/3.0.0: + /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} dev: true - /has-flag/4.0.0: + /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} dev: true - /has-property-descriptors/1.0.0: + /has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: get-intrinsic: 1.2.0 dev: true - /has-proto/1.0.1: + /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} dev: true - /has-symbols/1.0.3: + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} dev: true - /has-tostringtag/1.0.0: + /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 dev: true - /has/1.0.3: + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 dev: true - /html-encoding-sniffer/2.0.1: + /html-encoding-sniffer@2.0.1: resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} engines: {node: '>=10'} dependencies: whatwg-encoding: 1.0.5 dev: true - /html-escaper/2.0.2: + /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true - /http-proxy-agent/4.0.1: + /http-proxy-agent@4.0.1: resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} engines: {node: '>= 6'} dependencies: @@ -3522,7 +3572,7 @@ packages: - supports-color dev: true - /https-proxy-agent/5.0.1: + /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} dependencies: @@ -3532,29 +3582,29 @@ packages: - supports-color dev: true - /human-signals/2.1.0: + /human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} dev: true - /iconv-lite/0.4.24: + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 dev: true - /ignore/4.0.6: + /ignore@4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} engines: {node: '>= 4'} dev: true - /ignore/5.2.4: + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} dev: true - /import-fresh/3.3.0: + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} dependencies: @@ -3562,7 +3612,7 @@ packages: resolve-from: 4.0.0 dev: true - /import-local/3.1.0: + /import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} hasBin: true @@ -3571,23 +3621,23 @@ packages: resolve-cwd: 3.0.0 dev: true - /imurmurhash/0.1.4: + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} dev: true - /inflight/1.0.6: + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: once: 1.4.0 wrappy: 1.0.2 dev: true - /inherits/2.0.4: + /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true - /internal-slot/1.0.5: + /internal-slot@1.0.5: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} dependencies: @@ -3596,7 +3646,7 @@ packages: side-channel: 1.0.4 dev: true - /is-array-buffer/3.0.2: + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: call-bind: 1.0.2 @@ -3604,17 +3654,17 @@ packages: is-typed-array: 1.1.10 dev: true - /is-arrayish/0.2.1: + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true - /is-bigint/1.0.4: + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: has-bigints: 1.0.2 dev: true - /is-boolean-object/1.1.2: + /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} dependencies: @@ -3622,79 +3672,79 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-builtin-module/3.2.1: + /is-builtin-module@3.2.1: resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} engines: {node: '>=6'} dependencies: builtin-modules: 3.3.0 dev: true - /is-callable/1.2.7: + /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} dev: true - /is-core-module/2.11.0: + /is-core-module@2.11.0: resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} dependencies: has: 1.0.3 dev: true - /is-date-object/1.0.5: + /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 dev: true - /is-extglob/2.1.1: + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} dev: true - /is-fullwidth-code-point/3.0.0: + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} dev: true - /is-generator-fn/2.1.0: + /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} dev: true - /is-glob/4.0.3: + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 dev: true - /is-module/1.0.0: + /is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: true - /is-negative-zero/2.0.2: + /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} dev: true - /is-number-object/1.0.7: + /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 dev: true - /is-number/7.0.0: + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} dev: true - /is-potential-custom-element-name/1.0.1: + /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true - /is-regex/1.1.4: + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: @@ -3702,32 +3752,32 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-shared-array-buffer/1.0.2: + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: call-bind: 1.0.2 dev: true - /is-stream/2.0.1: + /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} dev: true - /is-string/1.0.7: + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 dev: true - /is-symbol/1.0.4: + /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 dev: true - /is-typed-array/1.1.10: + /is-typed-array@1.1.10: resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} engines: {node: '>= 0.4'} dependencies: @@ -3738,26 +3788,26 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-typedarray/1.0.0: + /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: true - /is-weakref/1.0.2: + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true - /isexe/2.0.0: + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true - /istanbul-lib-coverage/3.2.0: + /istanbul-lib-coverage@3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} dev: true - /istanbul-lib-instrument/5.2.1: + /istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: @@ -3770,7 +3820,7 @@ packages: - supports-color dev: true - /istanbul-lib-report/3.0.0: + /istanbul-lib-report@3.0.0: resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} engines: {node: '>=8'} dependencies: @@ -3779,7 +3829,7 @@ packages: supports-color: 7.2.0 dev: true - /istanbul-lib-source-maps/4.0.1: + /istanbul-lib-source-maps@4.0.1: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: @@ -3790,7 +3840,7 @@ packages: - supports-color dev: true - /istanbul-reports/3.1.5: + /istanbul-reports@3.1.5: resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} engines: {node: '>=8'} dependencies: @@ -3798,7 +3848,7 @@ packages: istanbul-lib-report: 3.0.0 dev: true - /jest-changed-files/27.5.1: + /jest-changed-files@27.5.1: resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -3807,7 +3857,7 @@ packages: throat: 6.0.2 dev: true - /jest-circus/27.5.1: + /jest-circus@27.5.1: resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -3834,7 +3884,7 @@ packages: - supports-color dev: true - /jest-cli/27.5.1: + /jest-cli@27.5.1: resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true @@ -3864,7 +3914,7 @@ packages: - utf-8-validate dev: true - /jest-config/27.5.1: + /jest-config@27.5.1: resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: @@ -3876,7 +3926,7 @@ packages: '@babel/core': 7.21.0 '@jest/test-sequencer': 27.5.1 '@jest/types': 27.5.1 - babel-jest: 27.5.1_@babel+core@7.21.0 + babel-jest: 27.5.1(@babel/core@7.21.0) chalk: 4.1.2 ci-info: 3.8.0 deepmerge: 4.3.0 @@ -3904,11 +3954,11 @@ packages: - utf-8-validate dev: true - /jest-date-mock/1.0.8: + /jest-date-mock@1.0.8: resolution: {integrity: sha512-0Lyp+z9xvuNmLbK+5N6FOhSiBeux05Lp5bbveFBmYo40Aggl2wwxFoIrZ+rOWC8nDNcLeBoDd2miQdEDSf3iQw==} dev: true - /jest-diff/26.6.2: + /jest-diff@26.6.2: resolution: {integrity: sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==} engines: {node: '>= 10.14.2'} dependencies: @@ -3918,7 +3968,7 @@ packages: pretty-format: 26.6.2 dev: true - /jest-diff/27.5.1: + /jest-diff@27.5.1: resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -3928,14 +3978,14 @@ packages: pretty-format: 27.5.1 dev: true - /jest-docblock/27.5.1: + /jest-docblock@27.5.1: resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: detect-newline: 3.1.0 dev: true - /jest-each/27.5.1: + /jest-each@27.5.1: resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -3946,7 +3996,7 @@ packages: pretty-format: 27.5.1 dev: true - /jest-environment-jsdom/27.5.1: + /jest-environment-jsdom@27.5.1: resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -3964,7 +4014,7 @@ packages: - utf-8-validate dev: true - /jest-environment-node/27.5.1: + /jest-environment-node@27.5.1: resolution: {integrity: sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -3976,17 +4026,17 @@ packages: jest-util: 27.5.1 dev: true - /jest-get-type/26.3.0: + /jest-get-type@26.3.0: resolution: {integrity: sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==} engines: {node: '>= 10.14.2'} dev: true - /jest-get-type/27.5.1: + /jest-get-type@27.5.1: resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: true - /jest-haste-map/27.5.1: + /jest-haste-map@27.5.1: resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4006,7 +4056,7 @@ packages: fsevents: 2.3.2 dev: true - /jest-jasmine2/27.5.1: + /jest-jasmine2@27.5.1: resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4031,7 +4081,7 @@ packages: - supports-color dev: true - /jest-leak-detector/27.5.1: + /jest-leak-detector@27.5.1: resolution: {integrity: sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4039,7 +4089,7 @@ packages: pretty-format: 27.5.1 dev: true - /jest-matcher-utils/27.5.1: + /jest-matcher-utils@27.5.1: resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4049,7 +4099,7 @@ packages: pretty-format: 27.5.1 dev: true - /jest-message-util/27.5.1: + /jest-message-util@27.5.1: resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4064,7 +4114,7 @@ packages: stack-utils: 2.0.6 dev: true - /jest-mock/27.5.1: + /jest-mock@27.5.1: resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4072,7 +4122,7 @@ packages: '@types/node': 18.14.5 dev: true - /jest-pnp-resolver/1.2.3_jest-resolve@27.5.1: + /jest-pnp-resolver@1.2.3(jest-resolve@27.5.1): resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} peerDependencies: @@ -4084,12 +4134,12 @@ packages: jest-resolve: 27.5.1 dev: true - /jest-regex-util/27.5.1: + /jest-regex-util@27.5.1: resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: true - /jest-resolve-dependencies/27.5.1: + /jest-resolve-dependencies@27.5.1: resolution: {integrity: sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4100,7 +4150,7 @@ packages: - supports-color dev: true - /jest-resolve/27.5.1: + /jest-resolve@27.5.1: resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4108,7 +4158,7 @@ packages: chalk: 4.1.2 graceful-fs: 4.2.10 jest-haste-map: 27.5.1 - jest-pnp-resolver: 1.2.3_jest-resolve@27.5.1 + jest-pnp-resolver: 1.2.3(jest-resolve@27.5.1) jest-util: 27.5.1 jest-validate: 27.5.1 resolve: 1.22.1 @@ -4116,7 +4166,7 @@ packages: slash: 3.0.0 dev: true - /jest-runner/27.5.1: + /jest-runner@27.5.1: resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4148,7 +4198,7 @@ packages: - utf-8-validate dev: true - /jest-runtime/27.5.1: + /jest-runtime@27.5.1: resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4178,7 +4228,7 @@ packages: - supports-color dev: true - /jest-serializer/27.5.1: + /jest-serializer@27.5.1: resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4186,20 +4236,20 @@ packages: graceful-fs: 4.2.10 dev: true - /jest-snapshot/27.5.1: + /jest-snapshot@27.5.1: resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@babel/core': 7.21.0 '@babel/generator': 7.21.1 - '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.21.0 + '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.21.0) '@babel/traverse': 7.21.2 '@babel/types': 7.21.2 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 '@types/babel__traverse': 7.18.3 '@types/prettier': 2.7.2 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.21.0 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.21.0) chalk: 4.1.2 expect: 27.5.1 graceful-fs: 4.2.10 @@ -4216,7 +4266,7 @@ packages: - supports-color dev: true - /jest-util/27.5.1: + /jest-util@27.5.1: resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4228,7 +4278,7 @@ packages: picomatch: 2.3.1 dev: true - /jest-validate/27.5.1: + /jest-validate@27.5.1: resolution: {integrity: sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4240,7 +4290,7 @@ packages: pretty-format: 27.5.1 dev: true - /jest-watcher/27.5.1: + /jest-watcher@27.5.1: resolution: {integrity: sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4253,7 +4303,7 @@ packages: string-length: 4.0.2 dev: true - /jest-worker/26.6.2: + /jest-worker@26.6.2: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: @@ -4262,7 +4312,7 @@ packages: supports-color: 7.2.0 dev: true - /jest-worker/27.5.1: + /jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: @@ -4271,7 +4321,7 @@ packages: supports-color: 8.1.1 dev: true - /jest/27.5.1: + /jest@27.5.1: resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true @@ -4292,16 +4342,16 @@ packages: - utf-8-validate dev: true - /joycon/3.1.1: + /joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} dev: true - /js-tokens/4.0.0: + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true - /js-yaml/3.14.1: + /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true dependencies: @@ -4309,14 +4359,14 @@ packages: esprima: 4.0.1 dev: true - /js-yaml/4.1.0: + /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true dependencies: argparse: 2.0.1 dev: true - /jsdom/16.7.0: + /jsdom@16.7.0: resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==} engines: {node: '>=10'} peerDependencies: @@ -4358,61 +4408,61 @@ packages: - utf-8-validate dev: true - /jsesc/0.5.0: + /jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} hasBin: true dev: true - /jsesc/2.5.2: + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true dev: true - /json-parse-even-better-errors/2.3.1: + /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} dev: true - /json-schema-traverse/0.4.1: + /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true - /json-schema-traverse/1.0.0: + /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} dev: true - /json-stable-stringify-without-jsonify/1.0.1: + /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true - /json5/1.0.2: + /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true dependencies: minimist: 1.2.8 dev: true - /json5/2.2.3: + /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true dev: true - /jsonc-parser/3.2.0: + /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} dev: true - /kleur/3.0.3: + /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} dev: true - /leven/3.1.0: + /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} dev: true - /levn/0.3.0: + /levn@0.3.0: resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} engines: {node: '>= 0.8.0'} dependencies: @@ -4420,7 +4470,7 @@ packages: type-check: 0.3.2 dev: true - /levn/0.4.1: + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} dependencies: @@ -4428,81 +4478,81 @@ packages: type-check: 0.4.0 dev: true - /lines-and-columns/1.2.4: + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true - /locate-path/5.0.0: + /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} dependencies: p-locate: 4.1.0 dev: true - /lodash.debounce/4.0.8: + /lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} dev: true - /lodash.merge/4.6.2: + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true - /lodash.truncate/4.4.2: + /lodash.truncate@4.4.2: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} dev: true - /lodash/4.17.21: + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - /loupe/2.3.6: + /loupe@2.3.6: resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} dependencies: get-func-name: 2.0.0 dev: true - /lru-cache/5.1.1: + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 dev: true - /lru-cache/6.0.0: + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} dependencies: yallist: 4.0.0 dev: true - /magic-string/0.25.9: + /magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: sourcemap-codec: 1.4.8 dev: true - /make-dir/3.1.0: + /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} dependencies: semver: 6.3.0 dev: true - /makeerror/1.0.12: + /makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} dependencies: tmpl: 1.0.5 dev: true - /merge-stream/2.0.0: + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true - /merge2/1.4.1: + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} dev: true - /micromatch/4.0.5: + /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} dependencies: @@ -4510,86 +4560,86 @@ packages: picomatch: 2.3.1 dev: true - /mime-db/1.52.0: + /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} dev: true - /mime-types/2.1.35: + /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: mime-db: 1.52.0 dev: true - /mimic-fn/2.1.0: + /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} dev: true - /minimatch/3.1.2: + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 dev: true - /minimatch/5.1.6: + /minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 dev: true - /minimist/1.2.8: + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true - /ms/2.1.2: + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /ms/2.1.3: + /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /natural-compare/1.4.0: + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /node-int64/0.4.0: + /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true - /node-releases/2.0.10: + /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} dev: true - /normalize-path/3.0.0: + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} dev: true - /npm-run-path/4.0.1: + /npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} dependencies: path-key: 3.1.1 dev: true - /nwsapi/2.2.2: + /nwsapi@2.2.2: resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} dev: true - /object-inspect/1.12.3: + /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} dev: true - /object-keys/1.1.1: + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} dev: true - /object.assign/4.1.4: + /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} dependencies: @@ -4599,7 +4649,7 @@ packages: object-keys: 1.1.1 dev: true - /object.values/1.1.6: + /object.values@1.1.6: resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} dependencies: @@ -4608,20 +4658,20 @@ packages: es-abstract: 1.21.1 dev: true - /once/1.4.0: + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 dev: true - /onetime/5.1.2: + /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} dependencies: mimic-fn: 2.1.0 dev: true - /optionator/0.8.3: + /optionator@0.8.3: resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} engines: {node: '>= 0.8.0'} dependencies: @@ -4633,7 +4683,7 @@ packages: word-wrap: 1.2.3 dev: true - /optionator/0.9.1: + /optionator@0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} engines: {node: '>= 0.8.0'} dependencies: @@ -4645,33 +4695,33 @@ packages: word-wrap: 1.2.3 dev: true - /p-limit/2.3.0: + /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} dependencies: p-try: 2.2.0 dev: true - /p-locate/4.1.0: + /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} dependencies: p-limit: 2.3.0 dev: true - /p-try/2.2.0: + /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} dev: true - /parent-module/1.0.1: + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} dependencies: callsites: 3.1.0 dev: true - /parse-json/5.2.0: + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: @@ -4681,70 +4731,70 @@ packages: lines-and-columns: 1.2.4 dev: true - /parse5/6.0.1: + /parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} dev: true - /path-exists/4.0.0: + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} dev: true - /path-is-absolute/1.0.1: + /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} dev: true - /path-key/3.1.1: + /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} dev: true - /path-parse/1.0.7: + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true - /path-type/4.0.0: + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} dev: true - /pathval/1.1.1: + /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true - /picocolors/1.0.0: + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true - /picomatch/2.3.1: + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} dev: true - /pirates/4.0.5: + /pirates@4.0.5: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} dev: true - /pkg-dir/4.2.0: + /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} dependencies: find-up: 4.1.0 dev: true - /prelude-ls/1.1.2: + /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} dev: true - /prelude-ls/1.2.1: + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} dev: true - /pretty-format/26.6.2: + /pretty-format@26.6.2: resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} engines: {node: '>= 10'} dependencies: @@ -4754,7 +4804,7 @@ packages: react-is: 17.0.2 dev: true - /pretty-format/27.5.1: + /pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: @@ -4763,12 +4813,12 @@ packages: react-is: 17.0.2 dev: true - /progress/2.0.3: + /progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} dev: true - /prompts/2.4.2: + /prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} dependencies: @@ -4776,55 +4826,55 @@ packages: sisteransi: 1.0.5 dev: true - /psl/1.9.0: + /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: true - /punycode/2.3.0: + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} dev: true - /querystringify/2.2.0: + /querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} dev: true - /queue-microtask/1.2.3: + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /randombytes/2.1.0: + /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 dev: true - /react-is/17.0.2: + /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} dev: true - /regenerate-unicode-properties/10.1.0: + /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} engines: {node: '>=4'} dependencies: regenerate: 1.4.2 dev: true - /regenerate/1.4.2: + /regenerate@1.4.2: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} dev: true - /regenerator-runtime/0.13.11: + /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} dev: true - /regenerator-transform/0.15.1: + /regenerator-transform@0.15.1: resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} dependencies: '@babel/runtime': 7.21.0 dev: true - /regexp.prototype.flags/1.4.3: + /regexp.prototype.flags@1.4.3: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} engines: {node: '>= 0.4'} dependencies: @@ -4833,12 +4883,12 @@ packages: functions-have-names: 1.2.3 dev: true - /regexpp/3.2.0: + /regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} dev: true - /regexpu-core/5.3.1: + /regexpu-core@5.3.1: resolution: {integrity: sha512-nCOzW2V/X15XpLsK2rlgdwrysrBq+AauCn+omItIz4R1pIcmeot5zvjdmOBRLzEH/CkC6IxMJVmxDe3QcMuNVQ==} engines: {node: '>=4'} dependencies: @@ -4850,50 +4900,50 @@ packages: unicode-match-property-value-ecmascript: 2.1.0 dev: true - /regjsparser/0.9.1: + /regjsparser@0.9.1: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true dependencies: jsesc: 0.5.0 dev: true - /require-directory/2.1.1: + /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} dev: true - /require-from-string/2.0.2: + /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} dev: true - /requires-port/1.0.0: + /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: true - /resolve-cwd/3.0.0: + /resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} dependencies: resolve-from: 5.0.0 dev: true - /resolve-from/4.0.0: + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} dev: true - /resolve-from/5.0.0: + /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} dev: true - /resolve.exports/1.1.1: + /resolve.exports@1.1.1: resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} engines: {node: '>=10'} dev: true - /resolve/1.22.1: + /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true dependencies: @@ -4902,19 +4952,19 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true - /reusify/1.0.4: + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /rimraf/3.0.2: + /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true dependencies: glob: 7.2.3 dev: true - /rollup-plugin-dts/3.0.2_zptcx3kz3uwp66hzhyyt545weq: + /rollup-plugin-dts@3.0.2(rollup@2.79.1)(typescript@5.1.6): resolution: {integrity: sha512-hswlsdWu/x7k5pXzaLP6OvKRKcx8Bzprksz9i9mUe72zvt8LvqAb/AZpzs6FkLgmyRaN8B6rUQOVtzA3yEt9Yw==} engines: {node: '>=v12.22.1'} peerDependencies: @@ -4923,12 +4973,12 @@ packages: dependencies: magic-string: 0.25.9 rollup: 2.79.1 - typescript: 4.9.5 + typescript: 5.1.6 optionalDependencies: '@babel/code-frame': 7.18.6 dev: true - /rollup-plugin-esbuild/4.10.3_gkkadhp4kuvg7lmep2ttfihjii: + /rollup-plugin-esbuild@4.10.3(esbuild@0.14.54)(rollup@2.79.1): resolution: {integrity: sha512-RILwUCgnCL5vo8vyZ/ZpwcqRuE5KmLizEv6BujBQfgXFZ6ggcS0FiYvQN+gsTJfWCMaU37l0Fosh4eEufyO97Q==} engines: {node: '>=12'} peerDependencies: @@ -4946,7 +4996,7 @@ packages: - supports-color dev: true - /rollup-plugin-terser/7.0.2_rollup@2.79.1: + /rollup-plugin-terser@7.0.2(rollup@2.79.1): resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser peerDependencies: @@ -4959,7 +5009,7 @@ packages: terser: 5.16.5 dev: true - /rollup/2.79.1: + /rollup@2.79.1: resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} engines: {node: '>=10.0.0'} hasBin: true @@ -4967,23 +5017,23 @@ packages: fsevents: 2.3.2 dev: true - /run-parallel/1.2.0: + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 dev: true - /rxjs/7.8.0: + /rxjs@7.8.0: resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} dependencies: tslib: 2.5.0 dev: true - /safe-buffer/5.2.1: + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true - /safe-regex-test/1.0.0: + /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: call-bind: 1.0.2 @@ -4991,23 +5041,23 @@ packages: is-regex: 1.1.4 dev: true - /safer-buffer/2.1.2: + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true - /saxes/5.0.1: + /saxes@5.0.1: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} engines: {node: '>=10'} dependencies: xmlchars: 2.2.0 dev: true - /semver/6.3.0: + /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true dev: true - /semver/7.3.8: + /semver@7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} hasBin: true @@ -5015,29 +5065,29 @@ packages: lru-cache: 6.0.0 dev: true - /serialize-javascript/4.0.0: + /serialize-javascript@4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} dependencies: randombytes: 2.1.0 dev: true - /shebang-command/2.0.0: + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 dev: true - /shebang-regex/3.0.0: + /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} dev: true - /shell-quote/1.8.0: + /shell-quote@1.8.0: resolution: {integrity: sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==} dev: true - /side-channel/1.0.4: + /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: call-bind: 1.0.2 @@ -5045,20 +5095,20 @@ packages: object-inspect: 1.12.3 dev: true - /signal-exit/3.0.7: + /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true - /sisteransi/1.0.5: + /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true - /slash/3.0.0: + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} dev: true - /slice-ansi/4.0.0: + /slice-ansi@4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} dependencies: @@ -5067,44 +5117,44 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true - /source-map-support/0.5.21: + /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: buffer-from: 1.1.2 source-map: 0.6.1 dev: true - /source-map/0.6.1: + /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} dev: true - /source-map/0.7.4: + /source-map@0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} dev: true - /sourcemap-codec/1.4.8: + /sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead dev: true - /spawn-command/0.0.2-1: + /spawn-command@0.0.2-1: resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==} dev: true - /sprintf-js/1.0.3: + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true - /stack-utils/2.0.6: + /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 dev: true - /string-length/4.0.2: + /string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} dependencies: @@ -5112,7 +5162,7 @@ packages: strip-ansi: 6.0.1 dev: true - /string-width/4.2.3: + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} dependencies: @@ -5121,7 +5171,7 @@ packages: strip-ansi: 6.0.1 dev: true - /string.prototype.trimend/1.0.6: + /string.prototype.trimend@1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} dependencies: call-bind: 1.0.2 @@ -5129,7 +5179,7 @@ packages: es-abstract: 1.21.1 dev: true - /string.prototype.trimstart/1.0.6: + /string.prototype.trimstart@1.0.6: resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} dependencies: call-bind: 1.0.2 @@ -5137,55 +5187,55 @@ packages: es-abstract: 1.21.1 dev: true - /strip-ansi/6.0.1: + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 dev: true - /strip-bom/3.0.0: + /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} dev: true - /strip-bom/4.0.0: + /strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} dev: true - /strip-final-newline/2.0.0: + /strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} dev: true - /strip-json-comments/3.1.1: + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} dev: true - /supports-color/5.5.0: + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} dependencies: has-flag: 3.0.0 dev: true - /supports-color/7.2.0: + /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 dev: true - /supports-color/8.1.1: + /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} dependencies: has-flag: 4.0.0 dev: true - /supports-hyperlinks/2.3.0: + /supports-hyperlinks@2.3.0: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} engines: {node: '>=8'} dependencies: @@ -5193,16 +5243,16 @@ packages: supports-color: 7.2.0 dev: true - /supports-preserve-symlinks-flag/1.0.0: + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} dev: true - /symbol-tree/3.2.4: + /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true - /table/6.8.1: + /table@6.8.1: resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} engines: {node: '>=10.0.0'} dependencies: @@ -5213,7 +5263,7 @@ packages: strip-ansi: 6.0.1 dev: true - /terminal-link/2.1.1: + /terminal-link@2.1.1: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} dependencies: @@ -5221,7 +5271,7 @@ packages: supports-hyperlinks: 2.3.0 dev: true - /terser/5.16.5: + /terser@5.16.5: resolution: {integrity: sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==} engines: {node: '>=10'} hasBin: true @@ -5232,7 +5282,7 @@ packages: source-map-support: 0.5.21 dev: true - /test-exclude/6.0.0: + /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} dependencies: @@ -5241,38 +5291,38 @@ packages: minimatch: 3.1.2 dev: true - /text-table/0.2.0: + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true - /throat/6.0.2: + /throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} dev: true - /tiny-glob/0.2.9: + /tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} dependencies: globalyzer: 0.1.0 globrex: 0.1.2 dev: true - /tmpl/1.0.5: + /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true - /to-fast-properties/2.0.0: + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} dev: true - /to-regex-range/5.0.1: + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 dev: true - /tough-cookie/4.1.2: + /tough-cookie@4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} engines: {node: '>=6'} dependencies: @@ -5282,19 +5332,19 @@ packages: url-parse: 1.5.10 dev: true - /tr46/2.1.0: + /tr46@2.1.0: resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==} engines: {node: '>=8'} dependencies: punycode: 2.3.0 dev: true - /tree-kill/1.2.2: + /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true dev: true - /tsconfig-paths/3.14.2: + /tsconfig-paths@3.14.2: resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} dependencies: '@types/json5': 0.0.29 @@ -5303,54 +5353,54 @@ packages: strip-bom: 3.0.0 dev: true - /tslib/1.14.1: + /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /tslib/2.5.0: + /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} dev: true - /tsutils/3.21.0_typescript@4.9.5: + /tsutils@3.21.0(typescript@5.1.6): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.9.5 + typescript: 5.1.6 dev: true - /type-check/0.3.2: + /type-check@0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.1.2 dev: true - /type-check/0.4.0: + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 dev: true - /type-detect/4.0.8: + /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} dev: true - /type-fest/0.20.2: + /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} dev: true - /type-fest/0.21.3: + /type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} dev: true - /typed-array-length/1.0.4: + /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: call-bind: 1.0.2 @@ -5358,19 +5408,25 @@ packages: is-typed-array: 1.1.10 dev: true - /typedarray-to-buffer/3.1.5: + /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: is-typedarray: 1.0.0 dev: true - /typescript/4.9.5: + /typescript@4.9.5: resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true dev: true - /unbox-primitive/1.0.2: + /typescript@5.1.6: + resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: call-bind: 1.0.2 @@ -5379,12 +5435,12 @@ packages: which-boxed-primitive: 1.0.2 dev: true - /unicode-canonical-property-names-ecmascript/2.0.0: + /unicode-canonical-property-names-ecmascript@2.0.0: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} dev: true - /unicode-match-property-ecmascript/2.0.0: + /unicode-match-property-ecmascript@2.0.0: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} dependencies: @@ -5392,22 +5448,22 @@ packages: unicode-property-aliases-ecmascript: 2.1.0 dev: true - /unicode-match-property-value-ecmascript/2.1.0: + /unicode-match-property-value-ecmascript@2.1.0: resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} engines: {node: '>=4'} dev: true - /unicode-property-aliases-ecmascript/2.1.0: + /unicode-property-aliases-ecmascript@2.1.0: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} dev: true - /universalify/0.2.0: + /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} dev: true - /update-browserslist-db/1.0.10_browserslist@4.21.5: + /update-browserslist-db@1.0.10(browserslist@4.21.5): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true peerDependencies: @@ -5418,24 +5474,24 @@ packages: picocolors: 1.0.0 dev: true - /uri-js/4.4.1: + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 dev: true - /url-parse/1.5.10: + /url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} dependencies: querystringify: 2.2.0 requires-port: 1.0.0 dev: true - /v8-compile-cache/2.3.0: + /v8-compile-cache@2.3.0: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true - /v8-to-istanbul/8.1.1: + /v8-to-istanbul@8.1.1: resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==} engines: {node: '>=10.12.0'} dependencies: @@ -5444,47 +5500,47 @@ packages: source-map: 0.7.4 dev: true - /w3c-hr-time/1.0.2: + /w3c-hr-time@1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} deprecated: Use your platform's native performance.now() and performance.timeOrigin. dependencies: browser-process-hrtime: 1.0.0 dev: true - /w3c-xmlserializer/2.0.0: + /w3c-xmlserializer@2.0.0: resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==} engines: {node: '>=10'} dependencies: xml-name-validator: 3.0.0 dev: true - /walker/1.0.8: + /walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} dependencies: makeerror: 1.0.12 dev: true - /webidl-conversions/5.0.0: + /webidl-conversions@5.0.0: resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} engines: {node: '>=8'} dev: true - /webidl-conversions/6.1.0: + /webidl-conversions@6.1.0: resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==} engines: {node: '>=10.4'} dev: true - /whatwg-encoding/1.0.5: + /whatwg-encoding@1.0.5: resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} dependencies: iconv-lite: 0.4.24 dev: true - /whatwg-mimetype/2.3.0: + /whatwg-mimetype@2.3.0: resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} dev: true - /whatwg-url/8.7.0: + /whatwg-url@8.7.0: resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==} engines: {node: '>=10'} dependencies: @@ -5493,7 +5549,7 @@ packages: webidl-conversions: 6.1.0 dev: true - /which-boxed-primitive/1.0.2: + /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: is-bigint: 1.0.4 @@ -5503,7 +5559,7 @@ packages: is-symbol: 1.0.4 dev: true - /which-typed-array/1.1.9: + /which-typed-array@1.1.9: resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} engines: {node: '>= 0.4'} dependencies: @@ -5515,7 +5571,7 @@ packages: is-typed-array: 1.1.10 dev: true - /which/2.0.2: + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true @@ -5523,12 +5579,12 @@ packages: isexe: 2.0.0 dev: true - /word-wrap/1.2.3: + /word-wrap@1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} dev: true - /wrap-ansi/7.0.0: + /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} dependencies: @@ -5537,11 +5593,11 @@ packages: strip-ansi: 6.0.1 dev: true - /wrappy/1.0.2: + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /write-file-atomic/3.0.3: + /write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} dependencies: imurmurhash: 0.1.4 @@ -5550,7 +5606,7 @@ packages: typedarray-to-buffer: 3.1.5 dev: true - /ws/7.5.9: + /ws@7.5.9: resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} engines: {node: '>=8.3.0'} peerDependencies: @@ -5563,38 +5619,38 @@ packages: optional: true dev: true - /xml-name-validator/3.0.0: + /xml-name-validator@3.0.0: resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} dev: true - /xmlchars/2.2.0: + /xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true - /y18n/5.0.8: + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} dev: true - /yallist/3.1.1: + /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true - /yallist/4.0.0: + /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true - /yargs-parser/20.2.9: + /yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} dev: true - /yargs-parser/21.1.1: + /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} dev: true - /yargs/16.2.0: + /yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} dependencies: @@ -5607,7 +5663,7 @@ packages: yargs-parser: 20.2.9 dev: true - /yargs/17.7.1: + /yargs@17.7.1: resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} engines: {node: '>=12'} dependencies: From f4487f4899e7489bab24702000a86d10da98b461 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 11 Jul 2023 23:34:52 -0400 Subject: [PATCH 134/805] dont use reused --- packages/temporal-polyfill/src/new/options.ts | 14 +++++++------- packages/temporal-polyfill/src/new/utils.ts | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 6e6f74af..4ecbb5a1 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -15,7 +15,6 @@ import { roundHalfEven, roundHalfFloor, roundHalfTrunc, - Reused, } from './utils' import { ZonedDateTime } from './zonedDateTime' @@ -71,7 +70,7 @@ export function refineDiffOptions( Always related to time */ export function refineRoundOptions( - options: Options | undefined | Reused, + options: Options | undefined, maxUnit: DayTimeUnit = Unit.Day, ) { options = normalizeUnitNameOptions(options, smallestUnitStr) @@ -84,7 +83,7 @@ export function refineRoundOptions( } export function refineDurationRoundOptions( - options: Options | undefined | Reused, + options: Options | undefined, defaultLargestUnit: Unit ) { options = normalizeUnitNameOptions(options, smallestUnitStr) @@ -98,7 +97,7 @@ export function refineDurationRoundOptions( } export function refineTotalOptions( - options: Options | undefined | Reused + options: Options | undefined ) { options = normalizeUnitNameOptions(options, totalUnitStr) return [ @@ -112,7 +111,7 @@ export function refineRelativeToOptions(options: Options | undefined) { } export function refineInstantDisplayOptions( - options: Options | undefined | Reused + options: Options | undefined ) { options = normalizeOptions(options) return [ @@ -299,7 +298,7 @@ function invertRoundingMode(roundingMode: RoundingMode): RoundingMode { const roundingIncName = 'roundingIncrement' function refineRoundingInc(options: Options, smallestUnit: DayTimeUnit) { - let roundingInc = options[roundingIncName] as Reused + let roundingInc = options[roundingIncName] as number if (roundingInc === undefined) { return 1 } @@ -399,10 +398,11 @@ function refineChoiceOption( options: Options, defaultChoice = 0, ) { - const enumName = options[optionName] as Reused + const enumName = options[optionName] as string if (enumName === undefined) { return defaultChoice } + const enumNum = enumNameMap[enumName] if (enumNum < 0) { throw new RangeError('Must be one of the choices') diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index 42ee0ae3..7777b63c 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -1,7 +1,5 @@ import { Overflow } from './options' -export type Reused = any - const objectlikeRE = /object|function/ export function isObjectlike(arg: unknown): boolean { From 98cf870e05bbc48b3c8e64a35667ad7b506874ad Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 11 Jul 2023 23:44:37 -0400 Subject: [PATCH 135/805] better -1 --- packages/temporal-polyfill/src/new/options.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 4ecbb5a1..23bd7e1f 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -153,13 +153,13 @@ export type TimeDisplayTuple = [ ] function refineTimeDisplayTuple(options: Options): TimeDisplayTuple { - const smallestUnitI = refineSmallestUnit(options, Unit.Minute, Unit.Nanosecond, -1) - if (smallestUnitI !== -1) { + const smallestUnit = refineSmallestUnit(options, Unit.Minute, Unit.Nanosecond, -1 as number) + if ((smallestUnit as number) !== -1) { return [ - unitNanoMap[smallestUnitI], + unitNanoMap[smallestUnit], refineRoundingMode(options, RoundingMode.Trunc), - (smallestUnitI < Unit.Minute) - ? 9 - (smallestUnitI * 3) + (smallestUnit < Unit.Minute) + ? 9 - (smallestUnit * 3) : -1, // hide seconds ] } @@ -368,8 +368,8 @@ function refineUnitOption( options: Options, maxUnit: Unit = Unit.Year, minUnit: Unit = Unit.Nanosecond, - defaultUnit?: Unit | -1, -): Unit | -1 { + defaultUnit?: Unit, +): Unit { let unitName = options[optionName] if (unitName === undefined) { if (defaultUnit === undefined) { From ea6c9147a1326716cdeefad0b7d1f247ab9bbc74 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 11 Jul 2023 23:50:00 -0400 Subject: [PATCH 136/805] small fixes --- .../src/new/calendarFields.ts | 2 +- packages/temporal-polyfill/src/new/utils.ts | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index 113f9880..4141d6a5 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -268,7 +268,7 @@ export const dateTimeGetters = { export const timeFieldsToIso = remapProps.bind< any, [any, any], // bound - [IsoTimeFields], // unbound + [TimeFields], // unbound IsoTimeFields // return >(undefined, timeFieldNames, isoTimeFieldNames) diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index 7777b63c..a008c08e 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -55,7 +55,7 @@ export const mapPropNamesToIndex = mapPropNames.bind( export const mapPropNamesToConstant = mapPropNames.bind( undefined, - (propVal: any, i: number, extra: any) => extra, + (propVal: any, i: number, constant: any) => constant, ) as ( (propNames: (keyof P)[], c: C) => { [K in keyof P]: C } ) @@ -110,7 +110,7 @@ export const excludePropsByName = filterProps.bind( undefined, (propVal: any, propName: string, nameSet: any) => !nameSet.has(propName) ) as ( - (props: P, propNames: K[]) => Pick + (props: P, propNames: K[]) => Omit ) export const excludeUndefinedProps = filterProps.bind( @@ -144,15 +144,17 @@ export function hasAllPropsByName

( return true } -export function createLazyGenerator( - generator: (key: Key, ...otherArgs: OtherArgs) => Val, - MapClass: { new(): Map } = Map, -): (key: Key, ...otherArgs: OtherArgs) => Val { +export function createLazyGenerator( + generator: (key: K, ...otherArgs: A) => V, + MapClass: { new(): Map } = Map, +): ( + (key: K, ...otherArgs: A) => V +) { const map = new MapClass() - return (key: Key, ...otherArgs: OtherArgs) => { + return (key: K, ...otherArgs: A) => { if (map.has(key)) { - return map.get(key)! + return map.get(key) as V } else { const val = generator(key, ...otherArgs) map.set(key, val) From f883d82602d567d9cdca8aa6c28dbf4a08da3ee7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 16:18:39 -0400 Subject: [PATCH 137/805] more types, class.ts --- packages/temporal-polyfill/src/new/class.js | 171 ----------- packages/temporal-polyfill/src/new/class.ts | 279 ++++++++++++++++++ packages/temporal-polyfill/src/new/options.ts | 2 +- packages/temporal-polyfill/src/new/utils.ts | 36 ++- 4 files changed, 304 insertions(+), 184 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/class.js create mode 100644 packages/temporal-polyfill/src/new/class.ts diff --git a/packages/temporal-polyfill/src/new/class.js b/packages/temporal-polyfill/src/new/class.js deleted file mode 100644 index fc5d8ad7..00000000 --- a/packages/temporal-polyfill/src/new/class.js +++ /dev/null @@ -1,171 +0,0 @@ -import { DateTimeFormat } from './intlFormat' -import { ensureInstanceOf, toString } from './options' -import { - createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, - defineProps, - hasAllPropsByName, - identityFunc, - isObjectlike, - mapProps, - noop, -} from './utils' - -// Wrapper Class -// ------------------------------------------------------------------------------------------------- - -const internalsMap = new WeakMap() -export const getInternals = internalsMap.get.bind(internalsMap) - -export function createWrapperClass( - getters, - methods, - constructorToInternals = identityFunc, - extraPrototypeDescriptors = {}, - staticMembers = {}, - handleInstance = noop, -) { - function InternalObj(...args) { - internalsMap.set(this, constructorToInternals(...args)) - handleInstance(this) - } - - function curryMethod(method) { - return /* Object.setPrototypeOf( */ function(...args) { - if (!(this instanceof InternalObj)) { - throw new TypeError('Invalid receiver') - } - return method.call(this, getInternals(this), ...args) - } /* , null) */ - } - - Object.defineProperties(InternalObj.prototype, { - ...createGetterDescriptors(mapProps(curryMethod, getters)), - ...createPropDescriptors(mapProps(curryMethod, methods)), - ...extraPrototypeDescriptors, - }) - - defineProps(InternalObj, staticMembers) - - return InternalObj -} - -export function getStrictInternals(Class, res) { // rename: getInternalsStrict? - return getInternals(ensureInstanceOf(Class, res)) -} - -// Temporal Class -// ------------------------------------------------------------------------------------------------- - -const temporaNameMap = WeakMap() -export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) - -export function createTemporalClass( - temporalName, - constructorToInternals, - internalsConversionMap, - bagToInternals, - stringToInternals, - handleUnusedOptions, - getters, - methods, - staticMembers = {}, -) { - methods.toJSON = function() { - return String(this) - } - staticMembers.from = function(arg, options) { - return createInstance(toInternals(arg, options)) - } - - const TemporalObj = createWrapperClass( - getters, - methods, - constructorToInternals, - createTemporalNameDescriptors(temporalName), // extraPrototypeDescriptors - staticMembers, - setTemporalName, // handleInstance - ) - - function createInstance(internals) { - const instance = Object.create(TemporalObj.prototype) - internalsMap.set(instance, internals) - setTemporalName(instance) - return instance - } - - function toInternals(arg, options) { - let argInternals = getInternals(arg) - const argTemporalName = getTemporalName(arg) - - if (argInternals && argTemporalName !== temporalName) { - argInternals = (internalsConversionMap[argTemporalName] || noop)(argInternals) - } - - return (!argInternals && isObjectlike(arg) && bagToInternals(arg, options)) || - (handleUnusedOptions(options), argInternals || stringToInternals(toString(arg))) - } - - function setTemporalName(instance) { - temporaNameMap.set(instance, temporalName) - } - - return [TemporalObj, createInstance, toInternals] -} - -// Utils for Specific Classes -// ------------------------------------------------------------------------------------------------- - -export function toLocaleStringMethod(internals, locales, options) { - /* - Will create two internal Intl.DateTimeFormats :( - Create just one instead - */ - const format = new DateTimeFormat(locales, options) - return format.format(this) -} - -export function neverValueOf() { - throw new TypeError('Cannot convert object using valueOf') -} - -// Complex Objects with IDs -// ------------------------------------------------------------------------------------------------- - -export function createProtocolChecker(protocolMethods) { - const propNames = Object.keys(protocolMethods) - propNames.push('id') - propNames.sort() // TODO: order matters? - - return (obj) => { - if (!hasAllPropsByName(obj, propNames)) { - throw new TypeError('Invalid protocol') - } - } -} - -export function getCommonInnerObj(propName, obj0, obj1) { - const internal0 = obj0[propName] - const internal1 = obj1[propName] - - if (!isObjIdsEqual(internal0, internal1)) { - throw new TypeError(`${propName} not equal`) - } - - return internal0 -} - -export function isObjIdsEqual(obj0, obj1) { - return obj0 === obj1 || // short-circuit - obj0.id === obj1.id // .id could be getter with logic / side-effects (during testing) -} - -export function getObjId(internals) { - return internals.id -} - -function getObjIdStrict(internals) { - return toString(internals.id) -} - -export const idGetters = { id: getObjId } -export const idGettersStrict = { id: getObjIdStrict } diff --git a/packages/temporal-polyfill/src/new/class.ts b/packages/temporal-polyfill/src/new/class.ts new file mode 100644 index 00000000..0e9e3bce --- /dev/null +++ b/packages/temporal-polyfill/src/new/class.ts @@ -0,0 +1,279 @@ +import { DateTimeFormat } from './intlFormat' +import { ensureInstanceOf, ensureString, toString } from './options' +import { + createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, + defineProps, + hasAllPropsByName, + identityFunc, + isObjectlike, + mapProps, + noop, +} from './utils' + +type NonInternalArgs = + F extends (internals: I, ...otherArgs: infer A) => unknown + ? A + : never + +type PropertyDescriptorType = + D extends { value: infer V } + ? V + : D extends { get: () => infer R } + ? R + : never + +type WrapperClass< + A extends [unknown], + I, + G extends { [propName: string]: (internals: I) => unknown }, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + P extends PropertyDescriptorMap, + S extends {}, +> = { new(...args: A): WrapperInstance } & S + +type WrapperInstance< + I, + G extends { [propName: string]: (internals: I) => unknown }, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + P extends PropertyDescriptorMap = {}, +> = { [K in keyof G]: ReturnType } + & { [K in keyof M]: (...args: NonInternalArgs) => ReturnType } + & { [K in keyof P]: PropertyDescriptorType } + +// Wrapper Class +// ------------------------------------------------------------------------------------------------- + +const internalsMap = new WeakMap, unknown>() + +export const getInternals = internalsMap.get.bind(internalsMap) as + (inst: T) => T extends WrapperInstance ? I : undefined + +export function createWrapperClass< + A extends [any], // TODO: rename to C + I, + G extends { [propName: string]: (internals: I) => unknown }, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + P extends PropertyDescriptorMap, + S extends {}, +>( + getters: G, + methods: M, + constructorToInternals: (...args: A) => I = identityFunc, + extraPrototypeDescriptors: P | {} = {}, + staticMembers: S | {} = {}, + handleInstance: (inst: WrapperInstance) => void = noop, +): ( + WrapperClass +) { + function InternalObj(this: WrapperInstance, ...args: A) { + internalsMap.set(this, constructorToInternals(...args)) + handleInstance(this) + } + + function curryMethod( + method: (internals: I, ...args: AX) => R + ) { + return /* Object.setPrototypeOf( */ function( + this: WrapperInstance, + ...args: AX + ): R { + if (!(this instanceof InternalObj)) { + throw new TypeError('Invalid receiver') + } + return method.call(this, getInternals(this) as I, ...args) + } /* , null) */ + } + + Object.defineProperties(InternalObj.prototype, { + ...createGetterDescriptors(mapProps(curryMethod, getters)), + ...createPropDescriptors(mapProps(curryMethod, methods)), + ...extraPrototypeDescriptors, + }) + + defineProps(InternalObj, staticMembers) + + return InternalObj as any +} + +export function getStrictInternals( // rename: getInternalsStrict? + Class: { new(): T }, + arg: T +): ( + T extends WrapperInstance ? I : undefined +) { + return getInternals(ensureInstanceOf(Class, arg)) +} + +// Temporal Class +// ------------------------------------------------------------------------------------------------- + +type TemporalClass< + A extends [any], + I, + O, + G extends { [propName: string]: (internals: I) => unknown }, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + S extends {}, +> = { new(...args: A): WrapperInstance } + & S + & FromMethods + +interface ToJsonMethods { + toJSON: () => string +} + +type TemporalArg = TemporalInstance | Record | string + +interface FromMethods { + from: (arg: TemporalArg, options: O) => void +} + +type TemporalInstance< + I, + G extends { [propName: string]: (internals: I) => unknown }, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, +> = WrapperInstance< + I, + G, + M & ToJsonMethods +> & { [Symbol.toStringTag]: string } + +const temporaNameMap = new WeakMap, string>() + +export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) as + (arg: unknown) => string | undefined + +export function createTemporalClass< + A extends [any], + I, + O, + G extends { [propName: string]: (internals: I) => unknown }, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + S extends {}, +>( + temporalName: string, + constructorToInternals: (...args: A) => I = identityFunc, + internalsConversionMap: { [typeName: string]: (otherInternal: unknown) => I }, + bagToInternals: (bag: Record, options: O) => I, + stringToInternals: (str: string) => I, + handleUnusedOptions: (options: O) => void, + getters: G, + methods: M, + staticMembers: S | {} = {}, +): [ + Class: TemporalClass, + createInstance: (internals: I) => TemporalInstance, + toInternals: (arg: TemporalArg, options: O) => I +] { + ;(methods as unknown as ToJsonMethods).toJSON = function() { + return String(this) + } + + ;(staticMembers as FromMethods).from = function(arg: TemporalArg, options: O) { + return createInstance(toInternals(arg, options)) + } + + const TemporalClass = createWrapperClass( + getters, + methods, + constructorToInternals, + createTemporalNameDescriptors(temporalName), // extraPrototypeDescriptors + staticMembers, + setTemporalName, // handleInstance + ) + + function createInstance(internals: I) { + const instance: TemporalInstance = Object.create(TemporalClass.prototype) + internalsMap.set(instance, internals) + setTemporalName(instance) + return instance + } + + function toInternals(arg: TemporalArg, options: O): I { + let argInternals = getInternals(arg) + let argTemporalName + + if (argInternals && (argTemporalName = getTemporalName(arg)) !== temporalName) { + argInternals = (internalsConversionMap[argTemporalName!] || noop)(argInternals) + } + + return (!argInternals && isObjectlike(arg) && bagToInternals(arg, options)) || + (handleUnusedOptions(options), (argInternals as I) || stringToInternals(toString(arg))) + } + + function setTemporalName(instance: TemporalInstance) { + temporaNameMap.set(instance, temporalName) + } + + return [TemporalClass as any, createInstance, toInternals] +} + +// Utils for Specific Classes +// ------------------------------------------------------------------------------------------------- + +export function toLocaleStringMethod( + this: any, // !!! + internals: unknown, + locales: string | string[], + options: Intl.DateTimeFormatOptions, +) { + /* + Will create two internal Intl.DateTimeFormats :( + Create just one instead + */ + const format = new DateTimeFormat(locales, options) + return format.format(this) +} + +export function neverValueOf() { + throw new TypeError('Cannot convert object using valueOf') +} + +// Complex Objects with IDs +// ------------------------------------------------------------------------------------------------- + +export function createProtocolChecker(protocolMethods: Record unknown>) { + const propNames = Object.keys(protocolMethods) + propNames.push('id') + propNames.sort() // TODO: order matters? + + return (obj: Record) => { + if (!hasAllPropsByName(obj, propNames)) { + throw new TypeError('Invalid protocol') + } + } +} + +export function getCommonInnerObj( + propName: string, + obj0: Record, + obj1: Record, +) { + const internal0 = obj0[propName] as { id: string } + const internal1 = obj1[propName] as { id: string } + + if (!isObjIdsEqual(internal0, internal1)) { + throw new TypeError(`${propName} not equal`) + } + + return internal0 +} + +export function isObjIdsEqual( + obj0: { id: string }, + obj1: { id: string } +): boolean { + return obj0 === obj1 || // short-circuit + obj0.id === obj1.id // .id could be getter with logic / side-effects (during testing) +} + +export function getObjId(obj: { id: string }): string { + return obj.id +} + +function getObjIdStrict(obj: { id: string }): string { + return ensureString(obj.id) +} + +export const idGetters = { id: getObjId } +export const idGettersStrict = { id: getObjIdStrict } diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 23bd7e1f..57c4faaa 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -456,7 +456,7 @@ export function clampProp( // Primitives // ------------------------------------------------------------------------------------------------- -export function ensureInstanceOf(Class: any, obj: O): O { +export function ensureInstanceOf(Class: { new(): T }, obj: T): T { if (!(obj instanceof Class)) { throw new TypeError('Must be certain type') // TODO: show Class's symbol? } diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index a008c08e..702a2a40 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -2,7 +2,7 @@ import { Overflow } from './options' const objectlikeRE = /object|function/ -export function isObjectlike(arg: unknown): boolean { +export function isObjectlike(arg: unknown): arg is Record { return arg !== null && objectlikeRE.test(typeof arg) } @@ -55,7 +55,7 @@ export const mapPropNamesToIndex = mapPropNames.bind( export const mapPropNamesToConstant = mapPropNames.bind( undefined, - (propVal: any, i: number, constant: any) => constant, + (propVal: unknown, i: number, constant: unknown) => constant, ) as ( (propNames: (keyof P)[], c: C) => { [K in keyof P]: C } ) @@ -106,17 +106,23 @@ function filterProps( return filteredProps } -export const excludePropsByName = filterProps.bind( - undefined, - (propVal: any, propName: string, nameSet: any) => !nameSet.has(propName) -) as ( - (props: P, propNames: K[]) => Omit +export const excludePropsByName = filterProps.bind< + any, [any], [any, Set], any +>(undefined, ( + propVal: unknown, + propName: string, + nameSet: Set +) => { + return !nameSet.has(propName) +}) as ( + (props: P, propNames: Set) => Omit ) -export const excludeUndefinedProps = filterProps.bind( - undefined, - (propVal: any) => propVal !== undefined, -) as ( +export const excludeUndefinedProps = filterProps.bind(undefined, ( + propVal: unknown +) => { + return propVal !== undefined +}) as (

(props: P) => Partial

) @@ -192,7 +198,13 @@ export function createGetterDescriptors( }), getters) } -export function createTemporalNameDescriptors(temporalName: string): PropertyDescriptorMap { +export function createTemporalNameDescriptors(temporalName: string): { + // crazy + [Symbol.toStringTag]: { + value: string, + configurable: true, + }, +} { return { [Symbol.toStringTag]: { value: 'Temporal.' + temporalName, From 446c169de268c3980d11281a7e4f68d2237b5d99 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 18:31:04 -0400 Subject: [PATCH 138/805] lots of ts conversion --- packages/temporal-polyfill/src/new/class.ts | 35 +++--- .../src/new/{convert.js => convert.ts} | 4 +- .../src/new/{duration.js => duration.ts} | 110 +++++++++--------- .../src/new/durationFields.ts | 4 +- .../src/new/{instant.js => instant.ts} | 65 ++++++----- .../src/new/{isoParse.js => isoParse.ts} | 4 +- .../temporal-polyfill/src/new/timeZone.js | 8 +- 7 files changed, 124 insertions(+), 106 deletions(-) rename packages/temporal-polyfill/src/new/{convert.js => convert.ts} (99%) rename packages/temporal-polyfill/src/new/{duration.js => duration.ts} (70%) rename packages/temporal-polyfill/src/new/{instant.js => instant.ts} (69%) rename packages/temporal-polyfill/src/new/{isoParse.js => isoParse.ts} (98%) diff --git a/packages/temporal-polyfill/src/new/class.ts b/packages/temporal-polyfill/src/new/class.ts index 0e9e3bce..ed5f9b8d 100644 --- a/packages/temporal-polyfill/src/new/class.ts +++ b/packages/temporal-polyfill/src/new/class.ts @@ -33,20 +33,21 @@ type WrapperClass< type WrapperInstance< I, - G extends { [propName: string]: (internals: I) => unknown }, - M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + G extends { [propName: string]: (internals: I) => unknown } = {}, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown } = {}, P extends PropertyDescriptorMap = {}, > = { [K in keyof G]: ReturnType } & { [K in keyof M]: (...args: NonInternalArgs) => ReturnType } & { [K in keyof P]: PropertyDescriptorType } + & { __internals__: I } // HACK for inference // Wrapper Class // ------------------------------------------------------------------------------------------------- -const internalsMap = new WeakMap, unknown>() +const internalsMap = new WeakMap, unknown>() export const getInternals = internalsMap.get.bind(internalsMap) as - (inst: T) => T extends WrapperInstance ? I : undefined + (inst: T) => T extends WrapperInstance ? I : undefined export function createWrapperClass< A extends [any], // TODO: rename to C @@ -99,7 +100,7 @@ export function getStrictInternals( // rename: getInternalsStrict? Class: { new(): T }, arg: T ): ( - T extends WrapperInstance ? I : undefined + T extends WrapperInstance ? I : undefined ) { return getInternals(ensureInstanceOf(Class, arg)) } @@ -114,7 +115,7 @@ type TemporalClass< G extends { [propName: string]: (internals: I) => unknown }, M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, S extends {}, -> = { new(...args: A): WrapperInstance } +> = { new(...args: A): TemporalInstance } & S & FromMethods @@ -122,23 +123,23 @@ interface ToJsonMethods { toJSON: () => string } -type TemporalArg = TemporalInstance | Record | string +type TemporalArg = TemporalInstance | Record | string -interface FromMethods { +export interface FromMethods { from: (arg: TemporalArg, options: O) => void } -type TemporalInstance< +export type TemporalInstance< I, - G extends { [propName: string]: (internals: I) => unknown }, - M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + G extends { [propName: string]: (internals: I) => unknown } = {}, + M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown } = {}, > = WrapperInstance< I, G, M & ToJsonMethods > & { [Symbol.toStringTag]: string } -const temporaNameMap = new WeakMap, string>() +const temporaNameMap = new WeakMap, string>() export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) as (arg: unknown) => string | undefined @@ -149,21 +150,21 @@ export function createTemporalClass< O, G extends { [propName: string]: (internals: I) => unknown }, M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, - S extends {}, + S extends {} >( temporalName: string, constructorToInternals: (...args: A) => I = identityFunc, internalsConversionMap: { [typeName: string]: (otherInternal: unknown) => I }, - bagToInternals: (bag: Record, options: O) => I, + bagToInternals: (bag: Record, options?: O) => I, stringToInternals: (str: string) => I, - handleUnusedOptions: (options: O) => void, + handleUnusedOptions: (options?: O) => void, getters: G, methods: M, staticMembers: S | {} = {}, ): [ Class: TemporalClass, createInstance: (internals: I) => TemporalInstance, - toInternals: (arg: TemporalArg, options: O) => I + toInternals: (arg: TemporalArg, options?: O) => I ] { ;(methods as unknown as ToJsonMethods).toJSON = function() { return String(this) @@ -189,7 +190,7 @@ export function createTemporalClass< return instance } - function toInternals(arg: TemporalArg, options: O): I { + function toInternals(arg: TemporalArg, options?: O): I { let argInternals = getInternals(arg) let argTemporalName diff --git a/packages/temporal-polyfill/src/new/convert.js b/packages/temporal-polyfill/src/new/convert.ts similarity index 99% rename from packages/temporal-polyfill/src/new/convert.js rename to packages/temporal-polyfill/src/new/convert.ts index 6516bbba..92a27656 100644 --- a/packages/temporal-polyfill/src/new/convert.js +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -20,6 +20,8 @@ import { queryCalendarImpl } from './calendarImpl' import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { + DurationFields, + DurationInternals, durationFieldNames, durationFieldRefiners, updateDurationFieldsSign, @@ -343,7 +345,7 @@ function refineTimeFields(fields, overflow) { // Duration // ------------------------------------------------------------------------------------------------- -export function refineDurationBag(bag) { +export function refineDurationBag(bag: Partial): DurationInternals { const durationFields = refineFields(bag, durationFieldNames, []) return updateDurationFieldsSign(durationFields) } diff --git a/packages/temporal-polyfill/src/new/duration.js b/packages/temporal-polyfill/src/new/duration.ts similarity index 70% rename from packages/temporal-polyfill/src/new/duration.js rename to packages/temporal-polyfill/src/new/duration.ts index 6a5a6834..8e70dec4 100644 --- a/packages/temporal-polyfill/src/new/duration.js +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -1,4 +1,4 @@ -import { createTemporalClass, neverValueOf } from './class' +import { TemporalInstance, createTemporalClass, neverValueOf } from './class' import { mergeDurationBag, refineDurationBag } from './convert' import { diffZonedEpochNano } from './diff' import { @@ -8,6 +8,8 @@ import { durationGetters, negateDurationInternals, refineDurationFields, + DurationInternals, + DurationFields } from './durationFields' import { formatDurationInternals } from './isoFormat' import { isoToEpochNano } from './isoMath' @@ -27,14 +29,12 @@ import { totalDayTimeDuration, totalRelativeDuration, } from './round' -import { dayIndex } from './units' import { identityFunc, noop } from './utils' +import { Unit } from './units' -export const [ - Duration, - createDuration, - toDurationInternals, -] = createTemporalClass( +export type Duration = TemporalInstance +export type DurationArg = Duration | Partial | string +export const [Duration, createDuration, toDurationInternals] = createTemporalClass( 'Duration', // Creation @@ -42,16 +42,16 @@ export const [ // constructorToInternals ( - years = 0, - months = 0, - weeks = 0, - days = 0, - hours = 0, - minutes = 0, - seconds = 0, - milliseconds = 0, - microseconds = 0, - nanoseconds = 0, + years: number = 0, + months: number = 0, + weeks: number = 0, + days: number = 0, + hours: number = 0, + minutes: number = 0, + seconds: number = 0, + milliseconds: number = 0, + microseconds: number = 0, + nanoseconds: number = 0, ) => { return refineDurationFields({ years, @@ -85,7 +85,7 @@ export const [ { ...durationGetters, - blank(internals) { + blank(internals: DurationInternals): boolean { return !internals.sign }, }, @@ -94,35 +94,35 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with: mergeDurationBag, + with: mergeDurationBag, // TODO: wrong type!!! add: addToDuration.bind(undefined, 1), subtract: addToDuration.bind(undefined, -1), - negated(internals) { + negated(internals: DurationInternals): Duration { return createDuration(negateDurationInternals(internals)) }, - abs(internals) { + abs(internals: DurationInternals): Duration { return createDuration(absDurationInternals(internals)) }, - round(internals, options) { + round(internals: DurationInternals, options): Duration { const [ - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + largestUnit, + smallestUnit, + roundingInc, roundingMode, markerInternals, ] = refineDurationRoundOptions(options, getLargestDurationUnit(internals)) // TODO: move to round.js? - if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { + if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { // TODO: check internals doesn't have large fields return createDuration( - roundDayTimeDuration(internals, smallestUnitIndex, roundingIncrement, roundingMode), + roundDayTimeDuration(internals, smallestUnit, roundingInc, roundingMode), ) } @@ -130,25 +130,25 @@ export const [ throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnitIndex) + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) return createDuration( roundRelativeDuration( - ...spanDuration(internals, largestUnitIndex, ...markerSystem), - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + ...spanDuration(internals, largestUnit, ...markerSystem), + largestUnit, + smallestUnit, + roundingInc, roundingMode, ...markerSystem, ), ) }, - total(internals, options) { + total(internals: DurationInternals, options): number { const [totalUnitIndex, markerInternals] = refineTotalOptions(options) - const largestUnitIndex = getLargestDurationUnit(internals) + const largestUnit = getLargestDurationUnit(internals) - if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { + if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { return totalDayTimeDuration(internals, totalUnitIndex) } @@ -156,16 +156,16 @@ export const [ throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnitIndex) + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) return totalRelativeDuration( - ...spanDuration(internals, largestUnitIndex, ...markerSystem), + ...spanDuration(internals, largestUnit, ...markerSystem), totalUnitIndex, ...markerSystem, ) }, - toString(internals, options) { + toString(internals: DurationInternals, options): string { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatDurationInternals( @@ -181,16 +181,16 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(durationArg0, durationArg1, options) { + compare(durationArg0: DurationArg, durationArg1: DurationArg, options) { const durationFields0 = toDurationInternals(durationArg0) const durationFields1 = toDurationInternals(durationArg1) const markerInternals = refineRelativeToOptions(options) - const largestUnitIndex = Math.max( + const largestUnit = Math.max( getLargestDurationUnit(durationFields0), getLargestDurationUnit(durationFields1), ) - if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { + if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { return compareLargeInts( durationFieldsToNano(durationFields0), durationFieldsToNano(durationFields1), @@ -214,22 +214,27 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -function addToDuration(direction, internals, otherArg, options) { +function addToDuration( + direction: -1 | 1, + internals: DurationInternals, + otherArg: DurationArg, + options: any, // !!! +): Duration { const otherFields = toDurationInternals(otherArg) const markerInternals = refineRelativeToOptions(options) // optional - const largestUnitIndex = Math.max( + const largestUnit = Math.max( getLargestDurationUnit(internals), getLargestDurationUnit(otherFields), - ) + ) as Unit const addedDurationFields = addDurationFields(internals, otherFields, direction) - if (largestUnitIndex < dayIndex || (largestUnitIndex === dayIndex && !markerInternals)) { + if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { return balanceDurationDayTime(addedDurationFields) } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnitIndex) - return spanDuration(internals, largestUnitIndex, ...markerSystem)[0] + const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + return spanDuration(internals, largestUnit, ...markerSystem)[0] } function createMarkerSystem(markerInternals) { @@ -253,8 +258,8 @@ function createMarkerSystem(markerInternals) { } function spanDuration( - durationFields, - largestUnitIndex, + durationFields: DurationFields, + largestUnit: Unit, // TODO: more descrimination? // marker system... marker, markerToEpochNano, @@ -262,17 +267,18 @@ function spanDuration( diffMarkers, ) { const endMarker = markerToEpochNano(moveMarker(marker, durationFields)) - const balancedDuration = diffMarkers(marker, endMarker, largestUnitIndex) + const balancedDuration = diffMarkers(marker, endMarker, largestUnit) return [balancedDuration, endMarker] } function balanceDurationDayTime( durationFields, - largestUnitIndex, // day/time + largestUnit, // day/time ) { + // TODO } -function getLargestDurationUnit(durationFields) { +function getLargestDurationUnit(fields: DurationFields): Unit { // TODO: rename to getLargestDurationUnitIndex // TODO: move to DurationFields math } diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts index 25e1b8a3..7cb79573 100644 --- a/packages/temporal-polyfill/src/new/durationFields.ts +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -36,7 +36,7 @@ interface DurationTimeFields { export type DurationFields = DurationDateFields & DurationTimeFields -interface DurationInternals extends DurationFields { +export interface DurationInternals extends DurationFields { sign: NumSign } @@ -93,7 +93,7 @@ export const durationGetters = mapPropNames((propName: keyof DurationInternals) export function refineDurationFields( rawFields: DurationFields, -): DurationFields { +): DurationInternals { return updateDurationFieldsSign( mapProps(toIntegerStrict, rawFields), ) diff --git a/packages/temporal-polyfill/src/new/instant.js b/packages/temporal-polyfill/src/new/instant.ts similarity index 69% rename from packages/temporal-polyfill/src/new/instant.js rename to packages/temporal-polyfill/src/new/instant.ts index afcacc8b..25a8a387 100644 --- a/packages/temporal-polyfill/src/new/instant.js +++ b/packages/temporal-polyfill/src/new/instant.ts @@ -1,8 +1,8 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' -import { createTemporalClass, neverValueOf } from './class' +import { TemporalInstance, createTemporalClass, neverValueOf } from './class' import { diffEpochNano } from './diff' -import { createDuration, toDurationInternals } from './duration' +import { Duration, createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { formatIsoDateTimeFields, formatOffsetNano } from './isoFormat' import { @@ -14,7 +14,7 @@ import { checkEpochNano, } from './isoMath' import { parseInstant } from './isoParse' -import { compareLargeInts } from './largeInt' +import { LargeInt, compareLargeInts } from './largeInt' import { moveEpochNano } from './move' import { ensureObjectlike, @@ -25,14 +25,15 @@ import { } from './options' import { computeNanoInc, roundByIncLarge } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' -import { hourIndex, secondsIndex } from './units' import { noop } from './utils' import { createZonedDateTime } from './zonedDateTime' +import { Unit } from './units' +export type Instant = TemporalInstance export const [ Instant, createInstant, - toInstantEpochNanoseconds, + toInstantEpochNano, ] = createTemporalClass( 'Instant', @@ -40,8 +41,8 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (epochNanoseconds) => { - return checkEpochNano(toEpochNano(epochNanoseconds)) + (epochNano: LargeInt) => { + return checkEpochNano(toEpochNano(epochNano)) }, // internalsConversionMap @@ -67,7 +68,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - toZonedDateTimeISO(epochNanoseconds, timeZoneArg) { + toZonedDateTimeISO(epochNanoseconds, timeZoneArg): any { // TODO!!! createZonedDateTime({ epochNanoseconds, timeZone: queryTimeZoneOps(timeZoneArg), @@ -75,7 +76,7 @@ export const [ }) }, - toZonedDateTime(epochNanoseconds, options) { + toZonedDateTime(epochNanoseconds, options): any { // TODO!!! const refinedObj = ensureObjectlike(options) return createZonedDateTime({ @@ -85,7 +86,7 @@ export const [ }) }, - add(epochNanoseconds, durationArg) { + add(epochNanoseconds, durationArg): Instant { return createInstant( moveEpochNano( epochNanoseconds, @@ -94,7 +95,7 @@ export const [ ) }, - subtract(epochNanoseconds, durationArg) { + subtract(epochNanoseconds, durationArg): Instant { return createInstant( moveEpochNano( epochNanoseconds, @@ -103,30 +104,30 @@ export const [ ) }, - until(epochNanoseconds, otherArg, options) { - return diffInstants(epochNanoseconds, toInstantEpochNanoseconds(otherArg), options) + until(epochNanoseconds, otherArg, options): Duration { + return diffInstants(epochNanoseconds, toInstantEpochNano(otherArg), options) }, - since(epochNanoseconds, otherArg, options) { - return diffInstants(toInstantEpochNanoseconds(otherArg), epochNanoseconds, options, true) + since(epochNanoseconds, otherArg, options): Duration { + return diffInstants(toInstantEpochNano(otherArg), epochNanoseconds, options, true) }, - round(epochNano, options) { - const [smallestUnitI, roundingInc, roundingModeI] = refineRoundOptions(options, hourIndex) + round(epochNano, options): Instant { + const [smallestUnitI, roundingInc, roundingModeI] = refineRoundOptions(options, Unit.Hour) return createInstant( roundByIncLarge(epochNano, computeNanoInc(smallestUnitI, roundingInc), roundingModeI), ) }, - equals(epochNanoseconds, otherArg) { + equals(epochNanoseconds, otherArg): boolean { return !compareLargeInts( epochNanoseconds, - toInstantEpochNanoseconds(otherArg), + toInstantEpochNano(otherArg), ) }, - toString(epochNano, options) { + toString(epochNano: LargeInt, options): string { const [ timeZoneArg, nanoInc, @@ -143,7 +144,8 @@ export const [ formatOffsetNano(offsetNano) }, - toLocaleString(epochNanoseconds, locales, options) { + toLocaleString(epochNano: LargeInt, locales: string | string[], options): string { + // TODO return '' }, @@ -158,17 +160,22 @@ export const [ fromEpochMilliseconds: epochMilliToInstant, - fromEpochMicroseconds(epochMicro) { + fromEpochMicroseconds(epochMicro: LargeInt) { return epochMicroToInstant(toEpochNano(epochMicro)) }, - fromEpochNanoseconds(epochNanoseconds) { - return createInstant(toEpochNano(epochNanoseconds)) + fromEpochNanoseconds(epochNano: LargeInt) { + return createInstant(toEpochNano(epochNano)) }, }, ) -function diffInstants(epochNano0, epochNano1, options, roundingModeInvert) { +function diffInstants( + epochNano0: LargeInt, + epochNano1: LargeInt, + options, + roundingModeInvert?: boolean +): Duration { return createDuration( diffEpochNano( epochNano0, @@ -181,21 +188,21 @@ function diffInstants(epochNano0, epochNano1, options, roundingModeInvert) { // Unit Conversion // ------------------------------------------------------------------------------------------------- -function epochSecToInstant(epochSec) { +function epochSecToInstant(epochSec: number): Instant { return createInstant(epochSecToNano(epochSec)) } -function epochMilliToInstant(epochMilli) { +function epochMilliToInstant(epochMilli: number): Instant { return createInstant(epochMilliToNano(epochMilli)) } -function epochMicroToInstant(epochMicro) { +function epochMicroToInstant(epochMicro: LargeInt): Instant { return createInstant(epochMicroToNano(epochMicro)) } // Legacy Date // ------------------------------------------------------------------------------------------------- -export function toTemporalInstant() { +export function toTemporalInstant(this: Date) { return epochMilliToInstant(this.valueOf()) } diff --git a/packages/temporal-polyfill/src/new/isoParse.js b/packages/temporal-polyfill/src/new/isoParse.ts similarity index 98% rename from packages/temporal-polyfill/src/new/isoParse.js rename to packages/temporal-polyfill/src/new/isoParse.ts index 6b094665..347f4b08 100644 --- a/packages/temporal-polyfill/src/new/isoParse.js +++ b/packages/temporal-polyfill/src/new/isoParse.ts @@ -2,6 +2,7 @@ import { nanoIn, nanoInSecond } from '../dateUtils/units' import { isoCalendarId } from './calendarConfig' import { queryCalendarImpl } from './calendarImpl' import { + DurationInternals, durationFieldNamesAsc, negateDurationFields, updateDurationFieldsSign, @@ -210,7 +211,8 @@ export function parseOffsetNano(s) { return parts && parseOffsetParts(parts.slice(1)) } -export function parseDuration(s) { +// TODO: this should be guaranteed result +export function parseDuration(s: string): DurationInternals { const parts = durationRegExp.exec(s) return parts && parseDurationParts(parts) } diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js index b43aed54..c4351786 100644 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ b/packages/temporal-polyfill/src/new/timeZone.js @@ -3,7 +3,7 @@ import { Calendar } from './calendar' import { queryCalendarOps } from './calendarOps' import { createTemporalClass, getObjId, idGetters } from './class' import { refineComplexBag } from './convert' -import { createInstant, toInstantEpochNanoseconds } from './instant' +import { createInstant, toInstantEpochNano } from './instant' import { formatOffsetNano } from './isoFormat' import { parseTimeZoneId } from './isoParse' import { refineEpochDisambigOptions } from './options' @@ -57,7 +57,7 @@ export const [TimeZone, createTimeZone] = createTemporalClass( }, getPlainDateTimeFor(impl, instantArg, calendarArg) { - const epochNanoseconds = toInstantEpochNanoseconds(instantArg) + const epochNanoseconds = toInstantEpochNano(instantArg) return createPlainDateTime({ calendar: queryCalendarOps(calendarArg), @@ -82,10 +82,10 @@ export const [TimeZone, createTimeZone] = createTemporalClass( ) function getImplOffsetNanosecondsFor(impl, instantArg) { - return impl.getOffsetNanosecondsFor(toInstantEpochNanoseconds(instantArg)) + return impl.getOffsetNanosecondsFor(toInstantEpochNano(instantArg)) } function getImplTransition(direction, impl, instantArg) { - const epochNano = impl.getTransition(toInstantEpochNanoseconds(instantArg), direction) + const epochNano = impl.getTransition(toInstantEpochNano(instantArg), direction) return epochNano ? createInstant(epochNano) : null } From 390664fbf3ef13bc134bacba1d53bf77f95fb8b9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 19:48:50 -0400 Subject: [PATCH 139/805] more conversion --- .../src/new/calendarFields.ts | 22 +++---- .../new/{calendarOps.js => calendarOps.ts} | 5 +- packages/temporal-polyfill/src/new/class.ts | 40 +++++++------ .../temporal-polyfill/src/new/duration.ts | 2 +- packages/temporal-polyfill/src/new/options.ts | 2 +- .../src/new/{plainDate.js => plainDate.ts} | 57 +++++++++++-------- 6 files changed, 73 insertions(+), 55 deletions(-) rename packages/temporal-polyfill/src/new/{calendarOps.js => calendarOps.ts} (93%) rename packages/temporal-polyfill/src/new/{plainDate.js => plainDate.ts} (70%) diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index 4141d6a5..6c117d53 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -8,25 +8,25 @@ import { import { ensureBoolean, ensureInteger, toInteger, toString } from './options' import { mapPropNames, mapPropNamesToConstant, remapProps } from './utils' -interface EraYearFields { +export interface EraYearFields { era: string eraYear: number } -interface AllYearFields extends EraYearFields { +export interface AllYearFields extends EraYearFields { year: number } -interface MonthFields { +export interface MonthFields { monthCode: string month: number } type YearMonthFields = { year: number } & MonthFields -type DateFields = YearMonthFields & { day: number } +export type DateFields = YearMonthFields & { day: number } type MonthDayFields = MonthFields & { day: number } -interface TimeFields { +export interface TimeFields { hour: number microsecond: number millisecond: number @@ -37,33 +37,33 @@ interface TimeFields { type DateTimeFields = DateFields & TimeFields -interface DateBasics { +export interface DateBasics { year: number month: number day: number } -interface YearMonthBasics { +export interface YearMonthBasics { year: number month: number } -interface MonthDayBasics { +export interface MonthDayBasics { monthCode: string day: number } -interface YearStats { +export interface YearStats { daysInYear: number inLeapYear: boolean monthsInYear: number } -interface YearMonthStats extends YearStats { +export interface YearMonthStats extends YearStats { daysInMonth: number } -interface DateStats extends YearMonthStats { +export interface DateStats extends YearMonthStats { dayOfWeek: number dayOfYear: number weekOfYear: number diff --git a/packages/temporal-polyfill/src/new/calendarOps.js b/packages/temporal-polyfill/src/new/calendarOps.ts similarity index 93% rename from packages/temporal-polyfill/src/new/calendarOps.js rename to packages/temporal-polyfill/src/new/calendarOps.ts index eee69294..78a766a7 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.js +++ b/packages/temporal-polyfill/src/new/calendarOps.ts @@ -10,6 +10,7 @@ import { idGettersStrict, } from './class' import { createDuration } from './duration' +import { CalendarInternals, CalendarOps } from './isoFields' import { ensureArray, ensureObjectlike, ensureString, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' @@ -39,7 +40,9 @@ export function getPublicCalendar(internals) { createCalendar(calendar) // CalendarImpl (create outer Calendar) } -export const getCommonCalendarOps = getCommonInnerObj.bind(undefined, 'calendar') +export const getCommonCalendarOps = getCommonInnerObj.bind< + any, [any], [CalendarInternals, CalendarInternals], CalendarOps +>(undefined, 'calendar') // Adapter // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/class.ts b/packages/temporal-polyfill/src/new/class.ts index ed5f9b8d..30ee1d28 100644 --- a/packages/temporal-polyfill/src/new/class.ts +++ b/packages/temporal-polyfill/src/new/class.ts @@ -23,7 +23,7 @@ type PropertyDescriptorType = : never type WrapperClass< - A extends [unknown], + A extends any[], I, G extends { [propName: string]: (internals: I) => unknown }, M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, @@ -50,7 +50,7 @@ export const getInternals = internalsMap.get.bind(internalsMap) as (inst: T) => T extends WrapperInstance ? I : undefined export function createWrapperClass< - A extends [any], // TODO: rename to C + A extends any[], // TODO: rename to C... or just single 'wrapped' value? I, G extends { [propName: string]: (internals: I) => unknown }, M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, @@ -59,9 +59,9 @@ export function createWrapperClass< >( getters: G, methods: M, - constructorToInternals: (...args: A) => I = identityFunc, - extraPrototypeDescriptors: P | {} = {}, - staticMembers: S | {} = {}, + constructorToInternals: (...args: A) => I = (identityFunc as any), + extraPrototypeDescriptors: P = {} as any, + staticMembers: S = {} as any, handleInstance: (inst: WrapperInstance) => void = noop, ): ( WrapperClass @@ -109,7 +109,7 @@ export function getStrictInternals( // rename: getInternalsStrict? // ------------------------------------------------------------------------------------------------- type TemporalClass< - A extends [any], + A extends any[], I, O, G extends { [propName: string]: (internals: I) => unknown }, @@ -145,7 +145,7 @@ export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) as (arg: unknown) => string | undefined export function createTemporalClass< - A extends [any], + A extends any[], I, O, G extends { [propName: string]: (internals: I) => unknown }, @@ -153,14 +153,14 @@ export function createTemporalClass< S extends {} >( temporalName: string, - constructorToInternals: (...args: A) => I = identityFunc, - internalsConversionMap: { [typeName: string]: (otherInternal: unknown) => I }, + constructorToInternals: (...args: A) => I = (identityFunc as any), + internalsConversionMap: { [typeName: string]: (otherInternal: any) => I }, bagToInternals: (bag: Record, options?: O) => I, stringToInternals: (str: string) => I, handleUnusedOptions: (options?: O) => void, getters: G, methods: M, - staticMembers: S | {} = {}, + staticMembers: S = {} as any, ): [ Class: TemporalClass, createInstance: (internals: I) => TemporalInstance, @@ -170,7 +170,7 @@ export function createTemporalClass< return String(this) } - ;(staticMembers as FromMethods).from = function(arg: TemporalArg, options: O) { + ;(staticMembers as unknown as FromMethods).from = function(arg: TemporalArg, options: O) { return createInstance(toInternals(arg, options)) } @@ -245,13 +245,17 @@ export function createProtocolChecker(protocolMethods: Record unkn } } -export function getCommonInnerObj( - propName: string, - obj0: Record, - obj1: Record, -) { - const internal0 = obj0[propName] as { id: string } - const internal1 = obj1[propName] as { id: string } +export function getCommonInnerObj< + P, + K extends (keyof P & string), + R extends (P[K] & { id: string }) +>( + propName: K, + obj0: P, + obj1: P, +): R { + const internal0 = obj0[propName] as R + const internal1 = obj1[propName] as R if (!isObjIdsEqual(internal0, internal1)) { throw new TypeError(`${propName} not equal`) diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/new/duration.ts index 8e70dec4..a5725040 100644 --- a/packages/temporal-polyfill/src/new/duration.ts +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -83,7 +83,7 @@ export const [Duration, createDuration, toDurationInternals] = createTemporalCla // ----------------------------------------------------------------------------------------------- { - ...durationGetters, + ...durationGetters, // TODO: rename to `durationFieldGetters` blank(internals: DurationInternals): boolean { return !internals.sign diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 57c4faaa..b0bc47cb 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -41,7 +41,7 @@ export function refineEpochDisambigOptions(options: Options | undefined) { } export function refineDiffOptions( - roundingModeInvert: boolean, + roundingModeInvert: boolean | undefined, options: Options | undefined, defaultLargestUnit: Unit, maxUnit = Unit.Year, diff --git a/packages/temporal-polyfill/src/new/plainDate.js b/packages/temporal-polyfill/src/new/plainDate.ts similarity index 70% rename from packages/temporal-polyfill/src/new/plainDate.js rename to packages/temporal-polyfill/src/new/plainDate.ts index af505837..c61895b7 100644 --- a/packages/temporal-polyfill/src/new/plainDate.js +++ b/packages/temporal-polyfill/src/new/plainDate.ts @@ -1,11 +1,11 @@ import { isoCalendarId } from './calendarConfig' -import { dateGetters } from './calendarFields' +import { DateFields, dateGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps, } from './calendarOps' -import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -14,9 +14,10 @@ import { refinePlainDateBag, } from './convert' import { diffDates } from './diff' -import { createDuration, toDurationInternals } from './duration' +import { Duration, createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { + IsoDateInternals, generatePublicIsoDateFields, isoTimeFieldDefaults, pluckIsoDateInternals, @@ -28,20 +29,25 @@ import { refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } fr import { createPlainDateTime } from './plainDateTime' import { toPlainTimeInternals } from './plainTime' import { zonedInternalsToIso } from './timeZoneOps' -import { dayIndex, yearIndex } from './units' +import { Unit } from './units' +import { NumSign } from './utils' -export const [ - PlainDate, - createPlainDate, - toPlainDateInternals, -] = createTemporalClass( +export type PlainDate = TemporalInstance +export type PlainDateBag = PlainDate | Partial +export type PlainDateArg = PlainDateBag | string +export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporalClass( 'PlainDate', // Creation // ----------------------------------------------------------------------------------------------- // constructorToInternals - (isoYear, isoMonth, isoDay, calendar = isoCalendarId) => { + ( + isoYear: number, + isoMonth: number, + isoDay: number, + calendar: any = isoCalendarId + ): IsoDateInternals => { return refineIsoDateInternals({ isoYear, isoMonth, @@ -76,18 +82,18 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals, bag, options) { + with(internals: IsoDateInternals, bag: PlainDateBag, options): PlainDate { return createPlainDate(mergePlainDateBag(this, bag, options)) }, - withCalendar(internals, calendarArg) { + withCalendar(internals: IsoDateInternals, calendarArg): PlainDate { return createPlainDate({ ...internals, calendar: queryCalendarOps(calendarArg), }) }, - add(internals, durationArg, options) { + add(internals: IsoDateInternals, durationArg, options): PlainDate { return internals.calendar.dateAdd( internals, toDurationInternals(durationArg), @@ -95,7 +101,7 @@ export const [ ) }, - subtract(internals, durationArg, options) { + subtract(internals: IsoDateInternals, durationArg, options): PlainDate { return internals.calendar.dateAdd( internals, negateDurationInternals(toDurationInternals(durationArg)), @@ -103,21 +109,21 @@ export const [ ) }, - until(internals, otherArg, options) { + until(internals: IsoDateInternals, otherArg, options): Duration { return diffPlainDates(internals, toPlainDateInternals(otherArg), options) }, - since(internals, otherArg, options) { + since(internals: IsoDateInternals, otherArg, options): Duration { return diffPlainDates(toPlainDateInternals(otherArg), internals, options, true) }, - equals(internals, other) { + equals(internals: IsoDateInternals, other): boolean { const otherInternals = toPlainDateInternals(other) return !compareIsoDateTimeFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals, options) { + toString(internals: IsoDateInternals, options): string { return formatIsoDateFields(internals) + formatCalendar(internals.calendar, refineDateDisplayOptions(options)) }, @@ -137,11 +143,11 @@ export const [ }) }, - toPlainYearMonth() { + toPlainYearMonth(): any { // TODO!!! return convertToPlainYearMonth(this) }, - toPlainMonthDay() { + toPlainMonthDay(): any { // TODO!!! return convertToPlainMonthDay(this) }, @@ -154,7 +160,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(arg0, arg1) { + compare(arg0: PlainDateArg, arg1: PlainDateArg): NumSign { return compareIsoDateTimeFields( toPlainDateInternals(arg0), toPlainDateInternals(arg1), @@ -166,13 +172,18 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -function diffPlainDates(internals0, internals1, options, roundingModeInvert) { +function diffPlainDates( + internals0: IsoDateInternals, + internals1: IsoDateInternals, + options, + roundingModeInvert?: boolean, +) { return createDuration( diffDates( getCommonCalendarOps(internals0, internals1), internals0, internals1, - ...refineDiffOptions(roundingModeInvert, options, dayIndex, yearIndex, dayIndex), + ...refineDiffOptions(roundingModeInvert, options, Unit.Day, Unit.Year, Unit.Day), ), ) } From fc2d3847c429bc2668ec9b24812b609304df8921 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 21:12:07 -0400 Subject: [PATCH 140/805] convert ZonedDateTime --- packages/temporal-polyfill/src/new/class.ts | 30 ++--- packages/temporal-polyfill/src/new/convert.ts | 12 +- .../temporal-polyfill/src/new/plainDate.ts | 5 +- packages/temporal-polyfill/src/new/utils.ts | 2 + .../{zonedDateTime.js => zonedDateTime.ts} | 125 +++++++++++------- 5 files changed, 105 insertions(+), 69 deletions(-) rename packages/temporal-polyfill/src/new/{zonedDateTime.js => zonedDateTime.ts} (72%) diff --git a/packages/temporal-polyfill/src/new/class.ts b/packages/temporal-polyfill/src/new/class.ts index 30ee1d28..1a58b18e 100644 --- a/packages/temporal-polyfill/src/new/class.ts +++ b/packages/temporal-polyfill/src/new/class.ts @@ -1,6 +1,7 @@ import { DateTimeFormat } from './intlFormat' import { ensureInstanceOf, ensureString, toString } from './options' import { + Reused, createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, defineProps, hasAllPropsByName, @@ -109,6 +110,7 @@ export function getStrictInternals( // rename: getInternalsStrict? // ------------------------------------------------------------------------------------------------- type TemporalClass< + B, A extends any[], I, O, @@ -117,18 +119,15 @@ type TemporalClass< S extends {}, > = { new(...args: A): TemporalInstance } & S - & FromMethods + & { from: (arg: TemporalInstance | B | string) => TemporalInstance } interface ToJsonMethods { toJSON: () => string } -type TemporalArg = TemporalInstance | Record | string - -export interface FromMethods { - from: (arg: TemporalArg, options: O) => void -} - +/* +NOTE: only use G/M generic parameters for new()/::from +*/ export type TemporalInstance< I, G extends { [propName: string]: (internals: I) => unknown } = {}, @@ -145,6 +144,7 @@ export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) as (arg: unknown) => string | undefined export function createTemporalClass< + B, A extends any[], I, O, @@ -155,22 +155,22 @@ export function createTemporalClass< temporalName: string, constructorToInternals: (...args: A) => I = (identityFunc as any), internalsConversionMap: { [typeName: string]: (otherInternal: any) => I }, - bagToInternals: (bag: Record, options?: O) => I, + bagToInternals: (bag: B, options?: O) => I, stringToInternals: (str: string) => I, handleUnusedOptions: (options?: O) => void, getters: G, methods: M, staticMembers: S = {} as any, ): [ - Class: TemporalClass, - createInstance: (internals: I) => TemporalInstance, - toInternals: (arg: TemporalArg, options?: O) => I + Class: TemporalClass, + createInstance: (internals: I) => TemporalInstance, + toInternals: (arg: TemporalInstance | B | string, options?: O) => I ] { ;(methods as unknown as ToJsonMethods).toJSON = function() { return String(this) } - ;(staticMembers as unknown as FromMethods).from = function(arg: TemporalArg, options: O) { + ;(staticMembers as any).from = function(arg: TemporalInstance | B | string, options: O) { return createInstance(toInternals(arg, options)) } @@ -190,15 +190,15 @@ export function createTemporalClass< return instance } - function toInternals(arg: TemporalArg, options?: O): I { - let argInternals = getInternals(arg) + function toInternals(arg: TemporalInstance | B | string, options?: O): I { + let argInternals = getInternals(arg) as Reused let argTemporalName if (argInternals && (argTemporalName = getTemporalName(arg)) !== temporalName) { argInternals = (internalsConversionMap[argTemporalName!] || noop)(argInternals) } - return (!argInternals && isObjectlike(arg) && bagToInternals(arg, options)) || + return (!argInternals && isObjectlike(arg) && bagToInternals(arg as B, options)) || (handleUnusedOptions(options), (argInternals as I) || stringToInternals(toString(arg))) } diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/new/convert.ts index 92a27656..0ae7798e 100644 --- a/packages/temporal-polyfill/src/new/convert.ts +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -5,6 +5,7 @@ import { isoCalendarId, } from './calendarConfig' import { + DateFields, dateFieldNames, dateTimeFieldNames, dateTimeFieldRefiners, @@ -26,6 +27,7 @@ import { durationFieldRefiners, updateDurationFieldsSign, } from './durationFields' +import { IsoDateInternals } from './isoFields' import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNano } from './isoParse' import { @@ -39,7 +41,7 @@ import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' -import { createZonedDateTime } from './zonedDateTime' +import { ZonedDateTimeBag, ZonedInternals, createZonedDateTime } from './zonedDateTime' /* Rules: @@ -50,7 +52,7 @@ Rules: // ZonedDateTime // ------------------------------------------------------------------------------------------------- -export function refineZonedDateTimeBag(bag, options) { +export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options): ZonedInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, @@ -167,7 +169,11 @@ export function mergePlainDateTimeBag(plainDate, bag, options) { // PlainDate // ------------------------------------------------------------------------------------------------- -export function refinePlainDateBag(bag, options, calendar = getBagCalendarOps(bag)) { +export function refinePlainDateBag( + bag: DateFields, + options, + calendar = getBagCalendarOps(bag) +): IsoDateInternals { const fields = refineCalendarFields( calendar, bag, diff --git a/packages/temporal-polyfill/src/new/plainDate.ts b/packages/temporal-polyfill/src/new/plainDate.ts index c61895b7..90c9762e 100644 --- a/packages/temporal-polyfill/src/new/plainDate.ts +++ b/packages/temporal-polyfill/src/new/plainDate.ts @@ -32,9 +32,10 @@ import { zonedInternalsToIso } from './timeZoneOps' import { Unit } from './units' import { NumSign } from './utils' +export type PlainDateBag = DateFields +export type PlainDateArg = PlainDate | PlainDateBag | string + export type PlainDate = TemporalInstance -export type PlainDateBag = PlainDate | Partial -export type PlainDateArg = PlainDateBag | string export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporalClass( 'PlainDate', diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index 702a2a40..d9f14814 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -1,5 +1,7 @@ import { Overflow } from './options' +export type Reused = any + const objectlikeRE = /object|function/ export function isObjectlike(arg: unknown): arg is Record { diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.js b/packages/temporal-polyfill/src/new/zonedDateTime.ts similarity index 72% rename from packages/temporal-polyfill/src/new/zonedDateTime.js rename to packages/temporal-polyfill/src/new/zonedDateTime.ts index 6141edcd..ec2a711a 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.js +++ b/packages/temporal-polyfill/src/new/zonedDateTime.ts @@ -1,6 +1,6 @@ -import { dateTimeGetters } from './calendarFields' +import { DateFields, dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' -import { createTemporalClass, isObjIdsEqual, neverValueOf } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -8,8 +8,8 @@ import { refineZonedDateTimeBag, } from './convert' import { diffZonedEpochNano } from './diff' -import { createDuration, toDurationInternals } from './duration' -import { negateDurationInternals } from './durationFields' +import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' +import { DurationFields, negateDurationInternals } from './durationFields' import { createInstant } from './instant' import { resolveZonedFormattable } from './intlFormat' import { @@ -31,9 +31,10 @@ import { epochNanoToIso, } from './isoMath' import { parseZonedDateTime } from './isoParse' -import { compareLargeInts } from './largeInt' +import { LargeInt, compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' import { + Overflow, refineDiffOptions, refineOverflowOptions, refineRoundOptions, @@ -52,23 +53,36 @@ import { queryTimeZoneOps, zonedInternalsToIso, } from './timeZoneOps' -import { hourIndex, nanoInHour } from './units' +import { Unit, nanoInHour } from './units' import { mapProps } from './utils' -export const [ - ZonedDateTime, - createZonedDateTime, - toZonedDateTimeInternals, -] = createTemporalClass( +export interface ZonedInternals { + epochNanoseconds: LargeInt + timeZone: TimeZoneOps + calendar: CalendarOps +} + +export interface ZonedDateTimeBag extends DateFields { + timeZone: TimeZoneArg + calendar?: CalendarArg +} + +export type ZonedDateTime = TemporalInstance +export type ZonedDateTimeArg = ZonedDateTime | ZonedDateTimeBag | string +export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemporalClass( 'ZonedDateTime', // Creation // ----------------------------------------------------------------------------------------------- // constructorToInternals - (epochNanoseconds, timeZoneArg, calendarArg) => { + ( + epochNano: LargeInt, + timeZoneArg: TimeZoneArg, + calendarArg: CalendarArg, + ): ZonedInternals => { return { - epochNanoseconds: checkEpochNano(toEpochNano(epochNanoseconds)), + epochNanoseconds: checkEpochNano(toEpochNano(epochNano)), timeZone: queryTimeZoneOps(timeZoneArg), // TODO: validate string/object somehow? calendar: queryCalendarOps(calendarArg), } @@ -91,18 +105,18 @@ export const [ { ...mapProps((getter) => { - return function(internals) { + return function(internals: ZonedInternals) { return getter(internals.epochNanoseconds) } }, epochGetters), ...mapProps((getter) => { - return function(internals) { + return function(internals: ZonedInternals) { return getter(zonedInternalsToIso(internals)) } }, dateTimeGetters), - hoursInDay(internals) { + hoursInDay(internals: ZonedInternals) { return computeNanosecondsInDay( internals.timeZone, zonedInternalsToIso(internals), @@ -110,19 +124,19 @@ export const [ }, // TODO: make this a getter? - offsetNanoseconds(internals) { + offsetNanoseconds(internals: ZonedInternals): LargeInt { // TODO: more DRY return zonedInternalsToIso(internals).offsetNanoseconds }, - offset(internals) { + offset(internals): string { return formatOffsetNano( // TODO: more DRY zonedInternalsToIso(internals).offsetNanoseconds, ) }, - timeZoneId(internals) { + timeZoneId(internals): string { return internals.timeZone.id }, }, @@ -131,11 +145,11 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals, bag, options) { + with(internals: ZonedInternals, bag: ZonedBag, options): ZonedDateTime { return createZonedDateTime(mergeZonedDateTimeBag(this, bag, options)) }, - withPlainTime(internals, plainTimeArg) { + withPlainTime(internals: ZonedInternals, plainTimeArg): ZonedDateTime { const { calendar, timeZone } = internals const isoFields = { ...zonedInternalsToIso(internals), @@ -160,7 +174,7 @@ export const [ }, // TODO: more DRY with withPlainTime and zonedDateTimeWithBag? - withPlainDate(internals, plainDateArg) { + withPlainDate(internals: ZonedInternals, plainDateArg): ZonedDateTime { const { calendar, timeZone } = internals const isoFields = { ...zonedInternalsToIso(internals), @@ -184,21 +198,21 @@ export const [ }) }, - withTimeZone(internals, timeZoneArg) { + withTimeZone(internals: ZonedInternals, timeZoneArg: TimeZoneArg): ZonedDateTime { return createZonedDateTime({ ...internals, timeZone: queryTimeZoneOps(timeZoneArg), }) }, - withCalendar(internals, calendarArg) { + withCalendar(internals: ZonedInternals, calendarArg: CalendarArg): ZonedDateTime { return createZonedDateTime({ ...internals, calendar: queryCalendarOps(calendarArg), }) }, - add(internals, durationArg, options) { + add(internals: ZonedInternals, durationArg: DurationArg, options): ZonedDateTime { return moveZonedDateTime( internals, toDurationInternals(durationArg), @@ -206,7 +220,7 @@ export const [ ) }, - subtract(internals, durationArg, options) { + subtract(internals: ZonedInternals, durationArg: DurationArg, options): ZonedDateTime { return moveZonedDateTime( internals, negateDurationInternals(toDurationInternals(durationArg)), @@ -214,18 +228,18 @@ export const [ ) }, - until(internals, otherArg, options) { - return diffZonedDateTimes(internals, toZonedDateTimeInternals(otherArg), options) + until(internals: ZonedInternals, otherArg, options): Duration { + return diffZonedDateTimes(internals, toZonedInternals(otherArg), options) }, - since(internals, otherArg, options) { - return diffZonedDateTimes(toZonedDateTimeInternals(otherArg), internals, options, true) + since(internals: ZonedInternals, otherArg, options): Duration { + return diffZonedDateTimes(toZonedInternals(otherArg), internals, options, true) }, /* Do param-list destructuring here and other methods! */ - round(internals, options) { + round(internals: ZonedInternals, options): ZonedDateTime { let { epochNanoseconds, timeZone, calendar } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) @@ -253,7 +267,7 @@ export const [ }) }, - startOfDay(internals) { + startOfDay(internals: ZonedInternals): ZonedDateTime { let { epochNanoseconds, timeZone, calendar } = internals const isoFields = { @@ -278,15 +292,15 @@ export const [ }) }, - equals(internals, otherZonedDateTimeArg) { - const otherInternals = toZonedDateTimeInternals(otherZonedDateTimeArg) + equals(internals: ZonedInternals, otherZonedDateTimeArg): boolean { + const otherInternals = toZonedInternals(otherZonedDateTimeArg) return !compareLargeInts(internals.epochNanoseconds, otherInternals.epochNanoseconds) && isObjIdsEqual(internals.calendar, otherInternals.calendar) && isObjIdsEqual(internals.timeZone, otherInternals.timeZone) }, - toString(internals, options) { + toString(internals: ZonedInternals, options) { let { epochNanoseconds, timeZone, calendar } = internals const [ calendarDisplayI, @@ -321,26 +335,30 @@ export const [ formatCalendar(calendar, calendarDisplayI) }, - toLocaleString(internals, locales, options) { + toLocaleString( + internals: ZonedInternals, + locales: string | string[], + options + ): string { const [epochMilli, format] = resolveZonedFormattable(internals, locales, options) return format.format(epochMilli) }, valueOf: neverValueOf, - toInstant(internals) { + toInstant(internals: ZonedInternals) { return createInstant(internals.epochNanoseconds) }, - toPlainDate(internals) { + toPlainDate(internals: ZonedInternals) { return createPlainDate(pluckIsoDateInternals(zonedInternalsToIso(internals))) }, - toPlainTime(internals) { + toPlainTime(internals: ZonedInternals) { return createPlainTime(pluckIsoTimeFields(zonedInternalsToIso(internals))) }, - toPlainDateTime(internals) { + toPlainDateTime(internals: ZonedInternals) { return createPlainDateTime(pluckIsoDateTimeInternals(zonedInternalsToIso(internals))) }, @@ -352,11 +370,11 @@ export const [ return convertToPlainMonthDay(this) }, - getISOFields(internals) { + getISOFields(internals: ZonedInternals) { return { - // maintain alphabetical order - calendar: getPublicIdOrObj(internals.calendar), ...pluckIsoDateTimeInternals(zonedInternalsToIso(internals)), + // alphabetical + calendar: getPublicIdOrObj(internals.calendar), offset: formatOffsetNano( // TODO: more DRY zonedInternalsToIso(internals).offsetNanoseconds, @@ -373,10 +391,10 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(arg0, arg1) { + compare(arg0: ZonedDateTimeArg, arg1: ZonedDateTimeArg) { return compareLargeInts( - toZonedDateTimeInternals(arg0).epochNanoseconds, - toZonedDateTimeInternals(arg1).epochNanoseconds, + toZonedInternals(arg0).epochNanoseconds, + toZonedInternals(arg1).epochNanoseconds, ) }, }, @@ -385,7 +403,11 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -function moveZonedDateTime(internals, durationFields, overflowHandling) { +function moveZonedDateTime( + internals: ZonedInternals, + durationFields: DurationFields, + overflowHandling: Overflow +): ZonedDateTime { return createZonedDateTime( moveZonedEpochNano( internals.calendar, @@ -397,14 +419,19 @@ function moveZonedDateTime(internals, durationFields, overflowHandling) { ) } -function diffZonedDateTimes(internals, otherInternals, options, roundingModeInvert) { +function diffZonedDateTimes( + internals: ZonedInternals, + otherInternals: ZonedInternals, + options, + roundingModeInvert?: boolean +): Duration { return createDuration( diffZonedEpochNano( getCommonCalendarOps(internals, otherInternals), getCommonTimeZoneOps(internals, otherInternals), internals.epochNanoseconds, otherInternals.epochNanoseconds, - ...refineDiffOptions(roundingModeInvert, options, hourIndex), + ...refineDiffOptions(roundingModeInvert, options, Unit.Hour), ), ) } From 3397eb83b6cf5b7384da73a79069824d87852040 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 21:21:07 -0400 Subject: [PATCH 141/805] plain time --- .../src/new/{plainTime.js => plainTime.ts} | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) rename packages/temporal-polyfill/src/new/{plainTime.js => plainTime.ts} (64%) diff --git a/packages/temporal-polyfill/src/new/plainTime.js b/packages/temporal-polyfill/src/new/plainTime.ts similarity index 64% rename from packages/temporal-polyfill/src/new/plainTime.js rename to packages/temporal-polyfill/src/new/plainTime.ts index 3c6a1275..0ecb82e1 100644 --- a/packages/temporal-polyfill/src/new/plainTime.js +++ b/packages/temporal-polyfill/src/new/plainTime.ts @@ -1,14 +1,14 @@ -import { timeGetters } from './calendarFields' -import { createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { TimeFields, timeGetters } from './calendarFields' +import { TemporalInstance, createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { createZonedDateTimeConverter, mergePlainTimeBag, refinePlainTimeBag, } from './convert' import { diffTimes } from './diff' -import { createDuration, toDurationInternals } from './duration' -import { negateDurationInternals } from './durationFields' -import { pluckIsoTimeFields } from './isoFields' +import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' +import { DurationInternals, negateDurationInternals } from './durationFields' +import { IsoTimeFields, pluckIsoTimeFields } from './isoFields' import { formatIsoTimeFields } from './isoFormat' import { compareIsoTimeFields, refineIsoTimeInternals } from './isoMath' import { parsePlainTime } from './isoParse' @@ -23,13 +23,13 @@ import { toPlainDateInternals } from './plainDate' import { createPlainDateTime } from './plainDateTime' import { roundTime, roundTimeToNano } from './round' import { zonedInternalsToIso } from './timeZoneOps' -import { hourIndex } from './units' +import { Unit } from './units' -export const [ - PlainTime, - createPlainTime, - toPlainTimeInternals, -] = createTemporalClass( +export type PlainTimeBag = Partial +export type PlainTimeArg = PlainTime | PlainTimeBag | string + +export type PlainTime = TemporalInstance +export const [PlainTime, createPlainTime, toPlainTimeInternals] = createTemporalClass( 'PlainTime', // Creation @@ -37,13 +37,13 @@ export const [ // constructorToInternals ( - isoHour = 0, - isoMinute = 0, - isoSecond = 0, - isoMillisecond = 0, - isoMicrosecond = 0, - isoNanosecond = 0, - ) => { + isoHour: number = 0, + isoMinute: number = 0, + isoSecond: number = 0, + isoMillisecond: number = 0, + isoMicrosecond: number = 0, + isoNanosecond: number = 0, + ): IsoTimeFields => { return refineIsoTimeInternals({ isoHour, isoMinute, @@ -80,38 +80,38 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals, bag, options) { + with(internals: IsoTimeFields, bag, options): PlainTime { return createPlainTime(mergePlainTimeBag(this, bag, options)) }, - add(internals, durationArg) { + add(internals: IsoTimeFields, durationArg: DurationArg): PlainTime { return movePlainTime(internals, toDurationInternals(durationArg)) }, - subtract(internals, durationArg) { + subtract(internals: IsoTimeFields, durationArg: DurationArg): PlainTime { return movePlainTime(internals, negateDurationInternals(toDurationInternals(durationArg))) }, - until(internals, otherArg, options) { + until(internals: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { return diffPlainTimes(internals, toPlainTimeInternals(otherArg), options) }, - since(internals, otherArg, options) { + since(internals: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { return diffPlainTimes(toPlainTimeInternals(otherArg), internals, options, true) }, - round(internals, options) { + round(internals: IsoTimeFields, options): PlainTime { return createPlainTime( - roundTime(internals, ...refineRoundOptions(options, hourIndex)), + roundTime(internals, ...refineRoundOptions(options, Unit.Hour)), ) }, - equals(internals, other) { + equals(internals: IsoTimeFields, other: PlainTimeArg): boolean { const otherInternals = toPlainTimeInternals(other) - return compareIsoTimeFields(internals, otherInternals) + return !compareIsoTimeFields(internals, otherInternals) }, - toString(internals, options) { + toString(internals: IsoTimeFields, options) { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatIsoTimeFields( @@ -142,7 +142,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(arg0, arg1) { + compare(arg0: PlainTimeArg, arg1: PlainTimeArg) { return compareIsoTimeFields( toPlainTimeInternals(arg0), toPlainTimeInternals(arg1), @@ -154,11 +154,16 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -function movePlainTime(internals, durationInternals) { +function movePlainTime(internals: IsoTimeFields, durationInternals: DurationInternals): PlainTime { return createPlainTime(moveTime(internals, durationInternals)[0]) } -function diffPlainTimes(internals0, internals1, options, roundingModeInvert) { +function diffPlainTimes( + internals0: IsoTimeFields, + internals1: IsoTimeFields, + options, + roundingModeInvert?: boolean +): Duration { return createDuration( diffTimes( internals0, From 6256b22d6d19c12b3dacb9c5a4349cd82c0f436d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 22:15:55 -0400 Subject: [PATCH 142/805] more better types --- packages/temporal-polyfill/src/new/convert.ts | 5 +- .../temporal-polyfill/src/new/isoFields.ts | 21 ++-- .../temporal-polyfill/src/new/plainDate.ts | 38 +++--- .../{plainDateTime.js => plainDateTime.ts} | 110 ++++++++++-------- .../temporal-polyfill/src/new/plainTime.ts | 54 ++++----- .../src/new/zonedDateTime.ts | 69 +++++------ 6 files changed, 160 insertions(+), 137 deletions(-) rename packages/temporal-polyfill/src/new/{plainDateTime.js => plainDateTime.ts} (61%) diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/new/convert.ts index 0ae7798e..157429d9 100644 --- a/packages/temporal-polyfill/src/new/convert.ts +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -27,7 +27,7 @@ import { durationFieldRefiners, updateDurationFieldsSign, } from './durationFields' -import { IsoDateInternals } from './isoFields' +import { IsoDateInternals, IsoDateTimeInternals } from './isoFields' import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNano } from './isoParse' import { @@ -37,6 +37,7 @@ import { refineZonedFieldOptions, // TODO: shouldn't we use this all over the place? } from './options' import { createPlainDate } from './plainDate' +import { PlainDateTimeBag } from './plainDateTime' import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' @@ -134,7 +135,7 @@ export function createZonedDateTimeConverter(getExtraIsoFields) { // PlainDateTime // ------------------------------------------------------------------------------------------------- -export function refinePlainDateTimeBag(bag, options) { +export function refinePlainDateTimeBag(bag: PlainDateTimeBag, options): IsoDateTimeInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts index 440f71a1..7a9b2b90 100644 --- a/packages/temporal-polyfill/src/new/isoFields.ts +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -39,15 +39,15 @@ export interface CalendarOps { } // TODO: move -type CalendarIdOrObj = string | CalendarOps +type CalendarPublic = CalendarProtocol | string export interface CalendarInternals { calendar: CalendarOps } export type IsoDateInternals = IsoDateFields & CalendarInternals -type IsoDateTimeFields = IsoDateFields & IsoTimeFields -type IsoDateTimeInternals = IsoDateInternals & IsoTimeFields +export type IsoDateTimeFields = IsoDateFields & IsoTimeFields +export type IsoDateTimeInternals = IsoDateInternals & IsoTimeFields // Refiners // ------------------------------------------------------------------------------------------------- @@ -129,22 +129,25 @@ export const pluckIsoTimeFields = pluckProps.bind< function generatePublicIsoFields

( pluckFunc: (internals: P) => P, internals: P & { calendar: CalendarOps }, -): P & { calendar: CalendarIdOrObj } { - const publicFields = pluckFunc(internals) as P & { calendar: CalendarIdOrObj } +): P & { calendar: CalendarPublic } { + const publicFields = pluckFunc(internals) as P & { calendar: CalendarPublic } publicFields.calendar = getPublicIdOrObj(internals.calendar) return publicFields } +export type IsoDatePublic = IsoDateFields & { calendar: CalendarPublic } +export type IsoDateTimePublic = IsoDateTimeFields & { calendar: CalendarPublic } + export const generatePublicIsoDateFields = generatePublicIsoFields.bind< any, [any], // bound - [IsoDateFields & { calendar: CalendarOps }], // unbound - IsoDateFields & { calendar: CalendarIdOrObj } // return + [IsoDateInternals], // unbound + IsoDatePublic // return >(undefined, pluckIsoDateInternals) export const generatePublicIsoDateTimeFields = generatePublicIsoFields.bind< any, [any], // bound - [IsoDateTimeFields & { calendar: CalendarOps }], // unbound - IsoDateTimeFields & { calendar: CalendarIdOrObj } // return + [IsoDateTimeInternals], // unbound + IsoDateTimePublic // return >(undefined, pluckIsoDateTimeInternals) /* diff --git a/packages/temporal-polyfill/src/new/plainDate.ts b/packages/temporal-polyfill/src/new/plainDate.ts index 90c9762e..5c498ce6 100644 --- a/packages/temporal-polyfill/src/new/plainDate.ts +++ b/packages/temporal-polyfill/src/new/plainDate.ts @@ -14,10 +14,11 @@ import { refinePlainDateBag, } from './convert' import { diffDates } from './diff' -import { Duration, createDuration, toDurationInternals } from './duration' +import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { IsoDateInternals, + IsoTimeFields, generatePublicIsoDateFields, isoTimeFieldDefaults, pluckIsoDateInternals, @@ -27,13 +28,14 @@ import { compareIsoDateTimeFields, refineIsoDateInternals } from './isoMath' import { parsePlainDate } from './isoParse' import { refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' import { createPlainDateTime } from './plainDateTime' -import { toPlainTimeInternals } from './plainTime' +import { PlainTimeArg, toPlainTimeFields } from './plainTime' import { zonedInternalsToIso } from './timeZoneOps' import { Unit } from './units' import { NumSign } from './utils' -export type PlainDateBag = DateFields export type PlainDateArg = PlainDate | PlainDateBag | string +export type PlainDateBag = DateFields & { calendar?: CalendarArg } +export type PlainDateMod = Partial export type PlainDate = TemporalInstance export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporalClass( @@ -47,7 +49,7 @@ export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporal isoYear: number, isoMonth: number, isoDay: number, - calendar: any = isoCalendarId + calendar: CalendarArg = isoCalendarId ): IsoDateInternals => { return refineIsoDateInternals({ isoYear, @@ -83,8 +85,8 @@ export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporal // ----------------------------------------------------------------------------------------------- { - with(internals: IsoDateInternals, bag: PlainDateBag, options): PlainDate { - return createPlainDate(mergePlainDateBag(this, bag, options)) + with(internals: IsoDateInternals, mod: PlainDateMod, options): PlainDate { + return createPlainDate(mergePlainDateBag(this, mod, options)) }, withCalendar(internals: IsoDateInternals, calendarArg): PlainDate { @@ -94,7 +96,7 @@ export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporal }) }, - add(internals: IsoDateInternals, durationArg, options): PlainDate { + add(internals: IsoDateInternals, durationArg: DurationArg, options): PlainDate { return internals.calendar.dateAdd( internals, toDurationInternals(durationArg), @@ -102,7 +104,7 @@ export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporal ) }, - subtract(internals: IsoDateInternals, durationArg, options): PlainDate { + subtract(internals: IsoDateInternals, durationArg: DurationArg, options): PlainDate { return internals.calendar.dateAdd( internals, negateDurationInternals(toDurationInternals(durationArg)), @@ -110,16 +112,16 @@ export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporal ) }, - until(internals: IsoDateInternals, otherArg, options): Duration { + until(internals: IsoDateInternals, otherArg: PlainDateArg, options): Duration { return diffPlainDates(internals, toPlainDateInternals(otherArg), options) }, - since(internals: IsoDateInternals, otherArg, options): Duration { + since(internals: IsoDateInternals, otherArg: PlainDateArg, options): Duration { return diffPlainDates(toPlainDateInternals(otherArg), internals, options, true) }, - equals(internals: IsoDateInternals, other): boolean { - const otherInternals = toPlainDateInternals(other) + equals(internals: IsoDateInternals, otherArg: PlainDateArg): boolean { + const otherInternals = toPlainDateInternals(otherArg) return !compareIsoDateTimeFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) }, @@ -134,21 +136,21 @@ export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporal valueOf: neverValueOf, toZonedDateTime: createZonedDateTimeConverter((options) => { - return optionalToPlainTimeInternals(options.time) + return optionalToPlainTimeFields(options.time) }), toPlainDateTime(internals, timeArg) { return createPlainDateTime({ ...internals, - ...optionalToPlainTimeInternals(timeArg), + ...optionalToPlainTimeFields(timeArg), }) }, - toPlainYearMonth(): any { // TODO!!! + toPlainYearMonth(): PlainYearMonth { return convertToPlainYearMonth(this) }, - toPlainMonthDay(): any { // TODO!!! + toPlainMonthDay(): PlainMonthDay { return convertToPlainMonthDay(this) }, @@ -189,6 +191,6 @@ function diffPlainDates( ) } -function optionalToPlainTimeInternals(timeArg) { - return timeArg === undefined ? isoTimeFieldDefaults : toPlainTimeInternals(timeArg) +function optionalToPlainTimeFields(timeArg: PlainTimeArg): IsoTimeFields { + return timeArg === undefined ? isoTimeFieldDefaults : toPlainTimeFields(timeArg) } diff --git a/packages/temporal-polyfill/src/new/plainDateTime.js b/packages/temporal-polyfill/src/new/plainDateTime.ts similarity index 61% rename from packages/temporal-polyfill/src/new/plainDateTime.js rename to packages/temporal-polyfill/src/new/plainDateTime.ts index b245b835..dd99abae 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.js +++ b/packages/temporal-polyfill/src/new/plainDateTime.ts @@ -1,7 +1,7 @@ import { isoCalendarId } from './calendarConfig' -import { dateTimeGetters } from './calendarFields' +import { DateFields, TimeFields, dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' -import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -9,9 +9,10 @@ import { refinePlainDateTimeBag, } from './convert' import { diffDateTimes } from './diff' -import { createDuration, toDurationInternals } from './duration' -import { negateDurationInternals } from './durationFields' +import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' +import { DurationInternals, negateDurationInternals } from './durationFields' import { + IsoDateTimeInternals, generatePublicIsoDateTimeFields, isoTimeFieldDefaults, pluckIsoDateInternals, @@ -29,18 +30,20 @@ import { refineOverflowOptions, refineRoundOptions, } from './options' -import { createPlainDate, toPlainDateInternals } from './plainDate' -import { createPlainTime, toPlainTimeInternals } from './plainTime' +import { PlainDate, PlainDateArg, createPlainDate, toPlainDateInternals } from './plainDate' +import { PlainTime, createPlainTime, toPlainTimeFields } from './plainTime' import { roundDateTime, roundDateTimeToNano } from './round' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' -import { dayIndex } from './units' -import { createZonedDateTime } from './zonedDateTime' - -export const [ - PlainDateTime, - createPlainDateTime, - toPlainDateTimeInternals, -] = createTemporalClass( +import { Unit } from './units' +import { NumSign } from './utils' +import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' + +export type PlainDateTimeArg = PlainDateTime | PlainDateTimeBag | string +export type PlainDateTimeBag = DateFields & Partial & { calendar?: CalendarArg } +export type PlainDateTimeMod = Partial & Partial + +export type PlainDateTime = TemporalInstance +export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = createTemporalClass( 'PlainDateTime', // Creation @@ -48,16 +51,16 @@ export const [ // constructorToInternals ( - isoYear, - isoMonth, - isoDay, - isoHour = 0, - isoMinute = 0, - isoSecond = 0, - isoMillisecond = 0, - isoMicrosecond = 0, - isoNanosecond = 0, - calendar = isoCalendarId, + isoYear: number, + isoMonth: number, + isoDay: number, + isoHour: number = 0, + isoMinute: number = 0, + isoSecond: number = 0, + isoMillisecond: number = 0, + isoMicrosecond: number = 0, + isoNanosecond: number = 0, + calendar: CalendarArg = isoCalendarId, ) => { return refineIsoDateTimeInternals({ isoYear, @@ -99,32 +102,32 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals, bag, options) { - return createPlainDateTime(mergePlainDateTimeBag(this, bag, options)) + with(internals: IsoDateTimeInternals, mod: PlainDateTimeMod, options): PlainDateTime { + return createPlainDateTime(mergePlainDateTimeBag(this, mod, options)) }, - withPlainTime(internals, plainTimeArg) { + withPlainTime(internals: IsoDateTimeInternals, plainTimeArg: PlainDateTimeArg): PlainDateTime { return createPlainDateTime({ ...internals, - ...toPlainTimeInternals(plainTimeArg), + ...toPlainTimeFields(plainTimeArg), }) }, - withPlainDate(internals, plainDateArg) { + withPlainDate(internals: IsoDateTimeInternals, plainDateArg: PlainDateArg): PlainDateTime { return createPlainDateTime({ ...internals, ...toPlainDateInternals(plainDateArg), }) }, - withCalendar(internals, calendarArg) { + withCalendar(internals: IsoDateTimeInternals, calendarArg: CalendarArg): PlainDateTime { return createPlainDateTime({ ...internals, calendar: queryCalendarOps(calendarArg), }) }, - add(internals, durationArg, options) { + add(internals: IsoDateTimeInternals, durationArg: DurationArg, options): PlainDateTime { return movePlainDateTime( internals, toDurationInternals(durationArg), @@ -132,7 +135,7 @@ export const [ ) }, - subtract(internals, durationArg, options) { + subtract(internals: IsoDateTimeInternals, durationArg: DurationArg, options): PlainDateTime { return movePlainDateTime( internals, negateDurationInternals(toDurationInternals(durationArg)), @@ -140,15 +143,15 @@ export const [ ) }, - until(internals, otherArg, options) { + until(internals: IsoDateTimeInternals, otherArg: PlainDateTimeArg, options): Duration { return diffPlainDateTimes(internals, toPlainDateTimeInternals(otherArg), options) }, - since(internals, otherArg, options) { + since(internals: IsoDateTimeInternals, otherArg: PlainDateTimeArg, options): Duration { return diffPlainDateTimes(toPlainDateTimeInternals(otherArg), internals, options, true) }, - round(internals, options) { + round(internals: IsoDateTimeInternals, options): PlainDateTime { const isoDateTimeFields = roundDateTime( internals, ...refineRoundOptions(options), @@ -160,13 +163,13 @@ export const [ }) }, - equals(internals, other) { - const otherInternals = toPlainDateTimeInternals(other) + equals(internals: IsoDateTimeInternals, otherArg: PlainDateTimeArg): boolean { + const otherInternals = toPlainDateTimeInternals(otherArg) return !compareIsoDateTimeFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals, options) { + toString(internals: IsoDateTimeInternals, options): string { const [ calendarDisplayI, nanoInc, @@ -185,10 +188,10 @@ export const [ valueOf: neverValueOf, toZonedDateTime( - internals, - timeZoneArg, + internals: IsoDateTimeInternals, + timeZoneArg: TimeZoneArg, options, // { disambiguation } - optional - ) { + ): ZonedDateTime { const { calendar } = internals const timeZone = queryTimeZoneOps(timeZoneArg) const epochDisambig = refineEpochDisambigOptions(options) @@ -201,19 +204,19 @@ export const [ }) }, - toPlainDate(internals) { + toPlainDate(internals: IsoDateTimeInternals): PlainDate { return createPlainDate(pluckIsoDateInternals(internals)) }, - toPlainYearMonth() { + toPlainYearMonth(): PlainYearMonth { return convertToPlainYearMonth(this) }, - toPlainMonthDay() { + toPlainMonthDay(): PlainMonthDay { return convertToPlainMonthDay(this) }, - toPlainTime(internals) { + toPlainTime(internals: IsoDateTimeInternals): PlainTime { return createPlainTime(pluckIsoTimeFields(internals)) }, @@ -226,7 +229,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(arg0, arg1) { + compare(arg0: PlainDateTimeArg, arg1: PlainDateTimeArg): NumSign { return compareIsoDateTimeFields( toPlainDateTimeInternals(arg0), toPlainDateTimeInternals(arg1), @@ -238,7 +241,11 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -function movePlainDateTime(internals, durationInternals, options) { +function movePlainDateTime( + internals: IsoDateTimeInternals, + durationInternals: DurationInternals, + options, +): PlainDateTime { return createPlainDateTime( moveDateTime( internals.calendar, @@ -249,13 +256,18 @@ function movePlainDateTime(internals, durationInternals, options) { ) } -function diffPlainDateTimes(internals0, internals1, options, roundingModeInvert) { +function diffPlainDateTimes( + internals0: IsoDateTimeInternals, + internals1: IsoDateTimeInternals, + options, + roundingModeInvert?: boolean +): Duration { return createDuration( diffDateTimes( getCommonCalendarOps(internals0, internals1), internals0, internals1, - ...refineDiffOptions(roundingModeInvert, options, dayIndex), + ...refineDiffOptions(roundingModeInvert, options, Unit.Day), ), ) } diff --git a/packages/temporal-polyfill/src/new/plainTime.ts b/packages/temporal-polyfill/src/new/plainTime.ts index 0ecb82e1..9b0ebcdc 100644 --- a/packages/temporal-polyfill/src/new/plainTime.ts +++ b/packages/temporal-polyfill/src/new/plainTime.ts @@ -19,17 +19,19 @@ import { refineRoundOptions, refineTimeDisplayOptions, } from './options' -import { toPlainDateInternals } from './plainDate' -import { createPlainDateTime } from './plainDateTime' +import { PlainDateArg, toPlainDateInternals } from './plainDate' +import { PlainDateTime, createPlainDateTime } from './plainDateTime' import { roundTime, roundTimeToNano } from './round' import { zonedInternalsToIso } from './timeZoneOps' import { Unit } from './units' +import { NumSign } from './utils' -export type PlainTimeBag = Partial export type PlainTimeArg = PlainTime | PlainTimeBag | string +export type PlainTimeBag = Partial +export type PlainTimeMod = Partial export type PlainTime = TemporalInstance -export const [PlainTime, createPlainTime, toPlainTimeInternals] = createTemporalClass( +export const [PlainTime, createPlainTime, toPlainTimeFields] = createTemporalClass( 'PlainTime', // Creation @@ -80,42 +82,42 @@ export const [PlainTime, createPlainTime, toPlainTimeInternals] = createTemporal // ----------------------------------------------------------------------------------------------- { - with(internals: IsoTimeFields, bag, options): PlainTime { - return createPlainTime(mergePlainTimeBag(this, bag, options)) + with(fields: IsoTimeFields, mod: PlainTimeMod, options): PlainTime { + return createPlainTime(mergePlainTimeBag(this, mod, options)) }, - add(internals: IsoTimeFields, durationArg: DurationArg): PlainTime { - return movePlainTime(internals, toDurationInternals(durationArg)) + add(fields: IsoTimeFields, durationArg: DurationArg): PlainTime { + return movePlainTime(fields, toDurationInternals(durationArg)) }, - subtract(internals: IsoTimeFields, durationArg: DurationArg): PlainTime { - return movePlainTime(internals, negateDurationInternals(toDurationInternals(durationArg))) + subtract(fields: IsoTimeFields, durationArg: DurationArg): PlainTime { + return movePlainTime(fields, negateDurationInternals(toDurationInternals(durationArg))) }, - until(internals: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { - return diffPlainTimes(internals, toPlainTimeInternals(otherArg), options) + until(fields: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { + return diffPlainTimes(fields, toPlainTimeFields(otherArg), options) }, - since(internals: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { - return diffPlainTimes(toPlainTimeInternals(otherArg), internals, options, true) + since(fields: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { + return diffPlainTimes(toPlainTimeFields(otherArg), fields, options, true) }, - round(internals: IsoTimeFields, options): PlainTime { + round(fields: IsoTimeFields, options): PlainTime { return createPlainTime( - roundTime(internals, ...refineRoundOptions(options, Unit.Hour)), + roundTime(fields, ...refineRoundOptions(options, Unit.Hour)), ) }, - equals(internals: IsoTimeFields, other: PlainTimeArg): boolean { - const otherInternals = toPlainTimeInternals(other) - return !compareIsoTimeFields(internals, otherInternals) + equals(fields: IsoTimeFields, other: PlainTimeArg): boolean { + const otherInternals = toPlainTimeFields(other) + return !compareIsoTimeFields(fields, otherInternals) }, - toString(internals: IsoTimeFields, options) { + toString(fields: IsoTimeFields, options) { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatIsoTimeFields( - roundTimeToNano(internals, nanoInc, roundingMode), + roundTimeToNano(fields, nanoInc, roundingMode), subsecDigits, ) }, @@ -128,9 +130,9 @@ export const [PlainTime, createPlainTime, toPlainTimeInternals] = createTemporal return toPlainDateInternals(options.plainDate) }), - toPlainDateTime(internals, plainDateArg) { + toPlainDateTime(fields: IsoTimeFields, plainDateArg: PlainDateArg): PlainDateTime { return createPlainDateTime({ - ...internals, + ...fields, ...toPlainDateInternals(plainDateArg), }) }, @@ -142,10 +144,10 @@ export const [PlainTime, createPlainTime, toPlainTimeInternals] = createTemporal // ----------------------------------------------------------------------------------------------- { - compare(arg0: PlainTimeArg, arg1: PlainTimeArg) { + compare(arg0: PlainTimeArg, arg1: PlainTimeArg): NumSign { return compareIsoTimeFields( - toPlainTimeInternals(arg0), - toPlainTimeInternals(arg1), + toPlainTimeFields(arg0), + toPlainTimeFields(arg1), ) }, }, diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.ts b/packages/temporal-polyfill/src/new/zonedDateTime.ts index ec2a711a..19771d63 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/new/zonedDateTime.ts @@ -1,4 +1,5 @@ -import { DateFields, dateTimeGetters } from './calendarFields' +import { isoCalendarId } from './calendarConfig' +import { dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { @@ -10,9 +11,10 @@ import { import { diffZonedEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { DurationFields, negateDurationInternals } from './durationFields' -import { createInstant } from './instant' +import { Instant, createInstant } from './instant' import { resolveZonedFormattable } from './intlFormat' import { + IsoDateTimePublic, getPublicIdOrObj, isoTimeFieldDefaults, pluckIsoDateInternals, @@ -41,9 +43,9 @@ import { refineZonedDateTimeDisplayOptions, toEpochNano, } from './options' -import { createPlainDate, toPlainDateInternals } from './plainDate' -import { createPlainDateTime } from './plainDateTime' -import { createPlainTime, toPlainTimeInternals } from './plainTime' +import { PlainDate, createPlainDate, toPlainDateInternals } from './plainDate' +import { PlainDateTime, PlainDateTimeBag, PlainDateTimeMod, createPlainDateTime } from './plainDateTime' +import { PlainTime, createPlainTime, toPlainTimeFields } from './plainTime' import { roundDateTime, roundDateTimeToNano } from './round' import { computeNanosecondsInDay, @@ -54,7 +56,14 @@ import { zonedInternalsToIso, } from './timeZoneOps' import { Unit, nanoInHour } from './units' -import { mapProps } from './utils' +import { NumSign, mapProps } from './utils' + +export type ZonedDateTimeArg = ZonedDateTime | ZonedDateTimeBag | string +export type ZonedDateTimeBag = PlainDateTimeBag & { timeZone: TimeZoneArg } +export type ZonedDateTimeMod = PlainDateTimeMod + +export type TimeZonePublic = TimeZoneProtocol | string +export type ZonedPublic = IsoDateTimePublic & { timeZone: TimeZonePublic, offset: string } export interface ZonedInternals { epochNanoseconds: LargeInt @@ -62,13 +71,7 @@ export interface ZonedInternals { calendar: CalendarOps } -export interface ZonedDateTimeBag extends DateFields { - timeZone: TimeZoneArg - calendar?: CalendarArg -} - export type ZonedDateTime = TemporalInstance -export type ZonedDateTimeArg = ZonedDateTime | ZonedDateTimeBag | string export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemporalClass( 'ZonedDateTime', @@ -79,7 +82,7 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp ( epochNano: LargeInt, timeZoneArg: TimeZoneArg, - calendarArg: CalendarArg, + calendarArg: CalendarArg = isoCalendarId, ): ZonedInternals => { return { epochNanoseconds: checkEpochNano(toEpochNano(epochNano)), @@ -116,7 +119,7 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp } }, dateTimeGetters), - hoursInDay(internals: ZonedInternals) { + hoursInDay(internals: ZonedInternals): number { return computeNanosecondsInDay( internals.timeZone, zonedInternalsToIso(internals), @@ -129,14 +132,14 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp return zonedInternalsToIso(internals).offsetNanoseconds }, - offset(internals): string { + offset(internals: ZonedInternals): string { return formatOffsetNano( // TODO: more DRY zonedInternalsToIso(internals).offsetNanoseconds, ) }, - timeZoneId(internals): string { + timeZoneId(internals: ZonedInternals): string { return internals.timeZone.id }, }, @@ -145,21 +148,21 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp // ----------------------------------------------------------------------------------------------- { - with(internals: ZonedInternals, bag: ZonedBag, options): ZonedDateTime { - return createZonedDateTime(mergeZonedDateTimeBag(this, bag, options)) + with(internals: ZonedInternals, mod: ZonedDateTimeMod, options): ZonedDateTime { + return createZonedDateTime(mergeZonedDateTimeBag(this, mod, options)) }, withPlainTime(internals: ZonedInternals, plainTimeArg): ZonedDateTime { const { calendar, timeZone } = internals const isoFields = { ...zonedInternalsToIso(internals), - ...toPlainTimeInternals(plainTimeArg), + ...toPlainTimeFields(plainTimeArg), } const epochNano = getMatchingInstantFor( timeZone, isoFields, - isoFields.offsetNano, + isoFields.offsetNanoseconds, false, // hasZ undefined, // offsetHandling undefined, // disambig @@ -228,11 +231,11 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp ) }, - until(internals: ZonedInternals, otherArg, options): Duration { + until(internals: ZonedInternals, otherArg: ZonedDateTimeArg, options): Duration { return diffZonedDateTimes(internals, toZonedInternals(otherArg), options) }, - since(internals: ZonedInternals, otherArg, options): Duration { + since(internals: ZonedInternals, otherArg: ZonedDateTimeArg, options): Duration { return diffZonedDateTimes(toZonedInternals(otherArg), internals, options, true) }, @@ -292,15 +295,15 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp }) }, - equals(internals: ZonedInternals, otherZonedDateTimeArg): boolean { - const otherInternals = toZonedInternals(otherZonedDateTimeArg) + equals(internals: ZonedInternals, otherArg: ZonedDateTimeArg): boolean { + const otherInternals = toZonedInternals(otherArg) return !compareLargeInts(internals.epochNanoseconds, otherInternals.epochNanoseconds) && isObjIdsEqual(internals.calendar, otherInternals.calendar) && isObjIdsEqual(internals.timeZone, otherInternals.timeZone) }, - toString(internals: ZonedInternals, options) { + toString(internals: ZonedInternals, options): string { let { epochNanoseconds, timeZone, calendar } = internals const [ calendarDisplayI, @@ -346,31 +349,31 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp valueOf: neverValueOf, - toInstant(internals: ZonedInternals) { + toInstant(internals: ZonedInternals): Instant { return createInstant(internals.epochNanoseconds) }, - toPlainDate(internals: ZonedInternals) { + toPlainDate(internals: ZonedInternals): PlainDate { return createPlainDate(pluckIsoDateInternals(zonedInternalsToIso(internals))) }, - toPlainTime(internals: ZonedInternals) { + toPlainTime(internals: ZonedInternals): PlainTime { return createPlainTime(pluckIsoTimeFields(zonedInternalsToIso(internals))) }, - toPlainDateTime(internals: ZonedInternals) { + toPlainDateTime(internals: ZonedInternals): PlainDateTime { return createPlainDateTime(pluckIsoDateTimeInternals(zonedInternalsToIso(internals))) }, - toPlainYearMonth() { + toPlainYearMonth(): PlainYearMonth { return convertToPlainYearMonth(this) }, - toPlainMonthDay() { + toPlainMonthDay(): PlainMonthDay { return convertToPlainMonthDay(this) }, - getISOFields(internals: ZonedInternals) { + getISOFields(internals: ZonedInternals): ZonedPublic { return { ...pluckIsoDateTimeInternals(zonedInternalsToIso(internals)), // alphabetical @@ -391,7 +394,7 @@ export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemp // ----------------------------------------------------------------------------------------------- { - compare(arg0: ZonedDateTimeArg, arg1: ZonedDateTimeArg) { + compare(arg0: ZonedDateTimeArg, arg1: ZonedDateTimeArg): NumSign { return compareLargeInts( toZonedInternals(arg0).epochNanoseconds, toZonedInternals(arg1).epochNanoseconds, From 9dc077ddc9b38e5e07502377a0171b65e2ba92d3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 22:24:55 -0400 Subject: [PATCH 143/805] instant improvements --- packages/temporal-polyfill/src/new/instant.ts | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/packages/temporal-polyfill/src/new/instant.ts b/packages/temporal-polyfill/src/new/instant.ts index 25a8a387..d0938b1a 100644 --- a/packages/temporal-polyfill/src/new/instant.ts +++ b/packages/temporal-polyfill/src/new/instant.ts @@ -2,7 +2,7 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { TemporalInstance, createTemporalClass, neverValueOf } from './class' import { diffEpochNano } from './diff' -import { Duration, createDuration, toDurationInternals } from './duration' +import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { negateDurationInternals } from './durationFields' import { formatIsoDateTimeFields, formatOffsetNano } from './isoFormat' import { @@ -26,15 +26,12 @@ import { import { computeNanoInc, roundByIncLarge } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { noop } from './utils' -import { createZonedDateTime } from './zonedDateTime' +import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' import { Unit } from './units' +export type InstantArg = Instant | LargeInt | string export type Instant = TemporalInstance -export const [ - Instant, - createInstant, - toInstantEpochNano, -] = createTemporalClass( +export const [Instant, createInstant, toInstantEpochNano] = createTemporalClass( 'Instant', // Creation @@ -68,51 +65,51 @@ export const [ // ----------------------------------------------------------------------------------------------- { - toZonedDateTimeISO(epochNanoseconds, timeZoneArg): any { // TODO!!! - createZonedDateTime({ - epochNanoseconds, + toZonedDateTimeISO(epochNano: LargeInt, timeZoneArg: TimeZoneArg): ZonedDateTime { + return createZonedDateTime({ + epochNanoseconds: epochNano, timeZone: queryTimeZoneOps(timeZoneArg), calendar: isoCalendarId, }) }, - toZonedDateTime(epochNanoseconds, options): any { // TODO!!! + toZonedDateTime(epochNano: LargeInt, options): ZonedDateTime { const refinedObj = ensureObjectlike(options) return createZonedDateTime({ - epochNanoseconds, + epochNanoseconds: epochNano, timeZone: queryTimeZoneOps(refinedObj.timeZone), calendar: queryCalendarOps(refinedObj.calendar), }) }, - add(epochNanoseconds, durationArg): Instant { + add(epochNano: LargeInt, durationArg: DurationArg): Instant { return createInstant( moveEpochNano( - epochNanoseconds, + epochNano, toDurationInternals(durationArg), ), ) }, - subtract(epochNanoseconds, durationArg): Instant { + subtract(epochNano: LargeInt, durationArg: DurationArg): Instant { return createInstant( moveEpochNano( - epochNanoseconds, + epochNano, negateDurationInternals(toDurationInternals(durationArg)), ), ) }, - until(epochNanoseconds, otherArg, options): Duration { - return diffInstants(epochNanoseconds, toInstantEpochNano(otherArg), options) + until(epochNano: LargeInt, otherArg: InstantArg, options): Duration { + return diffInstants(epochNano, toInstantEpochNano(otherArg), options) }, - since(epochNanoseconds, otherArg, options): Duration { - return diffInstants(toInstantEpochNano(otherArg), epochNanoseconds, options, true) + since(epochNano: LargeInt, otherArg: InstantArg, options): Duration { + return diffInstants(toInstantEpochNano(otherArg), epochNano, options, true) }, - round(epochNano, options): Instant { + round(epochNano: LargeInt, options): Instant { const [smallestUnitI, roundingInc, roundingModeI] = refineRoundOptions(options, Unit.Hour) return createInstant( @@ -120,9 +117,9 @@ export const [ ) }, - equals(epochNanoseconds, otherArg): boolean { + equals(epochNano: LargeInt, otherArg: InstantArg): boolean { return !compareLargeInts( - epochNanoseconds, + epochNano, toInstantEpochNano(otherArg), ) }, @@ -160,11 +157,11 @@ export const [ fromEpochMilliseconds: epochMilliToInstant, - fromEpochMicroseconds(epochMicro: LargeInt) { + fromEpochMicroseconds(epochMicro: LargeInt): Instant { return epochMicroToInstant(toEpochNano(epochMicro)) }, - fromEpochNanoseconds(epochNano: LargeInt) { + fromEpochNanoseconds(epochNano: LargeInt): Instant { return createInstant(toEpochNano(epochNano)) }, }, @@ -203,6 +200,6 @@ function epochMicroToInstant(epochMicro: LargeInt): Instant { // Legacy Date // ------------------------------------------------------------------------------------------------- -export function toTemporalInstant(this: Date) { +export function toTemporalInstant(this: Date): Instant { return epochMilliToInstant(this.valueOf()) } From a9afcb3f5b1993c8bc6191658d22ddb4fd5d6939 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 23:32:08 -0400 Subject: [PATCH 144/805] yearmonth/monthday ts --- .../src/new/calendarFields.ts | 2 +- packages/temporal-polyfill/src/new/convert.ts | 4 +- packages/temporal-polyfill/src/new/instant.ts | 7 +- .../temporal-polyfill/src/new/plainDate.ts | 14 ++-- .../{plainMonthDay.js => plainMonthDay.ts} | 29 +++++--- .../temporal-polyfill/src/new/plainTime.ts | 8 ++- .../{plainYearMonth.js => plainYearMonth.ts} | 67 ++++++++++++------- .../src/new/zonedDateTime.ts | 8 ++- 8 files changed, 94 insertions(+), 45 deletions(-) rename packages/temporal-polyfill/src/new/{plainMonthDay.js => plainMonthDay.ts} (62%) rename packages/temporal-polyfill/src/new/{plainYearMonth.js => plainYearMonth.ts} (59%) diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index 6c117d53..aad6d282 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -22,7 +22,7 @@ export interface MonthFields { month: number } -type YearMonthFields = { year: number } & MonthFields +export type YearMonthFields = { year: number } & MonthFields export type DateFields = YearMonthFields & { day: number } type MonthDayFields = MonthFields & { day: number } diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/new/convert.ts index 157429d9..76c0e645 100644 --- a/packages/temporal-polyfill/src/new/convert.ts +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -42,7 +42,7 @@ import { createPlainMonthDay } from './plainMonthDay' import { createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' -import { ZonedDateTimeBag, ZonedInternals, createZonedDateTime } from './zonedDateTime' +import { ZonedDateTime, ZonedDateTimeBag, ZonedInternals, createZonedDateTime } from './zonedDateTime' /* Rules: @@ -117,7 +117,7 @@ export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { } export function createZonedDateTimeConverter(getExtraIsoFields) { - return (internals, options) => { + return (internals, options): ZonedDateTime => { const { calendar, timeZone } = internals const epochNanoseconds = getSingleInstantFor(timeZone, { ...internals, diff --git a/packages/temporal-polyfill/src/new/instant.ts b/packages/temporal-polyfill/src/new/instant.ts index d0938b1a..7e0c3add 100644 --- a/packages/temporal-polyfill/src/new/instant.ts +++ b/packages/temporal-polyfill/src/new/instant.ts @@ -30,8 +30,13 @@ import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' import { Unit } from './units' export type InstantArg = Instant | LargeInt | string + export type Instant = TemporalInstance -export const [Instant, createInstant, toInstantEpochNano] = createTemporalClass( +export const [ + Instant, + createInstant, + toInstantEpochNano +] = createTemporalClass( 'Instant', // Creation diff --git a/packages/temporal-polyfill/src/new/plainDate.ts b/packages/temporal-polyfill/src/new/plainDate.ts index 5c498ce6..e6685a55 100644 --- a/packages/temporal-polyfill/src/new/plainDate.ts +++ b/packages/temporal-polyfill/src/new/plainDate.ts @@ -27,8 +27,10 @@ import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoDateTimeFields, refineIsoDateInternals } from './isoMath' import { parsePlainDate } from './isoParse' import { refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' -import { createPlainDateTime } from './plainDateTime' +import { PlainDateTime, createPlainDateTime } from './plainDateTime' +import { PlainMonthDay } from './plainMonthDay' import { PlainTimeArg, toPlainTimeFields } from './plainTime' +import { PlainYearMonth } from './plainYearMonth' import { zonedInternalsToIso } from './timeZoneOps' import { Unit } from './units' import { NumSign } from './utils' @@ -38,7 +40,11 @@ export type PlainDateBag = DateFields & { calendar?: CalendarArg } export type PlainDateMod = Partial export type PlainDate = TemporalInstance -export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporalClass( +export const [ + PlainDate, + createPlainDate, + toPlainDateInternals +] = createTemporalClass( 'PlainDate', // Creation @@ -139,7 +145,7 @@ export const [PlainDate, createPlainDate, toPlainDateInternals] = createTemporal return optionalToPlainTimeFields(options.time) }), - toPlainDateTime(internals, timeArg) { + toPlainDateTime(internals, timeArg): PlainDateTime { return createPlainDateTime({ ...internals, ...optionalToPlainTimeFields(timeArg), @@ -180,7 +186,7 @@ function diffPlainDates( internals1: IsoDateInternals, options, roundingModeInvert?: boolean, -) { +): Duration { return createDuration( diffDates( getCommonCalendarOps(internals0, internals1), diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.js b/packages/temporal-polyfill/src/new/plainMonthDay.ts similarity index 62% rename from packages/temporal-polyfill/src/new/plainMonthDay.js rename to packages/temporal-polyfill/src/new/plainMonthDay.ts index aa34b064..14e370f6 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.js +++ b/packages/temporal-polyfill/src/new/plainMonthDay.ts @@ -1,22 +1,28 @@ import { isoCalendarId } from './calendarConfig' -import { monthDayGetters } from './calendarFields' +import { YearMonthFields, monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' -import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertPlainMonthDayToDate, mergePlainMonthDayBag, refinePlainMonthDayBag, } from './convert' -import { generatePublicIsoDateFields } from './isoFields' +import { IsoDateInternals, generatePublicIsoDateFields } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields, isoEpochFirstLeapYear, refineIsoDateInternals } from './isoMath' import { parsePlainMonthDay } from './isoParse' import { refineOverflowOptions } from './options' +import { PlainDate } from './plainDate' +export type PlainMonthDayArg = PlainMonthDay | PlainMonthDayBag | string +export type PlainMonthDayBag = YearMonthFields & { calendar?: CalendarArg } +export type PlainMonthDayMod = Partial + +export type PlainMonthDay = TemporalInstance export const [ PlainMonthDay, createPlainMonthDay, - toPlainMonthDayInternals, + toPlainMonthDayInternals ] = createTemporalClass( 'PlainMonthDay', @@ -24,7 +30,12 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (isoMonth, isoDay, calendar = isoCalendarId, referenceIsoYear = isoEpochFirstLeapYear) => { + ( + isoMonth: number, + isoDay: number, + calendar: CalendarArg = isoCalendarId, + referenceIsoYear: number = isoEpochFirstLeapYear + ): IsoDateInternals => { return refineIsoDateInternals({ isoYear: referenceIsoYear, isoMonth, @@ -54,11 +65,11 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals, bag, options) { - return createPlainMonthDay(mergePlainMonthDayBag(this, bag, options)) + with(internals: IsoDateInternals, mod: PlainMonthDayMod, options): PlainMonthDay { + return createPlainMonthDay(mergePlainMonthDayBag(this, mod, options)) }, - equals(internals, otherArg) { + equals(internals: IsoDateInternals, otherArg: PlainMonthDayArg): boolean { const otherInternals = toPlainMonthDayInternals(otherArg) return !compareIsoDateTimeFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) @@ -70,7 +81,7 @@ export const [ valueOf: neverValueOf, - toPlainDate(internals, bag) { + toPlainDate(internals: IsoDateInternals, bag: { year: number }): PlainDate { return convertPlainMonthDayToDate(this, bag) }, diff --git a/packages/temporal-polyfill/src/new/plainTime.ts b/packages/temporal-polyfill/src/new/plainTime.ts index 9b0ebcdc..db6c6fda 100644 --- a/packages/temporal-polyfill/src/new/plainTime.ts +++ b/packages/temporal-polyfill/src/new/plainTime.ts @@ -31,7 +31,11 @@ export type PlainTimeBag = Partial export type PlainTimeMod = Partial export type PlainTime = TemporalInstance -export const [PlainTime, createPlainTime, toPlainTimeFields] = createTemporalClass( +export const [ + PlainTime, + createPlainTime, + toPlainTimeFields +] = createTemporalClass( 'PlainTime', // Creation @@ -113,7 +117,7 @@ export const [PlainTime, createPlainTime, toPlainTimeFields] = createTemporalCla return !compareIsoTimeFields(fields, otherInternals) }, - toString(fields: IsoTimeFields, options) { + toString(fields: IsoTimeFields, options): string { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatIsoTimeFields( diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.js b/packages/temporal-polyfill/src/new/plainYearMonth.ts similarity index 59% rename from packages/temporal-polyfill/src/new/plainYearMonth.js rename to packages/temporal-polyfill/src/new/plainYearMonth.ts index 78b5ad0f..409d7507 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.js +++ b/packages/temporal-polyfill/src/new/plainYearMonth.ts @@ -1,27 +1,34 @@ import { isoCalendarId } from './calendarConfig' -import { yearMonthGetters } from './calendarFields' +import { YearMonthFields, yearMonthGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar } from './calendarOps' -import { createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { convertPlainYearMonthToDate, mergePlainYearMonthBag, refinePlainYearMonthBag, } from './convert' import { diffDates } from './diff' -import { createDuration, toDurationInternals } from './duration' -import { negateDurationInternals } from './durationFields' -import { generatePublicIsoDateFields } from './isoFields' +import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' +import { DurationInternals, negateDurationInternals } from './durationFields' +import { IsoDateFields, IsoDateInternals, generatePublicIsoDateFields } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields, refineIsoDateInternals } from './isoMath' import { parsePlainYearMonth } from './isoParse' import { moveDateByDays } from './move' import { refineDiffOptions, refineOverflowOptions } from './options' -import { dayIndex, yearIndex } from './units' +import { PlainDate } from './plainDate' +import { Unit } from './units' +import { NumSign } from './utils' +export type PlainYearMonthArg = PlainYearMonth | PlainYearMonthBag | string +export type PlainYearMonthBag = YearMonthFields & { calendar?: CalendarArg } +export type PlainYearMonthMod = Partial + +export type PlainYearMonth = TemporalInstance export const [ PlainYearMonth, createPlainYearMonth, - toPlainYearMonthInternals, + toPlainYearMonthInternals ] = createTemporalClass( 'PlainYearMonth', @@ -29,7 +36,12 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (isoYear, isoMonth, calendar = isoCalendarId, referenceIsoDay = 1) => { + ( + isoYear: number, + isoMonth: number, + calendar: CalendarArg = isoCalendarId, + referenceIsoDay: number = 1 + ): IsoDateInternals => { return refineIsoDateInternals({ isoYear, isoMonth, @@ -59,11 +71,11 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals, bag, options) { - return createPlainYearMonth(mergePlainYearMonthBag(internals, bag, options)) + with(internals: IsoDateInternals, mod: PlainYearMonthMod, options): PlainYearMonth { + return createPlainYearMonth(mergePlainYearMonthBag(internals, mod, options)) }, - add(internals, durationArg, options) { + add(internals: IsoDateInternals, durationArg: DurationArg, options): PlainYearMonth { return movePlainYearMonth( internals, toDurationInternals(durationArg), @@ -71,7 +83,7 @@ export const [ ) }, - subtract(internals, durationArg, options) { + subtract(internals: IsoDateInternals, durationArg: DurationArg, options): PlainYearMonth { return movePlainYearMonth( internals, negateDurationInternals(toDurationInternals(durationArg)), @@ -79,15 +91,15 @@ export const [ ) }, - until(internals, otherArg, options) { + until(internals: IsoDateInternals, otherArg: PlainYearMonthArg, options): Duration { return diffPlainYearMonths(internals, toPlainYearMonthInternals(otherArg), options) }, - since(internals, otherArg, options) { + since(internals: IsoDateInternals, otherArg: PlainYearMonthArg, options): Duration { return diffPlainYearMonths(toPlainYearMonthInternals(otherArg), internals, options, true) }, - equals(internals, otherArg) { + equals(internals: IsoDateInternals, otherArg: PlainYearMonthArg): boolean { const otherInternals = toPlainYearMonthInternals(otherArg) return !compareIsoDateTimeFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) @@ -99,7 +111,7 @@ export const [ valueOf: neverValueOf, - toPlainDate(internals, bag) { + toPlainDate(internals: IsoDateInternals, bag: { day: number }): PlainDate { return convertPlainYearMonthToDate(this, bag) }, @@ -112,7 +124,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(arg0, arg1) { + compare(arg0: PlainYearMonthArg, arg1: PlainYearMonthArg): NumSign { return compareIsoDateTimeFields( toPlainYearMonthInternals(arg0), toPlainYearMonthInternals(arg1), @@ -124,36 +136,41 @@ export const [ // Utils // ------------------------------------------------------------------------------------------------- -function diffPlainYearMonths(internals0, internals1, options, roundingModeInvert) { +function diffPlainYearMonths( + internals0: IsoDateInternals, + internals1: IsoDateInternals, + options, + roundingModeInvert?: boolean +): Duration { return createDuration( diffDates( getCommonCalendarOps(internals0, internals1), movePlainYearMonthToDay(internals0), movePlainYearMonthToDay(internals1), - ...refineDiffOptions(roundingModeInvert, options, yearIndex, yearIndex, dayIndex), + ...refineDiffOptions(roundingModeInvert, options, Unit.Year, Unit.Year, Unit.Day), ), ) } function movePlainYearMonth( - internals, - durationFields, + internals: IsoDateInternals, + durationInternals: DurationInternals, options, -) { +): PlainYearMonth { const { calendar } = internals const isoDateFields = movePlainYearMonthToDay( internals, - durationFields.sign < 0 + durationInternals.sign < 0 ? calendar.daysInMonth(internals) : 1, ) return createPlainYearMonth( - calendar.dateAdd(isoDateFields, durationFields, refineOverflowOptions(options)), + calendar.dateAdd(isoDateFields, durationInternals, refineOverflowOptions(options)), ) } -function movePlainYearMonthToDay(internals, day = 1) { +function movePlainYearMonthToDay(internals: IsoDateInternals, day = 1): IsoDateFields { return moveDateByDays( internals, day - internals.calendar.day(internals), diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.ts b/packages/temporal-polyfill/src/new/zonedDateTime.ts index 19771d63..265a95fa 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/new/zonedDateTime.ts @@ -45,7 +45,9 @@ import { } from './options' import { PlainDate, createPlainDate, toPlainDateInternals } from './plainDate' import { PlainDateTime, PlainDateTimeBag, PlainDateTimeMod, createPlainDateTime } from './plainDateTime' +import { PlainMonthDay } from './plainMonthDay' import { PlainTime, createPlainTime, toPlainTimeFields } from './plainTime' +import { PlainYearMonth } from './plainYearMonth' import { roundDateTime, roundDateTimeToNano } from './round' import { computeNanosecondsInDay, @@ -72,7 +74,11 @@ export interface ZonedInternals { } export type ZonedDateTime = TemporalInstance -export const [ZonedDateTime, createZonedDateTime, toZonedInternals] = createTemporalClass( +export const [ + ZonedDateTime, + createZonedDateTime, + toZonedInternals +] = createTemporalClass( 'ZonedDateTime', // Creation From bbcfdd0abf04d89fbb7ab83b7388699643b261d8 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 23:40:11 -0400 Subject: [PATCH 145/805] rename easy files --- packages/temporal-polyfill/src/new/{global.js => global.ts} | 0 packages/temporal-polyfill/src/new/{impl.js => impl.ts} | 0 packages/temporal-polyfill/src/new/{index.js => index.ts} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename packages/temporal-polyfill/src/new/{global.js => global.ts} (100%) rename packages/temporal-polyfill/src/new/{impl.js => impl.ts} (100%) rename packages/temporal-polyfill/src/new/{index.js => index.ts} (100%) diff --git a/packages/temporal-polyfill/src/new/global.js b/packages/temporal-polyfill/src/new/global.ts similarity index 100% rename from packages/temporal-polyfill/src/new/global.js rename to packages/temporal-polyfill/src/new/global.ts diff --git a/packages/temporal-polyfill/src/new/impl.js b/packages/temporal-polyfill/src/new/impl.ts similarity index 100% rename from packages/temporal-polyfill/src/new/impl.js rename to packages/temporal-polyfill/src/new/impl.ts diff --git a/packages/temporal-polyfill/src/new/index.js b/packages/temporal-polyfill/src/new/index.ts similarity index 100% rename from packages/temporal-polyfill/src/new/index.js rename to packages/temporal-polyfill/src/new/index.ts From 5c0de6a79dd87fe5aa7eef133f7fb17911eadcd7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 23:43:57 -0400 Subject: [PATCH 146/805] tweaks --- packages/temporal-polyfill/src/new/duration.ts | 10 +++++----- packages/temporal-polyfill/src/new/durationFields.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/new/duration.ts index a5725040..c609a3be 100644 --- a/packages/temporal-polyfill/src/new/duration.ts +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -5,7 +5,7 @@ import { absDurationInternals, addDurationFields, durationFieldsToNano, - durationGetters, + durationInternalGetters, negateDurationInternals, refineDurationFields, DurationInternals, @@ -29,7 +29,7 @@ import { totalDayTimeDuration, totalRelativeDuration, } from './round' -import { identityFunc, noop } from './utils' +import { NumSign, identityFunc, noop } from './utils' import { Unit } from './units' export type Duration = TemporalInstance @@ -52,7 +52,7 @@ export const [Duration, createDuration, toDurationInternals] = createTemporalCla milliseconds: number = 0, microseconds: number = 0, nanoseconds: number = 0, - ) => { + ): DurationInternals => { return refineDurationFields({ years, months, @@ -83,7 +83,7 @@ export const [Duration, createDuration, toDurationInternals] = createTemporalCla // ----------------------------------------------------------------------------------------------- { - ...durationGetters, // TODO: rename to `durationFieldGetters` + ...durationInternalGetters, blank(internals: DurationInternals): boolean { return !internals.sign @@ -181,7 +181,7 @@ export const [Duration, createDuration, toDurationInternals] = createTemporalCla // ----------------------------------------------------------------------------------------------- { - compare(durationArg0: DurationArg, durationArg1: DurationArg, options) { + compare(durationArg0: DurationArg, durationArg1: DurationArg, options): NumSign { const durationFields0 = toDurationInternals(durationArg0) const durationFields1 = toDurationInternals(durationArg1) const markerInternals = refineRelativeToOptions(options) diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts index 7cb79573..b8434601 100644 --- a/packages/temporal-polyfill/src/new/durationFields.ts +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -82,7 +82,7 @@ export const durationFieldRefiners = mapPropNamesToConstant(durationFieldNames, // Getters // ------------------------------------------------------------------------------------------------- -export const durationGetters = mapPropNames((propName: keyof DurationInternals) => { +export const durationInternalGetters = mapPropNames((propName: keyof DurationInternals) => { return (internals: DurationInternals) => { return internals[propName] } From 6849d97a44a7ba1e8d159de2b4367e70b27d8856 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 12 Jul 2023 23:51:15 -0400 Subject: [PATCH 147/805] duration improvements --- packages/temporal-polyfill/src/new/convert.ts | 8 ++++-- .../temporal-polyfill/src/new/duration.ts | 25 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/new/convert.ts index 76c0e645..d2327dda 100644 --- a/packages/temporal-polyfill/src/new/convert.ts +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -20,6 +20,7 @@ import { import { queryCalendarImpl } from './calendarImpl' import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' +import { DurationBag, DurationMod } from './duration' import { DurationFields, DurationInternals, @@ -352,12 +353,15 @@ function refineTimeFields(fields, overflow) { // Duration // ------------------------------------------------------------------------------------------------- -export function refineDurationBag(bag: Partial): DurationInternals { +export function refineDurationBag(bag: DurationBag): DurationInternals { const durationFields = refineFields(bag, durationFieldNames, []) return updateDurationFieldsSign(durationFields) } -export function mergeDurationBag(durationInternals, bag) { +export function mergeDurationBag( + durationInternals: DurationInternals, + bag: DurationMod +): DurationInternals { const partialDurationFields = refineFields(bag, durationFieldNames) return updateDurationFieldsSign({ ...durationInternals, ...partialDurationFields }) } diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/new/duration.ts index c609a3be..a607bbe8 100644 --- a/packages/temporal-polyfill/src/new/duration.ts +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -30,11 +30,18 @@ import { totalRelativeDuration, } from './round' import { NumSign, identityFunc, noop } from './utils' -import { Unit } from './units' +import { DayTimeUnit, Unit } from './units' + +export type DurationArg = Duration | DurationBag | string +export type DurationBag = Partial +export type DurationMod = Partial export type Duration = TemporalInstance -export type DurationArg = Duration | Partial | string -export const [Duration, createDuration, toDurationInternals] = createTemporalClass( +export const [ + Duration, + createDuration, + toDurationInternals +] = createTemporalClass( 'Duration', // Creation @@ -94,7 +101,9 @@ export const [Duration, createDuration, toDurationInternals] = createTemporalCla // ----------------------------------------------------------------------------------------------- { - with: mergeDurationBag, // TODO: wrong type!!! + with(internals: DurationInternals, mod: DurationMod): Duration { + return createDuration(mergeDurationBag(internals, mod)) + }, add: addToDuration.bind(undefined, 1), @@ -230,7 +239,7 @@ function addToDuration( const addedDurationFields = addDurationFields(internals, otherFields, direction) if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { - return balanceDurationDayTime(addedDurationFields) + return balanceDurationDayTime(addedDurationFields, largestUnit as DayTimeUnit) } const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) @@ -272,9 +281,9 @@ function spanDuration( } function balanceDurationDayTime( - durationFields, - largestUnit, // day/time -) { + durationFields: DurationFields, + largestUnit: DayTimeUnit, // day/time +): Duration { // TODO } From 45b7f37a0a3af97b4b82d109f53aee7a9aa8646d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 22 Jul 2023 19:00:46 -0400 Subject: [PATCH 148/805] implement duration TODOs, other cleanup --- .../temporal-polyfill/src/new/duration.ts | 19 ++++++++++++++----- .../src/new/durationFields.ts | 4 ---- packages/temporal-polyfill/src/new/instant.ts | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/new/duration.ts index a607bbe8..3a71de6c 100644 --- a/packages/temporal-polyfill/src/new/duration.ts +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -9,7 +9,10 @@ import { negateDurationInternals, refineDurationFields, DurationInternals, - DurationFields + DurationFields, + durationFieldNamesAsc, + nanoToDurationFields, + updateDurationFieldsSign, } from './durationFields' import { formatDurationInternals } from './isoFormat' import { isoToEpochNano } from './isoMath' @@ -284,10 +287,16 @@ function balanceDurationDayTime( durationFields: DurationFields, largestUnit: DayTimeUnit, // day/time ): Duration { - // TODO + const nano = durationFieldsToNano(durationFields) + return createDuration( + updateDurationFieldsSign(nanoToDurationFields(nano, largestUnit)) + ) } -function getLargestDurationUnit(fields: DurationFields): Unit { - // TODO: rename to getLargestDurationUnitIndex - // TODO: move to DurationFields math +function getLargestDurationUnit(fields: DurationFields): Unit | undefined { + for (let unit: Unit = Unit.Year; unit >= Unit.Nanosecond; unit--) { + if (fields[durationFieldNamesAsc[unit]]) { + return unit + } + } } diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts index b8434601..2fc73560 100644 --- a/packages/temporal-polyfill/src/new/durationFields.ts +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -40,10 +40,6 @@ export interface DurationInternals extends DurationFields { sign: NumSign } -type DurationGetters = { - [K in keyof DurationInternals]: (internals: DurationInternals) => DurationInternals[K] -} - // Property Names // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/instant.ts b/packages/temporal-polyfill/src/new/instant.ts index 7e0c3add..79da729b 100644 --- a/packages/temporal-polyfill/src/new/instant.ts +++ b/packages/temporal-polyfill/src/new/instant.ts @@ -43,7 +43,7 @@ export const [ // ----------------------------------------------------------------------------------------------- // constructorToInternals - (epochNano: LargeInt) => { + (epochNano: bigint) => { return checkEpochNano(toEpochNano(epochNano)) }, From 7b02921a23c7b86efdcfdbf23fbcf102e6f48142 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 24 Jul 2023 12:29:45 -0400 Subject: [PATCH 149/805] isoMath to ts --- .../src/new/calendarFields.ts | 11 +- .../temporal-polyfill/src/new/isoFields.ts | 26 ++- .../src/new/{isoMath.js => isoMath.ts} | 204 +++++++++++------- .../temporal-polyfill/src/new/isoParse.ts | 6 +- .../temporal-polyfill/src/new/largeInt.ts | 5 +- packages/temporal-polyfill/src/new/options.ts | 11 +- packages/temporal-polyfill/src/new/utils.ts | 37 ++-- 7 files changed, 181 insertions(+), 119 deletions(-) rename packages/temporal-polyfill/src/new/{isoMath.js => isoMath.ts} (58%) diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index aad6d282..9f0d46e2 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -6,7 +6,7 @@ import { isoTimeFieldNames, } from './isoFields' import { ensureBoolean, ensureInteger, toInteger, toString } from './options' -import { mapPropNames, mapPropNamesToConstant, remapProps } from './utils' +import { FilterPropValues, mapPropNames, mapPropNamesToConstant, remapProps } from './utils' export interface EraYearFields { era: string @@ -71,21 +71,12 @@ export interface DateStats extends YearMonthStats { daysInWeek: number } -// TODO: move -type FilterPropValues = { - [K in keyof P as P[K] extends F ? K : never]: P[K] -} - type DateMethods = FilterPropValues any> type DateGetters = { [K in keyof DateMethods]: (internals: IsoDateInternals) => ReturnType } -type TimeGetters = { - [K in keyof TimeFields]: (isoFields: IsoTimeFields) => number -} - type CalendarIdGetters = { calendarId: (internals: { calendar: CalendarOps }) => string } diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts index 7a9b2b90..25834f59 100644 --- a/packages/temporal-polyfill/src/new/isoFields.ts +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -1,7 +1,7 @@ import { queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { toInteger } from './options' -import { mapPropNamesToConstant, pluckProps } from './utils' +import { mapPropNamesToConstant, pluckProps, pluckPropsTuple } from './utils' export interface IsoDateFields { isoDay: number @@ -114,18 +114,30 @@ export const pluckIsoDateTimeInternals = pluckProps.bind< IsoDateTimeInternals // return >(undefined, isoDateTimeInternalNames) -export const pluckIsoDateTimeFields = pluckProps.bind< - any, [any], // bound - [IsoDateTimeFields], // unbound - IsoDateTimeFields // return ->(undefined, isoDateTimeFieldNamesAsc) - export const pluckIsoTimeFields = pluckProps.bind< any, [any], // bound [IsoTimeFields], // unbound IsoTimeFields // return >(undefined, isoTimeFieldNames) +// TODO: move? +export type IsoTuple = [ + isoYear: number, + isoMonth?: number, + isoDay?: number, + isoHour?: number, + isoMinute?: number, + isoSecond?: number, + isoMilli?: number, +] + +// TODO: move? +export const pluckIsoTuple = pluckPropsTuple.bind< + any, [any], + [Partial & { isoYear: number }], // unbound + IsoTuple // return +>(undefined, isoDateTimeFieldNamesAsc.reverse()) + function generatePublicIsoFields

( pluckFunc: (internals: P) => P, internals: P & { calendar: CalendarOps }, diff --git a/packages/temporal-polyfill/src/new/isoMath.js b/packages/temporal-polyfill/src/new/isoMath.ts similarity index 58% rename from packages/temporal-polyfill/src/new/isoMath.js rename to packages/temporal-polyfill/src/new/isoMath.ts index 63a9421d..5716afa3 100644 --- a/packages/temporal-polyfill/src/new/isoMath.js +++ b/packages/temporal-polyfill/src/new/isoMath.ts @@ -1,26 +1,33 @@ import { isoFieldsToEpochMilli } from '../dateUtils/epoch' import { diffEpochMilliByDay } from './diff' import { + IsoDateFields, + IsoDateInternals, + IsoDateTimeFields, + IsoDateTimeInternals, + IsoTimeFields, + IsoTuple, isoDateInternalRefiners, isoDateTimeFieldNamesAsc, isoDateTimeInternalRefiners, isoTimeFieldNamesAsc, isoTimeFieldRefiners, - pluckIsoDateTimeFields, + pluckIsoTuple, } from './isoFields' -import { compareLargeInts, numberToLargeInt } from './largeInt' -import { clampProp, rejectI } from './options' // use 1 instead of rejectI? +import { LargeInt, compareLargeInts, numberToLargeInt } from './largeInt' +import { Overflow, clampProp } from './options' import { + Unit, givenFieldsToNano, - hourIndex, milliInSec, nanoInMicro, nanoInMilli, nanoInSec, nanoInUtcDay, nanoToGivenFields, + secInDay, } from './units' -import { compareProps, divFloorMod, mapPropsWithRefiners } from './utils' +import { compareProps, divFloorMod, mapPropsWithRefiners, pluckPropsTuple } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -30,11 +37,11 @@ export const isoEpochFirstLeapYear = 1972 export const isoMonthsInYear = 12 export const isoDaysInWeek = 7 -export function computeIsoMonthsInYear(isoYear) { // for methods +export function computeIsoMonthsInYear(isoYear: number): number { // for methods return isoMonthsInYear } -export function computeIsoDaysInMonth(isoYear, isoMonth) { +export function computeIsoDaysInMonth(isoYear: number, isoMonth: number): number { switch (isoMonth) { case 2: return computeIsoIsLeapYear(isoYear) ? 29 : 28 @@ -47,22 +54,22 @@ export function computeIsoDaysInMonth(isoYear, isoMonth) { return 31 } -export function computeIsoDaysInYear(isoYear) { +export function computeIsoDaysInYear(isoYear: number): number { return computeIsoIsLeapYear(isoYear) ? 365 : 366 } -export function computeIsoIsLeapYear(isoYear) { +export function computeIsoIsLeapYear(isoYear: number): boolean { return isoYear % 4 === 0 && (isoYear % 100 !== 0 || isoYear % 400 === 0) } -export function computeIsoDayOfYear(isoDateFields) { +export function computeIsoDayOfYear(isoDateFields: IsoDateFields): number { return diffEpochMilliByDay( isoFieldsToEpochMilli(isoDateMonthStart(isoDateFields)), isoFieldsToEpochMilli(isoDateFields), ) } -export function computeIsoDayOfWeek(isoDateFields) { +export function computeIsoDayOfWeek(isoDateFields: IsoDateFields): number { return isoToLegacyDate( isoDateFields.isoYear, isoDateFields.isoMonth, @@ -70,15 +77,18 @@ export function computeIsoDayOfWeek(isoDateFields) { ).getDay() + 1 } -export function computeIsoYearOfWeek(isoDateFields) { +export function computeIsoYearOfWeek(isoDateFields: IsoDateFields): number { return computeIsoWeekInfo(isoDateFields).isoYear } -export function computeIsoWeekOfYear(isoDateFields) { +export function computeIsoWeekOfYear(isoDateFields: IsoDateFields): number { return computeIsoWeekInfo(isoDateFields).isoWeek } -function computeIsoWeekInfo(isoDateFields) { +function computeIsoWeekInfo(isoDateFields: IsoDateFields): { + isoYear: number, + isoWeek: number, +} { const doy = computeIsoDayOfYear(isoDateFields) const dow = computeIsoDayOfWeek(isoDateFields) const doj = computeIsoDayOfWeek(isoDateMonthStart(isoDateFields)) @@ -103,39 +113,42 @@ function computeIsoWeekInfo(isoDateFields) { return { isoYear, isoWeek } } -function isoDateMonthStart(isoDateFields) { +function isoDateMonthStart(isoDateFields: IsoDateFields): IsoDateFields { return { ...isoDateFields, isoMonth: 1, isoDay: 1 } } // Refining // ------------------------------------------------------------------------------------------------- -export function refineIsoDateTimeInternals(rawIsoDateTimeInternals) { - return checkIsoDateTimeInternals( +export function refineIsoDateTimeInternals(rawIsoDateTimeInternals: IsoDateTimeInternals): IsoDateTimeInternals { + return checkIso( constrainIsoDateTimeInternals( mapPropsWithRefiners(rawIsoDateTimeInternals, isoDateTimeInternalRefiners), ), ) } -export function refineIsoDateInternals(rawIsoDateInternals) { - return checkIsoDateTimeInternals( +export function refineIsoDateInternals(rawIsoDateInternals: IsoDateInternals): IsoDateInternals { + return checkIso( constrainIsoDateInternals( mapPropsWithRefiners(rawIsoDateInternals, isoDateInternalRefiners), ), ) } -export function refineIsoTimeInternals(rawIsoTimeInternals) { +export function refineIsoTimeInternals(rawIsoTimeInternals: IsoTimeFields): IsoTimeFields { + const asdf = mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners) return constrainIsoTimeFields( - mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), + asdf, ) } // Constraining // ------------------------------------------------------------------------------------------------- -export function constrainIsoDateTimeInternals(isoDateTimeFields) { +export function constrainIsoDateTimeInternals( + isoDateTimeFields: IsoDateTimeInternals, +): IsoDateTimeInternals { return { ...constrainIsoDateInternals(isoDateTimeFields), ...constrainIsoTimeFields(isoDateTimeFields), @@ -144,16 +157,34 @@ export function constrainIsoDateTimeInternals(isoDateTimeFields) { /* accepts iso-date-like fields and will pass all through -accepts returnUndefinedI */ -export function constrainIsoDateInternals(isoDateFields, overflowI = rejectI) { - const isoMonth = clampProp(isoDateFields, 'isoMonth', 1, isoMonthsInYear, overflowI) +export function constrainIsoDateInternals

( + isoInternals: P, + overflow?: Overflow, +): P +export function constrainIsoDateInternals

( + isoInternals: P, + overflow: Overflow | -1, +): P | undefined +export function constrainIsoDateInternals

( + isoInternals: P, + overflow: Overflow | -1 = Overflow.Reject, +): P | undefined { + const isoMonth = clampProp( + isoInternals as IsoDateFields, + 'isoMonth', + 1, + isoMonthsInYear, + overflow, + ) + if (isoMonth) { - const daysInMonth = computeIsoDaysInMonth(isoDateFields.isoYear, isoMonth) - const isoDay = clampProp(isoDateFields, 'isoDay', 1, daysInMonth, overflowI) + const daysInMonth = computeIsoDaysInMonth(isoInternals.isoYear, isoMonth) + const isoDay = clampProp(isoInternals as IsoDateFields, 'isoDay', 1, daysInMonth, overflow) + if (isoDay) { return { - ...isoDateFields, // calendar,(timeZone),isoYear + ...isoInternals, isoMonth, isoDay, } @@ -161,40 +192,37 @@ export function constrainIsoDateInternals(isoDateFields, overflowI = rejectI) { } } -export function constrainIsoTimeFields(isoTimeFields, overflowI = rejectI) { +export function constrainIsoTimeFields(isoTimeFields: IsoTimeFields, overflow: Overflow = Overflow.Reject) { // TODO: clever way to compress this, using functional programming // Will this kill need for clampProp? return { - isoHour: clampProp(isoTimeFields, 'isoHour', 0, 23, overflowI), - isoMinute: clampProp(isoTimeFields, 'isoMinute', 0, 59, overflowI), - isoSecond: clampProp(isoTimeFields, 'isoSecond', 0, 59, overflowI), - isoMillisecond: clampProp(isoTimeFields, 'isoMillisecond', 0, 999, overflowI), - isoMicrosecond: clampProp(isoTimeFields, 'isoMicrosecond', 0, 999, overflowI), - isoNanosecond: clampProp(isoTimeFields, 'isoNanosecond', 0, 999, overflowI), + isoHour: clampProp(isoTimeFields, 'isoHour', 0, 23, overflow), + isoMinute: clampProp(isoTimeFields, 'isoMinute', 0, 59, overflow), + isoSecond: clampProp(isoTimeFields, 'isoSecond', 0, 59, overflow), + isoMillisecond: clampProp(isoTimeFields, 'isoMillisecond', 0, 999, overflow), + isoMicrosecond: clampProp(isoTimeFields, 'isoMicrosecond', 0, 999, overflow), + isoNanosecond: clampProp(isoTimeFields, 'isoNanosecond', 0, 999, overflow), } } -// Epoch-checking -// ------------------------------------------------------------------------------------------------- - -const epochNanoMax = numberToLargeInt(nanoInUtcDay).mult(100000000) // inclusive +const epochNanoMax = numberToLargeInt(secInDay).mult(1e17) // TODO: define this better const epochNanoMin = epochNanoMax.mult(-1) // inclusive const isoYearMax = 275760 // optimization. isoYear at epochNanoMax const isoYearMin = -271821 // optimization. isoYear at epochNanoMin -export function checkIsoDateTimeInternals(isoDateTimeInternals) { - const isoYear = clampProp(isoDateTimeInternals, 'isoYear', isoYearMin, isoYearMax, rejectI) +export function checkIso(isoFields: T): T { + const isoYear = clampProp(isoFields as IsoDateFields, 'isoYear', isoYearMin, isoYearMax, Overflow.Reject) const nudge = isoYear === isoYearMin ? 1 : isoYear === isoYearMax ? -1 : 0 if (nudge) { - const epochNano = isoToEpochNano(isoDateTimeInternals) + const epochNano = isoToEpochNano(isoFields) checkEpochNano(epochNano && epochNano.addNumber((nanoInUtcDay - 1) * nudge)) } - return isoDateTimeInternals + return isoFields } -export function checkEpochNano(epochNano) { +export function checkEpochNano(epochNano: LargeInt | undefined): LargeInt { if ( epochNano === undefined || compareLargeInts(epochNano, epochNanoMin) === 1 || // epochNano < epochNanoMin @@ -208,13 +236,13 @@ export function checkEpochNano(epochNano) { // Field <-> Nanosecond Conversion // ------------------------------------------------------------------------------------------------- -export function isoTimeFieldsToNano(isoTimeFields) { - return givenFieldsToNano(isoTimeFields, hourIndex, isoTimeFieldNamesAsc) +export function isoTimeFieldsToNano(isoTimeFields: IsoTimeFields): number { + return givenFieldsToNano(isoTimeFields, Unit.Hour, isoTimeFieldNamesAsc) } -export function nanoToIsoTimeAndDay(nano) { +export function nanoToIsoTimeAndDay(nano: number): [IsoTimeFields, number] { const [dayDelta, timeNano] = divFloorMod(nano, nanoInUtcDay) - const isoTimeFields = nanoToGivenFields(timeNano, hourIndex, isoTimeFieldNamesAsc) + const isoTimeFields = nanoToGivenFields(timeNano, Unit.Hour, isoTimeFieldNamesAsc) return [isoTimeFields, dayDelta] } @@ -223,43 +251,43 @@ export function nanoToIsoTimeAndDay(nano) { // nano -> [micro/milli/sec] (with floor) -export function epochNanoToSec(epochNano) { +export function epochNanoToSec(epochNano: LargeInt): number { return epochNanoToSecMod(epochNano)[0].toNumber() } -export function epochNanoToMilli(epochNano) { +export function epochNanoToMilli(epochNano: LargeInt): number { return epochNanoToMilliMod(epochNano)[0].toNumber() } -function epochNanoToMicro(epochNano) { +function epochNanoToMicro(epochNano: LargeInt): bigint { return epochNanoToMicroMod(epochNano)[0].toBigInt() } // nano -> [micro/milli/sec] (with remainder) -export function epochNanoToSecMod(epochNano) { +export function epochNanoToSecMod(epochNano: LargeInt): [LargeInt, number] { return epochNano.divFloorMod(nanoInSec) } -function epochNanoToMilliMod(epochNano) { +function epochNanoToMilliMod(epochNano: LargeInt): [LargeInt, number] { return epochNano.divFloorMod(nanoInMilli) } -function epochNanoToMicroMod(epochNano) { +function epochNanoToMicroMod(epochNano: LargeInt): [LargeInt, number] { return epochNano.divFloorMod(nanoInMicro) } // [micro/milli/sec] -> nano -export function epochSecToNano(epochSec) { +export function epochSecToNano(epochSec: number): LargeInt { return numberToLargeInt(epochSec).mult(nanoInSec) } -export function epochMilliToNano(epochMilli) { +export function epochMilliToNano(epochMilli: number): LargeInt { return numberToLargeInt(epochMilli).mult(nanoInMilli) } -export function epochMicroToNano(epochMicro) { +export function epochMicroToNano(epochMicro: LargeInt): LargeInt { return epochMicro.mult(nanoInMicro) } @@ -270,7 +298,7 @@ export const epochGetters = { epochSeconds: epochNanoToSec, epochMilliseconds: epochNanoToMilli, epochMicroseconds: epochNanoToMicro, - epochNanoseconds(epochNano) { + epochNanoseconds(epochNano: LargeInt): bigint { return epochNano.toBigInt() }, } @@ -280,8 +308,8 @@ export const epochGetters = { // ISO Fields -> Epoch -export function isoToEpochSec(isoDateTimeFields) { - const epochSec = isoArgsToEpochSec(...pluckIsoDateTimeFields(isoDateTimeFields)) +export function isoToEpochSec(isoDateTimeFields: IsoDateTimeFields): [number, number] { + const epochSec = isoArgsToEpochSec(...pluckIsoTuple(isoDateTimeFields)) // ^assume valid const subsecNano = @@ -295,36 +323,43 @@ export function isoToEpochSec(isoDateTimeFields) { /* If out-of-bounds, returns undefined */ -export function isoToEpochMilli(isoDateTimeFields) { - return isoArgsToEpochMilli(...pluckIsoDateTimeFields(isoDateTimeFields)) +export function isoToEpochMilli( + isoDateTimeFields: IsoDateTimeFields | IsoDateFields, +): number | undefined { + return isoArgsToEpochMilli(...pluckIsoTuple(isoDateTimeFields)) } /* If out-of-bounds, returns undefined */ -export function isoToEpochNano(isoDateTimeFields) { - const epochMilli = isoToEpochMilli(isoDateTimeFields) +export function isoToEpochNano( + isoFields: IsoDateTimeFields | IsoDateFields, +): LargeInt | undefined { + const epochMilli = isoToEpochMilli(isoFields) if (epochMilli !== undefined) { return numberToLargeInt(epochMilli) .mult(nanoInMilli) .addNumber( - isoDateTimeFields.isoMicrosecond * nanoInMicro + - isoDateTimeFields.isoNanosecond, + ((isoFields as IsoDateTimeInternals).isoMicrosecond || 0) * nanoInMicro + + ((isoFields as IsoDateTimeInternals).isoNanosecond || 0), ) } } // ISO Arguments -> Epoch -export function isoArgsToEpochSec(...args) { - return isoArgsToEpochMilli(...args) / milliInSec // assume valid +/* +Assumes in-bounds +*/ +export function isoArgsToEpochSec(...args: IsoTuple): number { + return isoArgsToEpochMilli(...args)! / milliInSec } /* If out-of-bounds, returns undefined */ -export function isoArgsToEpochMilli(...args) { +export function isoArgsToEpochMilli(...args: IsoTuple): number | undefined { const legacyDate = isoToLegacyDate(...args) const epochMilli = legacyDate.getTime() @@ -334,35 +369,44 @@ export function isoArgsToEpochMilli(...args) { } function isoToLegacyDate( - isoYear, - isoMonth = 1, // rest are optional... - isoDate, - isoHour, - isoMinute, - isoSec, - isoMilli, + isoYear: number, + isoMonth: number = 1, + isoDay: number = 0, + isoHour: number = 0, + isoMinute: number = 0, + isoSec: number = 0, + isoMilli: number = 0, ) { // Note: Date.UTC() interprets one and two-digit years as being in the // 20th century, so don't use it const legacyDate = new Date() legacyDate.setUTCHours(isoHour, isoMinute, isoSec, isoMilli) - legacyDate.setUTCFullYear(isoYear, isoMonth - 1, isoDate) + legacyDate.setUTCFullYear(isoYear, isoMonth - 1, isoDay) return legacyDate } // Epoch -> ISO Fields -export function epochNanoToIso(epochNano) { +export function epochNanoToIso(epochNano: LargeInt): IsoDateTimeFields { const [epochMilli, nanoRemainder] = epochNano.divFloorMod(nanoInMilli) const [isoMicrosecond, isoNanosecond] = divFloorMod(nanoRemainder, nanoInMicro) return { - ...epochMilliToIso(epochMilli), + ...epochMilliToIso(epochMilli.toNumber()), isoMicrosecond, isoNanosecond, } } -export function epochMilliToIso(epochMilli) { +export function epochMilliToIso(epochMilli: number): { + // return value + isoYear: number, + isoMonth: number, + isoDay: number, + isoHour: number, + isoMinute: number, + isoSecond: number, + isoMillisecond: number, +} { const legacyDate = new Date(epochMilli) return { isoYear: legacyDate.getUTCFullYear(), diff --git a/packages/temporal-polyfill/src/new/isoParse.ts b/packages/temporal-polyfill/src/new/isoParse.ts index 347f4b08..650b2473 100644 --- a/packages/temporal-polyfill/src/new/isoParse.ts +++ b/packages/temporal-polyfill/src/new/isoParse.ts @@ -9,7 +9,7 @@ import { } from './durationFields' import { isoTimeFieldDefaults } from './isoFields' import { - checkIsoDateTimeInternals, + checkIso, constrainIsoDateInternals, constrainIsoDateTimeInternals, constrainIsoTimeFields, @@ -170,7 +170,7 @@ function processZonedDateTimeParse(parsed) { } function processDateTimeParse(parsed) { - return checkIsoDateTimeInternals(constrainIsoDateTimeInternals(parsed)) + return checkIso(constrainIsoDateTimeInternals(parsed)) } /* @@ -180,7 +180,7 @@ function processDatelikeParse(parsed) { if (!parsed) { throw new RangeError() } - return checkIsoDateTimeInternals(constrainIsoDateInternals(parsed)) + return checkIso(constrainIsoDateInternals(parsed)) } // Low-level diff --git a/packages/temporal-polyfill/src/new/largeInt.ts b/packages/temporal-polyfill/src/new/largeInt.ts index 0d2fc61c..2990b730 100644 --- a/packages/temporal-polyfill/src/new/largeInt.ts +++ b/packages/temporal-polyfill/src/new/largeInt.ts @@ -16,7 +16,10 @@ export class LargeInt { different than PlainTime/Duration::add, for minification */ addNumber(num: number): LargeInt { - return balanceAndCreate(this.high, this.low + num) + if (num) { + return balanceAndCreate(this.high, this.low + num) + } + return this } mult(multiplier: number): LargeInt { diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index b0bc47cb..4bda13c1 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -7,6 +7,7 @@ import { PlainDate } from './plainDate' import { PlainDateTime } from './plainDateTime' import { DayTimeUnit, Unit, UnitName, unitNameMap, unitNanoMap } from './units' import { + FilterPropValues, clamp, hasAnyPropsByName, isObjectlike, @@ -443,14 +444,14 @@ export function toEpochNano(arg: any): LargeInt { return bigIntToLargeInt(arg) } -export function clampProp( - props: Record, - propName: string, +export function clampProp

( + props: P, + propName: keyof FilterPropValues & string, min: number, max: number, - overflow: Overflow, + overflow: Overflow | -1, ): number { - return clamp(props[propName], min, max, overflow, propName) + return clamp(props[propName] as number, min, max, overflow, propName) } // Primitives diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index d9f14814..75f226a0 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -22,15 +22,16 @@ export function mapProps( return res } -export type PropsRefinerMap = { - [K in keyof P]: (propVal: P[K], propName: K) => V -} - export const mapPropsWithRefiners = mapProps.bind( undefined, (propVal: any, propName: string, refinerMap: any) => refinerMap[propName](propVal, propName), ) as ( - (props: P, refinerMap: PropsRefinerMap) => { [K in keyof P]: V } + any }>( + props: P, + refinerMap: M, + ) => { + [K in keyof P]: ReturnType + } ) export function mapPropNames( @@ -86,6 +87,16 @@ export function pluckProps

(propNames: (keyof P)[], props: P): P { return res } +export function pluckPropsTuple

(propNames: (keyof P)[], props: P): any { + const res = [] + + for (const propName of propNames) { + res.push(props[propName]) + } + + return res +} + export function excludeArrayDuplicates(a: V[]): V[] { return [...new Set(a)] } @@ -259,21 +270,15 @@ export function clamp( num: number, min: number, max: number, - overflow?: Overflow.Constrain, + overflow?: Overflow.Constrain | -1, // -1 for returning undefined ): number export function clamp( num: number, min: number, max: number, - overflow: Overflow | Overflow.Reject, + overflow: Overflow | -1, // might be Overflow.Reject, require noun noun: string, ): number -export function clamp( - num: number, - min: number, - max: number, - overflow: -1, // for returning undefined -): number | undefined export function clamp( num: number, min: number, @@ -335,3 +340,9 @@ export function roundHalfEven(num: number): number { function hasHalf(num: number): boolean { return Math.abs(num % 1) === 0.5 } + +// types + +export type FilterPropValues = { + [K in keyof P as P[K] extends F ? K : never]: P[K] +} From de666d5488fa198464b62d28fe095bcf36b47bb0 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 24 Jul 2023 18:28:24 -0400 Subject: [PATCH 150/805] calendar ts stuff --- .../temporal-polyfill/src/new/calendar.js | 5 - .../{calendarConfig.js => calendarConfig.ts} | 10 +- .../src/new/calendarFields.ts | 4 +- .../new/{calendarImpl.js => calendarImpl.ts} | 428 +++++++++++------- .../temporal-polyfill/src/new/calendarOps.ts | 78 +++- packages/temporal-polyfill/src/new/class.ts | 2 +- .../temporal-polyfill/src/new/isoFields.ts | 22 +- packages/temporal-polyfill/src/new/isoMath.ts | 6 +- packages/temporal-polyfill/src/new/utils.ts | 8 +- .../src/new/zonedDateTime.ts | 2 +- 10 files changed, 358 insertions(+), 207 deletions(-) rename packages/temporal-polyfill/src/new/{calendarConfig.js => calendarConfig.ts} (91%) rename packages/temporal-polyfill/src/new/{calendarImpl.js => calendarImpl.ts} (59%) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.js index 63445859..cd332c76 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.js @@ -8,7 +8,6 @@ import { refinePlainYearMonthBag, } from './convert' import { createDuration, toDurationInternals } from './duration' -import { isoDaysInWeek } from './isoMath' import { parseCalendarId } from './isoParse' import { ensureArray, ensureObjectlike, ensureString, refineOverflowOptions } from './options' import { createPlainDate, toPlainDateInternals } from './plainDate' @@ -24,10 +23,6 @@ export const calendarProtocolMethods = { } }, dateGetterNames), - daysInWeek() { - return isoDaysInWeek - }, - dateAdd(impl, plainDateArg, durationArg, options) { return createPlainDate( impl.dateAdd( diff --git a/packages/temporal-polyfill/src/new/calendarConfig.js b/packages/temporal-polyfill/src/new/calendarConfig.ts similarity index 91% rename from packages/temporal-polyfill/src/new/calendarConfig.js rename to packages/temporal-polyfill/src/new/calendarConfig.ts index 2ed5c949..76cef8a0 100644 --- a/packages/temporal-polyfill/src/new/calendarConfig.js +++ b/packages/temporal-polyfill/src/new/calendarConfig.ts @@ -11,7 +11,9 @@ if origin is <0, consider the era to be 'reverse' direction year = -origin - eraYear year = -(origin + eraYear) */ -export const eraOriginsByCalendarId = { +export const eraOriginsByCalendarId: { + [calendarId: string]: Record +} = { [gregoryCalendarId]: { bce: -1, ce: 0, @@ -54,7 +56,7 @@ export const eraOriginsByCalendarId = { }, } -export const eraRemaps = { +export const eraRemaps: Record = { bc: 'bce', ad: 'ce', } @@ -67,7 +69,9 @@ export function getErasBeginMidYear(calendarOps) { return calendarOps.id === japaneseCalendarId } -export const leapYearMetas = { +export const leapYearMetas: { + [calendarId: string]: number +} = { chinese: 11, // (positive) max possible leap month dangi: 11, // " hebrew: -6, // (negative) constant leap month diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index 9f0d46e2..670c1f9e 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -1,5 +1,5 @@ +import { CalendarOps } from './calendarOps' import { - CalendarOps, IsoDateFields, IsoDateInternals, IsoTimeFields, @@ -126,7 +126,7 @@ export const dateTimeFieldRefiners = { } // Ordered alphabetically, for predictable macros -const yearStatRefiners = { +export const yearStatRefiners = { daysInYear: ensureInteger, inLeapYear: ensureBoolean, monthsInYear: ensureInteger, diff --git a/packages/temporal-polyfill/src/new/calendarImpl.js b/packages/temporal-polyfill/src/new/calendarImpl.ts similarity index 59% rename from packages/temporal-polyfill/src/new/calendarImpl.js rename to packages/temporal-polyfill/src/new/calendarImpl.ts index 3a762024..50563b8f 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.js +++ b/packages/temporal-polyfill/src/new/calendarImpl.ts @@ -10,11 +10,11 @@ import { } from './calendarConfig' import { allYearFieldNames, - dateBasicNames, eraYearFieldNames, monthDayFieldNames, monthFieldNames, yearStatNames, + yearStatRefiners, } from './calendarFields' import { computeIntlMonthsInYearSpan, @@ -23,10 +23,11 @@ import { diffEpochMilliByDay, } from './diff' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' -import { isoDateFieldNames, isoTimeFieldDefaults } from './isoFields' +import { IsoDateFields, IsoDateInternals, isoTimeFieldDefaults } from './isoFields' import { computeIsoDayOfWeek, computeIsoDaysInMonth, + computeIsoDaysInWeek, computeIsoDaysInYear, computeIsoIsLeapYear, computeIsoMonthsInYear, @@ -39,60 +40,65 @@ import { isoToEpochMilli, } from './isoMath' import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' -import { rejectI } from './options' -import { milliInDay } from './units' +import { Overflow } from './options' +import { Unit, milliInDay } from './units' import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './utils' +import { CalendarOps } from './calendarOps' +import { DurationFields, DurationInternals } from './durationFields' // Base ISO Calendar // ------------------------------------------------------------------------------------------------- +// TODO: rename to 'CalendarImpl', since it's a base? -class IsoCalendarImpl { - constructor(id) { - this.id = id - } +class IsoCalendarImpl implements CalendarOps { + constructor(public id: string) {} - year(isoDateFields) { + year(isoDateFields: IsoDateFields): number { return isoDateFields.isoYear } - month(isoDateFields) { + month(isoDateFields: IsoDateFields): number { return isoDateFields.isoMonth } - day(isoDateFields) { + day(isoDateFields: IsoDateFields): number { return isoDateFields.isoDay } - era(isoDateFields) { - // undefined + era(isoDateFields: IsoDateFields): string | undefined { + return undefined // hopefully minifier will remove } - eraYear(isoDateFields) { - // undefined + eraYear(isoDateFields: IsoDateFields): number | undefined { + return undefined // hopefully minifier will remove } - monthCode(isoDateFields) { + monthCode(isoDateFields: IsoDateFields): string { return formatMonthCode(isoDateFields.isoMonth) } - daysInMonth(isoDateFields) { - return this.queryDaysInMonth(...this.queryYearMonthDay(isoDateFields)) + daysInMonth(isoDateFields: IsoDateFields): number { + return this.queryDaysInMonth( + ...(this.queryYearMonthDay(isoDateFields) as unknown as [number, number]), + ) } - dateFromFields(fields, overflow) { + dateFromFields(fields: any, overflow: Overflow): IsoDateInternals { const year = this.refineYear(fields) const month = this.refineMonth(fields, year, overflow) const day = this.refineDay(fields, month, year, overflow) + return this.queryIsoFields(year, month, day) } - yearMonthFromFields(fields, overflow) { + yearMonthFromFields(fields: any, overflow: Overflow): IsoDateInternals { const year = this.refineYear(fields) const month = this.refineMonth(fields, year, overflow) + return this.queryIsoFields(year, month, 1) } - monthDayFromFields(fields, overflow) { + monthDayFromFields(fields: any, overflow: Overflow): IsoDateInternals { let { month, monthCode, day } = fields let year @@ -109,7 +115,7 @@ class IsoCalendarImpl { return this.queryIsoFields(year, month, day) } - fields(fieldNames) { + fields(fieldNames: string[]): string[] { if (getAllowErasInFields(this) && fieldNames.includes('year')) { return [...fieldNames, ...eraYearFieldNames] } @@ -117,7 +123,7 @@ class IsoCalendarImpl { return fieldNames } - mergeFields(baseFields, additionalFields) { + mergeFields(baseFields: any, additionalFields: any): any { const merged = { ...baseFields } removeIfAnyProps(merged, additionalFields, monthFieldNames) @@ -141,7 +147,7 @@ class IsoCalendarImpl { // Internal Querying // ----------------- - queryIsoFields(year, month, day) { + queryIsoFields(year: number, month: number, day: number): IsoDateInternals { return { calendar: this, isoYear: year, @@ -150,22 +156,22 @@ class IsoCalendarImpl { } } - queryYearMonthDay(isoDateFields) { + queryYearMonthDay(isoDateFields: IsoDateFields): [number, number, number] { return [isoDateFields.isoYear, isoDateFields.isoMonth, isoDateFields.isoDay] } - queryYearMonthForMonthDay(monthCodeNumber /*, isLeapMonth, day */) { + queryYearMonthForMonthDay(monthCodeNumber: number, isLeapMonth: boolean, day: number): [number, number] { return [isoEpochFirstLeapYear, monthCodeNumber] } - queryLeapMonth(year) { - // undefined + queryLeapMonth(year: number): number | undefined { + return undefined // hopefully removed by minifier } // Algorithmic Computations // ------------------------ - dayOfYear(isoDateFields) { + dayOfYear(isoDateFields: IsoDateFields): number { const dayEpochMilli = isoToEpochMilli({ ...isoDateFields, ...isoTimeFieldDefaults, @@ -174,18 +180,26 @@ class IsoCalendarImpl { return diffEpochMilliByDay(yearStartEpochMilli, dayEpochMilli) } - dateAdd(isoDateFields, durationFields, overflow) { + dateAdd( + isoDateFields: IsoDateFields, + durationFields: DurationFields, + overflow: Overflow, + ): IsoDateFields { return moveDate(this, isoDateFields, durationFields, overflow) } - dateUntil(startIsoDateFields, endIsoDateFields, largestUnitIndex) { - return diffDatesExact(this, startIsoDateFields, endIsoDateFields, largestUnitIndex) + dateUntil( + startIsoDateFields: IsoDateFields, + endIsoDateFields: IsoDateFields, + largestUnit: Unit, // TODO: only year/month/week/day? + ): DurationInternals { + return diffDatesExact(this, startIsoDateFields, endIsoDateFields, largestUnit) } // Field Refining // -------------- - refineYear(fields) { + refineYear(fields: any): number { let { era, eraYear, year } = fields const allowEras = getAllowErasInFields(this) @@ -205,14 +219,14 @@ class IsoCalendarImpl { } refineMonth( - fields, - year, // optional if known that calendar doesn't support leap months - overflowI = rejectI, - ) { + fields: any, + year: number, // optional if known that calendar doesn't support leap months + overflow: Overflow = Overflow.Reject, + ): number { let { month, monthCode } = fields if (monthCode !== undefined) { - const monthByCode = refineMonthCode(this, monthCode, year, overflowI) + const monthByCode = refineMonthCode(this, monthCode, year, overflow) if (month !== undefined && month !== monthByCode) { throw new RangeError('The month and monthCode do not agree') @@ -224,29 +238,115 @@ class IsoCalendarImpl { } return clamp( - this.readMonth(fields, year, overflowI), + month, 1, - this.queryMonthsInYear(year), - overflowI, + this.queryMonthsInYear(year!), + overflow, 'month', ) } - refineDay(fields, month, year, overflowI) { + refineDay(fields: any, month: number, year: number, overflow: Overflow) { return clamp( fields.day, // day guaranteed to exist because of required*Fields 1, this.queryDaysInMonth(year, month), - overflowI, + overflow, 'day', ) } } +// IsoCalendarImpl - Year Query Methods +// ------------------------------------------------------------------------------------------------- +// TODO: rename 'query' -> 'compute' + +interface IsoYearQueryMethods { + queryDaysInYear(year: number): number + queryIsLeapYear(year: number): boolean + queryMonthsInYear(year: number): number +} + +// sorted alphabetically, for predictable macros +const isoYearQueryMethods: IsoYearQueryMethods = { + queryDaysInYear: computeIsoDaysInYear, + queryIsLeapYear: computeIsoIsLeapYear, + queryMonthsInYear: computeIsoMonthsInYear, +} + +// IsoCalendarImpl - Year Methods +// ------------------------------------------------------------------------------------------------- + +interface IsoYearMethods { + daysInYear(isoFields: IsoDateFields): number + inLeapYear(isoFields: IsoDateFields): boolean + monthsInYear(isoFields: IsoDateFields): number +} + +const isoYearMethods = {} as IsoYearMethods + +Object.keys(isoYearQueryMethods).forEach((queryMethodName, i) => { + isoYearMethods[yearStatNames[i]] = function( + this: IsoCalendarImpl, + isoDateFields: IsoDateFields, + ) { + return this[queryMethodName as keyof IsoYearMethods](this.year(isoDateFields)) + } as any +}) + +// IsoCalendarImpl - Week Methods +// ------------------------------------------------------------------------------------------------- + +interface IsoWeekMethods { + daysInWeek(isoFields: IsoDateFields): number + dayOfWeek(isoFields: IsoDateFields): number + weekOfYear(isoFields: IsoDateFields): number + yearOfWeek(isoFields: IsoDateFields): number +} + +const isoWeekMethods: IsoWeekMethods = { + daysInWeek: computeIsoDaysInWeek, + dayOfWeek: computeIsoDayOfWeek, + weekOfYear: computeIsoWeekOfYear, + yearOfWeek: computeIsoYearOfWeek, +} + +// IsoCalendarImpl - Misc Methods +// ------------------------------------------------------------------------------------------------- + +interface IsoMiscMethods { + addMonths(year: number, month: number, monthDelta: number): [number, number] + queryDateStart(year: number, month?: number, day?: number): number + queryDaysInMonth(year: number, month: number): number + queryMonthsInYearSpan(yearStart: number, yearEnd: number): number +} + +const isoMiscMethods: IsoMiscMethods = { + addMonths: moveByIsoMonths, + queryDateStart: isoArgsToEpochMilli as (year: number, month?: number, day?: number) => number, + queryDaysInMonth: computeIsoDaysInMonth, + queryMonthsInYearSpan: computeIsoMonthsInYearSpan, +} + +// IsoCalendarImpl - Prototype Extension +// ------------------------------------------------------------------------------------------------- + +interface IsoCalendarImpl extends IsoYearQueryMethods {} +interface IsoCalendarImpl extends IsoYearMethods {} +interface IsoCalendarImpl extends IsoWeekMethods {} +interface IsoCalendarImpl extends IsoMiscMethods {} + +Object.assign(IsoCalendarImpl.prototype, { + ...isoYearQueryMethods, + ...isoYearMethods, + ...isoWeekMethods, + ...isoMiscMethods, +}) + // Refining Utils -// -------------- +// ------------------------------------------------------------------------------------------------- -function refineEraYear(calendar, era, eraYear) { +function refineEraYear(calendar: IsoCalendarImpl, era: string, eraYear: number): number { const eraOrigins = getEraOrigins(calendar.id) if (eraOrigins === undefined) { throw new RangeError('Does not accept era/eraYear') @@ -261,10 +361,10 @@ function refineEraYear(calendar, era, eraYear) { } function refineMonthCode( - calendar, - monthCode, - year, // optional if known that calendar doesn't support leap months - overflow = 'reject', + calendar: IsoCalendarImpl, + monthCode: string, + year: number, // optional if known that calendar doesn't support leap months + overflow: Overflow = Overflow.Reject, ) { const leapMonth = calendar.queryLeapMonth(year) const [monthCodeNumber, isLeapMonth] = parseMonthCode(monthCode) @@ -284,7 +384,7 @@ function refineMonthCode( throw new RangeError('Invalid leap-month month code') } - if (overflow === 'reject' && month !== leapMonth) { + if (overflow === Overflow.Reject && month !== leapMonth) { throw new RangeError('Invalid leap-month month code') } } @@ -292,59 +392,24 @@ function refineMonthCode( return month } -// Prototype Trickery -// ------------------ - -const isoYearQueryMethods = { - // sorted alphabetically, for predictable macros - queryDaysInYear: computeIsoDaysInYear, - queryIsLeapYear: computeIsoIsLeapYear, - queryMonthsInYear: computeIsoMonthsInYear, -} - -Object.assign(IsoCalendarImpl.prototype, { - dayOfWeek: computeIsoDayOfWeek, - weekOfYear: computeIsoWeekOfYear, - yearOfWeek: computeIsoYearOfWeek, - addMonths: moveByIsoMonths, - queryDateStart: isoArgsToEpochMilli, - queryDaysInMonth: computeIsoDaysInMonth, - queryMonthsInYearSpan: computeIsoMonthsInYearSpan, - ...isoYearQueryMethods, -}) - -// year/month/day -dateBasicNames.forEach((dateFieldName, i) => { - IsoCalendarImpl.prototype[dateFieldName] = function(isoDateFields) { - return isoDateFields[isoDateFieldNames[i]] - } -}) - -// daysInYear/inLeapYear/monthsInYear -Object.keys(isoYearQueryMethods).forEach((queryMethodName, i) => { - IsoCalendarImpl.prototype[yearStatNames[i]] = function(isoDateFields) { - return this[queryMethodName](this.year(isoDateFields)) - } -}) - // Gregory Calendar // ------------------------------------------------------------------------------------------------- class GregoryCalendarImpl extends IsoCalendarImpl { - era(isoDateFields) { + era(isoDateFields: IsoDateFields): string | undefined { return computeGregoryEra(isoDateFields.isoYear) } - eraYear(isoDateFields) { + eraYear(isoDateFields: IsoDateFields): number | undefined { return computeGregoryEraYear(isoDateFields.isoYear) } } -function computeGregoryEra(isoYear) { +function computeGregoryEra(isoYear: number): string { return isoYear < 1 ? 'bce' : 'ce' } -function computeGregoryEraYear(isoYear) { +function computeGregoryEraYear(isoYear: number): number { return isoYear < 1 ? -(isoYear - 1) : isoYear } @@ -354,11 +419,11 @@ function computeGregoryEraYear(isoYear) { class JapaneseCalendarImpl extends GregoryCalendarImpl { isoDateFieldsToIntl = createJapaneseFieldCache() - era(isoDateFields) { + era(isoDateFields: IsoDateFields): string | undefined { return this.isoDateFieldsToIntl(isoDateFields).era } - eraYear(isoDateFields) { + eraYear(isoDateFields: IsoDateFields): number | undefined { return this.isoDateFieldsToIntl(isoDateFields).eraYear } } @@ -367,7 +432,11 @@ class JapaneseCalendarImpl extends GregoryCalendarImpl { // ------------------------------------------------------------------------------------------------- class IntlCalendarImpl extends IsoCalendarImpl { - constructor(id) { + isoDateFieldsToIntl: (isoDateFields: IsoDateFields) => IntlFields + queryYear: YearQueryFunc + yearAtEpoch: number + + constructor(id: string) { super(id) const epochMilliToIntlFields = createEpochMilliToIntlFields(id) @@ -378,54 +447,64 @@ class IntlCalendarImpl extends IsoCalendarImpl { this.yearAtEpoch = yearAtEpoch } - year(isoDateFields) { + year(isoDateFields: IsoDateFields): number { return this.queryYearMonthDay(isoDateFields)[0] } - month(isoDateFields) { + month(isoDateFields: IsoDateFields): number { return this.queryYearMonthDay(isoDateFields)[1] } - monthCode(isoDateFields) { + monthCode(isoDateFields: IsoDateFields): string { const [year, month] = this.queryYearMonthDay(isoDateFields) const leapMonth = this.queryLeapMonth(year) return formatMonthCode(month, leapMonth) } - addMonths(year, month, monthDelta) { + addMonths(year: number, month: number, monthDelta: number): [ + year: number, + month: number, + ] { return moveByIntlMonths(year, month, monthDelta, this) } // Internal Querying // ----------------- - queryIsoFields(year, month, day) { + queryIsoFields(year: number, month: number, day: number): IsoDateInternals { return { calendar: this, ...epochMilliToIso(this.queryDateStart(year, month, day)), } } - queryDaysInYear(year) { + queryDaysInYear(year: number): number { const milli = this.queryDateStart(year) const milliNext = this.queryDateStart(year + 1) return diffEpochMilliByDay(milli, milliNext) } - queryIsLeapYear(year) { + queryIsLeapYear(year: number): boolean { const days = this.queryDaysInYear(year) return days > this.queryDaysInYear(year - 1) && days > this.queryDaysInYear(year + 1) } - queryYearMonthDay(isoDateFields) { + queryYearMonthDay(isoDateFields: IsoDateFields): [ + year: number, + month: number, + day: number, + ] { const intlFields = this.isoDateFieldsToIntl(isoDateFields) const { year, month, day } = intlFields const { monthStrToIndex } = this.queryYear(year) return [year, monthStrToIndex[month] + 1, day] } - queryYearMonthForMonthDay(monthCodeNumber, isLeapMonth, day) { + queryYearMonthForMonthDay(monthCodeNumber: number, isLeapMonth: boolean, day: number): [ + year: number, + month: number, + ] { let year = this.yearAtEpoch const endYear = year + 100 @@ -444,7 +523,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { throw new RangeError('Could not guess year') } - queryLeapMonth(year) { + queryLeapMonth(year: number): number | undefined { const currentMonthStrs = this.queryMonthStrs(year) const prevMonthStrs = this.queryMonthStrs(year - 1) const prevLength = currentMonthStrs.length @@ -458,16 +537,16 @@ class IntlCalendarImpl extends IsoCalendarImpl { } } - queryMonthsInYear(year) { + queryMonthsInYear(year: number): number { const { monthEpochMilli } = this.queryYear(year) return monthEpochMilli.length } - queryMonthsInYearSpan(yearDelta, yearStart) { + queryMonthsInYearSpan(yearDelta: number, yearStart: number): number { return computeIntlMonthsInYearSpan(yearDelta, yearStart, this) } - queryDaysInMonth(year, month) { + queryDaysInMonth(year: number, month: number): number { const { monthEpochMilli } = this.queryYear(year) let nextMonth = month + 1 let nextMonthEpochMilli = monthEpochMilli @@ -483,30 +562,35 @@ class IntlCalendarImpl extends IsoCalendarImpl { ) } - queryDateStart(year, month = 1, day = 1) { + queryDateStart(year: number, month: number = 1, day: number = 1): number { return this.queryYear(year).monthEpochMilli[month - 1] + (day - 1) * milliInDay } - queryMonthStrs(year) { + queryMonthStrs(year: number): string[] { return Object.keys(this.queryYear(year).monthStrToIndex) } } -// Prototype Trickery -// ------------------ +// IntlCalendarImpl - Prototype Trickery +// ------------------------------------------------------------------------------------------------- // era/eraYear/year/day [...allYearFieldNames, 'day'].forEach((dateFieldName) => { - IntlCalendarImpl.prototype[dateFieldName] = function(isoDateFields) { - return this.isoDateFieldsToIntl(isoDateFields)[dateFieldName] + (IntlCalendarImpl as any).prototype[dateFieldName] = function( + this: IntlCalendarImpl, + isoDateFields: IsoDateFields, + ) { + return (this.isoDateFieldsToIntl(isoDateFields) as any)[dateFieldName] } }) // CalendarImpl Querying // ------------------------------------------------------------------------------------------------- -const calendarImplClasses = { +const calendarImplClasses: { + [calendarId: string]: { new(calendarId: string): IsoCalendarImpl } +} = { [isoCalendarId]: IsoCalendarImpl, [gregoryCalendarId]: GregoryCalendarImpl, [japaneseCalendarId]: JapaneseCalendarImpl, @@ -516,7 +600,7 @@ const queryCalendarImplWithClass = createLazyGenerator((calendarId, CalendarImpl return new CalendarImplClass(calendarId) }) -export function queryCalendarImpl(calendarId) { +export function queryCalendarImpl(calendarId: string): IsoCalendarImpl { const calendarIdBase = getCalendarIdBase(calendarId) const CalendarImplClass = calendarImplClasses[calendarIdBase] @@ -530,29 +614,31 @@ export function queryCalendarImpl(calendarId) { // IntlFields Querying // ------------------------------------------------------------------------------------------------- -/* interface IntlFields { - era: string - eraYear: number + era: string | undefined + eraYear: number | undefined year: number month: string day: number } -*/ -function createIntlFieldCache(epochMilliToIntlFields) { - return createLazyGenerator((isoDateFields) => { - const epochMilli = isoToEpochMilli(isoDateFields) +function createIntlFieldCache( + epochMilliToIntlFields: (epochMilli: number) => IntlFields, +) { + return createLazyGenerator((isoDateFields: IsoDateFields) => { + const epochMilli = isoToEpochMilli(isoDateFields)! return epochMilliToIntlFields(epochMilli) }, WeakMap) } -function createJapaneseFieldCache() { +function createJapaneseFieldCache(): ( + (isoDateFields: IsoDateFields) => IntlFields +) { const epochMilliToIntlFields = createEpochMilliToIntlFields(japaneseCalendarId) - const primaryEraMilli = isoArgsToEpochMilli(1868, 9, 8) + const primaryEraMilli = isoArgsToEpochMilli(1868, 9, 8)! - return createLazyGenerator((isoDateFields) => { - const epochMilli = isoToEpochMilli(isoDateFields) + return createLazyGenerator((isoDateFields: IsoDateFields) => { + const epochMilli = isoToEpochMilli(isoDateFields)! const intlFields = epochMilliToIntlFields(epochMilli) if (epochMilli < primaryEraMilli) { @@ -564,36 +650,46 @@ function createJapaneseFieldCache() { }, WeakMap) } -function createEpochMilliToIntlFields(calendarId) { +function createEpochMilliToIntlFields(calendarId: string) { const intlFormat = buildIntlFormat(calendarId) if (!isCalendarIdsRelated(calendarId, intlFormat.resolvedOptions().calendar)) { throw new RangeError('Invalid calendar: ' + calendarId) } - return (epochMilli) => { - const intlParts = hashIntlFormatParts(intlFormat, epochMilli) - return parseIntlParts(intlParts, calendarId) + return (epochMilli: number) => { + const intlPartsHash = hashIntlFormatParts(intlFormat, epochMilli) + return parseIntlParts(intlPartsHash, calendarId) } } -function parseIntlParts(intlParts, calendarId) { +function parseIntlParts( + intlPartsHash: Record, + calendarId: string, +): IntlFields { return { - ...parseIntlYear(intlParts, calendarId), - month: intlParts.month, // a short month string - day: parseInt(intlParts.day), + ...parseIntlYear(intlPartsHash, calendarId), + month: intlPartsHash.month, // a short month string + day: parseInt(intlPartsHash.day), } } -export function parseIntlYear(intlParts, calendarId) { - let year = parseInt(intlParts.relatedYear || intlParts.year) - let era - let eraYear +export function parseIntlYear( + intlPartsHash: Record, + calendarId: string, +): { + era: string | undefined + eraYear: number | undefined + year: number +} { + let year = parseInt(intlPartsHash.relatedYear || intlPartsHash.year) + let era: string | undefined + let eraYear: number | undefined - if (intlParts.era) { + if (intlPartsHash.era) { const eraOrigins = getEraOrigins(calendarId) if (eraOrigins !== undefined) { - era = normalizeShortEra(intlParts.era) + era = normalizeShortEra(intlPartsHash.era) eraYear = year // TODO: will this get optimized to next line? year = eraYearToYear(eraYear, eraOrigins[era] || 0) } @@ -602,7 +698,7 @@ export function parseIntlYear(intlParts, calendarId) { return { era, eraYear, year } } -function buildIntlFormat(calendarId) { +function buildIntlFormat(calendarId: string): Intl.DateTimeFormat { return new IntlDateTimeFormat(standardCalendarId, { calendar: calendarId, timeZone: 'UTC', @@ -616,16 +712,27 @@ function buildIntlFormat(calendarId) { // Intl Month Cache // ------------------------------------------------------------------------------------------------- -function createIntlMonthCache(epochMilliToIntlFields) { +// TODO: rename to year 'info' (as opposed to year number?) +type YearQueryFunc = (year: number) => { + monthEpochMilli: number[], + monthStrToIndex: Record +} + +function createIntlMonthCache( + epochMilliToIntlFields: (epochMilli: number) => IntlFields, +): [ + queryYear: YearQueryFunc, + yearAtEpoch: number, +] { const yearAtEpoch = epochMilliToIntlFields(0).year const yearCorrection = yearAtEpoch - isoEpochOriginYear const queryYear = createLazyGenerator(buildYear) - function buildYear(year) { - let epochMilli = isoArgsToEpochMilli(year - yearCorrection) + function buildYear(year: number) { + let epochMilli = isoArgsToEpochMilli(year - yearCorrection)! let intlFields - const milliReversed = [] - const monthStrsReversed = [] + const milliReversed: number[] = [] + const monthStrsReversed: string[] = [] // move beyond current year do { @@ -658,16 +765,16 @@ function createIntlMonthCache(epochMilliToIntlFields) { // Era Utils // ------------------------------------------------------------------------------------------------- -function getEraOrigins(calendarId) { +function getEraOrigins(calendarId: string): Record { return eraOriginsByCalendarId[getCalendarIdBase(calendarId)] } -function eraYearToYear(eraYear, eraOrigin) { +function eraYearToYear(eraYear: number, eraOrigin: number): number { // see the origin format in calendarConfig return (eraOrigin + eraYear) * (Math.sign(eraOrigin) || 1) } -function normalizeShortEra(formattedEra) { +function normalizeShortEra(formattedEra: string): string { formattedEra = formattedEra .normalize('NFD') // 'Shōwa' -> 'Showa' .replace(/[^a-z0-9]/g, '') // 'Before R.O.C.' -> 'BeforeROC' @@ -681,7 +788,10 @@ function normalizeShortEra(formattedEra) { const monthCodeRegExp = /^M(\d{2})(L?)$/ -function parseMonthCode(monthCode) { +function parseMonthCode(monthCode: string): [ + monthCodeNumber: number, + isLeapMonth: boolean, +] { const m = monthCodeRegExp.exec(monthCode) if (!m) { throw new RangeError('Invalid monthCode format') @@ -693,7 +803,11 @@ function parseMonthCode(monthCode) { ] } -function refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) { +function refineMonthCodeNumber( + monthCodeNumber: number, + isLeapMonth: boolean, + leapMonth: number | undefined, +): number { return monthCodeNumber + ( (isLeapMonth || (leapMonth && monthCodeNumber >= leapMonth)) ? 1 @@ -701,7 +815,7 @@ function refineMonthCodeNumber(monthCodeNumber, isLeapMonth, leapMonth) { ) } -function formatMonthCode(month, leapMonth) { +function formatMonthCode(month: number, leapMonth?: number): string { return 'M' + padNumber2( month - ( (leapMonth && month >= leapMonth) @@ -714,11 +828,11 @@ function formatMonthCode(month, leapMonth) { // Calendar ID Utils // ------------------------------------------------------------------------------------------------- -function isCalendarIdsRelated(calendarId0, calendarId1) { +function isCalendarIdsRelated(calendarId0: string, calendarId1: string): boolean { return getCalendarIdBase(calendarId0) === getCalendarIdBase(calendarId1) } -function getCalendarIdBase(calendarId) { +function getCalendarIdBase(calendarId: string): string { return calendarId.split('-')[0] } @@ -726,11 +840,11 @@ function getCalendarIdBase(calendarId) { // ------------------------------------------------------------------------------------------------- function removeIfAnyProps( - targetObj, - testObj, - testPropNames, - deletablePropNames = testPropNames, -) { + targetObj: any, + testObj: any, + testPropNames: string[], + deletablePropNames: string[] = testPropNames, +): void { for (const testPropName of testPropNames) { if (testObj[testPropName] !== undefined) { for (const deletablePropName of deletablePropNames) { diff --git a/packages/temporal-polyfill/src/new/calendarOps.ts b/packages/temporal-polyfill/src/new/calendarOps.ts index 78a766a7..e827cd86 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.ts +++ b/packages/temporal-polyfill/src/new/calendarOps.ts @@ -10,14 +10,38 @@ import { idGettersStrict, } from './class' import { createDuration } from './duration' -import { CalendarInternals, CalendarOps } from './isoFields' -import { ensureArray, ensureObjectlike, ensureString, toString } from './options' +import { DurationInternals } from './durationFields' +import { CalendarInternals, IsoDateFields, IsoDateInternals } from './isoFields' +import { Overflow, ensureArray, ensureObjectlike, ensureString, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' -import { unitNamesAsc } from './units' +import { Unit, unitNamesAsc } from './units' import { mapProps } from './utils' +// types + +export interface CalendarOps { + id: string + era(isoFields: IsoDateFields): string | undefined + eraYear(isoFields: IsoDateFields): number | undefined + year(isoFields: IsoDateFields): number + monthCode(isoFields: IsoDateFields): string + month(isoFields: IsoDateFields): number + day(isoFields: IsoDateFields): number + daysInYear(isoFields: IsoDateFields): number + inLeapYear(isoFields: IsoDateFields): boolean + monthsInYear(isoFields: IsoDateFields): number + daysInMonth(isoFields: IsoDateFields): number + dayOfWeek(isoFields: IsoDateFields): number + dayOfYear(isoFields: IsoDateFields): number + weekOfYear(isoFields: IsoDateFields): number + yearOfWeek(isoFields: IsoDateFields): number + daysInWeek(isoFields: IsoDateFields): number +} + +// + const checkCalendarProtocol = createProtocolChecker(calendarProtocolMethods) export function queryCalendarOps(calendarArg) { @@ -47,13 +71,27 @@ export const getCommonCalendarOps = getCommonInnerObj.bind< // Adapter // ------------------------------------------------------------------------------------------------- -const getPlainDateInternals = getStrictInternals.bind(undefined, PlainDate) -const getPlainYearMonthInternals = getStrictInternals.bind(undefined, PlainYearMonth) -const getPlainMonthDayInternals = getStrictInternals.bind(undefined, PlainMonthDay) +const getPlainDateInternals = getStrictInternals.bind< + any, [any], // bound + [PlainDate], // unbound + IsoDateInternals // return +>(undefined, PlainDate) + +const getPlainYearMonthInternals = getStrictInternals.bind< + any, [any], // bound + [PlainYearMonth], // unbound + IsoDateInternals // return +>(undefined, PlainYearMonth) + +const getPlainMonthDayInternals = getStrictInternals.bind< + any, [any], // bound + [PlainMonthDay], // unbound + IsoDateInternals // return +>(undefined, PlainMonthDay) const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { ...mapProps((refiner, propName) => { - return (calendar, isoDateFields) => { + return (calendar: Calendar, isoDateFields: IsoDateInternals) => { return refiner(calendar[propName](createPlainDate(isoDateFields))) } }, { @@ -63,7 +101,12 @@ const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { ...dateStatRefiners, }), - dateAdd(calendar, isoDateFields, durationInternals, overflow) { + dateAdd( + calendar: Calendar, + isoDateFields: IsoDateInternals, + durationInternals: DurationInternals, + overflow: Overflow, + ): IsoDateInternals { return getPlainDateInternals( calendar.dateAdd( createPlainDate(isoDateFields), @@ -73,33 +116,38 @@ const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { ) }, - dateUntil(calendar, isoDateFields0, isoDateFields1, largestUnitIndex) { + dateUntil( + calendar: Calendar, + isoDateFields0: IsoDateFields, + isoDateFields1: IsoDateFields, + largestUnit: Unit, // TODO: ensure year/month/week/day??? + ) { return getPlainDateInternals( calendar.dateUntil( createPlainDate(isoDateFields0), createPlainDate(isoDateFields1), - { largestUnit: unitNamesAsc[largestUnitIndex] }, + { largestUnit: unitNamesAsc[largestUnit] }, ), ) }, - dateFromFields(calendar, fields, overflow) { + dateFromFields(calendar: Calendar, fields: any, overflow: Overflow): IsoDateInternals { return getPlainDateInternals(calendar.dateFromFields(fields, { overflow })) }, - yearMonthFromFields(calendar, fields, overflow) { + yearMonthFromFields(calendar: Calendar, fields: any, overflow: Overflow): IsoDateInternals { return getPlainYearMonthInternals(calendar.yearMonthFromFields(fields, { overflow })) }, - monthDayFromFields(calendar, fields, overflow) { + monthDayFromFields(calendar: Calendar, fields: any, overflow: Overflow): IsoDateInternals { return getPlainMonthDayInternals(calendar.monthDayFromFields(fields, { overflow })) }, - fields(calendar, fieldNames) { + fields(calendar: Calendar, fieldNames: string[]) { return ensureArray(calendar.fields(fieldNames)).map(ensureString) }, - mergeFields(calendar, fields0, fields1) { + mergeFields(calendar: Calendar, fields0: any, fields1: any) { return ensureObjectlike(calendar.mergeFields(fields0, fields1)) }, }) diff --git a/packages/temporal-polyfill/src/new/class.ts b/packages/temporal-polyfill/src/new/class.ts index 1a58b18e..a7366166 100644 --- a/packages/temporal-polyfill/src/new/class.ts +++ b/packages/temporal-polyfill/src/new/class.ts @@ -190,7 +190,7 @@ export function createTemporalClass< return instance } - function toInternals(arg: TemporalInstance | B | string, options?: O): I { + function toInternals(arg: TemporalInstance | B | string, options?: O): I { let argInternals = getInternals(arg) as Reused let argTemporalName diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts index 25834f59..6d2b97bf 100644 --- a/packages/temporal-polyfill/src/new/isoFields.ts +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -1,4 +1,4 @@ -import { queryCalendarOps } from './calendarOps' +import { CalendarOps, queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { toInteger } from './options' import { mapPropNamesToConstant, pluckProps, pluckPropsTuple } from './utils' @@ -18,26 +18,6 @@ export interface IsoTimeFields { isoHour: number, } -// TODO: temporary -export interface CalendarOps { - id: string - era(isoFields: IsoDateFields): string | undefined - eraYear(isoFields: IsoDateFields): number | undefined - year(isoFields: IsoDateFields): number - monthCode(isoFields: IsoDateFields): string - month(isoFields: IsoDateFields): number - day(isoFields: IsoDateFields): number - daysInYear(isoFields: IsoDateFields): number - inLeapYear(isoFields: IsoDateFields): number - monthsInYear(isoFields: IsoDateFields): number - daysInMonth(isoFields: IsoDateFields): number - dayOfWeek(isoFields: IsoDateFields): number - dayOfYear(isoFields: IsoDateFields): number - weekOfYear(isoFields: IsoDateFields): number - yearOfWeek(isoFields: IsoDateFields): number - daysInWeek(isoFields: IsoDateFields): number -} - // TODO: move type CalendarPublic = CalendarProtocol | string diff --git a/packages/temporal-polyfill/src/new/isoMath.ts b/packages/temporal-polyfill/src/new/isoMath.ts index 5716afa3..8add99c6 100644 --- a/packages/temporal-polyfill/src/new/isoMath.ts +++ b/packages/temporal-polyfill/src/new/isoMath.ts @@ -27,7 +27,7 @@ import { nanoToGivenFields, secInDay, } from './units' -import { compareProps, divFloorMod, mapPropsWithRefiners, pluckPropsTuple } from './utils' +import { compareProps, divFloorMod, mapPropsWithRefiners } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -37,6 +37,10 @@ export const isoEpochFirstLeapYear = 1972 export const isoMonthsInYear = 12 export const isoDaysInWeek = 7 +export function computeIsoDaysInWeek(isoDateFields: IsoDateFields) { + return isoDaysInWeek +} + export function computeIsoMonthsInYear(isoYear: number): number { // for methods return isoMonthsInYear } diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index 75f226a0..149be62a 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -163,9 +163,15 @@ export function hasAllPropsByName

( return true } +// interface MapInterface { +// has(key: K): boolean +// get(key: K): V, +// set(key: K, val: V): void +// } + export function createLazyGenerator( generator: (key: K, ...otherArgs: A) => V, - MapClass: { new(): Map } = Map, + MapClass: { new(): any } = Map, ): ( (key: K, ...otherArgs: A) => V ) { diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.ts b/packages/temporal-polyfill/src/new/zonedDateTime.ts index 265a95fa..328bbc36 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/new/zonedDateTime.ts @@ -1,6 +1,6 @@ import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' -import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' +import { CalendarOps, getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { convertToPlainMonthDay, From bd84be47e3b2cc302a5b3cbc3223be4eeae7c6a6 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 24 Jul 2023 18:37:21 -0400 Subject: [PATCH 151/805] renames --- .../src/new/calendarFields.ts | 2 +- .../temporal-polyfill/src/new/calendarImpl.ts | 99 +++++++++---------- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/new/calendarFields.ts index 670c1f9e..21bd7a08 100644 --- a/packages/temporal-polyfill/src/new/calendarFields.ts +++ b/packages/temporal-polyfill/src/new/calendarFields.ts @@ -126,7 +126,7 @@ export const dateTimeFieldRefiners = { } // Ordered alphabetically, for predictable macros -export const yearStatRefiners = { +const yearStatRefiners = { daysInYear: ensureInteger, inLeapYear: ensureBoolean, monthsInYear: ensureInteger, diff --git a/packages/temporal-polyfill/src/new/calendarImpl.ts b/packages/temporal-polyfill/src/new/calendarImpl.ts index 50563b8f..0fe59db4 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.ts +++ b/packages/temporal-polyfill/src/new/calendarImpl.ts @@ -14,7 +14,6 @@ import { monthDayFieldNames, monthFieldNames, yearStatNames, - yearStatRefiners, } from './calendarFields' import { computeIntlMonthsInYearSpan, @@ -46,11 +45,10 @@ import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './u import { CalendarOps } from './calendarOps' import { DurationFields, DurationInternals } from './durationFields' -// Base ISO Calendar +// Base Calendar Implementation // ------------------------------------------------------------------------------------------------- -// TODO: rename to 'CalendarImpl', since it's a base? -class IsoCalendarImpl implements CalendarOps { +export class CalendarImpl implements CalendarOps { constructor(public id: string) {} year(isoDateFields: IsoDateFields): number { @@ -240,7 +238,7 @@ class IsoCalendarImpl implements CalendarOps { return clamp( month, 1, - this.queryMonthsInYear(year!), + this.computeMonthsInYear(year), overflow, 'month', ) @@ -257,96 +255,95 @@ class IsoCalendarImpl implements CalendarOps { } } -// IsoCalendarImpl - Year Query Methods +// Base Calendar Implementation :: Year Query Methods // ------------------------------------------------------------------------------------------------- -// TODO: rename 'query' -> 'compute' -interface IsoYearQueryMethods { - queryDaysInYear(year: number): number - queryIsLeapYear(year: number): boolean - queryMonthsInYear(year: number): number +interface YearComputeMethods { + computeDaysInYear(year: number): number + computeIsLeapYear(year: number): boolean + computeMonthsInYear(year: number): number } // sorted alphabetically, for predictable macros -const isoYearQueryMethods: IsoYearQueryMethods = { - queryDaysInYear: computeIsoDaysInYear, - queryIsLeapYear: computeIsoIsLeapYear, - queryMonthsInYear: computeIsoMonthsInYear, +const yearComputeMethods: YearComputeMethods = { + computeDaysInYear: computeIsoDaysInYear, + computeIsLeapYear: computeIsoIsLeapYear, + computeMonthsInYear: computeIsoMonthsInYear, } -// IsoCalendarImpl - Year Methods +// Base Calendar Implementation :: Year Methods // ------------------------------------------------------------------------------------------------- -interface IsoYearMethods { +interface YearMethods { daysInYear(isoFields: IsoDateFields): number inLeapYear(isoFields: IsoDateFields): boolean monthsInYear(isoFields: IsoDateFields): number } -const isoYearMethods = {} as IsoYearMethods +const yearMethods = {} as YearMethods -Object.keys(isoYearQueryMethods).forEach((queryMethodName, i) => { - isoYearMethods[yearStatNames[i]] = function( - this: IsoCalendarImpl, +Object.keys(yearComputeMethods).forEach((queryMethodName, i) => { + yearMethods[yearStatNames[i]] = function( + this: CalendarImpl, isoDateFields: IsoDateFields, ) { - return this[queryMethodName as keyof IsoYearMethods](this.year(isoDateFields)) + return this[queryMethodName as keyof YearMethods](this.year(isoDateFields)) } as any }) -// IsoCalendarImpl - Week Methods +// Base Calendar Implementation :: Week Methods // ------------------------------------------------------------------------------------------------- -interface IsoWeekMethods { +interface WeekMethods { daysInWeek(isoFields: IsoDateFields): number dayOfWeek(isoFields: IsoDateFields): number weekOfYear(isoFields: IsoDateFields): number yearOfWeek(isoFields: IsoDateFields): number } -const isoWeekMethods: IsoWeekMethods = { +const weekMethods: WeekMethods = { daysInWeek: computeIsoDaysInWeek, dayOfWeek: computeIsoDayOfWeek, weekOfYear: computeIsoWeekOfYear, yearOfWeek: computeIsoYearOfWeek, } -// IsoCalendarImpl - Misc Methods +// Base Calendar Implementation :: Misc Methods // ------------------------------------------------------------------------------------------------- -interface IsoMiscMethods { +interface MiscMethods { addMonths(year: number, month: number, monthDelta: number): [number, number] queryDateStart(year: number, month?: number, day?: number): number queryDaysInMonth(year: number, month: number): number queryMonthsInYearSpan(yearStart: number, yearEnd: number): number } -const isoMiscMethods: IsoMiscMethods = { +const miscMethods: MiscMethods = { addMonths: moveByIsoMonths, queryDateStart: isoArgsToEpochMilli as (year: number, month?: number, day?: number) => number, queryDaysInMonth: computeIsoDaysInMonth, queryMonthsInYearSpan: computeIsoMonthsInYearSpan, } -// IsoCalendarImpl - Prototype Extension +// Base Calendar Implementation :: Prototype Extension // ------------------------------------------------------------------------------------------------- -interface IsoCalendarImpl extends IsoYearQueryMethods {} -interface IsoCalendarImpl extends IsoYearMethods {} -interface IsoCalendarImpl extends IsoWeekMethods {} -interface IsoCalendarImpl extends IsoMiscMethods {} +export interface CalendarImpl extends YearComputeMethods {} +export interface CalendarImpl extends YearMethods {} +export interface CalendarImpl extends WeekMethods {} +export interface CalendarImpl extends MiscMethods {} -Object.assign(IsoCalendarImpl.prototype, { - ...isoYearQueryMethods, - ...isoYearMethods, - ...isoWeekMethods, - ...isoMiscMethods, +Object.assign(CalendarImpl.prototype, { + ...yearComputeMethods, + ...yearMethods, + ...weekMethods, + ...miscMethods, }) // Refining Utils // ------------------------------------------------------------------------------------------------- -function refineEraYear(calendar: IsoCalendarImpl, era: string, eraYear: number): number { +function refineEraYear(calendar: CalendarImpl, era: string, eraYear: number): number { const eraOrigins = getEraOrigins(calendar.id) if (eraOrigins === undefined) { throw new RangeError('Does not accept era/eraYear') @@ -361,7 +358,7 @@ function refineEraYear(calendar: IsoCalendarImpl, era: string, eraYear: number): } function refineMonthCode( - calendar: IsoCalendarImpl, + calendar: CalendarImpl, monthCode: string, year: number, // optional if known that calendar doesn't support leap months overflow: Overflow = Overflow.Reject, @@ -395,7 +392,7 @@ function refineMonthCode( // Gregory Calendar // ------------------------------------------------------------------------------------------------- -class GregoryCalendarImpl extends IsoCalendarImpl { +class GregoryCalendarImpl extends CalendarImpl { era(isoDateFields: IsoDateFields): string | undefined { return computeGregoryEra(isoDateFields.isoYear) } @@ -431,7 +428,7 @@ class JapaneseCalendarImpl extends GregoryCalendarImpl { // Intl Calendar // ------------------------------------------------------------------------------------------------- -class IntlCalendarImpl extends IsoCalendarImpl { +class IntlCalendarImpl extends CalendarImpl { isoDateFieldsToIntl: (isoDateFields: IsoDateFields) => IntlFields queryYear: YearQueryFunc yearAtEpoch: number @@ -478,16 +475,16 @@ class IntlCalendarImpl extends IsoCalendarImpl { } } - queryDaysInYear(year: number): number { + computeDaysInYear(year: number): number { const milli = this.queryDateStart(year) const milliNext = this.queryDateStart(year + 1) return diffEpochMilliByDay(milli, milliNext) } - queryIsLeapYear(year: number): boolean { - const days = this.queryDaysInYear(year) - return days > this.queryDaysInYear(year - 1) && - days > this.queryDaysInYear(year + 1) + computeIsLeapYear(year: number): boolean { + const days = this.computeDaysInYear(year) + return days > this.computeDaysInYear(year - 1) && + days > this.computeDaysInYear(year + 1) } queryYearMonthDay(isoDateFields: IsoDateFields): [ @@ -537,7 +534,7 @@ class IntlCalendarImpl extends IsoCalendarImpl { } } - queryMonthsInYear(year: number): number { + computeMonthsInYear(year: number): number { const { monthEpochMilli } = this.queryYear(year) return monthEpochMilli.length } @@ -589,9 +586,9 @@ class IntlCalendarImpl extends IsoCalendarImpl { // ------------------------------------------------------------------------------------------------- const calendarImplClasses: { - [calendarId: string]: { new(calendarId: string): IsoCalendarImpl } + [calendarId: string]: { new(calendarId: string): CalendarImpl } } = { - [isoCalendarId]: IsoCalendarImpl, + [isoCalendarId]: CalendarImpl, [gregoryCalendarId]: GregoryCalendarImpl, [japaneseCalendarId]: JapaneseCalendarImpl, } @@ -600,7 +597,7 @@ const queryCalendarImplWithClass = createLazyGenerator((calendarId, CalendarImpl return new CalendarImplClass(calendarId) }) -export function queryCalendarImpl(calendarId: string): IsoCalendarImpl { +export function queryCalendarImpl(calendarId: string): CalendarImpl { const calendarIdBase = getCalendarIdBase(calendarId) const CalendarImplClass = calendarImplClasses[calendarIdBase] From fddd2aba09c13eb7fe40beae1deef5a742ac6886 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 24 Jul 2023 19:38:05 -0400 Subject: [PATCH 152/805] more calendar --- .../src/new/{calendar.js => calendar.ts} | 70 ++++++++++++++----- .../src/new/calendarConfig.ts | 13 ++-- .../temporal-polyfill/src/new/calendarOps.ts | 48 +++++++++---- packages/temporal-polyfill/src/new/class.ts | 9 +-- packages/temporal-polyfill/src/new/options.ts | 13 +++- 5 files changed, 109 insertions(+), 44 deletions(-) rename packages/temporal-polyfill/src/new/{calendar.js => calendar.ts} (56%) diff --git a/packages/temporal-polyfill/src/new/calendar.js b/packages/temporal-polyfill/src/new/calendar.ts similarity index 56% rename from packages/temporal-polyfill/src/new/calendar.js rename to packages/temporal-polyfill/src/new/calendar.ts index cd332c76..eea1e97b 100644 --- a/packages/temporal-polyfill/src/new/calendar.js +++ b/packages/temporal-polyfill/src/new/calendar.ts @@ -1,29 +1,40 @@ import { dateGetterNames } from './calendarFields' -import { queryCalendarImpl } from './calendarImpl' -import { createTemporalClass, getObjId, idGetters } from './class' +import { CalendarImpl, queryCalendarImpl } from './calendarImpl' +import { TemporalInstance, createTemporalClass, getObjId, idGetters } from './class' import { refineComplexBag, refinePlainDateBag, refinePlainMonthDayBag, refinePlainYearMonthBag, } from './convert' -import { createDuration, toDurationInternals } from './duration' +import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { parseCalendarId } from './isoParse' -import { ensureArray, ensureObjectlike, ensureString, refineOverflowOptions } from './options' -import { createPlainDate, toPlainDateInternals } from './plainDate' -import { createPlainMonthDay } from './plainMonthDay' -import { createPlainYearMonth } from './plainYearMonth' +import { + ensureArray, + ensureObjectlike, + ensureString, + refineCalendarDiffOptions, + refineOverflowOptions, +} from './options' +import { PlainDate, PlainDateArg, createPlainDate, toPlainDateInternals } from './plainDate' +import { PlainMonthDay, createPlainMonthDay } from './plainMonthDay' +import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' import { excludeUndefinedProps, mapPropNames, noop } from './utils' export const calendarProtocolMethods = { ...mapPropNames((propName) => { - return (impl, plainDateArg) => { + return ((impl: CalendarImpl, plainDateArg: PlainDateArg) => { return impl[propName](toPlainDateInternals(plainDateArg)) - } + }) as any }, dateGetterNames), - dateAdd(impl, plainDateArg, durationArg, options) { + dateAdd( + impl: CalendarImpl, + plainDateArg: PlainDateArg, + durationArg: DurationArg, + options?: any, + ): PlainDate { return createPlainDate( impl.dateAdd( toPlainDateInternals(plainDateArg), @@ -33,33 +44,50 @@ export const calendarProtocolMethods = { ) }, - dateUntil(impl, plainDateArg0, plainDateArg1, options) { + dateUntil( + impl: CalendarImpl, + plainDateArg0: PlainDateArg, + plainDateArg1: PlainDateArg, + options?: any, + ): Duration { return createDuration( impl.dateUntil( toPlainDateInternals(plainDateArg0), toPlainDateInternals(plainDateArg1), - refineOverflowOptions(options), + refineCalendarDiffOptions(options), ), ) }, - dateFromFields(impl, fields, options) { + dateFromFields( + impl: CalendarImpl, + fields: any, + options?: any, + ): PlainDate { return createPlainDate(refinePlainDateBag(fields, options, impl)) }, - yearMonthFromFields(impl, fields, options) { + yearMonthFromFields( + impl: CalendarImpl, + fields: any, + options?: any, + ): PlainYearMonth { return createPlainYearMonth(refinePlainYearMonthBag(fields, options, impl)) }, - monthDayFromFields(impl, fields, options) { + monthDayFromFields( + impl: CalendarImpl, + fields: any, + options?: any, + ): PlainMonthDay { return createPlainMonthDay(refinePlainMonthDayBag(fields, options, impl)) }, - fields(impl, fieldNames) { + fields(impl: CalendarImpl, fieldNames: string[]): string[] { return impl.fields(ensureArray(fieldNames).map(ensureString)) }, - mergeFields(impl, fields0, fields1) { + mergeFields(impl: CalendarImpl, fields0: any, fields1: any): any { return impl.mergeFields( excludeUndefinedProps(ensureObjectlike(fields0)), excludeUndefinedProps(ensureObjectlike(fields1)), @@ -67,6 +95,14 @@ export const calendarProtocolMethods = { }, } +export type CalendarArg = Calendar | string + +export type Calendar = TemporalInstance< + CalendarImpl, // internals + typeof idGetters, // getters + typeof calendarProtocolMethods // methods +> + export const [Calendar, createCalendar] = createTemporalClass( 'Calendar', diff --git a/packages/temporal-polyfill/src/new/calendarConfig.ts b/packages/temporal-polyfill/src/new/calendarConfig.ts index 76cef8a0..05701793 100644 --- a/packages/temporal-polyfill/src/new/calendarConfig.ts +++ b/packages/temporal-polyfill/src/new/calendarConfig.ts @@ -1,3 +1,4 @@ +import { CalendarOps } from "./calendarOps" export const isoCalendarId = 'iso8601' export const gregoryCalendarId = 'gregory' @@ -61,11 +62,11 @@ export const eraRemaps: Record = { ad: 'ce', } -export function getAllowErasInFields(calendarOps) { +export function getAllowErasInFields(calendarOps: CalendarOps): boolean { return calendarOps.id !== isoCalendarId } -export function getErasBeginMidYear(calendarOps) { +export function getErasBeginMidYear(calendarOps: CalendarOps): boolean { return calendarOps.id === japaneseCalendarId } @@ -81,26 +82,26 @@ export const leapYearMetas: { // ------------------------------------------------------------------------------------------------- const defaultRequiredDateFields = ['day'] -const defaultRequiredYearMonthFields = [] +const defaultRequiredYearMonthFields: string[] = [] const defaultRequiredMonthDayFields = ['day'] const isoRequiredDateFields = [...defaultRequiredDateFields, 'year'] const isoRequiredYearMonthFields = [...defaultRequiredYearMonthFields, 'year'] const isoRequiredMonthDayFields = defaultRequiredMonthDayFields -export function getRequiredDateFields(calendarOps) { +export function getRequiredDateFields(calendarOps: CalendarOps): string[] { return calendarOps.id === isoCalendarId ? isoRequiredDateFields : defaultRequiredDateFields } -export function getRequiredYearMonthFields(calendarOps) { +export function getRequiredYearMonthFields(calendarOps: CalendarOps): string[] { return calendarOps.id === isoCalendarId ? isoRequiredYearMonthFields : defaultRequiredYearMonthFields } -export function getRequiredMonthDayFields(calendarOps) { +export function getRequiredMonthDayFields(calendarOps: CalendarOps): string[] { return calendarOps.id === isoCalendarId ? isoRequiredMonthDayFields : defaultRequiredMonthDayFields diff --git a/packages/temporal-polyfill/src/new/calendarOps.ts b/packages/temporal-polyfill/src/new/calendarOps.ts index e827cd86..6a6e4636 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.ts +++ b/packages/temporal-polyfill/src/new/calendarOps.ts @@ -1,6 +1,6 @@ -import { Calendar, calendarProtocolMethods, createCalendar } from './calendar' +import { Calendar, CalendarArg, calendarProtocolMethods, createCalendar } from './calendar' import { dateFieldRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' -import { queryCalendarImpl } from './calendarImpl' +import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { createProtocolChecker, createWrapperClass, @@ -8,8 +8,9 @@ import { getInternals, getStrictInternals, idGettersStrict, + WrapperInstance, } from './class' -import { createDuration } from './duration' +import { Duration, createDuration } from './duration' import { DurationInternals } from './durationFields' import { CalendarInternals, IsoDateFields, IsoDateInternals } from './isoFields' import { Overflow, ensureArray, ensureObjectlike, ensureString, toString } from './options' @@ -44,7 +45,7 @@ export interface CalendarOps { const checkCalendarProtocol = createProtocolChecker(calendarProtocolMethods) -export function queryCalendarOps(calendarArg) { +export function queryCalendarOps(calendarArg: CalendarArg): CalendarOps { if (typeof calendarArg === 'object') { if (calendarArg instanceof Calendar) { return getInternals(calendarArg) @@ -57,11 +58,11 @@ export function queryCalendarOps(calendarArg) { return queryCalendarImpl(toString(calendarArg)) } -export function getPublicCalendar(internals) { +export function getPublicCalendar(internals: { calendar: CalendarOps }): Calendar { const { calendar } = internals - return getInternals(calendar) || // CalendarOpsAdapter (return internal Calendar) - createCalendar(calendar) // CalendarImpl (create outer Calendar) + return getInternals(calendar as CalendarOpsAdapter) || + createCalendar(calendar as CalendarImpl) } export const getCommonCalendarOps = getCommonInnerObj.bind< @@ -89,11 +90,17 @@ const getPlainMonthDayInternals = getStrictInternals.bind< IsoDateInternals // return >(undefined, PlainMonthDay) -const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { +const getDurationInternals = getStrictInternals.bind< + any, [any], // bound + [Duration], // unbound + DurationInternals // return +>(undefined, Duration) + +const calendarOpsAdaptedMethods = { ...mapProps((refiner, propName) => { - return (calendar: Calendar, isoDateFields: IsoDateInternals) => { + return ((calendar: Calendar, isoDateFields: IsoDateInternals) => { return refiner(calendar[propName](createPlainDate(isoDateFields))) - } + }) as any }, { // TODO: more DRY with DateGetters or something? ...eraYearFieldRefiners, @@ -121,13 +128,13 @@ const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { isoDateFields0: IsoDateFields, isoDateFields1: IsoDateFields, largestUnit: Unit, // TODO: ensure year/month/week/day??? - ) { - return getPlainDateInternals( + ): DurationInternals { + return getDurationInternals( calendar.dateUntil( createPlainDate(isoDateFields0), createPlainDate(isoDateFields1), { largestUnit: unitNamesAsc[largestUnit] }, - ), + ) ) }, @@ -150,4 +157,17 @@ const CalendarOpsAdapter = createWrapperClass(idGettersStrict, { mergeFields(calendar: Calendar, fields0: any, fields1: any) { return ensureObjectlike(calendar.mergeFields(fields0, fields1)) }, -}) +} + +type CalendarOpsAdapter = WrapperInstance< + Calendar, // internals + typeof idGettersStrict, // getters + typeof calendarOpsAdaptedMethods // methods +> + +const CalendarOpsAdapter = createWrapperClass< + [Calendar], // constructor arguments + Calendar, // internals + typeof idGettersStrict, // getters + typeof calendarOpsAdaptedMethods // methods +>(idGettersStrict, calendarOpsAdaptedMethods) diff --git a/packages/temporal-polyfill/src/new/class.ts b/packages/temporal-polyfill/src/new/class.ts index a7366166..e9639447 100644 --- a/packages/temporal-polyfill/src/new/class.ts +++ b/packages/temporal-polyfill/src/new/class.ts @@ -32,7 +32,7 @@ type WrapperClass< S extends {}, > = { new(...args: A): WrapperInstance } & S -type WrapperInstance< +export type WrapperInstance< I, G extends { [propName: string]: (internals: I) => unknown } = {}, M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown } = {}, @@ -55,8 +55,8 @@ export function createWrapperClass< I, G extends { [propName: string]: (internals: I) => unknown }, M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, - P extends PropertyDescriptorMap, - S extends {}, + P extends PropertyDescriptorMap = {}, + S extends {} = {}, >( getters: G, methods: M, @@ -233,7 +233,8 @@ export function neverValueOf() { // Complex Objects with IDs // ------------------------------------------------------------------------------------------------- -export function createProtocolChecker(protocolMethods: Record unknown>) { +// any - Record unknown> +export function createProtocolChecker(protocolMethods: any) { const propNames = Object.keys(protocolMethods) propNames.push('id') propNames.sort() // TODO: order matters? diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 4bda13c1..7ad3acef 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -24,7 +24,7 @@ type Options = Record // Compound Options // ------------------------------------------------------------------------------------------------- -export function refineOverflowOptions(options: Options | undefined) { +export function refineOverflowOptions(options: Options | undefined): Overflow { return refineOverflow(normalizeOptions(options)) } @@ -37,7 +37,7 @@ export function refineZonedFieldOptions(options: Options | undefined) { ] } -export function refineEpochDisambigOptions(options: Options | undefined) { +export function refineEpochDisambigOptions(options: Options | undefined): EpochDisambig { return refineEpochDisambig(normalizeOptions(options)) } @@ -67,6 +67,13 @@ export function refineDiffOptions( return [largestUnit, smallestUnit, roundingInc, roundingMode] } +export function refineCalendarDiffOptions( + options: Options | undefined, +): Unit { // TODO: only year/month/week/day??? + options = normalizeOptions(options) + return refineLargestUnit(options, Unit.Year, Unit.Day, Unit.Day) +} + /* Always related to time */ @@ -372,7 +379,7 @@ function refineUnitOption( defaultUnit?: Unit, ): Unit { let unitName = options[optionName] - if (unitName === undefined) { + if (unitName === undefined || unitName === 'auto') { if (defaultUnit === undefined) { throw new RangeError('Must specify' + optionName) // best error? } From 9b18d7276571133a7c3b8473a1affdda83efc08a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 24 Jul 2023 19:42:35 -0400 Subject: [PATCH 153/805] temporal module to ts --- packages/temporal-polyfill/src/new/{temporal.js => temporal.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/temporal-polyfill/src/new/{temporal.js => temporal.ts} (100%) diff --git a/packages/temporal-polyfill/src/new/temporal.js b/packages/temporal-polyfill/src/new/temporal.ts similarity index 100% rename from packages/temporal-polyfill/src/new/temporal.js rename to packages/temporal-polyfill/src/new/temporal.ts From 14f23b64ab857b4d48b426b3dfd7c2c07d3653de Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 25 Jul 2023 11:01:07 -0400 Subject: [PATCH 154/805] timeZoneImpl ts --- .../temporal-polyfill/src/new/calendarImpl.ts | 1 + .../new/{timeZoneImpl.js => timeZoneImpl.ts} | 122 ++++++++++++------ 2 files changed, 84 insertions(+), 39 deletions(-) rename packages/temporal-polyfill/src/new/{timeZoneImpl.js => timeZoneImpl.ts} (64%) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.ts b/packages/temporal-polyfill/src/new/calendarImpl.ts index 0fe59db4..7f7c1a09 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.ts +++ b/packages/temporal-polyfill/src/new/calendarImpl.ts @@ -671,6 +671,7 @@ function parseIntlParts( } } +// TODO: best place for this? Used by timeZoneImpl export function parseIntlYear( intlPartsHash: Record, calendarId: string, diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.js b/packages/temporal-polyfill/src/new/timeZoneImpl.ts similarity index 64% rename from packages/temporal-polyfill/src/new/timeZoneImpl.js rename to packages/temporal-polyfill/src/new/timeZoneImpl.ts index 8317e108..e543936c 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.js +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.ts @@ -2,6 +2,7 @@ /* eslint-disable no-unmodified-loop-condition */ import { parseIntlYear } from './calendarImpl' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' +import { IsoDateTimeFields } from './isoFields' import { epochNanoToSec, epochNanoToSecMod, @@ -11,6 +12,7 @@ import { isoToEpochSec, } from './isoMath' import { parseOffsetNano } from './isoParse' +import { LargeInt } from './largeInt' import { milliInSec, nanoInSec, secInDay } from './units' import { clamp, compareNumbers, createLazyGenerator } from './utils' @@ -18,56 +20,73 @@ const periodDur = secInDay * 60 const minPossibleTransition = isoArgsToEpochSec(1847) const maxPossibleTransition = isoArgsToEpochSec(new Date().getUTCFullYear() + 10) -const intlTimeZoneImplCache = {} +const queryIntlTimeZoneImpl = createLazyGenerator((timeZoneId: string) => { + return new IntlTimeZoneImpl(timeZoneId) +}) -export function queryTimeZoneImpl(timeZoneId) { +export function queryTimeZoneImpl(timeZoneId: string): TimeZoneImpl { const offsetNano = parseOffsetNano(timeZoneId) if (offsetNano !== undefined) { return new FixedTimeZoneImpl(timeZoneId, offsetNano) } - return intlTimeZoneImplCache[timeZoneId] || ( - intlTimeZoneImplCache[timeZoneId] = new IntlTimeZoneImpl(timeZoneId) - ) + return queryIntlTimeZoneImpl(timeZoneId) +} + +export interface TimeZoneImpl { + getOffsetNanosecondsFor(epochNano: LargeInt): number + getPossibleInstantsFor(isoDateTimeFields: IsoDateTimeFields): LargeInt[] + getTransition(epochNano: LargeInt, direction: -1 | 1): LargeInt | undefined } // Fixed // ------------------------------------------------------------------------------------------------- -export class FixedTimeZoneImpl { - constructor(id, offetNano) { - this.id = id - this.offsetNano = offetNano - } +export class FixedTimeZoneImpl implements TimeZoneImpl { + constructor( + public id: string, + public offsetNano: number, + ) {} - getOffsetNanosecondsFor(epochNano) { - return [this.offsetNano] + getOffsetNanosecondsFor(epochNano: LargeInt): number { + return this.offsetNano } - getPossibleInstantsFor(isoDateTimeFields) { - return [isoToEpochNano(isoDateTimeFields).addNumber(this.offsetNano)] + getPossibleInstantsFor(isoDateTimeFields: IsoDateTimeFields): LargeInt[] { + return [isoToEpochNano(isoDateTimeFields)!.addNumber(this.offsetNano)] } - getTransition(epochNano, direction) { + getTransition(epochNano: LargeInt, direction: -1 | 1): LargeInt | undefined { + return undefined // hopefully minifier will remove } } // Intl // ------------------------------------------------------------------------------------------------- -export class IntlTimeZoneImpl { - constructor(id) { - this.id = id +interface IntlTimeZoneStore { + getPossibleEpochSec: (zonedEpochSec: number) => number[] + getOffsetSec: (epochSec: number) => number + getTransition: (epochSec: number, direction: -1 | 1) => number | undefined +} + +export class IntlTimeZoneImpl implements TimeZoneImpl { + store: IntlTimeZoneStore + + constructor( + public id: string + ) { this.store = createIntlTimeZoneStore(createComputeOffsetSec(id)) } - getOffsetNanosecondsFor(epochNano) { + getOffsetNanosecondsFor(epochNano: LargeInt): number { return this.store.getOffsetSec(epochNanoToSec(epochNano)) * nanoInSec } - getPossibleInstantsFor(isoDateTimeFields) { + getPossibleInstantsFor(isoDateTimeFields: IsoDateTimeFields): LargeInt[] { const [zonedEpochSec, subsecNano] = isoToEpochSec(isoDateTimeFields) + return this.store.getPossibleEpochSec(zonedEpochSec) .map((epochSec) => epochSecToNano(epochSec).addNumber(subsecNano)) } @@ -75,7 +94,7 @@ export class IntlTimeZoneImpl { /* exclusive for both directions */ - getTransition(epochNano, direction) { + getTransition(epochNano: LargeInt, direction: -1 | 1): LargeInt | undefined { const [epochSec, subsecNano] = epochNanoToSecMod(epochNano) const resEpochSec = this.store.getTransition( epochSec.toNumber() + ((direction > 0 || subsecNano) ? 1 : 0), @@ -87,13 +106,15 @@ export class IntlTimeZoneImpl { } } -function createIntlTimeZoneStore(computeOffsetSec) { +function createIntlTimeZoneStore( + computeOffsetSec: (epochSec: number) => number, +): IntlTimeZoneStore { const getSample = createLazyGenerator(computeOffsetSec) // always given startEpochSec/endEpochSec - const getSplit = createLazyGenerator((startEpochSec, endEpochSec) => [startEpochSec, endEpochSec]) + const getSplit = createLazyGenerator(createSplitTuple) let minTransition = minPossibleTransition let maxTransition = maxPossibleTransition - function getPossibleEpochSec(zonedEpochSec) { + function getPossibleEpochSec(zonedEpochSec: number): number[] { let startOffsetSec = getOffsetSec(zonedEpochSec - secInDay) let endOffsetSec = getOffsetSec(zonedEpochSec + secInDay) const startUtcEpochSec = zonedEpochSec - startOffsetSec @@ -117,7 +138,7 @@ function createIntlTimeZoneStore(computeOffsetSec) { return [] } - function getOffsetSec(epochSec) { + function getOffsetSec(epochSec: number): number { const clampedEpochSec = clamp(epochSec, minTransition, maxTransition) const [startEpochSec, endEpochSec] = computePeriod(clampedEpochSec) const startOffsetSec = getSample(startEpochSec) @@ -134,7 +155,7 @@ function createIntlTimeZoneStore(computeOffsetSec) { /* inclusive for positive direction, exclusive for negative */ - function getTransition(epochSec, direction) { + function getTransition(epochSec: number, direction: -1 | 1): number | undefined { const clampedEpochSec = clamp(epochSec, minTransition, maxTransition) let [startEpochSec, endEpochSec] = computePeriod(clampedEpochSec) @@ -167,18 +188,35 @@ function createIntlTimeZoneStore(computeOffsetSec) { transition is the first reading of a new offset period just one isolated sample doesn't make it known */ - function pinch(split, startOffsetSec, endOffsetSec, forEpochSec) { - let offsetSec - let splitDurSec + function pinch( + split: [number, number], + startOffsetSec: number, + endOffsetSec: number, + ): undefined + function pinch( + split: [number, number], + startOffsetSec: number, + endOffsetSec: number, + forEpochSec: number, + ): number + function pinch( + split: [number, number], + startOffsetSec: number, + endOffsetSec: number, + forEpochSec?: number, + ): number | undefined { + let offsetSec: number | undefined + let splitDurSec: number | undefined while ( (forEpochSec === undefined || - (forEpochSec < split[0] - ? startOffsetSec - : forEpochSec >= split[1] - ? endOffsetSec - : undefined - ) === undefined + (offsetSec = ( + forEpochSec < split[0] + ? startOffsetSec + : forEpochSec >= split[1] + ? endOffsetSec + : undefined + )) === undefined ) && (splitDurSec = split[1] - split[0]) ) { @@ -198,16 +236,22 @@ function createIntlTimeZoneStore(computeOffsetSec) { return { getPossibleEpochSec, getOffsetSec, getTransition } } -function computePeriod(epochSec) { +function createSplitTuple(startEpochSec: number, endEpochSec: number): [number, number] { + return [startEpochSec, endEpochSec] +} + +function computePeriod(epochSec: number): [number, number] { const startEpochSec = Math.floor(epochSec / periodDur) const endEpochSec = startEpochSec + periodDur return [startEpochSec, endEpochSec] } -function createComputeOffsetSec(timeZoneId) { +function createComputeOffsetSec(timeZoneId: string): ( + (epochSec: number) => number +) { const format = buildIntlFormat(timeZoneId) - return (epochSec) => { + return (epochSec: number) => { const intlParts = hashIntlFormatParts(format, epochSec * milliInSec) const zonedEpochSec = isoArgsToEpochSec( parseIntlYear(intlParts).year, @@ -221,7 +265,7 @@ function createComputeOffsetSec(timeZoneId) { } } -function buildIntlFormat(timeZoneId) { +function buildIntlFormat(timeZoneId: string): Intl.DateTimeFormat { // format will ALWAYS do gregorian. need to parse year return new IntlDateTimeFormat(standardCalendarId, { timeZone: timeZoneId, From 9df6e18eedba0db42fe9fd7dd23b5de62ff7df3d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 25 Jul 2023 11:50:52 -0400 Subject: [PATCH 155/805] time zome ts, more --- .../temporal-polyfill/src/new/calendar.ts | 14 +- .../temporal-polyfill/src/new/calendarOps.ts | 14 +- .../src/new/plainYearMonth.ts | 1 + .../temporal-polyfill/src/new/timeZone.js | 91 ------------ .../temporal-polyfill/src/new/timeZone.ts | 102 ++++++++++++++ .../temporal-polyfill/src/new/timeZoneImpl.ts | 7 +- .../new/{timeZoneOps.js => timeZoneOps.ts} | 129 ++++++++++++------ 7 files changed, 205 insertions(+), 153 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/timeZone.js create mode 100644 packages/temporal-polyfill/src/new/timeZone.ts rename packages/temporal-polyfill/src/new/{timeZoneOps.js => timeZoneOps.ts} (53%) diff --git a/packages/temporal-polyfill/src/new/calendar.ts b/packages/temporal-polyfill/src/new/calendar.ts index eea1e97b..33319128 100644 --- a/packages/temporal-polyfill/src/new/calendar.ts +++ b/packages/temporal-polyfill/src/new/calendar.ts @@ -95,12 +95,18 @@ export const calendarProtocolMethods = { }, } +const calendarMethods = { + ...calendarProtocolMethods, + + toString: getObjId, +} + export type CalendarArg = Calendar | string export type Calendar = TemporalInstance< CalendarImpl, // internals typeof idGetters, // getters - typeof calendarProtocolMethods // methods + typeof calendarMethods // methods > export const [Calendar, createCalendar] = createTemporalClass( @@ -132,9 +138,5 @@ export const [Calendar, createCalendar] = createTemporalClass( // Methods // ----------------------------------------------------------------------------------------------- - { - ...calendarProtocolMethods, - - toString: getObjId, - }, + calendarMethods, ) diff --git a/packages/temporal-polyfill/src/new/calendarOps.ts b/packages/temporal-polyfill/src/new/calendarOps.ts index 6a6e4636..50a2f9ab 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.ts +++ b/packages/temporal-polyfill/src/new/calendarOps.ts @@ -66,7 +66,9 @@ export function getPublicCalendar(internals: { calendar: CalendarOps }): Calenda } export const getCommonCalendarOps = getCommonInnerObj.bind< - any, [any], [CalendarInternals, CalendarInternals], CalendarOps + any, [any], // bound + [CalendarInternals, CalendarInternals], // unbound + CalendarOps // return >(undefined, 'calendar') // Adapter @@ -96,7 +98,7 @@ const getDurationInternals = getStrictInternals.bind< DurationInternals // return >(undefined, Duration) -const calendarOpsAdaptedMethods = { +const calendarOpsAdapterMethods = { ...mapProps((refiner, propName) => { return ((calendar: Calendar, isoDateFields: IsoDateInternals) => { return refiner(calendar[propName](createPlainDate(isoDateFields))) @@ -162,12 +164,12 @@ const calendarOpsAdaptedMethods = { type CalendarOpsAdapter = WrapperInstance< Calendar, // internals typeof idGettersStrict, // getters - typeof calendarOpsAdaptedMethods // methods + typeof calendarOpsAdapterMethods // methods > const CalendarOpsAdapter = createWrapperClass< - [Calendar], // constructor arguments + [Calendar], // constructor Calendar, // internals typeof idGettersStrict, // getters - typeof calendarOpsAdaptedMethods // methods ->(idGettersStrict, calendarOpsAdaptedMethods) + typeof calendarOpsAdapterMethods // methods +>(idGettersStrict, calendarOpsAdapterMethods) diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.ts b/packages/temporal-polyfill/src/new/plainYearMonth.ts index 409d7507..d0ec9cbb 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/new/plainYearMonth.ts @@ -1,3 +1,4 @@ +import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { YearMonthFields, yearMonthGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar } from './calendarOps' diff --git a/packages/temporal-polyfill/src/new/timeZone.js b/packages/temporal-polyfill/src/new/timeZone.js deleted file mode 100644 index c4351786..00000000 --- a/packages/temporal-polyfill/src/new/timeZone.js +++ /dev/null @@ -1,91 +0,0 @@ -import { queryTimeZoneImpl } from '../timeZoneImpl/timeZoneImplQuery' -import { Calendar } from './calendar' -import { queryCalendarOps } from './calendarOps' -import { createTemporalClass, getObjId, idGetters } from './class' -import { refineComplexBag } from './convert' -import { createInstant, toInstantEpochNano } from './instant' -import { formatOffsetNano } from './isoFormat' -import { parseTimeZoneId } from './isoParse' -import { refineEpochDisambigOptions } from './options' -import { createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' -import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' -import { noop } from './utils' - -export const timeZoneProtocolMethods = { - getPossibleInstantsFor(impl, plainDateTimeArg) { - return impl.getPossibleInstantsFor(toPlainDateTimeInternals(plainDateTimeArg)) - .map(createInstant) - }, - - getOffsetNanosecondsFor: getImplOffsetNanosecondsFor, -} - -export const [TimeZone, createTimeZone] = createTemporalClass( - 'TimeZone', - - // Creation - // ----------------------------------------------------------------------------------------------- - - // constructorToInternals - queryTimeZoneImpl, - - // internalsConversionMap - {}, - - // bagToInternals - refineComplexBag.bind(undefined, 'timeZone', Calendar), - - // stringToInternals - (str) => queryTimeZoneImpl(parseTimeZoneId(str)), - - // handleUnusedOptions - noop, - - // Getters - // ----------------------------------------------------------------------------------------------- - - idGetters, - - // Methods - // ----------------------------------------------------------------------------------------------- - - { - ...timeZoneProtocolMethods, - - getOffsetStringFor(impl, instantArg) { - return formatOffsetNano(getImplOffsetNanosecondsFor(impl, instantArg)) - }, - - getPlainDateTimeFor(impl, instantArg, calendarArg) { - const epochNanoseconds = toInstantEpochNano(instantArg) - - return createPlainDateTime({ - calendar: queryCalendarOps(calendarArg), - ...zonedEpochNanoToIso(impl, epochNanoseconds), - }) - }, - - getInstantFor(impl, plainDateTimeArg, options) { - return getSingleInstantFor( - impl, - toPlainDateTimeInternals(plainDateTimeArg), - refineEpochDisambigOptions(options), - ) - }, - - getNextTransition: getImplTransition.bind(undefined, 1), - - getPreviousTransition: getImplTransition.bind(undefined, -1), - - toString: getObjId, - }, -) - -function getImplOffsetNanosecondsFor(impl, instantArg) { - return impl.getOffsetNanosecondsFor(toInstantEpochNano(instantArg)) -} - -function getImplTransition(direction, impl, instantArg) { - const epochNano = impl.getTransition(toInstantEpochNano(instantArg), direction) - return epochNano ? createInstant(epochNano) : null -} diff --git a/packages/temporal-polyfill/src/new/timeZone.ts b/packages/temporal-polyfill/src/new/timeZone.ts new file mode 100644 index 00000000..83ae405e --- /dev/null +++ b/packages/temporal-polyfill/src/new/timeZone.ts @@ -0,0 +1,102 @@ +import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' +import { Calendar, CalendarArg } from './calendar' +import { queryCalendarOps } from './calendarOps' +import { TemporalInstance, createTemporalClass, getObjId, idGetters } from './class' +import { refineComplexBag } from './convert' +import { Instant, InstantArg, createInstant, toInstantEpochNano } from './instant' +import { formatOffsetNano } from './isoFormat' +import { parseTimeZoneId } from './isoParse' +import { refineEpochDisambigOptions } from './options' +import { PlainDateTime, PlainDateTimeArg, createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' +import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' +import { noop } from './utils' + +// TODO: implements some other interface? +export const timeZoneProtocolMethods = { + getPossibleInstantsFor(impl: TimeZoneImpl, plainDateTimeArg: PlainDateTimeArg): Instant[] { + return impl.getPossibleInstantsFor(toPlainDateTimeInternals(plainDateTimeArg)) + .map(createInstant) + }, + + getOffsetNanosecondsFor: getImplOffsetNanosecondsFor, +} + +const timeZoneMethods = { + ...timeZoneProtocolMethods, + + getOffsetStringFor(impl: TimeZoneImpl, instantArg: InstantArg): string { + return formatOffsetNano(getImplOffsetNanosecondsFor(impl, instantArg)) + }, + + getPlainDateTimeFor(impl: TimeZoneImpl, instantArg: InstantArg, calendarArg: CalendarArg): PlainDateTime { + const epochNanoseconds = toInstantEpochNano(instantArg) + + return createPlainDateTime({ + calendar: queryCalendarOps(calendarArg), + ...zonedEpochNanoToIso(impl, epochNanoseconds), + }) + }, + + getInstantFor(impl: TimeZoneImpl, plainDateTimeArg: PlainDateTimeArg, options: any): Instant { + return getSingleInstantFor( + impl, + toPlainDateTimeInternals(plainDateTimeArg), + refineEpochDisambigOptions(options), + ) + }, + + getNextTransition: getImplTransition.bind(undefined, 1), + + getPreviousTransition: getImplTransition.bind(undefined, -1), + + toString: getObjId, +} + +export type TimeZoneArg = TimeZone | string + +export type TimeZone = TemporalInstance< + TimeZoneImpl, // internals + typeof idGetters, // getters + typeof timeZoneMethods // methods +> + +export const [TimeZone, createTimeZone] = createTemporalClass( + 'TimeZone', + + // Creation + // ----------------------------------------------------------------------------------------------- + + // constructorToInternals + queryTimeZoneImpl, + + // internalsConversionMap + {}, + + // bagToInternals + refineComplexBag.bind(undefined, 'timeZone', Calendar), + + // stringToInternals + (str) => queryTimeZoneImpl(parseTimeZoneId(str)), + + // handleUnusedOptions + noop, + + // Getters + // ----------------------------------------------------------------------------------------------- + + idGetters, + + // Methods + // ----------------------------------------------------------------------------------------------- + + timeZoneMethods, +) + +function getImplOffsetNanosecondsFor(impl: TimeZoneImpl, instantArg: InstantArg): number { + return impl.getOffsetNanosecondsFor(toInstantEpochNano(instantArg)) +} + +function getImplTransition(direction: -1 | 1, impl: TimeZoneImpl, instantArg: InstantArg): Instant | null { + const epochNano = impl.getTransition(toInstantEpochNano(instantArg), direction) + return epochNano ? createInstant(epochNano) : null +} diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.ts b/packages/temporal-polyfill/src/new/timeZoneImpl.ts index e543936c..96859f19 100644 --- a/packages/temporal-polyfill/src/new/timeZoneImpl.ts +++ b/packages/temporal-polyfill/src/new/timeZoneImpl.ts @@ -1,5 +1,3 @@ -/* eslint-disable no-return-assign */ -/* eslint-disable no-unmodified-loop-condition */ import { parseIntlYear } from './calendarImpl' import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' import { IsoDateTimeFields } from './isoFields' @@ -13,6 +11,7 @@ import { } from './isoMath' import { parseOffsetNano } from './isoParse' import { LargeInt } from './largeInt' +import { TimeZoneOps } from './timeZoneOps' import { milliInSec, nanoInSec, secInDay } from './units' import { clamp, compareNumbers, createLazyGenerator } from './utils' @@ -34,9 +33,7 @@ export function queryTimeZoneImpl(timeZoneId: string): TimeZoneImpl { return queryIntlTimeZoneImpl(timeZoneId) } -export interface TimeZoneImpl { - getOffsetNanosecondsFor(epochNano: LargeInt): number - getPossibleInstantsFor(isoDateTimeFields: IsoDateTimeFields): LargeInt[] +export interface TimeZoneImpl extends TimeZoneOps { getTransition(epochNano: LargeInt, direction: -1 | 1): LargeInt | undefined } diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.js b/packages/temporal-polyfill/src/new/timeZoneOps.ts similarity index 53% rename from packages/temporal-polyfill/src/new/timeZoneOps.js rename to packages/temporal-polyfill/src/new/timeZoneOps.ts index 45d3d245..bdd61f87 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.js +++ b/packages/temporal-polyfill/src/new/timeZoneOps.ts @@ -1,4 +1,5 @@ import { + WrapperInstance, createProtocolChecker, createWrapperClass, getCommonInnerObj, @@ -7,25 +8,37 @@ import { idGettersStrict, } from './class' import { Instant, createInstant } from './instant' -import { isoTimeFieldDefaults } from './isoFields' +import { IsoDateFields, IsoDateTimeFields, isoTimeFieldDefaults } from './isoFields' import { epochNanoToIso, isoToEpochNano, } from './isoMath' +import { LargeInt } from './largeInt' import { moveDateByDays } from './move' -import { ensureArray } from './options' +import { EpochDisambig, OffsetDisambig, ensureArray, toString } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' -import { TimeZone, createTimeZone, timeZoneProtocolMethods } from './timeZone' -import { queryTimeZoneImpl } from './timeZoneImpl' +import { TimeZone, TimeZoneArg, createTimeZone, timeZoneProtocolMethods } from './timeZone' +import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' import { nanoInUtcDay } from './units' import { createLazyGenerator } from './utils' +import { ZonedInternals } from './zonedDateTime' + +export interface TimeZoneOps { + getOffsetNanosecondsFor(epochNano: LargeInt): number + getPossibleInstantsFor(isoDateTimeFields: IsoDateTimeFields): LargeInt[] +} + +// TODO: best place for this? see CalendarInternals. see ZonedInternals +export interface TimeZoneInternals { + timeZone: TimeZoneOps +} export const utcTimeZoneId = 'UTC' const checkTimeZoneProtocol = createProtocolChecker(timeZoneProtocolMethods) -export function queryTimeZoneOps(timeZoneArg) { +export function queryTimeZoneOps(timeZoneArg: TimeZoneArg): TimeZoneOps { if (typeof timeZoneArg === 'object') { if (timeZoneArg instanceof TimeZone) { return getInternals(timeZoneArg) @@ -38,42 +51,46 @@ export function queryTimeZoneOps(timeZoneArg) { return queryTimeZoneImpl(toString(timeZoneArg)) } -export function getPublicTimeZone(internals) { +export function getPublicTimeZone(internals: { timeZone: TimeZoneOps }): TimeZone { const { timeZone } = internals - return getInternals(timeZone) || // TimeZoneOpsAdapter (return internal TimeZone) - createTimeZone(timeZone) // TimeZoneImpl (create outer TimeZone) + return getInternals(timeZone as TimeZoneOpsAdapter) || + createTimeZone(timeZone as TimeZoneImpl) } -export const getCommonTimeZoneOps = getCommonInnerObj.bind(undefined, 'timeZone') +export const getCommonTimeZoneOps = getCommonInnerObj.bind< + any, [any], // bound + [TimeZoneInternals, TimeZoneInternals], // unbound + TimeZoneOps // return +>(undefined, 'timeZone') // Public Utils // ------------ export function computeNanosecondsInDay( - timeZoneOps, - isoDateFields, // could contain time fields though -) { + timeZoneOps: TimeZoneOps, + isoDateFields: IsoDateFields, // could contain time fields though +): number { isoDateFields = { ...isoDateFields, ...isoTimeFieldDefaults } - const epochNano0 = getSingleInstantFor(timeZoneOps, isoDateFields) + const epochNano0 = getSingleInstantFor(timeZoneOps, { ...isoTimeFieldDefaults, ...isoDateFields }) const epochNano1 = getSingleInstantFor(timeZoneOps, moveDateByDays(isoDateFields, 1)) - return epochNano1.sub(epochNano0).toNumber() + return epochNano1.addLargeInt(epochNano0, -1).toNumber() } export function getMatchingInstantFor( - timeZoneOps, - isoDateTimeFields, - offsetNano, // optional - hasZ, + timeZoneOps: TimeZoneOps, + isoDateTimeFields: IsoDateTimeFields, + offsetNano: number, // optional + hasZ: boolean, // need these defaults? - offsetHandling = 'reject', - disambig = 'compatible', + offsetHandling: OffsetDisambig = OffsetDisambig.Reject, + disambig: EpochDisambig = EpochDisambig.Compat, fuzzy = false, ) { - if (offsetNano !== undefined && offsetHandling !== 'ignore') { + if (offsetNano !== undefined && offsetHandling !== OffsetDisambig.Ignore) { // we ALWAYS use Z as a zero offset - if (offsetHandling === 'use' || hasZ) { - return isoToEpochNano(isoDateTimeFields).sub(offsetNano) + if (offsetHandling === OffsetDisambig.Use || hasZ) { + return isoToEpochNano(isoDateTimeFields)!.addNumber(-offsetNano) } const matchingEpochNano = findMatchingEpochNano( @@ -87,7 +104,7 @@ export function getMatchingInstantFor( return matchingEpochNano } - if (offsetHandling === 'reject') { + if (offsetHandling === OffsetDisambig.Reject) { throw new RangeError('Mismatching offset/timezone') } // else (offsetHandling === 'prefer') ... @@ -96,16 +113,21 @@ export function getMatchingInstantFor( return getSingleInstantFor(timeZoneOps, isoDateTimeFields, disambig) } -function findMatchingEpochNano(timeZoneOps, isoDateTimeFields, offsetNano, fuzzy) { +function findMatchingEpochNano( + timeZoneOps: TimeZoneOps, + isoDateTimeFields: IsoDateTimeFields, + offsetNano: number, + fuzzy: boolean, +): LargeInt | undefined { const possibleEpochNanos = timeZoneOps.getPossibleInstantsFor(isoDateTimeFields) - const zonedEpochNano = isoToEpochNano(isoDateTimeFields) + const zonedEpochNano = isoToEpochNano(isoDateTimeFields)! if (fuzzy) { offsetNano = roundToMinute(offsetNano) } for (const possibleEpochNano of possibleEpochNanos) { - let possibleOffsetNano = zonedEpochNano.sub(possibleEpochNano).toNumber() + let possibleOffsetNano = zonedEpochNano.addLargeInt(possibleEpochNano, -1).toNumber() if (fuzzy) { possibleOffsetNano = roundToMinute(possibleOffsetNano) @@ -118,17 +140,17 @@ function findMatchingEpochNano(timeZoneOps, isoDateTimeFields, offsetNano, fuzzy } export function getSingleInstantFor( - timeZoneOps, - isoDateTimeFields, - disambig = 'compatible', -) { + timeZoneOps: TimeZoneOps, + isoDateTimeFields: IsoDateTimeFields, + disambig: EpochDisambig = EpochDisambig.Compat, +): LargeInt { let epochNanos = timeZoneOps.getPossibleInstantsFor(isoDateTimeFields) if (epochNanos.length === 1) { return epochNanos[0] } - if (disambig === 'reject') { + if (disambig === EpochDisambig.Reject) { throw new RangeError('Ambiguous offset') } @@ -136,7 +158,7 @@ export function getSingleInstantFor( // ('compatible' means 'earlier') if (epochNanos.length) { return epochNanos[ - disambig === 'later' + disambig === EpochDisambig.Later ? 1 : 0 // 'earlier' and 'compatible' ] @@ -145,13 +167,13 @@ export function getSingleInstantFor( // within a transition that jumps forward... // ('compatible' means 'later') - const zonedEpochNano = isoToEpochNano(isoDateTimeFields) + const zonedEpochNano = isoToEpochNano(isoDateTimeFields)! const gapNano = computeGapNear(timeZoneOps, zonedEpochNano) epochNanos = timeZoneOps.getPossibleInstantsFor( epochNanoToIso( zonedEpochNano.addNumber(gapNano * ( - disambig === 'earlier' + disambig === EpochDisambig.Earlier ? -1 : 1 // 'later' or 'compatible' )), @@ -159,13 +181,13 @@ export function getSingleInstantFor( ) return epochNanos[ - disambig === 'earlier' + disambig === EpochDisambig.Earlier ? 0 : epochNanos.length - 1 // 'later' or 'compatible' ] } -function computeGapNear(timeZoneOps, zonedEpochNano) { +function computeGapNear(timeZoneOps: TimeZoneOps, zonedEpochNano: LargeInt): number { const startOffsetNano = timeZoneOps.getOffsetNanosecondsFor( zonedEpochNano.addNumber(-nanoInUtcDay), ) @@ -175,7 +197,7 @@ function computeGapNear(timeZoneOps, zonedEpochNano) { return endOffsetNano - startOffsetNano } -export const zonedInternalsToIso = createLazyGenerator((internals) => { +export const zonedInternalsToIso = createLazyGenerator((internals: ZonedInternals) => { const { timeZone, epochNanoseconds } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) const isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) @@ -186,7 +208,7 @@ export const zonedInternalsToIso = createLazyGenerator((internals) => { } }) -export function zonedEpochNanoToIso(timeZoneOps, epochNano) { +export function zonedEpochNanoToIso(timeZoneOps: TimeZoneOps, epochNano: LargeInt): IsoDateTimeFields { const offsetNano = timeZoneOps.getOffsetNanosecondsFor(epochNano) return epochNanoToIso(epochNano.addNumber(offsetNano)) } @@ -194,20 +216,37 @@ export function zonedEpochNanoToIso(timeZoneOps, epochNano) { // Adapter // ------- -const getInstantEpochNano = getStrictInternals.bind(undefined, Instant) +const getInstantEpochNano = getStrictInternals.bind< + any, [any], // bound + [Instant], // unbound + LargeInt // return +>(undefined, Instant) -export const TimeZoneOpsAdapter = createWrapperClass(idGettersStrict, { - getOffsetNanosecondsFor(timeZone, epochNano) { +const timeZoneOpsAdapterMethods = { + getOffsetNanosecondsFor(timeZone: TimeZone, epochNano: LargeInt): number { return validateOffsetNano(timeZone.getOffsetNanosecondsFor(createInstant(epochNano))) }, - getPossibleInstantsFor(timeZone, isoDateTimeFields) { + getPossibleInstantsFor(timeZone: TimeZone, isoDateTimeFields: IsoDateTimeFields) { return ensureArray(timeZone.getPossibleInstantsFor(createPlainDateTime(isoDateTimeFields))) .map(getInstantEpochNano) }, -}) +} + +type TimeZoneOpsAdapter = WrapperInstance< + TimeZone, // internals + typeof idGettersStrict, // getters + typeof timeZoneOpsAdapterMethods // methods +> + +const TimeZoneOpsAdapter = createWrapperClass< + [TimeZone], // constructor + TimeZone, // internals + typeof idGettersStrict, // getters + typeof timeZoneOpsAdapterMethods // methods +>(idGettersStrict, timeZoneOpsAdapterMethods) -function validateOffsetNano(offsetNano) { +function validateOffsetNano(offsetNano: number): number { if (!Number.isInteger(offsetNano)) { // will return false on non-number (good) throw new RangeError('must be integer number') } From a6bcf8861900249a3981eec2f9aedc31e75ed89b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 25 Jul 2023 11:55:42 -0400 Subject: [PATCH 156/805] more --- packages/temporal-polyfill/src/new/plainDate.ts | 7 ++++--- packages/temporal-polyfill/src/new/plainDateTime.ts | 8 ++++++-- packages/temporal-polyfill/src/new/plainMonthDay.ts | 1 + packages/temporal-polyfill/src/new/plainTime.ts | 4 ++-- packages/temporal-polyfill/src/new/zonedDateTime.ts | 7 +++++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/temporal-polyfill/src/new/plainDate.ts b/packages/temporal-polyfill/src/new/plainDate.ts index e6685a55..c06639db 100644 --- a/packages/temporal-polyfill/src/new/plainDate.ts +++ b/packages/temporal-polyfill/src/new/plainDate.ts @@ -1,3 +1,4 @@ +import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { DateFields, dateGetters } from './calendarFields' import { @@ -132,7 +133,7 @@ export const [ isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals: IsoDateInternals, options): string { + toString(internals: IsoDateInternals, options: any): string { return formatIsoDateFields(internals) + formatCalendar(internals.calendar, refineDateDisplayOptions(options)) }, @@ -141,7 +142,7 @@ export const [ valueOf: neverValueOf, - toZonedDateTime: createZonedDateTimeConverter((options) => { + toZonedDateTime: createZonedDateTimeConverter((options: any) => { return optionalToPlainTimeFields(options.time) }), @@ -184,7 +185,7 @@ export const [ function diffPlainDates( internals0: IsoDateInternals, internals1: IsoDateInternals, - options, + options: any, roundingModeInvert?: boolean, ): Duration { return createDuration( diff --git a/packages/temporal-polyfill/src/new/plainDateTime.ts b/packages/temporal-polyfill/src/new/plainDateTime.ts index dd99abae..9d4314c9 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.ts +++ b/packages/temporal-polyfill/src/new/plainDateTime.ts @@ -1,3 +1,4 @@ +import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { DateFields, TimeFields, dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' @@ -31,8 +32,11 @@ import { refineRoundOptions, } from './options' import { PlainDate, PlainDateArg, createPlainDate, toPlainDateInternals } from './plainDate' +import { PlainMonthDay } from './plainMonthDay' import { PlainTime, createPlainTime, toPlainTimeFields } from './plainTime' +import { PlainYearMonth } from './plainYearMonth' import { roundDateTime, roundDateTimeToNano } from './round' +import { TimeZoneArg } from './timeZone' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' import { Unit } from './units' import { NumSign } from './utils' @@ -244,7 +248,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr function movePlainDateTime( internals: IsoDateTimeInternals, durationInternals: DurationInternals, - options, + options: any, ): PlainDateTime { return createPlainDateTime( moveDateTime( @@ -259,7 +263,7 @@ function movePlainDateTime( function diffPlainDateTimes( internals0: IsoDateTimeInternals, internals1: IsoDateTimeInternals, - options, + options: any, roundingModeInvert?: boolean ): Duration { return createDuration( diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.ts b/packages/temporal-polyfill/src/new/plainMonthDay.ts index 14e370f6..14363f4b 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/new/plainMonthDay.ts @@ -1,3 +1,4 @@ +import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { YearMonthFields, monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' diff --git a/packages/temporal-polyfill/src/new/plainTime.ts b/packages/temporal-polyfill/src/new/plainTime.ts index db6c6fda..2f754bd2 100644 --- a/packages/temporal-polyfill/src/new/plainTime.ts +++ b/packages/temporal-polyfill/src/new/plainTime.ts @@ -117,7 +117,7 @@ export const [ return !compareIsoTimeFields(fields, otherInternals) }, - toString(fields: IsoTimeFields, options): string { + toString(fields: IsoTimeFields, options: any): string { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatIsoTimeFields( @@ -167,7 +167,7 @@ function movePlainTime(internals: IsoTimeFields, durationInternals: DurationInte function diffPlainTimes( internals0: IsoTimeFields, internals1: IsoTimeFields, - options, + options: any, roundingModeInvert?: boolean ): Duration { return createDuration( diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.ts b/packages/temporal-polyfill/src/new/zonedDateTime.ts index 328bbc36..0ac22d25 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/new/zonedDateTime.ts @@ -1,3 +1,4 @@ +import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { dateTimeGetters } from './calendarFields' import { CalendarOps, getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' @@ -49,7 +50,9 @@ import { PlainMonthDay } from './plainMonthDay' import { PlainTime, createPlainTime, toPlainTimeFields } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { roundDateTime, roundDateTimeToNano } from './round' +import { TimeZoneArg } from './timeZone' import { + TimeZoneOps, computeNanosecondsInDay, getCommonTimeZoneOps, getMatchingInstantFor, @@ -309,7 +312,7 @@ export const [ isObjIdsEqual(internals.timeZone, otherInternals.timeZone) }, - toString(internals: ZonedInternals, options): string { + toString(internals: ZonedInternals, options: any): string { let { epochNanoseconds, timeZone, calendar } = internals const [ calendarDisplayI, @@ -431,7 +434,7 @@ function moveZonedDateTime( function diffZonedDateTimes( internals: ZonedInternals, otherInternals: ZonedInternals, - options, + options: any, roundingModeInvert?: boolean ): Duration { return createDuration( From 64e898f4a37fc216b5c52ec8810d3d84f3e9bdb3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 25 Jul 2023 14:17:39 -0400 Subject: [PATCH 157/805] disabled certain things --- .github/workflows/{ci.yml => ci.yml.disabled} | 0 .../temporal-polyfill/{.eslintrc.cjs => .eslintrc.cjs.disabled} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{ci.yml => ci.yml.disabled} (100%) rename packages/temporal-polyfill/{.eslintrc.cjs => .eslintrc.cjs.disabled} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml.disabled similarity index 100% rename from .github/workflows/ci.yml rename to .github/workflows/ci.yml.disabled diff --git a/packages/temporal-polyfill/.eslintrc.cjs b/packages/temporal-polyfill/.eslintrc.cjs.disabled similarity index 100% rename from packages/temporal-polyfill/.eslintrc.cjs rename to packages/temporal-polyfill/.eslintrc.cjs.disabled From b447651ec52e7a1bb614fdb49e40756d3b94e8a3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 25 Jul 2023 20:29:07 -0400 Subject: [PATCH 158/805] Protocol stuff --- .../temporal-polyfill/src/new/calendar.ts | 77 ++++++++++++++++--- .../temporal-polyfill/src/new/calendarImpl.ts | 2 +- .../temporal-polyfill/src/new/calendarOps.ts | 35 +++++---- packages/temporal-polyfill/src/new/instant.ts | 3 +- .../temporal-polyfill/src/new/isoFields.ts | 1 + packages/temporal-polyfill/src/new/isoMath.ts | 15 ++-- .../temporal-polyfill/src/new/isoParse.ts | 2 +- .../temporal-polyfill/src/new/plainDate.ts | 2 +- .../src/new/plainMonthDay.ts | 3 +- .../src/new/plainYearMonth.ts | 1 + .../temporal-polyfill/src/new/timeZone.ts | 42 ++++++++-- .../temporal-polyfill/src/new/timeZoneOps.ts | 14 ++-- packages/temporal-polyfill/src/new/utils.ts | 1 + .../src/new/zonedDateTime.ts | 2 +- 14 files changed, 149 insertions(+), 51 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendar.ts b/packages/temporal-polyfill/src/new/calendar.ts index 33319128..35d6e1fd 100644 --- a/packages/temporal-polyfill/src/new/calendar.ts +++ b/packages/temporal-polyfill/src/new/calendar.ts @@ -1,6 +1,6 @@ import { dateGetterNames } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' -import { TemporalInstance, createTemporalClass, getObjId, idGetters } from './class' +import { TemporalInstance, createTemporalClass, getInternals, getObjId, getTemporalName, idGetters } from './class' import { refineComplexBag, refinePlainDateBag, @@ -10,7 +10,6 @@ import { import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { parseCalendarId } from './isoParse' import { - ensureArray, ensureObjectlike, ensureString, refineCalendarDiffOptions, @@ -22,10 +21,62 @@ import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' import { excludeUndefinedProps, mapPropNames, noop } from './utils' +interface CalendarProtocolMethods { + year(dateArg: PlainYearMonth | PlainDateArg): number + month(dateArg: PlainYearMonth | PlainDateArg): number + monthCode(dateArg: PlainYearMonth | PlainMonthDay | PlainDateArg): string + day(dateArg: PlainMonthDay | PlainDateArg): number + era(dateArg: PlainYearMonth | PlainDateArg): string | undefined + eraYear(dateArg: PlainYearMonth | PlainDateArg): number | undefined + dayOfWeek(dateArg: PlainDateArg): number + dayOfYear(dateArg: PlainDateArg): number + weekOfYear(dateArg: PlainDateArg): number + yearOfWeek(dateArg: PlainDateArg): number + daysInWeek(dateArg: PlainDateArg): number + daysInMonth(dateArg: PlainYearMonth | PlainDateArg): number + daysInYear(dateArg: PlainYearMonth | PlainDateArg): number + monthsInYear(dateArg: PlainYearMonth | PlainDateArg): number + inLeapYear(dateArg: PlainYearMonth | PlainDateArg): boolean + dateFromFields(fields: any, options: any): PlainDate + yearMonthFromFields(fields: any, options: any): PlainYearMonth + monthDayFromFields(fields: any, options: any): PlainMonthDay + dateAdd(dateArg: PlainDateArg, duration: DurationArg, options: any): PlainDate + dateUntil(dateArg0: PlainDateArg, dateArg1: PlainDateArg, options: any): Duration + fields(fieldNames: Iterable): Iterable + mergeFields(fields0: any, fields1: any): any + toString?(): string; + toJSON?(): string; +} + +export interface CalendarProtocol extends CalendarProtocolMethods{ + id: string +} + +// TODO: compress this somehow +const dateArgWhitelist = { + era: 'PlainYearMonth', + eraYear: 'PlainYearMonth', + year: 'PlainYearMonth', + daysInYear: 'PlainYearMonth', + monthsInYear: 'PlainYearMonth', + inLeapYear: 'PlainYearMonth', + daysInMonth: 'PlainYearMonth', + month: 'PlainYearMonth', + monthCode: 'Month', // PlainYearMonth or PlainMonthDay + day: 'PlainMonthDay', +} + +// the *required* protocol methods export const calendarProtocolMethods = { ...mapPropNames((propName) => { - return ((impl: CalendarImpl, plainDateArg: PlainDateArg) => { - return impl[propName](toPlainDateInternals(plainDateArg)) + const whitelistName = dateArgWhitelist[propName as keyof typeof dateArgWhitelist] + + return ((impl: CalendarImpl, dateArg: any) => { + const isoFields = whitelistName && (getTemporalName(dateArg) || '').includes(whitelistName) + ? getInternals(dateArg) + : toPlainDateInternals(dateArg) + + return impl[propName](isoFields) }) as any }, dateGetterNames), @@ -83,8 +134,9 @@ export const calendarProtocolMethods = { return createPlainMonthDay(refinePlainMonthDayBag(fields, options, impl)) }, - fields(impl: CalendarImpl, fieldNames: string[]): string[] { - return impl.fields(ensureArray(fieldNames).map(ensureString)) + fields(impl: CalendarImpl, fieldNames: Iterable): Iterable { + return impl.fields([...fieldNames].map(ensureString)) + // TODO: kill ensureArray everywhere? use [...] technique? }, mergeFields(impl: CalendarImpl, fields0: any, fields1: any): any { @@ -95,13 +147,20 @@ export const calendarProtocolMethods = { }, } -const calendarMethods = { - ...calendarProtocolMethods, +// TODO: move elsewhere +// TODO: use TS `satisfies` on main class? +type Unmethodize = F extends ((...args: infer A) => infer R) + ? (impl: CalendarImpl, ...args: A) => R + : never +const calendarMethods: { + [K in keyof CalendarProtocolMethods]: Unmethodize +} = { + ...calendarProtocolMethods, toString: getObjId, } -export type CalendarArg = Calendar | string +export type CalendarArg = CalendarProtocol | string export type Calendar = TemporalInstance< CalendarImpl, // internals diff --git a/packages/temporal-polyfill/src/new/calendarImpl.ts b/packages/temporal-polyfill/src/new/calendarImpl.ts index 7f7c1a09..ef23fdf0 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.ts +++ b/packages/temporal-polyfill/src/new/calendarImpl.ts @@ -180,7 +180,7 @@ export class CalendarImpl implements CalendarOps { dateAdd( isoDateFields: IsoDateFields, - durationFields: DurationFields, + durationFields: DurationInternals, overflow: Overflow, ): IsoDateFields { return moveDate(this, isoDateFields, durationFields, overflow) diff --git a/packages/temporal-polyfill/src/new/calendarOps.ts b/packages/temporal-polyfill/src/new/calendarOps.ts index 50a2f9ab..743db46f 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.ts +++ b/packages/temporal-polyfill/src/new/calendarOps.ts @@ -1,4 +1,4 @@ -import { Calendar, CalendarArg, calendarProtocolMethods, createCalendar } from './calendar' +import { Calendar, CalendarArg, CalendarProtocol, calendarProtocolMethods, createCalendar } from './calendar' import { dateFieldRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { @@ -13,7 +13,7 @@ import { import { Duration, createDuration } from './duration' import { DurationInternals } from './durationFields' import { CalendarInternals, IsoDateFields, IsoDateInternals } from './isoFields' -import { Overflow, ensureArray, ensureObjectlike, ensureString, toString } from './options' +import { Overflow, ensureObjectlike, ensureString, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' @@ -39,6 +39,8 @@ export interface CalendarOps { weekOfYear(isoFields: IsoDateFields): number yearOfWeek(isoFields: IsoDateFields): number daysInWeek(isoFields: IsoDateFields): number + dateAdd(isoFields: IsoDateFields, durationInternals: DurationInternals, overflow: Overflow): IsoDateFields + dateUntil(isoFields0: IsoDateFields, isoFields1: IsoDateFields, options: any): DurationInternals } // @@ -58,7 +60,7 @@ export function queryCalendarOps(calendarArg: CalendarArg): CalendarOps { return queryCalendarImpl(toString(calendarArg)) } -export function getPublicCalendar(internals: { calendar: CalendarOps }): Calendar { +export function getPublicCalendar(internals: { calendar: CalendarOps }): CalendarProtocol { const { calendar } = internals return getInternals(calendar as CalendarOpsAdapter) || @@ -100,8 +102,8 @@ const getDurationInternals = getStrictInternals.bind< const calendarOpsAdapterMethods = { ...mapProps((refiner, propName) => { - return ((calendar: Calendar, isoDateFields: IsoDateInternals) => { - return refiner(calendar[propName](createPlainDate(isoDateFields))) + return ((calendar: CalendarProtocol, isoDateFields: IsoDateInternals) => { + return refiner(calendar[propName](createPlainDate(isoDateFields)) as any) }) as any }, { // TODO: more DRY with DateGetters or something? @@ -111,7 +113,7 @@ const calendarOpsAdapterMethods = { }), dateAdd( - calendar: Calendar, + calendar: CalendarProtocol, isoDateFields: IsoDateInternals, durationInternals: DurationInternals, overflow: Overflow, @@ -126,7 +128,7 @@ const calendarOpsAdapterMethods = { }, dateUntil( - calendar: Calendar, + calendar: CalendarProtocol, isoDateFields0: IsoDateFields, isoDateFields1: IsoDateFields, largestUnit: Unit, // TODO: ensure year/month/week/day??? @@ -140,36 +142,37 @@ const calendarOpsAdapterMethods = { ) }, - dateFromFields(calendar: Calendar, fields: any, overflow: Overflow): IsoDateInternals { + dateFromFields(calendar: CalendarProtocol, fields: any, overflow: Overflow): IsoDateInternals { return getPlainDateInternals(calendar.dateFromFields(fields, { overflow })) }, - yearMonthFromFields(calendar: Calendar, fields: any, overflow: Overflow): IsoDateInternals { + yearMonthFromFields(calendar: CalendarProtocol, fields: any, overflow: Overflow): IsoDateInternals { return getPlainYearMonthInternals(calendar.yearMonthFromFields(fields, { overflow })) }, - monthDayFromFields(calendar: Calendar, fields: any, overflow: Overflow): IsoDateInternals { + monthDayFromFields(calendar: CalendarProtocol, fields: any, overflow: Overflow): IsoDateInternals { return getPlainMonthDayInternals(calendar.monthDayFromFields(fields, { overflow })) }, - fields(calendar: Calendar, fieldNames: string[]) { - return ensureArray(calendar.fields(fieldNames)).map(ensureString) + fields(calendar: CalendarProtocol, fieldNames: Iterable): Iterable { + return [...calendar.fields(fieldNames)].map(ensureString) + // TODO: kill ensureArray elsewhere? }, - mergeFields(calendar: Calendar, fields0: any, fields1: any) { + mergeFields(calendar: CalendarProtocol, fields0: any, fields1: any): any { return ensureObjectlike(calendar.mergeFields(fields0, fields1)) }, } type CalendarOpsAdapter = WrapperInstance< - Calendar, // internals + CalendarProtocol, // internals typeof idGettersStrict, // getters typeof calendarOpsAdapterMethods // methods > const CalendarOpsAdapter = createWrapperClass< - [Calendar], // constructor - Calendar, // internals + [CalendarProtocol], // constructor + CalendarProtocol, // internals typeof idGettersStrict, // getters typeof calendarOpsAdapterMethods // methods >(idGettersStrict, calendarOpsAdapterMethods) diff --git a/packages/temporal-polyfill/src/new/instant.ts b/packages/temporal-polyfill/src/new/instant.ts index 79da729b..39f31e8f 100644 --- a/packages/temporal-polyfill/src/new/instant.ts +++ b/packages/temporal-polyfill/src/new/instant.ts @@ -28,8 +28,9 @@ import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { noop } from './utils' import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' import { Unit } from './units' +import { TimeZoneArg } from './timeZone' -export type InstantArg = Instant | LargeInt | string +export type InstantArg = Instant | string export type Instant = TemporalInstance export const [ diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts index 6d2b97bf..0507589d 100644 --- a/packages/temporal-polyfill/src/new/isoFields.ts +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -1,3 +1,4 @@ +import { CalendarProtocol } from './calendar' import { CalendarOps, queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { toInteger } from './options' diff --git a/packages/temporal-polyfill/src/new/isoMath.ts b/packages/temporal-polyfill/src/new/isoMath.ts index 8add99c6..a76706c0 100644 --- a/packages/temporal-polyfill/src/new/isoMath.ts +++ b/packages/temporal-polyfill/src/new/isoMath.ts @@ -124,7 +124,9 @@ function isoDateMonthStart(isoDateFields: IsoDateFields): IsoDateFields { // Refining // ------------------------------------------------------------------------------------------------- -export function refineIsoDateTimeInternals(rawIsoDateTimeInternals: IsoDateTimeInternals): IsoDateTimeInternals { +export function refineIsoDateTimeInternals( + rawIsoDateTimeInternals: IsoDateTimeInternals, // wrong +): IsoDateTimeInternals { return checkIso( constrainIsoDateTimeInternals( mapPropsWithRefiners(rawIsoDateTimeInternals, isoDateTimeInternalRefiners), @@ -132,7 +134,9 @@ export function refineIsoDateTimeInternals(rawIsoDateTimeInternals: IsoDateTimeI ) } -export function refineIsoDateInternals(rawIsoDateInternals: IsoDateInternals): IsoDateInternals { +export function refineIsoDateInternals( + rawIsoDateInternals: IsoDateInternals, // wrong +): IsoDateInternals { return checkIso( constrainIsoDateInternals( mapPropsWithRefiners(rawIsoDateInternals, isoDateInternalRefiners), @@ -140,10 +144,11 @@ export function refineIsoDateInternals(rawIsoDateInternals: IsoDateInternals): I ) } -export function refineIsoTimeInternals(rawIsoTimeInternals: IsoTimeFields): IsoTimeFields { - const asdf = mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners) +export function refineIsoTimeInternals( + rawIsoTimeInternals: IsoTimeFields, // wrong +): IsoTimeFields { return constrainIsoTimeFields( - asdf, + mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), ) } diff --git a/packages/temporal-polyfill/src/new/isoParse.ts b/packages/temporal-polyfill/src/new/isoParse.ts index 650b2473..65a14064 100644 --- a/packages/temporal-polyfill/src/new/isoParse.ts +++ b/packages/temporal-polyfill/src/new/isoParse.ts @@ -46,7 +46,7 @@ export function parseInstant(s) { } else if (parsed.offset) { offsetNano = parseOffsetNano(parsed.offset) } else { - return new RangeError() + throw new RangeError() } return isoToEpochNano(parsed).addNumber(offsetNano) diff --git a/packages/temporal-polyfill/src/new/plainDate.ts b/packages/temporal-polyfill/src/new/plainDate.ts index c06639db..e8152dbd 100644 --- a/packages/temporal-polyfill/src/new/plainDate.ts +++ b/packages/temporal-polyfill/src/new/plainDate.ts @@ -96,7 +96,7 @@ export const [ return createPlainDate(mergePlainDateBag(this, mod, options)) }, - withCalendar(internals: IsoDateInternals, calendarArg): PlainDate { + withCalendar(internals: IsoDateInternals, calendarArg: CalendarArg): PlainDate { return createPlainDate({ ...internals, calendar: queryCalendarOps(calendarArg), diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.ts b/packages/temporal-polyfill/src/new/plainMonthDay.ts index 14363f4b..3c3c065e 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/new/plainMonthDay.ts @@ -8,7 +8,7 @@ import { mergePlainMonthDayBag, refinePlainMonthDayBag, } from './convert' -import { IsoDateInternals, generatePublicIsoDateFields } from './isoFields' +import { IsoDateInternals, generatePublicIsoDateFields, pluckIsoDateInternals } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields, isoEpochFirstLeapYear, refineIsoDateInternals } from './isoMath' import { parsePlainMonthDay } from './isoParse' @@ -46,6 +46,7 @@ export const [ }, // internalsConversionMap + // NOTE: PlainDate(Time) is refined as bag {}, // bagToInternals diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.ts b/packages/temporal-polyfill/src/new/plainYearMonth.ts index d0ec9cbb..cda64dee 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/new/plainYearMonth.ts @@ -52,6 +52,7 @@ export const [ }, // internalsConversionMap + // NOTE: PlainDate(Time) is refined as bag {}, // bagToInternals diff --git a/packages/temporal-polyfill/src/new/timeZone.ts b/packages/temporal-polyfill/src/new/timeZone.ts index 83ae405e..5754aa2f 100644 --- a/packages/temporal-polyfill/src/new/timeZone.ts +++ b/packages/temporal-polyfill/src/new/timeZone.ts @@ -11,7 +11,23 @@ import { PlainDateTime, PlainDateTimeArg, createPlainDateTime, toPlainDateTimeIn import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { noop } from './utils' -// TODO: implements some other interface? +interface TimeZoneProtocolMethods { + getOffsetNanosecondsFor(instant: InstantArg): number + getOffsetStringFor?(instant: InstantArg): string + getPlainDateTimeFor?(instant: InstantArg, calendar?: CalendarArg): PlainDateTime + getInstantFor?(dateTime: PlainDateTimeArg, options?: any): Instant + getNextTransition?(startingPoint: InstantArg): Instant | null + getPreviousTransition?(startingPoint: InstantArg): Instant | null + getPossibleInstantsFor(dateTime: PlainDateTimeArg): Instant[] + toString?(): string; + toJSON?(): string; +} + +export interface TimeZoneProtocol extends TimeZoneProtocolMethods { + id: string; +} + +// the *required* protocol methods export const timeZoneProtocolMethods = { getPossibleInstantsFor(impl: TimeZoneImpl, plainDateTimeArg: PlainDateTimeArg): Instant[] { return impl.getPossibleInstantsFor(toPlainDateTimeInternals(plainDateTimeArg)) @@ -21,14 +37,22 @@ export const timeZoneProtocolMethods = { getOffsetNanosecondsFor: getImplOffsetNanosecondsFor, } -const timeZoneMethods = { +// TODO: move elsewhere +// TODO: use TS `satisfies` on main class? +type Unmethodize = F extends ((...args: infer A) => infer R) + ? (impl: TimeZoneImpl, ...args: A) => R + : never + +const timeZoneMethods: { + [K in keyof TimeZoneProtocolMethods]: Unmethodize +} = { ...timeZoneProtocolMethods, getOffsetStringFor(impl: TimeZoneImpl, instantArg: InstantArg): string { return formatOffsetNano(getImplOffsetNanosecondsFor(impl, instantArg)) }, - getPlainDateTimeFor(impl: TimeZoneImpl, instantArg: InstantArg, calendarArg: CalendarArg): PlainDateTime { + getPlainDateTimeFor(impl: TimeZoneImpl, instantArg: InstantArg, calendarArg?: CalendarArg): PlainDateTime { const epochNanoseconds = toInstantEpochNano(instantArg) return createPlainDateTime({ @@ -38,10 +62,12 @@ const timeZoneMethods = { }, getInstantFor(impl: TimeZoneImpl, plainDateTimeArg: PlainDateTimeArg, options: any): Instant { - return getSingleInstantFor( - impl, - toPlainDateTimeInternals(plainDateTimeArg), - refineEpochDisambigOptions(options), + return createInstant( + getSingleInstantFor( + impl, + toPlainDateTimeInternals(plainDateTimeArg), + refineEpochDisambigOptions(options), + ) ) }, @@ -52,7 +78,7 @@ const timeZoneMethods = { toString: getObjId, } -export type TimeZoneArg = TimeZone | string +export type TimeZoneArg = TimeZoneProtocol | string export type TimeZone = TemporalInstance< TimeZoneImpl, // internals diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.ts b/packages/temporal-polyfill/src/new/timeZoneOps.ts index bdd61f87..ce1cf91f 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.ts +++ b/packages/temporal-polyfill/src/new/timeZoneOps.ts @@ -18,7 +18,7 @@ import { moveDateByDays } from './move' import { EpochDisambig, OffsetDisambig, ensureArray, toString } from './options' import { createPlainDateTime } from './plainDateTime' import { roundToMinute } from './round' -import { TimeZone, TimeZoneArg, createTimeZone, timeZoneProtocolMethods } from './timeZone' +import { TimeZone, TimeZoneArg, TimeZoneProtocol, createTimeZone, timeZoneProtocolMethods } from './timeZone' import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' import { nanoInUtcDay } from './units' import { createLazyGenerator } from './utils' @@ -51,7 +51,7 @@ export function queryTimeZoneOps(timeZoneArg: TimeZoneArg): TimeZoneOps { return queryTimeZoneImpl(toString(timeZoneArg)) } -export function getPublicTimeZone(internals: { timeZone: TimeZoneOps }): TimeZone { +export function getPublicTimeZone(internals: { timeZone: TimeZoneOps }): TimeZoneProtocol { const { timeZone } = internals return getInternals(timeZone as TimeZoneOpsAdapter) || @@ -223,25 +223,25 @@ const getInstantEpochNano = getStrictInternals.bind< >(undefined, Instant) const timeZoneOpsAdapterMethods = { - getOffsetNanosecondsFor(timeZone: TimeZone, epochNano: LargeInt): number { + getOffsetNanosecondsFor(timeZone: TimeZoneProtocol, epochNano: LargeInt): number { return validateOffsetNano(timeZone.getOffsetNanosecondsFor(createInstant(epochNano))) }, - getPossibleInstantsFor(timeZone: TimeZone, isoDateTimeFields: IsoDateTimeFields) { + getPossibleInstantsFor(timeZone: TimeZoneProtocol, isoDateTimeFields: IsoDateTimeFields): LargeInt[] { return ensureArray(timeZone.getPossibleInstantsFor(createPlainDateTime(isoDateTimeFields))) .map(getInstantEpochNano) }, } type TimeZoneOpsAdapter = WrapperInstance< - TimeZone, // internals + TimeZoneProtocol, // internals typeof idGettersStrict, // getters typeof timeZoneOpsAdapterMethods // methods > const TimeZoneOpsAdapter = createWrapperClass< - [TimeZone], // constructor - TimeZone, // internals + [TimeZoneProtocol], // constructor + TimeZoneProtocol, // internals typeof idGettersStrict, // getters typeof timeZoneOpsAdapterMethods // methods >(idGettersStrict, timeZoneOpsAdapterMethods) diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/new/utils.ts index 149be62a..a3ab2113 100644 --- a/packages/temporal-polyfill/src/new/utils.ts +++ b/packages/temporal-polyfill/src/new/utils.ts @@ -4,6 +4,7 @@ export type Reused = any const objectlikeRE = /object|function/ +// TODO: Record export function isObjectlike(arg: unknown): arg is Record { return arg !== null && objectlikeRE.test(typeof arg) } diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.ts b/packages/temporal-polyfill/src/new/zonedDateTime.ts index 0ac22d25..73412150 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/new/zonedDateTime.ts @@ -50,7 +50,7 @@ import { PlainMonthDay } from './plainMonthDay' import { PlainTime, createPlainTime, toPlainTimeFields } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { roundDateTime, roundDateTimeToNano } from './round' -import { TimeZoneArg } from './timeZone' +import { TimeZoneArg, TimeZoneProtocol } from './timeZone' import { TimeZoneOps, computeNanosecondsInDay, From 5b0b2816ef6be9aeb2ce849b85a21d041dd1270b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 10:52:36 -0400 Subject: [PATCH 159/805] fix relativeTo object refining --- packages/temporal-polyfill/src/new/convert.ts | 42 +++++++++++++++++++ packages/temporal-polyfill/src/new/options.ts | 4 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/new/convert.ts index d2327dda..0c6177ef 100644 --- a/packages/temporal-polyfill/src/new/convert.ts +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -32,6 +32,9 @@ import { IsoDateInternals, IsoDateTimeInternals } from './isoFields' import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNano } from './isoParse' import { + EpochDisambig, + OffsetDisambig, + Overflow, ensureObjectlike, normalizeOptions, refineOverflowOptions, @@ -51,6 +54,45 @@ Rules: - converting returns public object */ +// TODO: make more DRY with other methods +export function refineMaybeZonedDateTimeBag(bag: any): ZonedInternals | IsoDateInternals { + const calendar = getBagCalendarOps(bag) + const fields = refineCalendarFields( + calendar, + bag, + dateTimeFieldNames, // validFieldNames + getRequiredDateFields(calendar), // requireFields + ['timeZone', 'offset'], // forcedValidFieldNames + ) + + if (fields.timeZone) { + const timeZone = queryTimeZoneOps(fields.timeZone) + const isoDateFields = calendar.dateFromFields(fields, Overflow.Constrain) + const isoTimeFields = refineTimeFields(fields, Overflow.Constrain) + + const epochNanoseconds = getMatchingInstantFor( + timeZone, + { ...isoDateFields, ...isoTimeFields }, + fields.offset !== undefined && parseOffsetNano(fields.offset), + false, // z? + OffsetDisambig.Use, // TODO: is default already? + EpochDisambig.Compat, // TODO: is default already? + false, // fuzzy + ) + + return { + calendar, + timeZone, + epochNanoseconds, + } + } else { + const isoDateInternals = calendar.dateFromFields(fields, Overflow.Constrain) + const isoTimeFields = refineTimeFields(fields, Overflow.Constrain) + + return { ...isoDateInternals, ...isoTimeFields } + } +} + // ZonedDateTime // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 7ad3acef..7ae7908b 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -1,4 +1,5 @@ import { getInternals } from './class' +import { refineMaybeZonedDateTimeBag } from './convert' import { DurationFields, durationFieldIndexes } from './durationFields' import { pluckIsoDateInternals } from './isoFields' import { parseMaybeZonedDateTime } from './isoParse' @@ -358,7 +359,8 @@ function refineRelativeTo(options: Options) { } else if (relativeTo instanceof PlainDateTime) { return pluckIsoDateInternals(getInternals(relativeTo)) } - throw new TypeError() + + return refineMaybeZonedDateTimeBag(relativeTo) } return parseMaybeZonedDateTime(toString(relativeTo)) From fef8828af72604f94fd5bca046b82ba363edb152 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 11:19:59 -0400 Subject: [PATCH 160/805] refine convert.ts --- .../temporal-polyfill/src/new/calendarOps.ts | 5 + packages/temporal-polyfill/src/new/convert.ts | 170 +++++++++++------- 2 files changed, 111 insertions(+), 64 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarOps.ts b/packages/temporal-polyfill/src/new/calendarOps.ts index 743db46f..1bc899e5 100644 --- a/packages/temporal-polyfill/src/new/calendarOps.ts +++ b/packages/temporal-polyfill/src/new/calendarOps.ts @@ -39,8 +39,13 @@ export interface CalendarOps { weekOfYear(isoFields: IsoDateFields): number yearOfWeek(isoFields: IsoDateFields): number daysInWeek(isoFields: IsoDateFields): number + dateFromFields(fields: any, overflow: Overflow): IsoDateInternals + yearMonthFromFields(fields: any, overflow: Overflow): IsoDateInternals + monthDayFromFields(fields: any, overflow: Overflow): IsoDateInternals dateAdd(isoFields: IsoDateFields, durationInternals: DurationInternals, overflow: Overflow): IsoDateFields dateUntil(isoFields0: IsoDateFields, isoFields1: IsoDateFields, options: any): DurationInternals + fields(fieldNames: Iterable): Iterable + mergeFields(fields0: any, fields1: any): any } // diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/new/convert.ts index 0c6177ef..c198c0f6 100644 --- a/packages/temporal-polyfill/src/new/convert.ts +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -18,17 +18,16 @@ import { yearMonthFieldNames, } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' -import { queryCalendarOps } from './calendarOps' +import { CalendarOps, queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { DurationBag, DurationMod } from './duration' import { - DurationFields, DurationInternals, durationFieldNames, durationFieldRefiners, updateDurationFieldsSign, } from './durationFields' -import { IsoDateInternals, IsoDateTimeInternals } from './isoFields' +import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields } from './isoFields' import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNano } from './isoParse' import { @@ -38,12 +37,14 @@ import { ensureObjectlike, normalizeOptions, refineOverflowOptions, - refineZonedFieldOptions, // TODO: shouldn't we use this all over the place? + refineZonedFieldOptions, + toString, // TODO: shouldn't we use this all over the place? } from './options' -import { createPlainDate } from './plainDate' -import { PlainDateTimeBag } from './plainDateTime' -import { createPlainMonthDay } from './plainMonthDay' -import { createPlainYearMonth } from './plainYearMonth' +import { PlainDate, createPlainDate } from './plainDate' +import { PlainDateTime, PlainDateTimeBag } from './plainDateTime' +import { PlainMonthDay, createPlainMonthDay } from './plainMonthDay' +import { PlainTime } from './plainTime' +import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' import { ZonedDateTime, ZonedDateTimeBag, ZonedInternals, createZonedDateTime } from './zonedDateTime' @@ -96,7 +97,7 @@ export function refineMaybeZonedDateTimeBag(bag: any): ZonedInternals | IsoDateI // ZonedDateTime // ------------------------------------------------------------------------------------------------- -export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options): ZonedInternals { +export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: any): ZonedInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, @@ -128,7 +129,11 @@ export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options): ZonedInt } } -export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { +export function mergeZonedDateTimeBag( + zonedDateTime: ZonedDateTime, + bag: any, + options: any, +): ZonedInternals { const { calendar, timeZone } = getInternals(zonedDateTime) const fields = mergeCalendarFields( calendar, @@ -159,8 +164,12 @@ export function mergeZonedDateTimeBag(zonedDateTime, bag, options) { } } -export function createZonedDateTimeConverter(getExtraIsoFields) { - return (internals, options): ZonedDateTime => { +export function createZonedDateTimeConverter( + getExtraIsoFields: (options: any) => any, +): ( + (internals: any, options: any) => ZonedDateTime +) { + return (internals, options) => { const { calendar, timeZone } = internals const epochNanoseconds = getSingleInstantFor(timeZone, { ...internals, @@ -178,7 +187,7 @@ export function createZonedDateTimeConverter(getExtraIsoFields) { // PlainDateTime // ------------------------------------------------------------------------------------------------- -export function refinePlainDateTimeBag(bag: PlainDateTimeBag, options): IsoDateTimeInternals { +export function refinePlainDateTimeBag(bag: PlainDateTimeBag, options: any): IsoDateTimeInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, @@ -194,11 +203,15 @@ export function refinePlainDateTimeBag(bag: PlainDateTimeBag, options): IsoDateT return { ...isoDateInternals, ...isoTimeFields } } -export function mergePlainDateTimeBag(plainDate, bag, options) { - const { calendar } = getInternals(plainDate) +export function mergePlainDateTimeBag( + plainDateTime: PlainDateTime, + bag: any, + options: any, +): IsoDateTimeInternals { + const { calendar } = getInternals(plainDateTime) const fields = mergeCalendarFields( calendar, - plainDate, + plainDateTime, bag, dateTimeFieldNames, ) @@ -215,8 +228,8 @@ export function mergePlainDateTimeBag(plainDate, bag, options) { export function refinePlainDateBag( bag: DateFields, - options, - calendar = getBagCalendarOps(bag) + options: any, + calendar: CalendarOps | undefined = getBagCalendarOps(bag) ): IsoDateInternals { const fields = refineCalendarFields( calendar, @@ -228,7 +241,11 @@ export function refinePlainDateBag( return calendar.dateFromFields(fields, refineOverflowOptions(options)) } -export function mergePlainDateBag(plainDate, bag, options) { +export function mergePlainDateBag( + plainDate: PlainDate, + bag: any, + options: any +): IsoDateInternals { const { calendar } = getInternals(plainDate) const fields = mergeCalendarFields( calendar, @@ -241,11 +258,11 @@ export function mergePlainDateBag(plainDate, bag, options) { } function convertToIso( - input, - inputFieldNames, - extra, - extraFieldNames, -) { + input: any, + inputFieldNames: string[], + extra: any, + extraFieldNames: string[], +): IsoDateInternals { const { calendar } = getInternals(input) inputFieldNames = calendar.fields(inputFieldNames) @@ -264,7 +281,11 @@ function convertToIso( // PlainYearMonth // ------------------------------------------------------------------------------------------------- -export function refinePlainYearMonthBag(bag, options, calendar = getBagCalendarOps(bag)) { +export function refinePlainYearMonthBag( + bag: any, + options: any, + calendar: CalendarOps | undefined = getBagCalendarOps(bag) +): IsoDateInternals { const fields = refineCalendarFields( calendar, bag, @@ -275,7 +296,11 @@ export function refinePlainYearMonthBag(bag, options, calendar = getBagCalendarO return calendar.yearMonthFromFields(fields, refineOverflowOptions(options)) } -export function mergePlainYearMonthBag(plainYearMonth, bag, options) { +export function mergePlainYearMonthBag( + plainYearMonth: PlainYearMonth, + bag: any, + options: any, +): IsoDateInternals { const { calendar } = getInternals(plainYearMonth) const fields = mergeCalendarFields( calendar, @@ -287,14 +312,17 @@ export function mergePlainYearMonthBag(plainYearMonth, bag, options) { return calendar.yearMonthFromFields(fields, refineOverflowOptions(options)) } -export function convertPlainYearMonthToDate(plainYearMonth, bag) { +export function convertPlainYearMonthToDate( + plainYearMonth: PlainYearMonth, + bag: any, +): PlainYearMonth { return createPlainDate( convertToIso(plainYearMonth, yearMonthBasicNames, ensureObjectlike(bag), ['day']), ) } export function convertToPlainYearMonth( - input, // PlainDate/PlainDateTime/ZonedDateTime + input: PlainDate | PlainDateTime | ZonedDateTime ) { const { calendar } = getInternals(input) const fields = refineCalendarFields( @@ -305,21 +333,25 @@ export function convertToPlainYearMonth( ) return createPlainYearMonth( - calendar.yearMonthFromFields(fields), + calendar.yearMonthFromFields(fields, Overflow.Constrain), // TODO: make default? ) } // PlainMonthDay // ------------------------------------------------------------------------------------------------- -export function refinePlainMonthDayBag(bag, options, calendar = extractBagCalendarOps(bag)) { +export function refinePlainMonthDayBag( + bag: any, + options: any, + calendar: CalendarOps | undefined = extractBagCalendarOps(bag), +): IsoDateInternals { const calendarAbsent = !calendar if (calendarAbsent) { calendar = queryCalendarImpl(isoCalendarId) } - const fieldNames = calendar.fields(dateFieldNames) + const fieldNames = calendar!.fields(dateFieldNames) const fields = refineFields(bag, fieldNames, []) // Callers who omit the calendar are not writing calendar-independent @@ -334,10 +366,14 @@ export function refinePlainMonthDayBag(bag, options, calendar = extractBagCalend fields.year = isoEpochFirstLeapYear } - return calendar.monthDayFromFields(calendar, fields, refineOverflowOptions(options)) + return calendar!.monthDayFromFields(fields, refineOverflowOptions(options)) } -export function mergePlainMonthDayBag(plainMonthDay, bag, options) { +export function mergePlainMonthDayBag( + plainMonthDay: PlainMonthDay, + bag: any, + options: any, +): IsoDateInternals { const { calendar } = getInternals(plainMonthDay) const fields = mergeCalendarFields( calendar, @@ -350,8 +386,8 @@ export function mergePlainMonthDayBag(plainMonthDay, bag, options) { } export function convertToPlainMonthDay( - input, // PlainDate/PlainDateTime/ZonedDateTime -) { + input: PlainDate | PlainDateTime | ZonedDateTime, +): PlainMonthDay { const { calendar } = getInternals(input) const fields = refineCalendarFields( calendar, @@ -361,11 +397,14 @@ export function convertToPlainMonthDay( ) return createPlainMonthDay( - calendar.monthDayFromFields(fields), + calendar.monthDayFromFields(fields, Overflow.Constrain), // TODO: default Constrain? ) } -export function convertPlainMonthDayToDate(plainMonthDay, bag) { +export function convertPlainMonthDayToDate( + plainMonthDay: PlainMonthDay, + bag: any, +): PlainDate { return createPlainDate( convertToIso(plainMonthDay, monthDayBasicNames, bag, ['year']), ) @@ -374,13 +413,13 @@ export function convertPlainMonthDayToDate(plainMonthDay, bag) { // PlainTime // ------------------------------------------------------------------------------------------------- -export function refinePlainTimeBag(bag, options) { +export function refinePlainTimeBag(bag: any, options: any): IsoTimeFields { const fields = refineFields(bag, timeFieldNames, []) return refineTimeFields(fields, refineOverflowOptions(options)) } -export function mergePlainTimeBag(plainTime, bag, options) { +export function mergePlainTimeBag(plainTime: PlainTime, bag: any, options: any): IsoTimeFields { const fields = pluckProps(timeFieldNames, plainTime) const partialFields = refineFields(bag, timeFieldNames) const mergeFields = { ...fields, ...partialFields } @@ -388,7 +427,7 @@ export function mergePlainTimeBag(plainTime, bag, options) { return refineTimeFields(mergeFields, refineOverflowOptions(options)) } -function refineTimeFields(fields, overflow) { +function refineTimeFields(fields: any, overflow: any): IsoTimeFields { return constrainIsoTimeFields(timeFieldsToIso(fields), overflow) } @@ -412,23 +451,23 @@ export function mergeDurationBag( // ------------------------------------------------------------------------------------------------- function refineCalendarFields( - calendar, - bag, - validFieldNames, - requiredFieldNames = [], // a subset of validFieldNames - forcedValidFieldNames = [], -) { + calendar: CalendarOps, + bag: any, + validFieldNames: string[], + requiredFieldNames: string[] = [], // a subset of validFieldNames + forcedValidFieldNames: string[] = [], +): any { const fieldNames = [...calendar.fields(validFieldNames), ...forcedValidFieldNames] return refineFields(bag, fieldNames, requiredFieldNames) } function mergeCalendarFields( - calendar, - obj, - bag, - validFieldNames, - forcedValidFieldNames = [], -) { + calendar: CalendarOps, + obj: any, + bag: any, + validFieldNames: string[], + forcedValidFieldNames: string[] = [], +): any { rejectInvalidBag(bag) const fieldNames = [...calendar.fields(validFieldNames), ...forcedValidFieldNames] @@ -439,23 +478,26 @@ function mergeCalendarFields( return refineFields(fields, fieldNames, []) // guard against ridiculous .mergeField results } -function getBagCalendarOps(bag) { // defaults to ISO +/* +defaults to ISO +*/ +function getBagCalendarOps(bag: any): CalendarOps { return extractBagCalendarOps(bag) || queryCalendarImpl(isoCalendarId) } -function extractBagCalendarOps(bag) { - const { calendar } = getInternals(bag) || {} +function extractBagCalendarOps(bag: any): CalendarOps | undefined { + let { calendar } = getInternals(bag) || {} if (calendar) { return calendar // CalendarOps } - ({ calendar }) = bag + ({ calendar } = bag) if (calendar) { return queryCalendarOps(calendar) } } -function rejectInvalidBag(bag) { +function rejectInvalidBag(bag: any): void { if (getInternals(bag)) { throw new TypeError('Cant pass any Temporal object') } @@ -480,12 +522,12 @@ const builtinRefiners = { const builtinDefaults = timeFieldDefaults function refineFields( - bag, - validFieldNames, - requiredFieldNames, // a subset of fieldNames + bag: any, + validFieldNames: string[], + requiredFieldNames?: string[], // a subset of fieldNames // if not given, then assumed to be 'partial' (defaults won't be applied) -) { - const res = {} +): any { + const res: any = {} let any = false for (const fieldName in validFieldNames) { @@ -515,7 +557,7 @@ function refineFields( return res } -export function refineComplexBag(key, ForbiddenClass, bag) { +export function refineComplexBag(key: string, ForbiddenClass: any, bag: any): any { const internalArg = getInternals(bag)?.[key] if (internalArg) { return internalArg @@ -536,7 +578,7 @@ export function refineComplexBag(key, ForbiddenClass, bag) { } } -function forbidInstanceClass(obj, Class) { +function forbidInstanceClass(obj: any, Class: any): void { if (obj instanceof Class) { throw new RangeError(`Unexpected ${Class.prototype[Symbol.toStringTag]}`) } From f12a2aa3782b790e432f988e197ba23a035090d7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 11:52:59 -0400 Subject: [PATCH 161/805] marker system ts --- .../temporal-polyfill/src/new/duration.ts | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/new/duration.ts index 3a71de6c..40174dac 100644 --- a/packages/temporal-polyfill/src/new/duration.ts +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -17,7 +17,7 @@ import { import { formatDurationInternals } from './isoFormat' import { isoToEpochNano } from './isoMath' import { parseDuration } from './isoParse' -import { compareLargeInts } from './largeInt' +import { LargeInt, compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' import { refineDurationRoundOptions, @@ -34,6 +34,8 @@ import { } from './round' import { NumSign, identityFunc, noop } from './utils' import { DayTimeUnit, Unit } from './units' +import { ZonedInternals } from './zonedDateTime' +import { IsoDateFields, IsoDateInternals } from './isoFields' export type DurationArg = Duration | DurationBag | string export type DurationBag = Partial @@ -142,7 +144,7 @@ export const [ throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + const markerSystem = createMarkerSystem(markerInternals) return createDuration( roundRelativeDuration( @@ -151,7 +153,7 @@ export const [ smallestUnit, roundingInc, roundingMode, - ...markerSystem, + ...(markerSystem as unknown as [Marker, MarkerToEpochNano, MoveMarker]), ), ) }, @@ -168,16 +170,16 @@ export const [ throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) + const markerSystem = createMarkerSystem(markerInternals) return totalRelativeDuration( ...spanDuration(internals, largestUnit, ...markerSystem), totalUnitIndex, - ...markerSystem, + ...(markerSystem as unknown as [Marker, MarkerToEpochNano, MoveMarker]), ) }, - toString(internals: DurationInternals, options): string { + toString(internals: DurationInternals, options: any): string { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatDurationInternals( @@ -193,7 +195,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(durationArg0: DurationArg, durationArg1: DurationArg, options): NumSign { + compare(durationArg0: DurationArg, durationArg1: DurationArg, options: any): NumSign { const durationFields0 = toDurationInternals(durationArg0) const durationFields1 = toDurationInternals(durationArg1) const markerInternals = refineRelativeToOptions(options) @@ -245,12 +247,25 @@ function addToDuration( return balanceDurationDayTime(addedDurationFields, largestUnit as DayTimeUnit) } - const markerSystem = createMarkerSystem(markerInternals, internals, largestUnit) - return spanDuration(internals, largestUnit, ...markerSystem)[0] + const markerSystem = createMarkerSystem(markerInternals) + return createDuration(spanDuration(internals, largestUnit, ...markerSystem)[0]) } -function createMarkerSystem(markerInternals) { - const { calendar, timeZone, epochNanoseconds } = markerInternals +type Marker = LargeInt | IsoDateFields +type MarkerToEpochNano = (marker: Marker) => LargeInt +type MoveMarker = (marker: Marker, durationInternals: DurationInternals) => Marker +type DiffMarkers = (marker0: Marker, marker1: Marker, largeUnit: Unit) => DurationInternals +type MarkerSystem = [ + Marker, + MarkerToEpochNano, + MoveMarker, + DiffMarkers, +] + +function createMarkerSystem( + markerInternals: ZonedInternals | IsoDateInternals +): MarkerSystem { + const { calendar, timeZone, epochNanoseconds } = markerInternals as ZonedInternals if (epochNanoseconds) { return [ @@ -261,8 +276,8 @@ function createMarkerSystem(markerInternals) { ] } else { return [ - markerInternals, // marker (IsoDateFields) - isoToEpochNano, // markerToEpochNano + markerInternals as IsoDateFields, // marker (IsoDateFields) + isoToEpochNano as (marker: Marker) => LargeInt, // markerToEpochNano calendar.dateAdd.bind(calendar), // moveMarker calendar.dateUntil.bind(calendar), // diffMarkers ] @@ -273,11 +288,14 @@ function spanDuration( durationFields: DurationFields, largestUnit: Unit, // TODO: more descrimination? // marker system... - marker, - markerToEpochNano, - moveMarker, - diffMarkers, -) { + marker: Marker, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, + diffMarkers: DiffMarkers, +): [ + DurationInternals, + Marker, +] { const endMarker = markerToEpochNano(moveMarker(marker, durationFields)) const balancedDuration = diffMarkers(marker, endMarker, largestUnit) return [balancedDuration, endMarker] @@ -293,10 +311,14 @@ function balanceDurationDayTime( ) } -function getLargestDurationUnit(fields: DurationFields): Unit | undefined { - for (let unit: Unit = Unit.Year; unit >= Unit.Nanosecond; unit--) { +function getLargestDurationUnit(fields: DurationFields): Unit { + let unit: Unit = Unit.Year + + for (; unit > Unit.Nanosecond; unit--) { if (fields[durationFieldNamesAsc[unit]]) { - return unit + break } } + + return unit } From 8dfec43924448423a09949e07850702d6c91306e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 12:40:20 -0400 Subject: [PATCH 162/805] improve isoParse types --- packages/temporal-polyfill/src/new/instant.ts | 4 +- .../temporal-polyfill/src/new/isoParse.ts | 204 +++++++++++------- .../temporal-polyfill/src/new/timeZoneOps.ts | 1 + packages/temporal-polyfill/src/new/units.ts | 12 +- 4 files changed, 139 insertions(+), 82 deletions(-) diff --git a/packages/temporal-polyfill/src/new/instant.ts b/packages/temporal-polyfill/src/new/instant.ts index 39f31e8f..e5b0fe8e 100644 --- a/packages/temporal-polyfill/src/new/instant.ts +++ b/packages/temporal-polyfill/src/new/instant.ts @@ -130,7 +130,7 @@ export const [ ) }, - toString(epochNano: LargeInt, options): string { + toString(epochNano: LargeInt, options: any): string { const [ timeZoneArg, nanoInc, @@ -176,7 +176,7 @@ export const [ function diffInstants( epochNano0: LargeInt, epochNano1: LargeInt, - options, + options: any, roundingModeInvert?: boolean ): Duration { return createDuration( diff --git a/packages/temporal-polyfill/src/new/isoParse.ts b/packages/temporal-polyfill/src/new/isoParse.ts index 65a14064..df97ac9f 100644 --- a/packages/temporal-polyfill/src/new/isoParse.ts +++ b/packages/temporal-polyfill/src/new/isoParse.ts @@ -1,13 +1,14 @@ import { nanoIn, nanoInSecond } from '../dateUtils/units' import { isoCalendarId } from './calendarConfig' -import { queryCalendarImpl } from './calendarImpl' +import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { + DurationFields, DurationInternals, durationFieldNamesAsc, negateDurationFields, updateDurationFieldsSign, } from './durationFields' -import { isoTimeFieldDefaults } from './isoFields' +import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' import { checkIso, constrainIsoDateInternals, @@ -16,24 +17,23 @@ import { isoToEpochNano, nanoToIsoTimeAndDay, } from './isoMath' -import { returnUndefinedI } from './options' -import { queryTimeZoneImpl } from './timeZoneImpl' +import { LargeInt } from './largeInt' +import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' import { getMatchingInstantFor, utcTimeZoneId } from './timeZoneOps' import { - hourIndex, - milliIndex, - minuteIndex, + TimeUnit, + Unit, nanoInHour, nanoInMinute, nanoToGivenFields, - secondsIndex, } from './units' import { divFloorMod } from './utils' +import { ZonedInternals } from './zonedDateTime' // High-level // ------------------------------------------------------------------------------------------------- -export function parseInstant(s) { +export function parseInstant(s: string): LargeInt { const parsed = parseDateTime(s) if (!parsed) { throw new RangeError() @@ -49,29 +49,29 @@ export function parseInstant(s) { throw new RangeError() } - return isoToEpochNano(parsed).addNumber(offsetNano) + return isoToEpochNano(parsed)!.addNumber(offsetNano) } -export function parseMaybeZonedDateTime(s) { +export function parseMaybeZonedDateTime(s: string): IsoDateInternals | ZonedInternals { const parsed = parseDateTime(s) if (!parsed) { throw new RangeError() } if (parsed.timeZone) { - return processZonedDateTimeParse(parsed) + return processZonedDateTimeParse(parsed as ZonedDateTimeParsed) } return processDatelikeParse(parsed) // unnecessarily checks for undefined } -export function parseZonedDateTime(s) { +export function parseZonedDateTime(s: string): ZonedInternals { const parsed = parseDateTime(s) if (!parsed || !parsed.timeZone) { throw new RangeError() } - return processZonedDateTimeParse(parsed) + return processZonedDateTimeParse(parsed as ZonedDateTimeParsed) } -export function parsePlainDateTime(s) { +export function parsePlainDateTime(s: string): IsoDateTimeInternals { const parsed = parseDateTime(s) if (!parsed) { throw new RangeError() @@ -79,24 +79,24 @@ export function parsePlainDateTime(s) { return processDateTimeParse(parsed) } -export function parsePlainDate(s) { +export function parsePlainDate(s: string): IsoDateInternals { return processDatelikeParse(parseDateTime(s)) } -export function parsePlainYearMonth(s) { +export function parsePlainYearMonth(s: string): IsoDateInternals { return processDatelikeParse(parseYearMonth(s) || parseDateTime(s)) } -export function parsePlainMonthDay(s) { +export function parsePlainMonthDay(s: string): IsoDateInternals { return processDatelikeParse(parseMonthDay(s) || parseDateTime(s)) } -export function parsePlainTime(s) { - let parsed = parseTime(s) +export function parsePlainTime(s: string): IsoTimeFields { + let parsed: IsoTimeFields | DateTimeParsed | undefined = parseTime(s) if (!parsed) { parsed = parseDateTime(s) - if (parsed && !parsed.hasTime) { + if (parsed && !(parsed as DateTimeParsed).hasTime) { throw new RangeError() } } @@ -104,25 +104,48 @@ export function parsePlainTime(s) { if (!parsed) { throw new RangeError() } - if (parsed.hasZ) { + if ((parsed as DateTimeParsed).hasZ) { throw new RangeError() } - if (parsed.calendar && parsed.calendar.id !== isoCalendarId) { + if ( + (parsed as DateTimeParsed).calendar && + (parsed as DateTimeParsed).calendar.id !== isoCalendarId + ) { throw new RangeError() } let altParsed - if ((altParsed = parseYearMonth(s)) && constrainIsoDateInternals(altParsed, returnUndefinedI)) { + // NOTE: -1 causes returning undefined rather than error + if ((altParsed = parseYearMonth(s)) && constrainIsoDateInternals(altParsed, -1)) { throw new RangeError() } - if ((altParsed = parseMonthDay(s)) && constrainIsoDateInternals(altParsed, returnUndefinedI)) { + if ((altParsed = parseMonthDay(s)) && constrainIsoDateInternals(altParsed, -1)) { throw new RangeError() } return constrainIsoTimeFields(parsed) } -export function parseCalendarId(s) { +export function parseDuration(s: string): DurationInternals { + const parsed = parseDurationInternals(s) + if (!parsed) { + throw new RangeError() + } + return parsed +} + +export function parseOffsetNano(s: string): number { + const parts = offsetRegExp.exec(s) + const parsed = parts && parseOffsetParts(parts.slice(1)) + + if (!parsed) { + throw new RangeError() + } + + return parsed +} + +export function parseCalendarId(s: string): string { if (s !== isoCalendarId) { s = ( parseDateTime(s) || parseYearMonth(s) || parseMonthDay(s) @@ -131,12 +154,12 @@ export function parseCalendarId(s) { return s } -export function parseTimeZoneId(s) { +export function parseTimeZoneId(s: string): string { const parsed = parseDateTime(s) if (parsed !== undefined) { if (parsed.timeZone) { - return parsed.timeZone.id + return (parsed.timeZone as TimeZoneImpl).id } if (parsed.hasZ) { return utcTimeZoneId @@ -152,12 +175,12 @@ export function parseTimeZoneId(s) { // Intermediate // ------------------------------------------------------------------------------------------------- -function processZonedDateTimeParse(parsed) { +function processZonedDateTimeParse(parsed: ZonedDateTimeParsed): ZonedInternals { const epochNanoseconds = getMatchingInstantFor( parsed.timeZone, parsed, parsed.offset ? parseOffsetNano(parsed.offset) : undefined, - parsed.z, + parsed.hasZ, 'reject', 'compatible', true, // fuzzy @@ -169,14 +192,14 @@ function processZonedDateTimeParse(parsed) { } } -function processDateTimeParse(parsed) { +function processDateTimeParse(parsed: DateTimeParsed): IsoDateTimeInternals { return checkIso(constrainIsoDateTimeInternals(parsed)) } /* Unlike others, throws an error */ -function processDatelikeParse(parsed) { +function processDatelikeParse(parsed: IsoDateInternals | undefined): IsoDateInternals { if (!parsed) { throw new RangeError() } @@ -185,36 +208,31 @@ function processDatelikeParse(parsed) { // Low-level // ------------------------------------------------------------------------------------------------- +// TODO: use new `Falsy` type instead of ternary operator? -function parseDateTime(s) { +function parseDateTime(s: string): DateTimeParsed | undefined { const parts = dateTimeRegExp.exec(s) - return parts && parseDateTimeParts(parts) + return parts ? parseDateTimeParts(parts) : undefined } -function parseYearMonth(s) { +function parseYearMonth(s: string): IsoDateInternals | undefined { const parts = yearMonthRegExp.exec(s) - return parts && parseYearMonthParts(parts) + return parts ? parseYearMonthParts(parts) : undefined } -function parseMonthDay(s) { +function parseMonthDay(s: string): IsoDateInternals | undefined { const parts = monthDayRegExp.exec(s) - return parts && parseMonthDayParts(parts) + return parts ? parseMonthDayParts(parts) : undefined } -function parseTime(s) { +function parseTime(s: string): IsoTimeFields | undefined { const parts = timeRegExp.exec(s) - return parts && parseTimeParts(parts.slice(1)) -} - -export function parseOffsetNano(s) { - const parts = offsetRegExp.exec(s) - return parts && parseOffsetParts(parts.slice(1)) + return parts ? parseTimeParts(parts.slice(1)) : undefined } -// TODO: this should be guaranteed result -export function parseDuration(s: string): DurationInternals { +function parseDurationInternals(s: string): DurationInternals | undefined { const parts = durationRegExp.exec(s) - return parts && parseDurationParts(parts) + return parts ? parseDurationParts(parts) : undefined } // RegExp & Parts @@ -279,9 +297,27 @@ const durationRegExp = createRegExp( ')?', ) -function parseDateTimeParts(parts) { // 0 is whole-match - const hasTime = parts[5] // boolean-like - const hasZ = parts[13] // " +type DateTimeParsed = IsoDateTimeInternals & AnnotationsParsed & { + hasTime: boolean + hasZ: boolean + offset: string | undefined +} + +type ZonedDateTimeParsed = IsoDateTimeInternals & { + calendar: CalendarImpl + timeZone: TimeZoneImpl // guaranteed annotation + hasTime: boolean + hasZ: boolean + offset: string | undefined +} + +/* +0 is whole-match +*/ +function parseDateTimeParts(parts: string[]): DateTimeParsed { + const offsetOrZ = parts[13] + const hasZ = offsetOrZ === 'Z' + const hasTime = Boolean(parts[5]) // boolean-like return { isoYear: parseIsoYearParts(parts), @@ -293,10 +329,14 @@ function parseDateTimeParts(parts) { // 0 is whole-match ), hasTime, hasZ, + offset: hasZ ? undefined : offsetOrZ, } } -function parseYearMonthParts(parts) { // 0 is whole-match +/* +0 is whole-match +*/ +function parseYearMonthParts(parts: string[]): IsoDateInternals { return { isoYear: parseIsoYearParts(parts), isoMonth: parseInt(parts[3]), @@ -305,7 +345,10 @@ function parseYearMonthParts(parts) { // 0 is whole-match } } -function parseMonthDayParts(parts) { // 0 is whole-match +/* +0 is whole-match +*/ +function parseMonthDayParts(parts: string[]): IsoDateInternals { return { isoYear: parseInt(parts[1]), isoMonth: parseInt(parts[2]), @@ -314,7 +357,10 @@ function parseMonthDayParts(parts) { // 0 is whole-match } } -function parseIsoYearParts(parts) { // 0 is whole-match +/* +0 is whole-match +*/ +function parseIsoYearParts(parts: string[]): number { const yearSign = parseSign(parts[1]) const year = parseInt(parts[2]) if (yearSign < 0 && !year) { @@ -323,7 +369,10 @@ function parseIsoYearParts(parts) { // 0 is whole-match return yearSign * year } -function parseTimeParts(parts) { // parses annotations +/* +validated annotations as well +*/ +function parseTimeParts(parts: string[]): IsoTimeFields & AnnotationsParsed { const isoSecond = parseInt0(parts[4]) return { ...nanoToIsoTimeAndDay(parseSubsecNano(parts[6] || ''))[0], @@ -334,7 +383,7 @@ function parseTimeParts(parts) { // parses annotations } } -function parseOffsetParts(parts) { +function parseOffsetParts(parts: string[]): number { return parseSign(parts[0]) * ( parseInt0(parts[0]) * nanoInHour + parseInt0(parts[2]) * nanoInMinute + @@ -343,7 +392,7 @@ function parseOffsetParts(parts) { ) } -function parseDurationParts(parts) { +function parseDurationParts(parts: string[]): DurationInternals { let hasAny = false let hasAnyFrac = false let leftoverNano = 0 @@ -352,11 +401,11 @@ function parseDurationParts(parts) { months: parseUnit(parts[3]), weeks: parseUnit(parts[4]), days: parseUnit(parts[5]), - hours: parseUnit(parts[7], parts[8], hourIndex), - minutes: parseUnit(parts[9], parts[10], minuteIndex), - seconds: parseUnit(parts[11], parts[12], secondsIndex), - ...nanoToGivenFields(leftoverNano, milliIndex, durationFieldNamesAsc), - } + hours: parseUnit(parts[7], parts[8], Unit.Hour), + minutes: parseUnit(parts[9], parts[10], Unit.Minute), + seconds: parseUnit(parts[11], parts[12], Unit.Second), + ...nanoToGivenFields(leftoverNano, Unit.Millisecond, durationFieldNamesAsc), + } as DurationFields if (!hasAny) { throw new RangeError('Duration string must have at least one field') @@ -368,12 +417,14 @@ function parseDurationParts(parts) { return updateDurationFieldsSign(durationFields) - function parseUnit(wholeStr, fracStr, timeUnitI) { + function parseUnit(wholeStr: string): number + function parseUnit(wholeStr: string, fracStr: string, timeUnit: TimeUnit): number + function parseUnit(wholeStr: string, fracStr?: string, timeUnit?: TimeUnit): number { let leftoverUnits = 0 // from previous round let wholeUnits = 0 - if (timeUnitI) { - [leftoverUnits, leftoverNano] = divFloorMod(leftoverNano, nanoIn[timeUnitI]) + if (timeUnit) { + [leftoverUnits, leftoverNano] = divFloorMod(leftoverNano, nanoIn[timeUnit]) } if (wholeStr !== undefined) { @@ -386,7 +437,7 @@ function parseDurationParts(parts) { if (fracStr) { // convert seconds to other units, abusing parseSubsecNano - leftoverNano = parseSubsecNano(fracStr) * (nanoIn[timeUnitI] / nanoInSecond) + leftoverNano = parseSubsecNano(fracStr) * (nanoIn[timeUnit!] / nanoInSecond) hasAnyFrac = true } } @@ -398,9 +449,14 @@ function parseDurationParts(parts) { // Utils // ------------------------------------------------------------------------------------------------- -function parseAnnotations(s) { - let calendarId - let timeZoneId +interface AnnotationsParsed { + calendar: CalendarImpl, + timeZone: TimeZoneImpl | undefined, +} + +function parseAnnotations(s: string): AnnotationsParsed { + let calendarId: string | undefined + let timeZoneId: string | undefined for (const chunk of s.split(']')) { if (chunk) { // not the empty end chunk @@ -430,22 +486,22 @@ function parseAnnotations(s) { return { calendar: queryCalendarImpl(calendarId || isoCalendarId), - timeZone: timeZoneId && queryTimeZoneImpl(timeZoneId), + timeZone: timeZoneId ? queryTimeZoneImpl(timeZoneId) : undefined, } } -function parseSubsecNano(fracStr) { +function parseSubsecNano(fracStr: string): number { return parseInt(fracStr.padEnd(9, '0')) } -function createRegExp(meat) { +function createRegExp(meat: string): RegExp { return new RegExp(`^${meat}$`, 'i') } -function parseSign(s) { +function parseSign(s: string): number { return !s || s === '+' ? 1 : -1 } -function parseInt0(s) { +function parseInt0(s: string): number { return s === undefined ? 0 : parseInt(s) } diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.ts b/packages/temporal-polyfill/src/new/timeZoneOps.ts index ce1cf91f..9c11084c 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.ts +++ b/packages/temporal-polyfill/src/new/timeZoneOps.ts @@ -25,6 +25,7 @@ import { createLazyGenerator } from './utils' import { ZonedInternals } from './zonedDateTime' export interface TimeZoneOps { + id: string getOffsetNanosecondsFor(epochNano: LargeInt): number getPossibleInstantsFor(isoDateTimeFields: IsoDateTimeFields): LargeInt[] } diff --git a/packages/temporal-polyfill/src/new/units.ts b/packages/temporal-polyfill/src/new/units.ts index 17764e8a..6cf4e307 100644 --- a/packages/temporal-polyfill/src/new/units.ts +++ b/packages/temporal-polyfill/src/new/units.ts @@ -31,7 +31,7 @@ export const unitNameMap = { export type UnitName = keyof typeof unitNameMap -type TimeUnit = +export type TimeUnit = Unit.Nanosecond | Unit.Microsecond | Unit.Millisecond | @@ -108,15 +108,15 @@ export function givenFieldsToNano( export function nanoToGivenFields( nano: number, - unitIndex: DayTimeUnit, + unit: DayTimeUnit, fieldNames: (keyof F)[], -): { [Key in keyof F]: number } { +): { [Key in keyof F]?: number } { const fields = {} as { [Key in keyof F]: number } - for (; unitIndex >= Unit.Nanosecond; unitIndex--) { - const divisor = unitNanoMap[unitIndex] + for (; unit >= Unit.Nanosecond; unit--) { + const divisor = unitNanoMap[unit] - fields[fieldNames[unitIndex]] = Math.trunc(nano / divisor) + fields[fieldNames[unit]] = Math.trunc(nano / divisor) nano %= divisor } From cd6a4b84fd5abc22ad0a0d6d25bd3fdd7923cb2a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 12:50:43 -0400 Subject: [PATCH 163/805] lots of misc type fixes --- .../temporal-polyfill/src/new/calendarImpl.ts | 2 +- packages/temporal-polyfill/src/new/convert.ts | 4 ++-- packages/temporal-polyfill/src/new/isoMath.ts | 9 +++---- .../temporal-polyfill/src/new/isoParse.ts | 5 ++-- .../src/new/plainDateTime.ts | 2 +- .../src/new/plainYearMonth.ts | 4 ++-- .../temporal-polyfill/src/new/timeZoneOps.ts | 7 +++--- .../src/new/zonedDateTime.ts | 24 ++++++++++--------- 8 files changed, 31 insertions(+), 26 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.ts b/packages/temporal-polyfill/src/new/calendarImpl.ts index ef23fdf0..7e4517e9 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.ts +++ b/packages/temporal-polyfill/src/new/calendarImpl.ts @@ -182,7 +182,7 @@ export class CalendarImpl implements CalendarOps { isoDateFields: IsoDateFields, durationFields: DurationInternals, overflow: Overflow, - ): IsoDateFields { + ): IsoDateInternals { return moveDate(this, isoDateFields, durationFields, overflow) } diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/new/convert.ts index c198c0f6..ebedfa42 100644 --- a/packages/temporal-polyfill/src/new/convert.ts +++ b/packages/temporal-polyfill/src/new/convert.ts @@ -74,7 +74,7 @@ export function refineMaybeZonedDateTimeBag(bag: any): ZonedInternals | IsoDateI const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoDateFields, ...isoTimeFields }, - fields.offset !== undefined && parseOffsetNano(fields.offset), + fields.offset !== undefined ? parseOffsetNano(fields.offset) : undefined, false, // z? OffsetDisambig.Use, // TODO: is default already? EpochDisambig.Compat, // TODO: is default already? @@ -115,7 +115,7 @@ export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: any): Zon const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoDateFields, ...isoTimeFields }, - fields.offset !== undefined && parseOffsetNano(fields.offset), + fields.offset !== undefined ? parseOffsetNano(fields.offset) : undefined, false, // z? offsetDisambig, epochDisambig, diff --git a/packages/temporal-polyfill/src/new/isoMath.ts b/packages/temporal-polyfill/src/new/isoMath.ts index a76706c0..bd779445 100644 --- a/packages/temporal-polyfill/src/new/isoMath.ts +++ b/packages/temporal-polyfill/src/new/isoMath.ts @@ -1,4 +1,5 @@ import { isoFieldsToEpochMilli } from '../dateUtils/epoch' +import { CalendarArg } from './calendar' import { diffEpochMilliByDay } from './diff' import { IsoDateFields, @@ -125,7 +126,7 @@ function isoDateMonthStart(isoDateFields: IsoDateFields): IsoDateFields { // ------------------------------------------------------------------------------------------------- export function refineIsoDateTimeInternals( - rawIsoDateTimeInternals: IsoDateTimeInternals, // wrong + rawIsoDateTimeInternals: IsoDateTimeFields & { calendar: CalendarArg }, ): IsoDateTimeInternals { return checkIso( constrainIsoDateTimeInternals( @@ -135,7 +136,7 @@ export function refineIsoDateTimeInternals( } export function refineIsoDateInternals( - rawIsoDateInternals: IsoDateInternals, // wrong + rawIsoDateInternals: IsoDateFields & { calendar: CalendarArg }, ): IsoDateInternals { return checkIso( constrainIsoDateInternals( @@ -145,7 +146,7 @@ export function refineIsoDateInternals( } export function refineIsoTimeInternals( - rawIsoTimeInternals: IsoTimeFields, // wrong + rawIsoTimeInternals: IsoTimeFields, ): IsoTimeFields { return constrainIsoTimeFields( mapPropsWithRefiners(rawIsoTimeInternals, isoTimeFieldRefiners), @@ -252,7 +253,7 @@ export function isoTimeFieldsToNano(isoTimeFields: IsoTimeFields): number { export function nanoToIsoTimeAndDay(nano: number): [IsoTimeFields, number] { const [dayDelta, timeNano] = divFloorMod(nano, nanoInUtcDay) const isoTimeFields = nanoToGivenFields(timeNano, Unit.Hour, isoTimeFieldNamesAsc) - return [isoTimeFields, dayDelta] + return [isoTimeFields as IsoTimeFields, dayDelta] } // Epoch Unit Conversion diff --git a/packages/temporal-polyfill/src/new/isoParse.ts b/packages/temporal-polyfill/src/new/isoParse.ts index df97ac9f..7378dbd5 100644 --- a/packages/temporal-polyfill/src/new/isoParse.ts +++ b/packages/temporal-polyfill/src/new/isoParse.ts @@ -18,6 +18,7 @@ import { nanoToIsoTimeAndDay, } from './isoMath' import { LargeInt } from './largeInt' +import { EpochDisambig, OffsetDisambig } from './options' import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' import { getMatchingInstantFor, utcTimeZoneId } from './timeZoneOps' import { @@ -181,8 +182,8 @@ function processZonedDateTimeParse(parsed: ZonedDateTimeParsed): ZonedInternals parsed, parsed.offset ? parseOffsetNano(parsed.offset) : undefined, parsed.hasZ, - 'reject', - 'compatible', + OffsetDisambig.Reject, + EpochDisambig.Compat, true, // fuzzy ) return { diff --git a/packages/temporal-polyfill/src/new/plainDateTime.ts b/packages/temporal-polyfill/src/new/plainDateTime.ts index 9d4314c9..2f24efc4 100644 --- a/packages/temporal-polyfill/src/new/plainDateTime.ts +++ b/packages/temporal-polyfill/src/new/plainDateTime.ts @@ -173,7 +173,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals: IsoDateTimeInternals, options): string { + toString(internals: IsoDateTimeInternals, options: any): string { const [ calendarDisplayI, nanoInc, diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.ts b/packages/temporal-polyfill/src/new/plainYearMonth.ts index cda64dee..24075764 100644 --- a/packages/temporal-polyfill/src/new/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/new/plainYearMonth.ts @@ -141,7 +141,7 @@ export const [ function diffPlainYearMonths( internals0: IsoDateInternals, internals1: IsoDateInternals, - options, + options: any, roundingModeInvert?: boolean ): Duration { return createDuration( @@ -157,7 +157,7 @@ function diffPlainYearMonths( function movePlainYearMonth( internals: IsoDateInternals, durationInternals: DurationInternals, - options, + options: any, ): PlainYearMonth { const { calendar } = internals const isoDateFields = movePlainYearMonthToDay( diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.ts b/packages/temporal-polyfill/src/new/timeZoneOps.ts index 9c11084c..52b06f47 100644 --- a/packages/temporal-polyfill/src/new/timeZoneOps.ts +++ b/packages/temporal-polyfill/src/new/timeZoneOps.ts @@ -81,13 +81,13 @@ export function computeNanosecondsInDay( export function getMatchingInstantFor( timeZoneOps: TimeZoneOps, isoDateTimeFields: IsoDateTimeFields, - offsetNano: number, // optional + offsetNano: number | undefined, hasZ: boolean, // need these defaults? offsetHandling: OffsetDisambig = OffsetDisambig.Reject, disambig: EpochDisambig = EpochDisambig.Compat, fuzzy = false, -) { +): LargeInt { if (offsetNano !== undefined && offsetHandling !== OffsetDisambig.Ignore) { // we ALWAYS use Z as a zero offset if (offsetHandling === OffsetDisambig.Use || hasZ) { @@ -199,13 +199,14 @@ function computeGapNear(timeZoneOps: TimeZoneOps, zonedEpochNano: LargeInt): num } export const zonedInternalsToIso = createLazyGenerator((internals: ZonedInternals) => { - const { timeZone, epochNanoseconds } = internals + const { calendar, timeZone, epochNanoseconds } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) const isoDateTimeFields = epochNanoToIso(epochNanoseconds.addNumber(offsetNanoseconds)) return { ...isoDateTimeFields, offsetNanoseconds, + calendar, } }) diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.ts b/packages/temporal-polyfill/src/new/zonedDateTime.ts index 73412150..a10bcf2d 100644 --- a/packages/temporal-polyfill/src/new/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/new/zonedDateTime.ts @@ -37,6 +37,8 @@ import { parseZonedDateTime } from './isoParse' import { LargeInt, compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' import { + EpochDisambig, + OffsetDisambig, Overflow, refineDiffOptions, refineOverflowOptions, @@ -196,7 +198,7 @@ export const [ const epochNano = getMatchingInstantFor( timeZone, isoFields, - isoFields.offsetNano, + isoFields.offsetNanoseconds, false, // hasZ undefined, // offsetHandling undefined, // disambig @@ -263,12 +265,12 @@ export const [ timeZone, ) epochNanoseconds = getMatchingInstantFor( - isoDateTimeFields, timeZone, + isoDateTimeFields, offsetNanoseconds, false, // z - 'prefer', // keep old offsetNanoseconds if possible - 'compatible', + OffsetDisambig.Prefer, // keep old offsetNanoseconds if possible + EpochDisambig.Compat, true, // fuzzy ) @@ -288,12 +290,12 @@ export const [ } epochNanoseconds = getMatchingInstantFor( - isoFields, timeZone, + isoFields, undefined, // offsetNanoseconds false, // z - 'reject', - 'compatible', + OffsetDisambig.Reject, + EpochDisambig.Compat, true, // fuzzy ) @@ -328,12 +330,12 @@ export const [ isoDateTimeFields = roundDateTimeToNano(isoDateTimeFields, nanoInc, roundingMode) epochNanoseconds = getMatchingInstantFor( - isoDateTimeFields, timeZone, + isoDateTimeFields, offsetNanoseconds, false, // z - 'prefer', // keep old offsetNanoseconds if possible - 'compatible', + OffsetDisambig.Prefer, // keep old offsetNanoseconds if possible + EpochDisambig.Compat, true, // fuzzy ) @@ -350,7 +352,7 @@ export const [ toLocaleString( internals: ZonedInternals, locales: string | string[], - options + options: any, ): string { const [epochMilli, format] = resolveZonedFormattable(internals, locales, options) return format.format(epochMilli) From cd40bd53d02d8ec06a05eeffb6f3f89ac2567417 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 14:55:36 -0400 Subject: [PATCH 164/805] convert now to ts --- .../temporal-polyfill/src/new/isoFields.ts | 1 + packages/temporal-polyfill/src/new/now.js | 91 --------------- packages/temporal-polyfill/src/new/now.ts | 110 ++++++++++++++++++ 3 files changed, 111 insertions(+), 91 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/now.js create mode 100644 packages/temporal-polyfill/src/new/now.ts diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/new/isoFields.ts index 0507589d..b2225cd9 100644 --- a/packages/temporal-polyfill/src/new/isoFields.ts +++ b/packages/temporal-polyfill/src/new/isoFields.ts @@ -20,6 +20,7 @@ export interface IsoTimeFields { } // TODO: move +// TODO: same as CalendarArg? type CalendarPublic = CalendarProtocol | string export interface CalendarInternals { diff --git a/packages/temporal-polyfill/src/new/now.js b/packages/temporal-polyfill/src/new/now.js deleted file mode 100644 index ef8d5fc7..00000000 --- a/packages/temporal-polyfill/src/new/now.js +++ /dev/null @@ -1,91 +0,0 @@ -import { nanoInMilli } from '../dateUtils/units' -import { isoCalendarId } from './calendarConfig' -import { queryCalendarOps } from './calendarOps' -import { createInstant } from './instant' -import { IntlDateTimeFormat } from './intlFormat' -import { pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields } from './isoFields' -import { numberToLargeInt } from './largeInt' -import { createPlainDate } from './plainDate' -import { createPlainDateTime } from './plainDateTime' -import { createPlainTime } from './plainTime' -import { queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' -import { createPropDescriptors, createTemporalNameDescriptors } from './utils' -import { createZonedDateTime } from './zonedDateTime' - -export const Now = Object.defineProperties({}, { - ...createTemporalNameDescriptors('Now'), - ...createPropDescriptors({ - zonedDateTime: getCurrentZonedDateTime, - zonedDateTimeISO: (timeZoneArg) => getCurrentZonedDateTime(isoCalendarId, timeZoneArg), - plainDateTime: getCurrentPlainDateTime, - plainDateTimeISO: (timeZoneArg) => getCurrentPlainDateTime(isoCalendarId, timeZoneArg), - plainDate: getCurrentPlainDate, - plainDateISO: (timeZoneArg) => getCurrentPlainDate(isoCalendarId, timeZoneArg), - plainTimeISO: getCurrentPlainTime, - instant: getCurrentInstant, - timeZoneId: getCurrentTimeZoneId, - }), -}) - -function getCurrentZonedDateTime(calendarArg, timeZoneArg) { - return createZonedDateTime( - getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg), - ) -} - -function getCurrentPlainDateTime(calendarArg, timeZoneArg) { - return createPlainDateTime( - getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg), - ) -} - -function getCurrentPlainDate(calendarArg, timeZoneArg) { - return createPlainDate( - pluckIsoDateInternals(getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg)), - ) -} - -function getCurrentPlainTime(timeZoneArg) { - return createPlainTime( - pluckIsoTimeFields(getCurrentPlainDateTimeSlots(isoCalendarId, timeZoneArg)), - ) -} - -function getCurrentInstant() { - return createInstant(getCurrentEpochNanoseconds()) -} - -function getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg) { - return pluckIsoDateTimeInternals( - zonedInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)), - ) -} - -function getCurrentZonedDateTimeSlots( - calendarArg, - timeZoneArg = getCurrentTimeZoneId(), -) { - return { - epochNanoseconds: getCurrentEpochNanoseconds(), - calendar: queryCalendarOps(calendarArg), - timeZone: queryTimeZoneOps(timeZoneArg), - } -} - -function getCurrentEpochNanoseconds() { - return numberToLargeInt(Date.now()).mult(nanoInMilli) -} - -// TimeZone -// -------- -// TODO: use lazy cache util? - -let queriedCurrentTimeZoneId - -function getCurrentTimeZoneId() { - return queriedCurrentTimeZoneId ?? (queriedCurrentTimeZoneId = queryCurrentTimeZoneId()) -} - -function queryCurrentTimeZoneId() { - return new IntlDateTimeFormat().resolvedOptions().timeZone -} diff --git a/packages/temporal-polyfill/src/new/now.ts b/packages/temporal-polyfill/src/new/now.ts new file mode 100644 index 00000000..28c2423b --- /dev/null +++ b/packages/temporal-polyfill/src/new/now.ts @@ -0,0 +1,110 @@ +import { nanoInMilli } from '../dateUtils/units' +import { CalendarArg } from './calendar' +import { isoCalendarId } from './calendarConfig' +import { queryCalendarOps } from './calendarOps' +import { Instant, createInstant } from './instant' +import { IntlDateTimeFormat } from './intlFormat' +import { IsoDateTimeInternals, pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields } from './isoFields' +import { LargeInt, numberToLargeInt } from './largeInt' +import { PlainDate, createPlainDate } from './plainDate' +import { PlainDateTime, createPlainDateTime } from './plainDateTime' +import { PlainTime, createPlainTime } from './plainTime' +import { TimeZoneArg } from './timeZone' +import { queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' +import { createPropDescriptors, createTemporalNameDescriptors } from './utils' +import { ZonedDateTime, ZonedInternals, createZonedDateTime } from './zonedDateTime' + +export const Now = Object.defineProperties({}, { + ...createTemporalNameDescriptors('Now'), + ...createPropDescriptors({ + zonedDateTime: getCurrentZonedDateTime, + zonedDateTimeISO(timeZoneArg: TimeZoneArg) { + return getCurrentZonedDateTime(isoCalendarId, timeZoneArg) + }, + plainDateTime: getCurrentPlainDateTime, + plainDateTimeISO(timeZoneArg: TimeZoneArg) { + return getCurrentPlainDateTime(isoCalendarId, timeZoneArg) + }, + plainDate: getCurrentPlainDate, + plainDateISO(timeZoneArg: TimeZoneArg) { + return getCurrentPlainDate(isoCalendarId, timeZoneArg) + }, + plainTimeISO: getCurrentPlainTime, + instant: getCurrentInstant, + timeZoneId: getCurrentTimeZoneId, + }), +}) + +function getCurrentZonedDateTime( + calendarArg: CalendarArg, + timeZoneArg: TimeZoneArg +): ZonedDateTime { + return createZonedDateTime( + getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg), + ) +} + +function getCurrentPlainDateTime( + calendarArg: CalendarArg, + timeZoneArg: TimeZoneArg, +): PlainDateTime { + return createPlainDateTime( + getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg), + ) +} + +function getCurrentPlainDate( + calendarArg: CalendarArg, + timeZoneArg: TimeZoneArg, +): PlainDate { + return createPlainDate( + pluckIsoDateInternals(getCurrentPlainDateTimeSlots(calendarArg, timeZoneArg)), + ) +} + +function getCurrentPlainTime(timeZoneArg: TimeZoneArg): PlainTime { + return createPlainTime( + pluckIsoTimeFields(getCurrentPlainDateTimeSlots(isoCalendarId, timeZoneArg)), + ) +} + +function getCurrentInstant(): Instant { + return createInstant(getCurrentEpochNanoseconds()) +} + +function getCurrentPlainDateTimeSlots( + calendarArg: CalendarArg, + timeZoneArg: TimeZoneArg, +): IsoDateTimeInternals { + return pluckIsoDateTimeInternals( + zonedInternalsToIso(getCurrentZonedDateTimeSlots(calendarArg, timeZoneArg)), + ) +} + +function getCurrentZonedDateTimeSlots( + calendarArg: CalendarArg, + timeZoneArg: TimeZoneArg = getCurrentTimeZoneId(), +): ZonedInternals { + return { + epochNanoseconds: getCurrentEpochNanoseconds(), + calendar: queryCalendarOps(calendarArg), + timeZone: queryTimeZoneOps(timeZoneArg), + } +} + +function getCurrentEpochNanoseconds(): LargeInt { + return numberToLargeInt(Date.now()).mult(nanoInMilli) +} + +// TimeZone +// -------- + +let queriedCurrentTimeZoneId: string | undefined + +function getCurrentTimeZoneId(): string { + return queriedCurrentTimeZoneId ?? (queriedCurrentTimeZoneId = queryCurrentTimeZoneId()) +} + +function queryCurrentTimeZoneId(): string { + return new IntlDateTimeFormat().resolvedOptions().timeZone +} From 4d2fe87f71d0cf67a6043e8f105b6577e7dc8a1b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 15:49:44 -0400 Subject: [PATCH 165/805] isoFormat ts --- .../temporal-polyfill/src/new/duration.ts | 5 +- .../src/new/durationFields.ts | 8 +- .../src/new/{isoFormat.js => isoFormat.ts} | 117 +++++++++++------- packages/temporal-polyfill/src/new/options.ts | 33 +++-- 4 files changed, 101 insertions(+), 62 deletions(-) rename packages/temporal-polyfill/src/new/{isoFormat.js => isoFormat.ts} (55%) diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/new/duration.ts index 40174dac..6b5a0a1c 100644 --- a/packages/temporal-polyfill/src/new/duration.ts +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -20,6 +20,7 @@ import { parseDuration } from './isoParse' import { LargeInt, compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' import { + SubsecDigits, refineDurationRoundOptions, refineRelativeToOptions, refineTimeDisplayOptions, @@ -180,11 +181,11 @@ export const [ }, toString(internals: DurationInternals, options: any): string { - const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) + const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options, Unit.Second) return formatDurationInternals( roundDurationToNano(internals, nanoInc, roundingMode), - subsecDigits, + subsecDigits as (SubsecDigits | undefined), // -1 won't happen (units can't be minutes) ) }, diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts index 2fc73560..b06b0c80 100644 --- a/packages/temporal-polyfill/src/new/durationFields.ts +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -3,6 +3,7 @@ import { LargeInt } from './largeInt' import { toIntegerStrict } from './options' import { DayTimeUnit, + TimeUnit, Unit, givenFieldsToLargeNano, nanoToGivenFields, @@ -118,8 +119,11 @@ export function durationFieldsToNano( return givenFieldsToLargeNano(fields, largestUnit, durationFieldNamesAsc) } -export function durationFieldsToTimeNano(fields: DurationFields): number { - return durationFieldsToNano(fields, Unit.Hour).toNumber() +export function durationFieldsToTimeNano( + fields: DurationFields, + largeUnit: TimeUnit = Unit.Hour, +): number { + return durationFieldsToNano(fields, largeUnit).toNumber() } export function nanoToDurationFields( diff --git a/packages/temporal-polyfill/src/new/isoFormat.js b/packages/temporal-polyfill/src/new/isoFormat.ts similarity index 55% rename from packages/temporal-polyfill/src/new/isoFormat.js rename to packages/temporal-polyfill/src/new/isoFormat.ts index 60f296b0..f397a80b 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.js +++ b/packages/temporal-polyfill/src/new/isoFormat.ts @@ -1,27 +1,34 @@ import { isoCalendarId } from './calendarConfig' -import { absDurationInternals, durationFieldsToNano } from './durationFields' -import { autoI, criticalI, neverI, refineDateDisplayOptions } from './options' +import { CalendarOps } from './calendarOps' +import { DurationInternals, absDurationInternals, durationFieldsToNano, durationFieldsToTimeNano } from './durationFields' +import { IsoDateFields, IsoDateInternals, IsoDateTimeFields, IsoTimeFields } from './isoFields' +import { CalendarDisplay, OffsetDisplay, refineDateDisplayOptions, SubsecDigits, TimeZoneDisplay } from './options' +import { TimeZoneOps } from './timeZoneOps' import { nanoInHour, nanoInMicro, nanoInMilli, nanoInMinute, nanoInSec, - secondsIndex, + Unit, } from './units' import { divFloorMod, padNumber, padNumber2 } from './utils' /* High-level. Refined options */ -export function formatPossibleDate(formatSimple, internals, options) { - const calendarDisplayI = refineDateDisplayOptions(options) +export function formatPossibleDate( + formatSimple: (internals: IsoDateInternals) => string, + internals: IsoDateInternals, + options: any, +) { + const calendarDisplay = refineDateDisplayOptions(options) const showCalendar = - calendarDisplayI > neverI || // critical or always - (calendarDisplayI === autoI && internals.calendar.id !== isoCalendarId) + calendarDisplay > CalendarDisplay.Never || // critical or always + (calendarDisplay === CalendarDisplay.Auto && internals.calendar.id !== isoCalendarId) if (showCalendar) { - return formatIsoDateFields(internals) + formatCalendar(internals.calendar, calendarDisplayI) + return formatIsoDateFields(internals) + formatCalendar(internals.calendar, calendarDisplay) } else { return formatSimple(internals) } @@ -32,18 +39,18 @@ Rounding already happened with these... */ export function formatIsoDateTimeFields( - isoDateTimeFields, - subsecDigits, + isoDateTimeFields: IsoDateTimeFields, + subsecDigits: SubsecDigits, ) { return formatIsoDateFields(isoDateTimeFields) + 'T' + formatIsoTimeFields(isoDateTimeFields, subsecDigits) } -export function formatIsoDateFields(isoDateFields) { +export function formatIsoDateFields(isoDateFields: IsoDateFields): string { return formatIsoYearMonthFields(isoDateFields) + '-' + padNumber2(isoDateFields.isoDay) } -export function formatIsoYearMonthFields(isoDateFields) { +export function formatIsoYearMonthFields(isoDateFields: IsoDateFields): string { const { isoYear } = isoDateFields return ( (isoYear < 0 || isoYear > 9999) @@ -52,14 +59,14 @@ export function formatIsoYearMonthFields(isoDateFields) { ) + '-' + padNumber2(isoDateFields.isoMonth) } -export function formatIsoMonthDayFields(isoDateFields) { +export function formatIsoMonthDayFields(isoDateFields: IsoDateFields): string { return padNumber2(isoDateFields.isoMonth) + '-' + padNumber2(isoDateFields.isoDay) } export function formatIsoTimeFields( - isoTimeFields, - subsecDigits, // undefined/-1/# -) { + isoTimeFields: IsoTimeFields, + subsecDigits: SubsecDigits | -1 | undefined, +): string { const parts = [ padNumber2(isoTimeFields.isoHour), padNumber2(isoTimeFields.isoMinute), @@ -81,10 +88,10 @@ export function formatIsoTimeFields( } export function formatOffsetNano( - offsetNano, - offsetDisplayI = autoI, // auto/never -) { - if (offsetDisplayI === neverI) { + offsetNano: number, + offsetDisplay: OffsetDisplay = OffsetDisplay.Auto, +): string { + if (offsetDisplay === OffsetDisplay.Never) { return '' } @@ -101,17 +108,20 @@ export function formatOffsetNano( } export function formatDurationInternals( - durationInternals, - subsecDigits, // undefined/-1/# -) { + durationInternals: DurationInternals, + subsecDigits: SubsecDigits | undefined, +): string { const { sign } = durationInternals const abs = absDurationInternals(durationInternals) const { hours, minutes } = abs - const secondsNano = durationFieldsToNano(abs, secondsIndex) + const secondsNano = durationFieldsToTimeNano(abs, Unit.Second) const [wholeSeconds, subsecNano] = divFloorMod(secondsNano, nanoInSec) const forceSeconds = - subsecDigits > 0 || // # of subsecond digits being forced? - !sign // completely empty? display 'PT0S' + // at least one subsecond digit being forced? + // allow `undefined` in comparison - will evaluate to false + (subsecDigits as number) > 0 || + // completely empty? display 'PT0S' + !sign return (sign < 0 ? '-' : '') + 'P' + formatDurationFragments({ Y: abs.years, @@ -125,7 +135,9 @@ export function formatDurationInternals( M: minutes, S: wholeSeconds + ( formatSubsecNano(subsecNano, subsecDigits) || - (forceSeconds ? '' : 0) // string concatenation will force truthiness + (forceSeconds + ? '' // will force truthiness ('0') + : 0 as unknown as string) // will leave wholeSeconds as number ), }) : '' @@ -135,13 +147,16 @@ export function formatDurationInternals( /* Values are guaranteed to be non-negative */ -function formatDurationFragments(fragObj) { +function formatDurationFragments(fragObj: Record): string { const parts = [] for (const fragName in fragObj) { const fragVal = fragObj[fragName] if (fragVal) { - parts.push(formatNumberNoSciNot(fragVal) + fragName) + parts.push( + (typeof fragVal === 'number' ? formatNumberUnscientific(fragVal) : fragVal) + + fragName + ) } } @@ -153,12 +168,12 @@ function formatDurationFragments(fragObj) { // export function formatTimeZone( - timeZoneOps, - timeZoneDisplayI, -) { - if (timeZoneDisplayI !== neverI) { + timeZoneOps: TimeZoneOps, + timeZoneDisplay: TimeZoneDisplay, +): string { + if (timeZoneDisplay !== TimeZoneDisplay.Never) { return '[' + - (timeZoneDisplayI === criticalI ? '!' : '') + + (timeZoneDisplay === TimeZoneDisplay.Critical ? '!' : '') + timeZoneOps.id + ']' } @@ -166,15 +181,15 @@ export function formatTimeZone( } export function formatCalendar( - calendarOps, - calendarDisplayI, -) { + calendarOps: CalendarOps, + calendarDisplay: CalendarDisplay, +): string { if ( - calendarDisplayI > neverI || // critical or always - (calendarDisplayI === autoI && calendarOps.id !== isoCalendarId) + calendarDisplay > CalendarDisplay.Never || // critical or always + (calendarDisplay === CalendarDisplay.Auto && calendarOps.id !== isoCalendarId) ) { return '[' + - (calendarDisplayI === criticalI ? '!' : '') + + (calendarDisplay === CalendarDisplay.Critical ? '!' : '') + calendarOps.id + ']' } @@ -185,12 +200,14 @@ export function formatCalendar( // utils // + + function formatSubsec( - isoMillisecond, - isoMicrosecond, - isoNanosecond, - subsecDigits, // undefined/# -) { + isoMillisecond: number, + isoMicrosecond: number, + isoNanosecond: number, + subsecDigits: SubsecDigits | undefined, +): string { return formatSubsecNano( isoMillisecond * nanoInMilli + isoMicrosecond * nanoInMicro + @@ -201,8 +218,12 @@ function formatSubsec( const trailingZerosRE = /0+$/ -function formatSubsecNano(totalNano, subsecDigits) { // subsecDigits can be undefined +function formatSubsecNano( + totalNano: number, + subsecDigits?: SubsecDigits, +): string { let s = padNumber(9, totalNano) + s = subsecDigits === undefined ? s.replace(trailingZerosRE, '') : s.slice(0, subsecDigits) @@ -210,11 +231,11 @@ function formatSubsecNano(totalNano, subsecDigits) { // subsecDigits can be unde return s ? '.' + s : '' } -function getSignStr(num) { +function getSignStr(num: number): string { return num < 0 ? '-' : '+' } -function formatNumberNoSciNot(n) { +function formatNumberUnscientific(n: number): string { // avoid outputting scientific notation // https://stackoverflow.com/a/50978675/96342 return n.toLocaleString('fullwide', { useGrouping: false }) diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 7ae7908b..8c6e0cd2 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -6,7 +6,7 @@ import { parseMaybeZonedDateTime } from './isoParse' import { LargeInt, bigIntToLargeInt } from './largeInt' import { PlainDate } from './plainDate' import { PlainDateTime } from './plainDateTime' -import { DayTimeUnit, Unit, UnitName, unitNameMap, unitNanoMap } from './units' +import { DayTimeUnit, TimeUnit, Unit, UnitName, unitNameMap, unitNanoMap } from './units' import { FilterPropValues, clamp, @@ -151,25 +151,38 @@ export function refineDateDisplayOptions(options: Options | undefined): Calendar return refineCalendarDisplay(normalizeOptions(options)) } -export function refineTimeDisplayOptions(options: Options | undefined): TimeDisplayTuple { - return refineTimeDisplayTuple(normalizeOptions(options)) +export function refineTimeDisplayOptions( + options: Options | undefined, + maxSmallestUnit?: TimeUnit +): TimeDisplayTuple { + return refineTimeDisplayTuple(normalizeOptions(options), maxSmallestUnit) } +/* +addons: + -1 means hide seconds + undefined means 'auto' (display all digits but no trailing zeros) +*/ +export type SubsecDigits = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 + export type TimeDisplayTuple = [ nanoInc: number, roundingMode: RoundingMode, - subsecDigits: number | undefined // (undefined = auto-digits, -1 = hide-seconds, >=0 = #-of-digits) + subsecDigits: SubsecDigits | -1 | undefined ] -function refineTimeDisplayTuple(options: Options): TimeDisplayTuple { - const smallestUnit = refineSmallestUnit(options, Unit.Minute, Unit.Nanosecond, -1 as number) +function refineTimeDisplayTuple( + options: Options, + maxSmallestUnit: TimeUnit = Unit.Minute +): TimeDisplayTuple { + const smallestUnit = refineSmallestUnit(options, maxSmallestUnit, Unit.Nanosecond, -1 as number) if ((smallestUnit as number) !== -1) { return [ unitNanoMap[smallestUnit], refineRoundingMode(options, RoundingMode.Trunc), (smallestUnit < Unit.Minute) - ? 9 - (smallestUnit * 3) - : -1, // hide seconds + ? (9 - (smallestUnit * 3)) as SubsecDigits + : -1, // hide seconds --- NOTE: not relevant when maxSmallestUnit is Date: Wed, 26 Jul 2023 16:41:47 -0400 Subject: [PATCH 166/805] convert intlFormat to ts --- .../src/new/{intlFormat.js => intlFormat.ts} | 173 +++++++++++++----- 1 file changed, 124 insertions(+), 49 deletions(-) rename packages/temporal-polyfill/src/new/{intlFormat.js => intlFormat.ts} (59%) diff --git a/packages/temporal-polyfill/src/new/intlFormat.js b/packages/temporal-polyfill/src/new/intlFormat.ts similarity index 59% rename from packages/temporal-polyfill/src/new/intlFormat.js rename to packages/temporal-polyfill/src/new/intlFormat.ts index 38165097..2e5a6020 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.js +++ b/packages/temporal-polyfill/src/new/intlFormat.ts @@ -1,7 +1,14 @@ import { isoCalendarId } from './calendarConfig' import { dateBasicNames, timeFieldDefaults } from './calendarFields' import { getInternals, getTemporalName } from './class' +import { Instant } from './instant' +import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' +import { LargeInt } from './largeInt' +import { PlainDate } from './plainDate' +import { PlainDateTime } from './plainDateTime' +import { PlainMonthDay } from './plainMonthDay' +import { PlainYearMonth } from './plainYearMonth' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { createLazyGenerator, @@ -10,12 +17,16 @@ import { identityFunc, mapPropNamesToConstant, } from './utils' +import { ZonedDateTime, ZonedInternals } from './zonedDateTime' export const standardCalendarId = 'en-GB' // gives 24-hour clock -export function hashIntlFormatParts(intlFormat, epochMilliseconds) { +export function hashIntlFormatParts( + intlFormat: Intl.DateTimeFormat, + epochMilliseconds: number, +): Record { const parts = intlFormat.formatToParts(epochMilliseconds) - const hash = {} + const hash = {} as Record for (const part of parts) { hash[part.type] = part.value @@ -33,8 +44,8 @@ export function hashIntlFormatParts(intlFormat, epochMilliseconds) { export const IntlDateTimeFormat = Intl.DateTimeFormat export class DateTimeFormat extends IntlDateTimeFormat { - format(arg) { - const [formattable, format] = resolveSingleFormattable(this, arg) + format(arg?: Formattable): string { + const [formattable, format] = resolveSingleFormattable(this as Intl.DateTimeFormat, arg) return format ? format.format(formattable) : super.format(formattable) @@ -42,8 +53,8 @@ export class DateTimeFormat extends IntlDateTimeFormat { // https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype.format } - formatToParts(arg) { - const [formattable, format] = resolveSingleFormattable(this, arg) + formatToParts(arg?: Formattable): Intl.DateTimeFormatPart[] { + const [formattable, format] = resolveSingleFormattable(this as Intl.DateTimeFormat, arg) return format ? format.formatToParts(formattable) : super.formatToParts(formattable) @@ -51,11 +62,14 @@ export class DateTimeFormat extends IntlDateTimeFormat { } ['formatRange', 'formatRangeToParts'].forEach((methodName) => { - const origMethod = IntlDateTimeFormat.prototype[methodName] + const origMethod = (IntlDateTimeFormat as any).prototype[methodName] if (origMethod) { - // TODO: not sufficient for defining method - DateTimeFormat.prototype[methodName] = function(arg0, arg1) { + // TODO: not sufficient for defining method. Use defineProperty! + (DateTimeFormat as any).prototype[methodName] = function( + arg0: Formattable, + arg1: Formattable, + ) { const [formattable0, formattable1, format] = resolveRangeFormattables(this, arg0, arg1) return origMethod.call(format, formattable0, formattable1) } @@ -65,21 +79,43 @@ export class DateTimeFormat extends IntlDateTimeFormat { // DateTimeFormat Helpers // ------------------------------------------------------------------------------------------------- -const getGetSpecificFormat = createLazyGenerator(() => createLazyGenerator(createSpecificFormat), WeakMap) +const getGetSpecificFormat = createLazyGenerator((dtf: Intl.DateTimeFormat) => { + return createLazyGenerator(createSpecificFormat) +}, WeakMap) -function createSpecificFormat(transformOptions, resolvedOptions) { +function createSpecificFormat( + transformOptions: OptionsTransformer, + resolvedOptions: Intl.ResolvedDateTimeFormatOptions, +): Intl.DateTimeFormat { return new IntlDateTimeFormat(resolvedOptions.locale, transformOptions(resolvedOptions)) } -function resolveSingleFormattable(format, arg) { +function resolveSingleFormattable( + format: Intl.DateTimeFormat, + arg: Formattable | undefined, +): [ + OrigFormattable | undefined, + Intl.DateTimeFormat | undefined +] { + if (arg === undefined) { + return [arg, format] + } + const getSpecificFormat = getGetSpecificFormat(format) const resolvedOptions = format.resolvedOptions() - // returned format might be undefined return resolveFormattable(arg, getSpecificFormat, resolvedOptions) } -function resolveRangeFormattables(format, arg0, arg1) { +function resolveRangeFormattables( + format: Intl.DateTimeFormat, + arg0: Formattable, + arg1: Formattable, +): [ + OrigFormattable, + OrigFormattable, + Intl.DateTimeFormat, +] { const getSpecificFormat = getGetSpecificFormat(format) const resolvedOptions = format.resolvedOptions() @@ -101,10 +137,13 @@ function resolveRangeFormattables(format, arg0, arg1) { // ------------------------------------------------------------------------------------------------- export function resolveZonedFormattable( - internals, // for ZonedDateTime - locales, - options, // NOT resolved yet (does not include locale) -) { + internals: ZonedInternals, + locales: string | string[], + options: Intl.DateTimeFormatOptions, // NOT resolved yet (does not include locale) +): [ + number, + Intl.DateTimeFormat, +] { options = { ...options } if (options.timeZone !== undefined) { @@ -114,7 +153,7 @@ export function resolveZonedFormattable( if ( options.timeZoneName === undefined && - !hasAnyPropsByName(options, dateTimeOptionNames) + !hasAnyPropsByName(options as Record, dateTimeOptionNames) ) { // The rest of the defaults will be filled in by formatting the Instant options.timeZoneName = 'short' @@ -133,16 +172,22 @@ export function resolveZonedFormattable( ] } +type OrigFormattable = number | Date +type Formattable = Instant | PlainDate | PlainDateTime | ZonedDateTime | PlainYearMonth | PlainMonthDay | OrigFormattable + function resolveFormattable( - arg, - getSpecificFormat, - resolvedOptions, -) { + arg: Formattable, + getSpecificFormat: (optionsTransformer: OptionsTransformer, resolvedOptions: Intl.ResolvedDateTimeFormatOptions) => Intl.DateTimeFormat, + resolvedOptions: Intl.ResolvedDateTimeFormatOptions, +): [ + OrigFormattable, + Intl.DateTimeFormat | undefined +] { const temporalName = getTemporalName(arg) - const transformOptions = optionTransformers[temporalName] + const transformOptions = temporalName && optionTransformers[temporalName] if (transformOptions) { - const internalsToEpochNano = epochNanoConverters[temporalName] || dateTimeInternalsToEpochNano + const internalsToEpochNano = epochNanoConverters[temporalName] || dateInternalsToEpochNano const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) return [ @@ -151,7 +196,8 @@ function resolveFormattable( ] } - return [arg] + return [arg as number] as + unknown as [number, undefined] } // Format Option Massagers @@ -195,7 +241,7 @@ const monthDayExclusions = [ ...timeOptionNames, ] -const optionTransformers = { +const optionTransformers: Record = { PlainTime: createTransformer(timeOptionNames, timeBasicNames, timeExclusions), PlainDateTime: createTransformer(dateTimeOptionNames, dateTimeBasicNames, dateTimeExclusions), PlainDate: createTransformer(dateOptionNames, dateBasicNames, dateExclusions), @@ -207,11 +253,18 @@ const optionTransformers = { }, } -function createTransformer(optionNames, basicNames, exclusionNames) { +// TODO: use Intl.DateTimeFormatOptions? +type OptionsTransformer = (options: any) => any + +function createTransformer( + optionNames: string[], + basicNames: string[], + exclusionNames: string[], +): OptionsTransformer { const defaults = mapPropNamesToConstant(basicNames, 'numeric') const exclusionNamesSet = new Set(exclusionNames) - return (options) => { + return (options: any) => { options = excludePropsByName(options, exclusionNamesSet) if (!hasAnyPropsByName(options, optionNames)) { @@ -225,46 +278,68 @@ function createTransformer(optionNames, basicNames, exclusionNames) { // Epoch Conversions // ------------------------------------------------------------------------------------------------- -const epochNanoConverters = { +type EpochNanoConverter = ( + internals: any, + resolvedOptions: Intl.ResolvedDateTimeFormatOptions, + temporalName: string, +) => LargeInt + +const epochNanoConverters: Record = { Instant: identityFunc, - PlainTime: timeInternalsToEpochNano, - // otherwise, use dateTimeInternalsToEpochNano + PlainTime: timeFieldsToEpochNano, + // otherwise, use dateInternalsToEpochNano } -function timeInternalsToEpochNano(internals, resolvedOptions) { - return getSingleInstantFor({ - isoYear: isoEpochOriginYear, - isoMonth: 1, - isoDay: 1, - ...internals, - timeZone: queryTimeZoneOps(resolvedOptions.timeZone), - }) +function timeFieldsToEpochNano( + internals: IsoTimeFields, + resolvedOptions: Intl.ResolvedDateTimeFormatOptions, +): LargeInt { + return getSingleInstantFor( + queryTimeZoneOps(resolvedOptions.timeZone), + { + isoYear: isoEpochOriginYear, + isoMonth: 1, + isoDay: 1, + ...internals, + }, + ) } -function dateTimeInternalsToEpochNano(internals, resolvedOptions, temporalName) { +function dateInternalsToEpochNano( + internals: IsoDateTimeInternals | IsoDateInternals, + resolvedOptions: Intl.ResolvedDateTimeFormatOptions, + temporalName: string, +): LargeInt { checkCalendarsCompatible( internals.calendar.id, resolvedOptions.calendar, strictCalendarCheck[temporalName], ) - return getSingleInstantFor({ - ...timeFieldDefaults, - isoHour: 12, // will not dst-shift into prev/next day - ...internals, - timeZone: queryTimeZoneOps(resolvedOptions.timeZone), - }) + return getSingleInstantFor( + queryTimeZoneOps(resolvedOptions.timeZone), + { + ...isoTimeFieldDefaults, + isoHour: 12, // for whole-day dates, will not dst-shift into prev/next day + ...internals, + }, + ) } // Calendar Check // ------------------------------------------------------------------------------------------------- -const strictCalendarCheck = { +// TODO: simply check for absense of 'Date' in name? +const strictCalendarCheck: Record = { PlainYearMonth: true, PlainMonthDay: true, } -function checkCalendarsCompatible(calendarId, resolveCalendarId, strict) { +function checkCalendarsCompatible( + calendarId: string, + resolveCalendarId: string, + strict?: boolean, +): void { if (!( calendarId === resolveCalendarId || (!strict && ( From 8873270437ee4fddb699bf752c30bcaee518d1e1 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 16:55:14 -0400 Subject: [PATCH 167/805] options tuples --- packages/temporal-polyfill/src/new/instant.ts | 6 +- .../temporal-polyfill/src/new/isoFormat.ts | 2 +- packages/temporal-polyfill/src/new/options.ts | 91 +++++++++++++------ 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/packages/temporal-polyfill/src/new/instant.ts b/packages/temporal-polyfill/src/new/instant.ts index e5b0fe8e..ca5320f5 100644 --- a/packages/temporal-polyfill/src/new/instant.ts +++ b/packages/temporal-polyfill/src/new/instant.ts @@ -147,7 +147,11 @@ export const [ formatOffsetNano(offsetNano) }, - toLocaleString(epochNano: LargeInt, locales: string | string[], options): string { + toLocaleString( + epochNano: LargeInt, + locales: string | string[], + options: any, + ): string { // TODO return '' }, diff --git a/packages/temporal-polyfill/src/new/isoFormat.ts b/packages/temporal-polyfill/src/new/isoFormat.ts index f397a80b..da86a996 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.ts +++ b/packages/temporal-polyfill/src/new/isoFormat.ts @@ -40,7 +40,7 @@ Rounding already happened with these... export function formatIsoDateTimeFields( isoDateTimeFields: IsoDateTimeFields, - subsecDigits: SubsecDigits, + subsecDigits: SubsecDigits | -1 | undefined, ) { return formatIsoDateFields(isoDateTimeFields) + 'T' + formatIsoTimeFields(isoDateTimeFields, subsecDigits) diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 8c6e0cd2..1707ab39 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -1,7 +1,7 @@ import { getInternals } from './class' import { refineMaybeZonedDateTimeBag } from './convert' import { DurationFields, durationFieldIndexes } from './durationFields' -import { pluckIsoDateInternals } from './isoFields' +import { IsoDateInternals, pluckIsoDateInternals } from './isoFields' import { parseMaybeZonedDateTime } from './isoParse' import { LargeInt, bigIntToLargeInt } from './largeInt' import { PlainDate } from './plainDate' @@ -18,18 +18,25 @@ import { roundHalfFloor, roundHalfTrunc, } from './utils' -import { ZonedDateTime } from './zonedDateTime' +import { ZonedDateTime, ZonedInternals } from './zonedDateTime' type Options = Record // Compound Options // ------------------------------------------------------------------------------------------------- +// TODO: always good to spread options tuples? better to nest? export function refineOverflowOptions(options: Options | undefined): Overflow { return refineOverflow(normalizeOptions(options)) } -export function refineZonedFieldOptions(options: Options | undefined) { +export type ZonedFieldTuple = [ + Overflow, + EpochDisambig, + OffsetDisambig, +] + +export function refineZonedFieldOptions(options: Options | undefined): ZonedFieldTuple { options = normalizeOptions(options) return [ refineOverflow(options), @@ -42,13 +49,20 @@ export function refineEpochDisambigOptions(options: Options | undefined): EpochD return refineEpochDisambig(normalizeOptions(options)) } +export type DiffTuple = [ + Unit, // largestUnit + Unit, // smallestUnit + number, + RoundingMode +] + export function refineDiffOptions( roundingModeInvert: boolean | undefined, options: Options | undefined, defaultLargestUnit: Unit, maxUnit = Unit.Year, minUnit = Unit.Nanosecond, -) { +): DiffTuple { options = normalizeOptions(options) const smallestUnit = refineSmallestUnit(options, maxUnit, minUnit, minUnit) const largestUnit = refineLargestUnit( @@ -75,13 +89,19 @@ export function refineCalendarDiffOptions( return refineLargestUnit(options, Unit.Year, Unit.Day, Unit.Day) } +export type RoundTuple = [ + Unit, // smallestUnit + number, + RoundingMode, +] + /* Always related to time */ export function refineRoundOptions( options: Options | undefined, maxUnit: DayTimeUnit = Unit.Day, -) { +): RoundTuple { options = normalizeUnitNameOptions(options, smallestUnitStr) const smallestUnit = refineSmallestUnit(options, maxUnit) as DayTimeUnit return [ @@ -91,10 +111,15 @@ export function refineRoundOptions( ] } +export type DurationRoundTuple = [ + ...DiffTuple, + RelativeToInternals | undefined, +] + export function refineDurationRoundOptions( options: Options | undefined, defaultLargestUnit: Unit -) { +): DurationRoundTuple { options = normalizeUnitNameOptions(options, smallestUnitStr) mustHaveMatch(options, [largestUnitStr, smallestUnitStr]) // will register unwanted read? // ^do a whitelist filter that copies instead? @@ -107,7 +132,10 @@ export function refineDurationRoundOptions( export function refineTotalOptions( options: Options | undefined -) { +): [ + Unit, + RelativeToInternals | undefined, +] { options = normalizeUnitNameOptions(options, totalUnitStr) return [ refineTotalUnit(options), // required @@ -115,13 +143,16 @@ export function refineTotalOptions( ] } -export function refineRelativeToOptions(options: Options | undefined) { +export function refineRelativeToOptions(options: Options | undefined): RelativeToInternals | undefined { return refineRelativeTo(normalizeOptions(options)) } -export function refineInstantDisplayOptions( - options: Options | undefined -) { +export type InstantDisplayTuple = [ + string, // TimeZoneArg + ...TimeDisplayTuple, +] + +export function refineInstantDisplayOptions(options: Options | undefined): InstantDisplayTuple { options = normalizeOptions(options) return [ options.timeZone, @@ -129,7 +160,14 @@ export function refineInstantDisplayOptions( ] } -export function refineZonedDateTimeDisplayOptions(options: Options | undefined) { +export type ZonedDateTimeDisplayTuple = [ + CalendarDisplay, + TimeZoneDisplay, + OffsetDisplay, + ...TimeDisplayTuple, +] + +export function refineZonedDateTimeDisplayOptions(options: Options | undefined): ZonedDateTimeDisplayTuple { options = normalizeOptions(options) return [ refineCalendarDisplay(options), @@ -139,7 +177,12 @@ export function refineZonedDateTimeDisplayOptions(options: Options | undefined) ] } -export function refineDateTimeDisplayOptions(options: Options | undefined) { +export type DateTimeDisplayTuple = [ + CalendarDisplay, + ...TimeDisplayTuple, +] + +export function refineDateTimeDisplayOptions(options: Options | undefined): DateTimeDisplayTuple { options = normalizeOptions(options) return [ refineCalendarDisplay(options), @@ -151,6 +194,12 @@ export function refineDateDisplayOptions(options: Options | undefined): Calendar return refineCalendarDisplay(normalizeOptions(options)) } +export type TimeDisplayTuple = [ + nanoInc: number, + roundingMode: RoundingMode, + subsecDigits: SubsecDigits | -1 | undefined +] + export function refineTimeDisplayOptions( options: Options | undefined, maxSmallestUnit?: TimeUnit @@ -165,12 +214,6 @@ addons: */ export type SubsecDigits = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 -export type TimeDisplayTuple = [ - nanoInc: number, - roundingMode: RoundingMode, - subsecDigits: SubsecDigits | -1 | undefined -] - function refineTimeDisplayTuple( options: Options, maxSmallestUnit: TimeUnit = Unit.Minute @@ -194,12 +237,6 @@ function refineTimeDisplayTuple( ] } -// Single Options -// ------------------------------------------------------------------------------------------------- - -const smallestUnitStr = 'smallestUnit' -const largestUnitStr = 'largestUnit' -const totalUnitStr = 'unit' const refineSmallestUnit = refineUnitOption.bind(undefined, smallestUnitStr) const refineLargestUnit = refineUnitOption.bind(undefined, largestUnitStr) @@ -359,7 +396,9 @@ function refineSubsecDigits(options: Options): SubsecDigits | undefined { // undefind means 'auto' } -function refineRelativeTo(options: Options) { +type RelativeToInternals = ZonedInternals | IsoDateInternals + +function refineRelativeTo(options: Options): RelativeToInternals | undefined { const { relativeTo } = options if (relativeTo) { From a3402572596c3fd543ee8a0e561a7300fbd792c7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 17:07:31 -0400 Subject: [PATCH 168/805] move ts --- .../temporal-polyfill/src/new/calendarImpl.ts | 1 + .../src/new/durationFields.ts | 3 + .../src/new/{move.js => move.ts} | 99 ++++++++++++------- 3 files changed, 70 insertions(+), 33 deletions(-) rename packages/temporal-polyfill/src/new/{move.js => move.ts} (60%) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.ts b/packages/temporal-polyfill/src/new/calendarImpl.ts index 7e4517e9..e1b16374 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.ts +++ b/packages/temporal-polyfill/src/new/calendarImpl.ts @@ -310,6 +310,7 @@ const weekMethods: WeekMethods = { // Base Calendar Implementation :: Misc Methods // ------------------------------------------------------------------------------------------------- +// TODO: what about 'query' -> 'compute' ? interface MiscMethods { addMonths(year: number, month: number, monthDelta: number): [number, number] diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts index b06b0c80..df950543 100644 --- a/packages/temporal-polyfill/src/new/durationFields.ts +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -102,6 +102,9 @@ export const durationTimeFieldsToIso = remapProps.bind< IsoTimeFields // return >(undefined, durationTimeFieldNames, isoTimeFieldNames) +/* +TODO: have method directly return nanoseconds. the only use! +*/ export function durationTimeFieldsToIsoStrict(fields: DurationFields): IsoTimeFields { if (durationHasDateParts(fields)) { throw new RangeError('Operation not allowed') // correct error? diff --git a/packages/temporal-polyfill/src/new/move.js b/packages/temporal-polyfill/src/new/move.ts similarity index 60% rename from packages/temporal-polyfill/src/new/move.js rename to packages/temporal-polyfill/src/new/move.ts index 85285da5..054576c0 100644 --- a/packages/temporal-polyfill/src/new/move.js +++ b/packages/temporal-polyfill/src/new/move.ts @@ -1,10 +1,15 @@ +import { CalendarImpl } from './calendarImpl' +import { CalendarOps } from './calendarOps' import { + DurationFields, durationFieldsToNano, durationHasDateParts, durationTimeFieldDefaults, durationTimeFieldsToIso, durationTimeFieldsToIsoStrict, + updateDurationFieldsSign, } from './durationFields' +import { IsoDateFields, IsoDateTimeFields, IsoTimeFields } from './isoFields' import { epochMilliToIso, isoDaysInWeek, @@ -13,20 +18,22 @@ import { isoToEpochMilli, nanoToIsoTimeAndDay, } from './isoMath' -import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' -import { hourIndex, milliInDay, nanoInUtcDay } from './units' +import { LargeInt } from './largeInt' +import { Overflow } from './options' +import { TimeZoneOps, getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' +import { Unit, milliInDay, nanoInUtcDay } from './units' import { clamp } from './utils' // Epoch // ------------------------------------------------------------------------------------------------- export function moveZonedEpochNano( - calendar, - timeZone, - epochNano, - durationFields, - overflowHandling, -) { + calendar: CalendarOps, + timeZone: TimeZoneOps, + epochNano: LargeInt, + durationFields: DurationFields, + overflowHandling: Overflow, +): LargeInt { const durationTimeNano = isoTimeFieldsToNano(durationTimeFieldsToIso(durationFields)) if (!durationHasDateParts(durationFields)) { @@ -35,10 +42,10 @@ export function moveZonedEpochNano( const isoDateTimeFields = zonedEpochNanoToIso(timeZone, epochNano) const movedIsoDateFields = calendar.dateAdd( isoDateTimeFields, - { + updateDurationFieldsSign({ // does CalendarOps really need sign? ...durationFields, // date parts ...durationTimeFieldDefaults, // time parts - }, + }), overflowHandling, ) const movedIsoDateTimeFields = { @@ -52,28 +59,32 @@ export function moveZonedEpochNano( return epochNano } -export function moveEpochNano(epochNanoseconds, durationFields) { - return epochNanoseconds.addNumber(durationTimeFieldsToIsoStrict(durationFields)) +export function moveEpochNano(epochNano: LargeInt, durationFields: DurationFields): LargeInt { + return epochNano.addNumber( + isoTimeFieldsToNano( + durationTimeFieldsToIsoStrict(durationFields) + ) + ) } // Date & Time // ------------------------------------------------------------------------------------------------- export function moveDateTime( - calendar, - isoDateTimeFields, - durationFields, - overflowHandling, -) { + calendar: CalendarOps, + isoDateTimeFields: IsoDateTimeFields, + durationFields: DurationFields, + overflowHandling: Overflow, +): IsoDateTimeFields { const [movedIsoTimeFields, dayDelta] = moveTime(isoDateTimeFields, durationFields) const movedIsoDateFields = calendar.dateAdd( isoDateTimeFields, // only date parts will be used - { + updateDurationFieldsSign({ // does CalendarOps really need sign? ...durationFields, // date parts ...durationTimeFieldDefaults, // time parts (zero-out so no balancing-up to days) days: durationFields.days + dayDelta, - }, + }), overflowHandling, ) @@ -83,12 +94,17 @@ export function moveDateTime( } } -export function moveDate(calendar, isoDateFields, durationFields, overflowI) { +export function moveDate( + calendar: CalendarImpl, + isoDateFields: IsoDateFields, + durationFields: DurationFields, + overflowHandling: Overflow, +) { let { years, months, weeks, days } = durationFields - let epochMilli + let epochMilli: number | undefined // convert time fields to days - days += durationFieldsToNano(durationFields, hourIndex) + days += durationFieldsToNano(durationFields, Unit.Hour) .divTruncMod(nanoInUtcDay)[0].toNumber() if (years || months) { @@ -96,12 +112,12 @@ export function moveDate(calendar, isoDateFields, durationFields, overflowI) { if (years) { year += years - month = clamp(month, 1, calendar.queryMonthsInYear(year), overflowI, 'month') + month = clamp(month, 1, calendar.computeMonthsInYear(year), overflowHandling, 'month') } if (months) { ([year, month] = calendar.addMonths(year, month, months)) - day = clamp(day, 1, calendar.queryDaysInMonth(year, month), overflowI, 'day') + day = clamp(day, 1, calendar.queryDaysInMonth(year, month), overflowHandling, 'day') } epochMilli = calendar.queryDateStart(year, month, day) @@ -111,22 +127,28 @@ export function moveDate(calendar, isoDateFields, durationFields, overflowI) { return isoDateFields } - epochMilli += (weeks * isoDaysInWeek + days) * milliInDay + epochMilli! += (weeks * isoDaysInWeek + days) * milliInDay return { calendar, - ...epochMilliToIso(epochMilli), + ...epochMilliToIso(epochMilli!), } } -export function moveDateByDays(isoDateFields, days) { // moveDateDays +export function moveDateByDays( // TODO: rename moveDateDays? + isoDateFields: IsoDateFields, + days: number, +): IsoDateFields { if (days) { - isoDateFields = epochMilliToIso(isoToEpochMilli(isoDateFields) + days * milliInDay) + isoDateFields = epochMilliToIso(isoToEpochMilli(isoDateFields)! + days * milliInDay) } return isoDateFields } -export function moveTime(isoTimeFields, durationFields) { +export function moveTime( + isoTimeFields: IsoTimeFields, + durationFields: DurationFields, +): [IsoTimeFields, number] { return nanoToIsoTimeAndDay( isoTimeFieldsToNano(isoTimeFields) + isoTimeFieldsToNano(durationTimeFieldsToIsoStrict(durationFields)), @@ -136,7 +158,10 @@ export function moveTime(isoTimeFields, durationFields) { // Calendar-related Utils // ------------------------------------------------------------------------------------------------- -export function moveByIsoMonths(year, month, monthDelta) { +export function moveByIsoMonths(year: number, month: number, monthDelta: number): [ + year: number, + month: number, +] { year += Math.trunc(monthDelta / isoMonthsInYear) month += monthDelta % isoMonthsInYear @@ -151,7 +176,15 @@ export function moveByIsoMonths(year, month, monthDelta) { return [year, month] } -export function moveByIntlMonths(year, month, monthDelta, calendarImpl) { +export function moveByIntlMonths( + year: number, + month: number, + monthDelta: number, + calendarImpl: CalendarImpl +): [ + year: number, + month: number, +] { month += monthDelta if (monthDelta < 0) { @@ -159,14 +192,14 @@ export function moveByIntlMonths(year, month, monthDelta, calendarImpl) { throw new RangeError('Months out of range') } while (month < 1) { - month += calendarImpl.monthsInYear(--year) + month += calendarImpl.computeMonthsInYear(--year) } } else { if (month > Number.MAX_SAFE_INTEGER) { throw new RangeError('Months out of range') } let monthsInYear - while (month > (monthsInYear = calendarImpl.monthsInYear(year))) { + while (month > (monthsInYear = calendarImpl.computeMonthsInYear(year))) { month -= monthsInYear year++ } From 8d765db93aed17a1e191952dcbbd31ddf69a2f2b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 17:33:37 -0400 Subject: [PATCH 169/805] diff ts --- .../src/new/{diff.js => diff.ts} | 233 ++++++++++-------- .../src/new/durationFields.ts | 7 +- packages/temporal-polyfill/src/new/options.ts | 2 +- packages/temporal-polyfill/src/new/units.ts | 2 +- 4 files changed, 137 insertions(+), 107 deletions(-) rename packages/temporal-polyfill/src/new/{diff.js => diff.ts} (61%) diff --git a/packages/temporal-polyfill/src/new/diff.js b/packages/temporal-polyfill/src/new/diff.ts similarity index 61% rename from packages/temporal-polyfill/src/new/diff.js rename to packages/temporal-polyfill/src/new/diff.ts index 610db164..186587d9 100644 --- a/packages/temporal-polyfill/src/new/diff.js +++ b/packages/temporal-polyfill/src/new/diff.ts @@ -1,9 +1,14 @@ +import { TimeZoneImpl } from '../timeZoneImpl/timeZoneImpl' +import { CalendarImpl } from './calendarImpl' +import { CalendarOps } from './calendarOps' import { + DurationFields, + DurationInternals, durationFieldDefaults, nanoToDurationFields, timeNanoToDurationFields, } from './durationFields' -import { pluckIsoTimeFields } from './isoFields' +import { IsoDateFields, IsoDateTimeFields, IsoTimeFields, pluckIsoTimeFields } from './isoFields' import { isoDaysInWeek, isoMonthsInYear, @@ -11,40 +16,42 @@ import { isoToEpochMilli, isoToEpochNano, } from './isoMath' -import { compareLargeInts } from './largeInt' +import { LargeInt, compareLargeInts } from './largeInt' import { moveDateByDays, moveDateTime, moveZonedEpochNano } from './move' +import { RoundingMode } from './options' import { computeNanoInc, roundByInc, roundByIncLarge, roundRelativeDuration } from './round' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { - dayIndex, milliInDay, - monthIndex, + DayTimeUnit, + TimeUnit, + Unit, + milliInDay, nanoInUtcDay, - weekIndex, } from './units' -import { identityFunc } from './utils' +import { NumSign, identityFunc } from './utils' // Dates & Times // ------------------------------------------------------------------------------------------------- export function diffDateTimes( - calendar, // calendarOps - startIsoFields, - endIsoFields, - largestUnitIndex, - smallestUnitIndex, // TODO: nanoDivisor - roundingIncrement, - roundingMode, -) { - const startEpochNano = isoToEpochNano(startIsoFields) - const endEpochNano = isoToEpochNano(endIsoFields) - - if (largestUnitIndex < dayIndex) { + calendar: CalendarOps, // calendarOps + startIsoFields: IsoDateTimeFields, + endIsoFields: IsoDateTimeFields, + largestUnit: Unit, + smallestUnit: Unit, + roundingInc: number, + roundingMode: RoundingMode, +): DurationFields { + const startEpochNano = isoToEpochNano(startIsoFields)! + const endEpochNano = isoToEpochNano(endIsoFields)! + + if (largestUnit < Unit.Day) { return diffEpochNano( startEpochNano, endEpochNano, - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + largestUnit as TimeUnit, + smallestUnit as TimeUnit, + roundingInc, roundingMode, ) } @@ -65,15 +72,15 @@ export function diffDateTimes( timeNano += nanoInUtcDay } - const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnitIndex) + const dateDiff = calendar.dateUntil(midIsoFields, endIsoFields, largestUnit) const timeDiff = timeNanoToDurationFields(timeNano) return roundRelativeDuration( { ...dateDiff, ...timeDiff, sign }, endEpochNano, - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + largestUnit, + smallestUnit, + roundingInc, roundingMode, startIsoFields, // marker isoToEpochNano, // markerToEpochNano @@ -82,33 +89,33 @@ export function diffDateTimes( } export function diffDates( - calendar, - startIsoFields, - endIsoFields, - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, - roundingMode, -) { - if (largestUnitIndex < dayIndex) { + calendar: CalendarImpl, + startIsoFields: IsoDateFields, + endIsoFields: IsoDateFields, + largestUnit: Unit, + smallestUnit: Unit, + roundingInc: number, + roundingMode: RoundingMode, +): DurationFields { + if (largestUnit < Unit.Day) { return diffEpochNano( - isoToEpochNano(startIsoFields), - isoToEpochNano(endIsoFields), - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + isoToEpochNano(startIsoFields)!, + isoToEpochNano(endIsoFields)!, + largestUnit as TimeUnit, + smallestUnit as TimeUnit, + roundingInc, roundingMode, ) } - const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnitIndex) + const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnit) return roundRelativeDuration( dateDiff, isoToEpochNano(endIsoFields), - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + largestUnit, + smallestUnit, + roundingInc, roundingMode, startIsoFields, // marker isoToEpochNano, // markerToEpochNano @@ -117,20 +124,20 @@ export function diffDates( } export function diffDatesExact( - calendar, - startIsoFields, - endIsoFields, - largestUnitIndex, -) { - if (largestUnitIndex <= weekIndex) { + calendar: CalendarImpl, + startIsoFields: IsoDateFields, + endIsoFields: IsoDateFields, + largestUnit: Unit, +): DurationInternals { + if (largestUnit <= Unit.Week) { let weeks = 0 let days = diffEpochMilliByDay( - isoToEpochMilli(startIsoFields), - isoToEpochMilli(endIsoFields), + isoToEpochMilli(startIsoFields)!, + isoToEpochMilli(endIsoFields)!, ) - const sign = Math.sign(days) + const sign = Math.sign(days) as NumSign - if (largestUnitIndex === weekIndex) { + if (largestUnit === Unit.Week) { weeks = Math.trunc(days / isoDaysInWeek) days %= isoDaysInWeek } @@ -146,7 +153,7 @@ export function diffDatesExact( ...yearMonthDayEnd, ) - if (largestUnitIndex === monthIndex) { + if (largestUnit === Unit.Month) { months += calendar.queryMonthsInYearSpan(years, yearMonthDayStart[0]) years = 0 } @@ -155,21 +162,21 @@ export function diffDatesExact( } export function diffTimes( - startIsoFields, - endIsoFields, - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, - roundingMode, -) { + startIsoFields: IsoTimeFields, + endIsoFields: IsoTimeFields, + largestUnit: TimeUnit, + smallestUnit: TimeUnit, + roundingInc: number, + roundingMode: RoundingMode, +): DurationFields { const startTimeNano = isoTimeFieldsToNano(startIsoFields) const endTimeNano = isoTimeFieldsToNano(endIsoFields) - const nanoInc = computeNanoInc(smallestUnitIndex, roundingIncrement) + const nanoInc = computeNanoInc(smallestUnit, roundingInc) const timeNano = roundByInc(endTimeNano - startTimeNano, nanoInc, roundingMode) return { ...durationFieldDefaults, - ...nanoToDurationFields(timeNano, largestUnitIndex), + ...timeNanoToDurationFields(timeNano, largestUnit), } } @@ -177,22 +184,22 @@ export function diffTimes( // ------------------------------------------------------------------------------------------------- export function diffZonedEpochNano( - calendar, - timeZone, - startEpochNano, - endEpochNano, - largestUnitIndex, - smallestUnitIndex, // optional. internally will default to 'nanoseconds' - roundingIncrement, // optional. internally will default to 1 - roundingMode, // optional. internally will default to 'halfExpand' -) { - if (largestUnitIndex < dayIndex) { + calendar: CalendarImpl, + timeZone: TimeZoneImpl, + startEpochNano: LargeInt, + endEpochNano: LargeInt, + largestUnit: Unit, + smallestUnit?: Unit, // internally will default to 'nanoseconds' + roundingInc?: number, // internally will default to 1 + roundingMode?: RoundingMode, // internally will default to 'halfExpand' +): DurationFields { + if (largestUnit < Unit.Day) { return diffEpochNano( startEpochNano, endEpochNano, - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + largestUnit as TimeUnit, + smallestUnit as TimeUnit, + roundingInc, roundingMode, ) } @@ -214,16 +221,16 @@ export function diffZonedEpochNano( midEpochNano = isoToZonedEpochNano(midIsoFields) } - const dateDiff = calendar.dateUntil(startIsoFields, midIsoFields, largestUnitIndex) + const dateDiff = calendar.dateUntil(startIsoFields, midIsoFields, largestUnit) const timeDiffNano = endEpochNano.addLargeInt(midEpochNano, -1).toNumber() const timeDiff = timeNanoToDurationFields(timeDiffNano) return roundRelativeDuration( { ...dateDiff, ...timeDiff, sign }, endEpochNano, - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, + largestUnit, + smallestUnit, + roundingInc, roundingMode, startEpochNano, // marker identityFunc, // markerToEpochNano @@ -232,22 +239,22 @@ export function diffZonedEpochNano( } export function diffEpochNano( - startEpochNano, - endEpochNano, - largestUnitIndex, - smallestUnitIndex, - roundingIncrement, - roundingMode, -) { + startEpochNano: LargeInt, + endEpochNano: LargeInt, + largestUnit: DayTimeUnit, + smallestUnit: DayTimeUnit, + roundingInc: number, + roundingMode: RoundingMode, +): DurationFields { return { ...durationFieldDefaults, ...nanoToDurationFields( roundByIncLarge( endEpochNano.addLargeInt(startEpochNano, -1), - computeNanoInc(smallestUnitIndex, roundingIncrement), + computeNanoInc(smallestUnit, roundingInc), roundingMode, ), - largestUnitIndex, + largestUnit, ), } } @@ -255,35 +262,51 @@ export function diffEpochNano( /* Must always be given start-of-day */ -export function diffEpochMilliByDay(epochMilli0, epochMilli1) { // diffEpochMilliDays +export function diffEpochMilliByDay( // TODO: rename diffEpochMilliDays? + epochMilli0: number, + epochMilli1: number, +): number { return Math.round((epochMilli1 - epochMilli0) / milliInDay) } // Calendar Utils // ------------------------------------------------------------------------------------------------- -function diffYearMonthDay(calendarImpl, year0, month0, day0, year1, month1, day1) { - let yearDiff - let monthsInYear1 - let monthDiff - let daysInMonth1 - let dayDiff +function diffYearMonthDay( + calendarImpl: CalendarImpl, + year0: number, + month0: number, + day0: number, + year1: number, + month1: number, + day1: number, +): [ + yearDiff: number, + monthDiff: number, + dayDiff: number, + sign: NumSign, +] { + let yearDiff!: number + let monthsInYear1!: number + let monthDiff!: number + let daysInMonth1!: number + let dayDiff!: number function updateYearMonth() { yearDiff = year1 - year0 - monthsInYear1 = calendarImpl.monthsInYear(year1) + monthsInYear1 = calendarImpl.computeMonthsInYear(year1) monthDiff = month1 - Math.min(month0, monthsInYear1) } function updateYearMonthDay() { updateYearMonth() - daysInMonth1 = calendarImpl.daysInMonth(year1, month1) + daysInMonth1 = calendarImpl.queryDaysInMonth(year1, month1) dayDiff = day1 - Math.min(day0, daysInMonth1) } updateYearMonthDay() - const daySign = Math.sign(dayDiff) - const sign = Math.sign(yearDiff) || Math.sign(monthDiff) || daySign + const daySign = Math.sign(dayDiff) as NumSign + const sign = (Math.sign(yearDiff) || Math.sign(monthDiff) || daySign) as NumSign if (sign) { // overshooting day? correct by moving to penultimate month @@ -311,18 +334,22 @@ function diffYearMonthDay(calendarImpl, year0, month0, day0, year1, month1, day1 return [yearDiff, monthDiff, dayDiff, sign] } -export function computeIsoMonthsInYearSpan(yearDelta) { +export function computeIsoMonthsInYearSpan(yearDelta: number): number { return yearDelta * isoMonthsInYear } -export function computeIntlMonthsInYearSpan(yearDelta, yearStart, calendarImpl) { +export function computeIntlMonthsInYearSpan( + yearDelta: number, + yearStart: number, + calendarImpl: CalendarImpl, +): number { const yearEnd = yearStart + yearDelta const yearSign = Math.sign(yearDelta) const yearCorrection = yearSign < 0 ? -1 : 0 let months = 0 for (let year = 0; year !== yearEnd; year += yearSign) { - months += calendarImpl.queryMonthsInYear(year + yearCorrection) + months += calendarImpl.computeMonthsInYear(year + yearCorrection) } return months diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/new/durationFields.ts index df950543..573d4a3e 100644 --- a/packages/temporal-polyfill/src/new/durationFields.ts +++ b/packages/temporal-polyfill/src/new/durationFields.ts @@ -142,10 +142,13 @@ export function nanoToDurationFields( } } -export function timeNanoToDurationFields(nano: number): DurationFields { +export function timeNanoToDurationFields( + nano: number, + largestUnit: TimeUnit = Unit.Hour, +): DurationFields { return nanoToGivenFields( nano, - Unit.Hour, + largestUnit, durationFieldNamesAsc, ) } diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index 1707ab39..e2ba6838 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -52,7 +52,7 @@ export function refineEpochDisambigOptions(options: Options | undefined): EpochD export type DiffTuple = [ Unit, // largestUnit Unit, // smallestUnit - number, + number, // roundingInc RoundingMode ] diff --git a/packages/temporal-polyfill/src/new/units.ts b/packages/temporal-polyfill/src/new/units.ts index 6cf4e307..8e6c0512 100644 --- a/packages/temporal-polyfill/src/new/units.ts +++ b/packages/temporal-polyfill/src/new/units.ts @@ -108,7 +108,7 @@ export function givenFieldsToNano( export function nanoToGivenFields( nano: number, - unit: DayTimeUnit, + unit: DayTimeUnit, // largestUnit fieldNames: (keyof F)[], ): { [Key in keyof F]?: number } { const fields = {} as { [Key in keyof F]: number } From 34a077c2038c3a931c5b6d3f1640fc88166bb9a0 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 18:21:15 -0400 Subject: [PATCH 170/805] round ts --- .../temporal-polyfill/src/new/duration.ts | 43 +- packages/temporal-polyfill/src/new/round.js | 433 --------------- packages/temporal-polyfill/src/new/round.ts | 516 ++++++++++++++++++ 3 files changed, 519 insertions(+), 473 deletions(-) delete mode 100644 packages/temporal-polyfill/src/new/round.js create mode 100644 packages/temporal-polyfill/src/new/round.ts diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/new/duration.ts index 6b5a0a1c..e2a4a7c4 100644 --- a/packages/temporal-polyfill/src/new/duration.ts +++ b/packages/temporal-polyfill/src/new/duration.ts @@ -1,6 +1,5 @@ import { TemporalInstance, createTemporalClass, neverValueOf } from './class' import { mergeDurationBag, refineDurationBag } from './convert' -import { diffZonedEpochNano } from './diff' import { absDurationInternals, addDurationFields, @@ -15,10 +14,8 @@ import { updateDurationFieldsSign, } from './durationFields' import { formatDurationInternals } from './isoFormat' -import { isoToEpochNano } from './isoMath' import { parseDuration } from './isoParse' -import { LargeInt, compareLargeInts } from './largeInt' -import { moveZonedEpochNano } from './move' +import { compareLargeInts } from './largeInt' import { SubsecDigits, refineDurationRoundOptions, @@ -33,10 +30,9 @@ import { totalDayTimeDuration, totalRelativeDuration, } from './round' -import { NumSign, identityFunc, noop } from './utils' +import { NumSign, noop } from './utils' import { DayTimeUnit, Unit } from './units' -import { ZonedInternals } from './zonedDateTime' -import { IsoDateFields, IsoDateInternals } from './isoFields' +import { Marker, MarkerToEpochNano, MoveMarker, DiffMarkers, createMarkerSystem } from './round' export type DurationArg = Duration | DurationBag | string export type DurationBag = Partial @@ -252,39 +248,6 @@ function addToDuration( return createDuration(spanDuration(internals, largestUnit, ...markerSystem)[0]) } -type Marker = LargeInt | IsoDateFields -type MarkerToEpochNano = (marker: Marker) => LargeInt -type MoveMarker = (marker: Marker, durationInternals: DurationInternals) => Marker -type DiffMarkers = (marker0: Marker, marker1: Marker, largeUnit: Unit) => DurationInternals -type MarkerSystem = [ - Marker, - MarkerToEpochNano, - MoveMarker, - DiffMarkers, -] - -function createMarkerSystem( - markerInternals: ZonedInternals | IsoDateInternals -): MarkerSystem { - const { calendar, timeZone, epochNanoseconds } = markerInternals as ZonedInternals - - if (epochNanoseconds) { - return [ - epochNanoseconds, // marker - identityFunc, // markerToEpochNano - moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker - diffZonedEpochNano.bind(undefined, calendar, timeZone), // diffMarkers - ] - } else { - return [ - markerInternals as IsoDateFields, // marker (IsoDateFields) - isoToEpochNano as (marker: Marker) => LargeInt, // markerToEpochNano - calendar.dateAdd.bind(calendar), // moveMarker - calendar.dateUntil.bind(calendar), // diffMarkers - ] - } -} - function spanDuration( durationFields: DurationFields, largestUnit: Unit, // TODO: more descrimination? diff --git a/packages/temporal-polyfill/src/new/round.js b/packages/temporal-polyfill/src/new/round.js deleted file mode 100644 index 3f43542b..00000000 --- a/packages/temporal-polyfill/src/new/round.js +++ /dev/null @@ -1,433 +0,0 @@ -import { - durationFieldDefaults, - durationFieldNamesAsc, - durationFieldsToNano, - durationFieldsToTimeNano, - durationTimeFieldDefaults, - nanoToDurationFields, - timeNanoToDurationFields, -} from './durationFields' -import { isoTimeFieldDefaults } from './isoFields' -import { isoTimeFieldsToNano, nanoToIsoTimeAndDay } from './isoMath' -import { moveDateByDays } from './move' -import { halfEvenI, roundingModeFuncs } from './options' -import { computeNanosecondsInDay } from './timeZoneOps' -import { - dayIndex, - nanoInMinute, - nanoInUtcDay, - nanoIndex, - unitNanoMap, - unitNamesAsc, - weekIndex, -} from './units' -import { identityFunc } from './utils' - -export function roundToMinute(offsetNano) { - return roundByInc(offsetNano, nanoInMinute, halfEvenI) -} - -// Rounding Dates -// ------------------------------------------------------------------------------------------------- - -export function roundDateTime( - isoFields, - smallestUnitI, // day/time - roundingInc, - roundingMode, - timeZoneOps = undefined, -) { - if (smallestUnitI === dayIndex) { - return roundDateTimeToDay(isoFields, timeZoneOps, roundingMode) - } - - return roundDateTimeToNano( - isoFields, - computeNanoInc(smallestUnitI, roundingInc), - roundingMode, - ) -} - -export function roundTime( - isoFields, - smallestUnitI, - roundingInc, - roundingMode, -) { - return roundTimeToNano( - isoFields, - computeNanoInc(smallestUnitI, roundingInc), - roundingMode, - ) -} - -function roundDateTimeToDay(isoFields, timeZoneOps, roundingMode) { - const nanoInDay = timeZoneOps - ? computeNanosecondsInDay(timeZoneOps, isoFields) - : nanoInUtcDay - - const dayDelta = roundByInc( - isoTimeFieldsToNano(isoFields), - nanoInDay, - roundingMode, - ) - - return { - ...moveDateByDays(isoFields, dayDelta), - ...isoTimeFieldDefaults, - } -} - -export function roundDateTimeToNano(isoFields, nanoInc, roundingMode) { - const [roundedIsoFields, dayDelta] = roundTimeToNano(isoFields, nanoInc, roundingMode) - return { - ...moveDateByDays(roundedIsoFields, dayDelta), - ...roundedIsoFields, - } -} - -export function roundTimeToNano(isoFields, nanoInc, roundingMode) { - return nanoToIsoTimeAndDay( - roundByInc(isoTimeFieldsToNano(isoFields), nanoInc, roundingMode), - ) -} - -// Rounding Duration -// ------------------------------------------------------------------------------------------------- - -export function roundDayTimeDuration( - durationFields, - smallestUnitI, - roundingInc, - roundingMode, -) { - return roundDurationToNano( - durationFields, - computeNanoInc(smallestUnitI, roundingInc), - roundingMode, - ) -} - -/* -Only does day-time rounding -*/ -export function roundDurationToNano(durationFields, nanoInc, roundingMode) { - const largeNano = durationFieldsToNano(durationFields) - const roundedLargeNano = roundByIncLarge(largeNano, nanoInc, roundingMode) - const dayTimeFields = nanoToDurationFields(roundedLargeNano) - - return { - ...durationFields, - ...dayTimeFields, - days: durationFields.days + dayTimeFields.days, - } -} - -export function roundRelativeDuration( - durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) - // ^has sign - endEpochNanoseconds, - largestUnitIndex, - smallestUnitI, - roundingInc, - roundingMode, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, -) { - if (smallestUnitI === nanoIndex && roundingInc === 1) { - return durationFields - } - - let [roundedDurationFields, roundedEpochNanoseconds, grew] = ( - smallestUnitI >= dayIndex - ? nudgeRelativeDuration - : markerToEpochMilliseconds === identityFunc // marker is ZonedDateTime's epochNanoseconds? - ? nudgeRelativeDurationTime - : nudgeDurationTime - )( - durationFields, - endEpochNanoseconds, - smallestUnitI, - roundingInc, - roundingMode, - // marker system only needed for nudgeRelativeDuration... - marker, - moveMarker, - markerToEpochMilliseconds, - ) - - // grew a day/week/month/year? - if (grew) { - roundedDurationFields = bubbleRelativeDuration( - roundedDurationFields, - roundedEpochNanoseconds, - largestUnitIndex, - smallestUnitI, - // marker system... - marker, - moveMarker, - markerToEpochMilliseconds, - ) - } - - return roundedDurationFields -} - -// Rounding Numbers -// ------------------------------------------------------------------------------------------------- - -export function computeNanoInc(smallestUnitI, roundingInc) { - return unitNanoMap[smallestUnitI] * roundingInc -} - -export function roundByInc(num, inc, roundingMode) { - return roundWithMode(num / inc, roundingMode) * inc -} - -export function roundByIncLarge(largeInt, inc, roundingMode) { - const [whole, remainder] = largeInt.divTruncMod(inc) - const mod2 = whole.mod2() // workaround for halfEven - - return whole.mult(inc).addNumber( - roundWithMode((remainder / inc) + mod2, roundingMode) - mod2, - ) -} - -function roundWithMode(num, roundingMode) { - return roundingModeFuncs[roundingMode](num) -} - -// Total Duration -// ------------------------------------------------------------------------------------------------- - -export function totalDayTimeDuration( // assumes iso-length days - durationFields, - totalUnitIndex, -) { - const largeNano = durationFieldsToNano(durationFields) - const divisor = unitNanoMap[totalUnitIndex] - const [fullUnits, remainder] = largeNano.divTruncMod(divisor) - return fullUnits.toNumber() + (remainder / divisor) -} - -export function totalRelativeDuration( - durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) - endEpochNanoseconds, - totalUnitIndex, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, -) { - const { sign } = durationFields - - const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( - clearDurationFields(durationFields, totalUnitIndex - 1), - totalUnitIndex, - sign, - // marker system... - marker, - moveMarker, - markerToEpochMilliseconds, - ) - - const portion = - endEpochNanoseconds.subtract(epochNanoseconds0).toNumber() / - epochNanoseconds1.subtract(epochNanoseconds0).toNumber() - - return durationFields[durationFieldNamesAsc[totalUnitIndex]] + portion -} - -// Nudge -// ------------------------------------------------------------------------------------------------- -/* -These functions actually do the heavy-lifting of rounding to a higher/lower marker, -and return the (day) delta. Also return the (potentially) unbalanced new duration. -*/ - -function nudgeDurationTime( - durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) - endEpochNanoseconds, // NOT NEEDED, just for adding result to - smallestUnitI, - roundingInc, - roundingMode, -) { - const timeNano = durationFieldsToTimeNano(durationFields) - const nanoInc = computeNanoInc(smallestUnitI, roundingInc) - const roundedTimeNano = roundByInc(timeNano, nanoInc, roundingMode) - const roundedFields = nanoToDurationFields(roundedTimeNano) - const dayDelta = roundedFields.days - const nudgedDurationFields = { // TODO: what about sign? - ...durationFields, - ...roundedFields, - days: durationFields.days + dayDelta, - } - - return [ - nudgedDurationFields, - endEpochNanoseconds.addNumber(roundedTimeNano - timeNano), - dayDelta, - ] -} - -function nudgeRelativeDurationTime( - durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) - endEpochNanoseconds, // NOT NEEDED, just for conformance - smallestUnitI, - roundingInc, - roundingMode, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, -) { - const { sign } = durationFields - const timeNano = durationFieldsToTimeNano(durationFields) - const nanoInc = computeNanoInc(smallestUnitI, roundingInc) - let roundedTimeNano = roundByInc(timeNano, nanoInc, roundingMode) - - const [dayEpochNanoseconds0, dayEpochNanoseconds1] = clampRelativeDuration( - { ...durationFields, ...durationTimeFieldDefaults }, - 'days', - sign, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, - ) - - const daySpanEpochNanoseconds = dayEpochNanoseconds1.subtract(dayEpochNanoseconds0).toNumber() - const beyondDay = roundedTimeNano - daySpanEpochNanoseconds - let dayDelta = 0 - - if (!beyondDay || Math.sign(beyondDay) === sign) { - dayDelta++ - roundedTimeNano = roundByInc(beyondDay, nanoInc, roundingMode) - endEpochNanoseconds = dayEpochNanoseconds1.addNumber(roundedTimeNano) - } else { - endEpochNanoseconds = dayEpochNanoseconds0.addNumber(roundedTimeNano) - } - - const durationTimeFields = timeNanoToDurationFields(roundedTimeNano) - const nudgedDurationFields = { - ...durationFields, - ...durationTimeFields, - days: durationFields.days + dayDelta, - } - - return [nudgedDurationFields, endEpochNanoseconds, dayDelta] -} - -function nudgeRelativeDuration( - durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) - endEpochNanoseconds, - smallestUnitI, - roundingInc, - roundingMode, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, -) { - const { sign } = durationFields - - const baseDurationFields = clearDurationFields(durationFields, smallestUnitI - 1) - baseDurationFields[smallestUnitI] = Math.trunc( - durationFields[smallestUnitI] / roundingInc, - ) - - const [epochNanoseconds0, epochNanoseconds1] = clampRelativeDuration( - baseDurationFields, - smallestUnitI, - roundingInc * sign, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, - ) - - const portion = - endEpochNanoseconds.subtract(epochNanoseconds0).toNumber() / - epochNanoseconds1.subtract(epochNanoseconds0).toNumber() - - const roundedPortion = roundWithMode(portion * sign, roundingMode) // -1/0/1 - - if (roundedPortion) { // enlarged? - baseDurationFields[smallestUnitI] += roundingInc * sign - - return [baseDurationFields, epochNanoseconds1, roundedPortion] - } else { - return [baseDurationFields, epochNanoseconds0, roundedPortion] - } -} - -// Utils -// ------------------------------------------------------------------------------------------------- - -function bubbleRelativeDuration( - durationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) - endEpochNanoseconds, - largestUnitIndex, - smallestUnitI, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, -) { - const { sign } = durationFields - - for ( - let currentUnitIndex = smallestUnitI + 1; - currentUnitIndex < largestUnitIndex; - currentUnitIndex++ - ) { - if (currentUnitIndex === weekIndex) { // correct? - continue - } - - const baseDurationFields = clearDurationFields(durationFields, currentUnitIndex - 1) - baseDurationFields[durationFieldNamesAsc[currentUnitIndex]] += sign - - const thresholdEpochNanoseconds = markerToEpochMilliseconds( - moveMarker(marker, baseDurationFields), - ) - - const beyondThreshold = endEpochNanoseconds.subtract(thresholdEpochNanoseconds).toNumber() - if (!beyondThreshold || Math.sign(beyondThreshold) === sign) { - durationFields = baseDurationFields - } else { - break - } - } - - return durationFields -} - -function clampRelativeDuration( - durationFields, - clampUnit, // baaa - clampDistance, - // marker system... - marker, - markerToEpochMilliseconds, - moveMarker, -) { - const clampDurationFields = { ...durationFieldDefaults, [clampUnit]: clampDistance } - const marker0 = moveMarker(marker, durationFields) - const marker1 = moveMarker(marker0, clampDurationFields) - const epochNanoseconds0 = markerToEpochMilliseconds(marker0) - const epochNanoseconds1 = markerToEpochMilliseconds(marker1) - return [epochNanoseconds0, epochNanoseconds1] -} - -function clearDurationFields(durationFields, lastUnitIndex) { - const copy = { ...durationFields } - - for (let unitIndex = nanoIndex; unitIndex <= lastUnitIndex; unitIndex++) { - copy[unitNamesAsc[unitIndex]] = 0 - } - - return copy -} diff --git a/packages/temporal-polyfill/src/new/round.ts b/packages/temporal-polyfill/src/new/round.ts new file mode 100644 index 00000000..e2957822 --- /dev/null +++ b/packages/temporal-polyfill/src/new/round.ts @@ -0,0 +1,516 @@ +import { diffZonedEpochNano } from './diff' +import { + DurationFields, + DurationInternals, + durationFieldDefaults, + durationFieldNamesAsc, + durationFieldsToNano, + durationFieldsToTimeNano, + durationTimeFieldDefaults, + nanoToDurationFields, + timeNanoToDurationFields, +} from './durationFields' +import { IsoDateFields, IsoDateInternals, IsoDateTimeFields, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' +import { isoTimeFieldsToNano, nanoToIsoTimeAndDay } from './isoMath' +import { LargeInt } from './largeInt' +import { moveDateByDays, moveZonedEpochNano } from './move' +import { RoundingMode, roundingModeFuncs } from './options' +import { TimeZoneOps, computeNanosecondsInDay } from './timeZoneOps' +import { + nanoInMinute, + nanoInUtcDay, + unitNanoMap, + Unit, + DayTimeUnit, + TimeUnit, +} from './units' +import { NumSign, identityFunc } from './utils' +import { ZonedInternals } from './zonedDateTime' + +export function roundToMinute(offsetNano: number): number { + return roundByInc(offsetNano, nanoInMinute, RoundingMode.HalfEven) +} + +// Rounding Dates +// ------------------------------------------------------------------------------------------------- + +export function roundDateTime( + isoFields: IsoDateTimeFields, + smallestUnit: DayTimeUnit, + roundingInc: number, + roundingMode: RoundingMode, + timeZoneOps: TimeZoneOps | undefined = undefined, +) { + if (smallestUnit === Unit.Day) { + return roundDateTimeToDay(isoFields, timeZoneOps, roundingMode) + } + + return roundDateTimeToNano( + isoFields, + computeNanoInc(smallestUnit, roundingInc), + roundingMode, + ) +} + +export function roundTime( + isoFields: IsoTimeFields, + smallestUnit: TimeUnit, + roundingInc: number, + roundingMode: RoundingMode, +): IsoTimeFields { + return roundTimeToNano( + isoFields, + computeNanoInc(smallestUnit, roundingInc), + roundingMode, + )[0] +} + +function roundDateTimeToDay( + isoFields: IsoDateTimeFields, + timeZoneOps: TimeZoneOps | undefined, + roundingMode: RoundingMode, +): IsoDateTimeFields { + const nanoInDay = timeZoneOps + ? computeNanosecondsInDay(timeZoneOps, isoFields) + : nanoInUtcDay + + const dayDelta = roundByInc( + isoTimeFieldsToNano(isoFields), + nanoInDay, + roundingMode, + ) + + return { + ...moveDateByDays(isoFields, dayDelta), + ...isoTimeFieldDefaults, + } +} + +export function roundDateTimeToNano( + isoFields: IsoDateTimeFields, + nanoInc: number, + roundingMode: RoundingMode, +): IsoDateTimeFields { + const [roundedIsoFields, dayDelta] = roundTimeToNano(isoFields, nanoInc, roundingMode) + + return { + ...moveDateByDays(isoFields, dayDelta), + ...roundedIsoFields, + } +} + +export function roundTimeToNano( + isoFields: IsoTimeFields, + nanoInc: number, + roundingMode: RoundingMode, +): [ + IsoTimeFields, + number, +] { + return nanoToIsoTimeAndDay( + roundByInc(isoTimeFieldsToNano(isoFields), nanoInc, roundingMode), + ) +} + +// Rounding Duration +// ------------------------------------------------------------------------------------------------- + +export function roundDayTimeDuration( + durationFields: DurationFields, + smallestUnit: DayTimeUnit, + roundingInc: number, + roundingMode: RoundingMode, +): DurationFields { + return roundDurationToNano( + durationFields, + computeNanoInc(smallestUnit, roundingInc), + roundingMode, + ) +} + +/* +Only does day-time rounding +*/ +export function roundDurationToNano( + durationFields: DurationFields, + nanoInc: number, + roundingMode: RoundingMode, +): DurationFields { + const largeNano = durationFieldsToNano(durationFields) + const roundedLargeNano = roundByIncLarge(largeNano, nanoInc, roundingMode) + const dayTimeFields = nanoToDurationFields(roundedLargeNano) + + return { + ...durationFields, + ...dayTimeFields, + days: durationFields.days + dayTimeFields.days, + } +} + +export function roundRelativeDuration( + durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + // ^has sign + endEpochNano: LargeInt, + largestUnit: Unit, + smallestUnit: Unit, + roundingInc: number, + roundingMode: RoundingMode, + // marker system... + marker: Marker, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, +): DurationFields { + if (smallestUnit === Unit.Nanosecond && roundingInc === 1) { + return durationFields + } + + let [roundedDurationFields, roundedEpochNanoseconds, grew] = ( + smallestUnit >= Unit.Day + ? nudgeRelativeDuration + : markerToEpochNano === identityFunc // marker is ZonedDateTime's epochNanoseconds? + ? nudgeRelativeDurationTime + : nudgeDurationTime + )( + durationFields, + endEpochNano, + smallestUnit, + roundingInc, + roundingMode, + // marker system only needed for nudgeRelativeDuration... + marker, + markerToEpochNano, + moveMarker, + ) + + // grew a day/week/month/year? + if (grew) { + roundedDurationFields = bubbleRelativeDuration( + roundedDurationFields, + roundedEpochNanoseconds, + largestUnit, + smallestUnit, + // marker system... + marker, + markerToEpochNano, + moveMarker, + ) + } + + return roundedDurationFields +} + +// Rounding Numbers +// ------------------------------------------------------------------------------------------------- + +export function computeNanoInc(smallestUnit: DayTimeUnit, roundingInc: number): number { + return unitNanoMap[smallestUnit] * roundingInc +} + +export function roundByInc(num: number, inc: number, roundingMode: RoundingMode): number { + return roundWithMode(num / inc, roundingMode) * inc +} + +export function roundByIncLarge( + num: LargeInt, + inc: number, + roundingMode: RoundingMode, +): LargeInt { + const [whole, remainder] = num.divTruncMod(inc) + const mod2 = whole.mod2() // workaround for halfEven + + return whole.mult(inc).addNumber( + roundWithMode((remainder / inc) + mod2, roundingMode) - mod2, + ) +} + +function roundWithMode(num: number, roundingMode: RoundingMode): number { + return roundingModeFuncs[roundingMode](num) +} + +// Total Duration +// ------------------------------------------------------------------------------------------------- + +export function totalDayTimeDuration( // assumes iso-length days + durationFields: DurationFields, + totalUnit: DayTimeUnit, +): number { + const largeNano = durationFieldsToNano(durationFields) + const divisor = unitNanoMap[totalUnit] + const [fullUnits, remainder] = largeNano.divTruncMod(divisor) + return fullUnits.toNumber() + (remainder / divisor) +} + +export function totalRelativeDuration( + durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNano: LargeInt, + totalUnit: Unit, + // marker system... + marker: Marker, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, +): number { + const { sign } = durationFields + + const [epochNano0, epochNano1] = clampRelativeDuration( + clearDurationFields(durationFields, totalUnit - 1), + totalUnit, + sign, + // marker system... + marker, + markerToEpochNano, + moveMarker, + ) + + const portion = + endEpochNano.addLargeInt(epochNano0, -1).toNumber() / + epochNano1.addLargeInt(epochNano0, -1).toNumber() + + return durationFields[durationFieldNamesAsc[totalUnit]] + portion +} + +// Nudge +// ------------------------------------------------------------------------------------------------- +/* +These functions actually do the heavy-lifting of rounding to a higher/lower marker, +and return the (day) delta. Also return the (potentially) unbalanced new duration. +*/ + +function nudgeDurationTime( + durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNano: LargeInt, // NOT NEEDED, just for adding result to + smallestUnit: TimeUnit, + roundingInc: number, + roundingMode: RoundingMode, +): [ + nudgedDurationFields: DurationFields, + nudgedEpochNano: LargeInt, + dayDelta: number, +] { + const timeNano = durationFieldsToTimeNano(durationFields) + const nanoInc = computeNanoInc(smallestUnit, roundingInc) + const roundedTimeNano = roundByInc(timeNano, nanoInc, roundingMode) + const roundedFields = timeNanoToDurationFields(roundedTimeNano) + const dayDelta = roundedFields.days + const nudgedDurationFields = { // TODO: what about sign? + ...durationFields, + ...roundedFields, + days: durationFields.days + dayDelta, + } + + return [ + nudgedDurationFields, + endEpochNano.addNumber(roundedTimeNano - timeNano), + dayDelta, + ] +} + +function nudgeRelativeDurationTime( + durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNano: LargeInt, // NOT NEEDED, just for conformance + smallestUnit: TimeUnit, + roundingInc: number, + roundingMode: RoundingMode, + // marker system... + marker: Marker, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, +): [ + nudgedDurationFields: DurationFields, + nudgedEpochNano: LargeInt, + dayDelta: number, +] { + const { sign } = durationFields + const timeNano = durationFieldsToTimeNano(durationFields) + const nanoInc = computeNanoInc(smallestUnit, roundingInc) + let roundedTimeNano = roundByInc(timeNano, nanoInc, roundingMode) + + const [dayEpochNano0, dayEpochNano1] = clampRelativeDuration( + { ...durationFields, ...durationTimeFieldDefaults }, + Unit.Day, + sign, + // marker system... + marker, + markerToEpochNano, + moveMarker, + ) + + const daySpanEpochNanoseconds = dayEpochNano1.addLargeInt(dayEpochNano0, -1).toNumber() + const beyondDay = roundedTimeNano - daySpanEpochNanoseconds + let dayDelta = 0 + + if (!beyondDay || Math.sign(beyondDay) === sign) { + dayDelta++ + roundedTimeNano = roundByInc(beyondDay, nanoInc, roundingMode) + endEpochNano = dayEpochNano1.addNumber(roundedTimeNano) + } else { + endEpochNano = dayEpochNano0.addNumber(roundedTimeNano) + } + + const durationTimeFields = timeNanoToDurationFields(roundedTimeNano) + const nudgedDurationFields = { + ...durationFields, + ...durationTimeFields, + days: durationFields.days + dayDelta, + } + + return [nudgedDurationFields, endEpochNano, dayDelta] +} + +function nudgeRelativeDuration( + durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNano: LargeInt, + smallestUnit: Unit, + roundingInc: number, + roundingMode: RoundingMode, + // marker system... + marker: Marker, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, +): [ + durationFields: DurationFields, + movedEpochNano: LargeInt, + grew: NumSign, +] { + const { sign } = durationFields + + const baseDurationFields = clearDurationFields(durationFields, smallestUnit - 1) + baseDurationFields[smallestUnit] = Math.trunc( + durationInternals[smallestUnit] / roundingInc, + ) + + const [epochNano0, epochNano1] = clampRelativeDuration( + baseDurationFields, + smallestUnit, + roundingInc * sign, + // marker system... + marker, + markerToEpochNano, + moveMarker, + ) + + const portion = + endEpochNano.addLargeInt(epochNano0, -1).toNumber() / + epochNano1.addLargeInt(epochNano0, -1).toNumber() + + const roundedPortion = roundWithMode(portion * sign, roundingMode) // -1/0/1 + + if (roundedPortion) { // enlarged? + baseDurationFields[smallestUnit] += roundingInc * sign + + return [baseDurationFields, epochNano1, roundedPortion as NumSign] + } else { + return [baseDurationFields, epochNano0, 0] + } +} + +// Marker System +// ------------------------------------------------------------------------------------------------- +// TODO: best place for this? + +export type Marker = LargeInt | IsoDateFields +export type MarkerToEpochNano = (marker: Marker) => LargeInt +export type MoveMarker = (marker: Marker, durationFields: DurationFields) => Marker +export type DiffMarkers = (marker0: Marker, marker1: Marker, largeUnit: Unit) => DurationInternals +export type MarkerSystem = [ + Marker, + MarkerToEpochNano, + MoveMarker, + DiffMarkers, +] + +export function createMarkerSystem( + markerInternals: ZonedInternals | IsoDateInternals +): MarkerSystem { + const { calendar, timeZone, epochNanoseconds } = markerInternals as ZonedInternals + + if (epochNanoseconds) { + return [ + epochNanoseconds, // marker + identityFunc, // markerToEpochNano + moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker + diffZonedEpochNano.bind(undefined, calendar, timeZone), // diffMarkers + ] + } else { + return [ + markerInternals as IsoDateFields, // marker (IsoDateFields) + isoToEpochNano as (marker: Marker) => LargeInt, // markerToEpochNano + calendar.dateAdd.bind(calendar), // moveMarker + calendar.dateUntil.bind(calendar), // diffMarkers + ] + } +} + +// Utils +// ------------------------------------------------------------------------------------------------- + +function bubbleRelativeDuration( + durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + endEpochNano: LargeInt, + largestUnit: Unit, + smallestUnit: Unit, + // marker system... + marker: Marker, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, +): DurationFields { + const { sign } = durationFields + + for ( + let currentUnit: Unit = smallestUnit + 1; + currentUnit < largestUnit; + currentUnit++ + ) { + if (currentUnit === Unit.Week) { // correct? + continue + } + + const baseDurationFields = clearDurationFields(durationFields, currentUnit - 1) + baseDurationFields[durationFieldNamesAsc[currentUnit]] += sign + + const thresholdEpochNano = markerToEpochNano( + moveMarker(marker, baseDurationFields), + ) + + const beyondThreshold = endEpochNano.addLargeInt(thresholdEpochNano, -1).toNumber() + if (!beyondThreshold || Math.sign(beyondThreshold) === sign) { + durationFields = baseDurationFields + } else { + break + } + } + + return durationFields +} + +function clampRelativeDuration( + durationFields: DurationFields, + clampUnit: Unit, + clampDistance: number, + // marker system... + marker: Marker, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, +) { + const clampDurationFields = { + ...durationFieldDefaults, + [durationFieldNamesAsc[clampUnit]]: clampDistance, + } + const marker0 = moveMarker(marker, durationFields) + const marker1 = moveMarker(marker0, clampDurationFields) + const epochNano0 = markerToEpochNano(marker0) + const epochNano1 = markerToEpochNano(marker1) + return [epochNano0, epochNano1] +} + +function clearDurationFields( + durationFields: DurationFields, + largestUnitToClear: Unit, +): DurationFields { + const copy = { ...durationFields } + + for (let unit: Unit = Unit.Nanosecond; unit <= largestUnitToClear; unit++) { + copy[durationFieldNamesAsc[unit]] = 0 + } + + return copy +} From 2f4c93f4802d6015c370563e85c7b0f13cb07fa1 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 18:26:17 -0400 Subject: [PATCH 171/805] ts fixes --- packages/temporal-polyfill/src/new/calendarImpl.ts | 2 +- packages/temporal-polyfill/src/new/intlFormat.ts | 2 +- packages/temporal-polyfill/src/new/isoFormat.ts | 2 +- packages/temporal-polyfill/src/new/options.ts | 6 +++--- packages/temporal-polyfill/src/new/plainMonthDay.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/temporal-polyfill/src/new/calendarImpl.ts b/packages/temporal-polyfill/src/new/calendarImpl.ts index e1b16374..70488e89 100644 --- a/packages/temporal-polyfill/src/new/calendarImpl.ts +++ b/packages/temporal-polyfill/src/new/calendarImpl.ts @@ -43,7 +43,7 @@ import { Overflow } from './options' import { Unit, milliInDay } from './units' import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './utils' import { CalendarOps } from './calendarOps' -import { DurationFields, DurationInternals } from './durationFields' +import { DurationInternals } from './durationFields' // Base Calendar Implementation // ------------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/new/intlFormat.ts b/packages/temporal-polyfill/src/new/intlFormat.ts index 2e5a6020..e0d79603 100644 --- a/packages/temporal-polyfill/src/new/intlFormat.ts +++ b/packages/temporal-polyfill/src/new/intlFormat.ts @@ -1,5 +1,5 @@ import { isoCalendarId } from './calendarConfig' -import { dateBasicNames, timeFieldDefaults } from './calendarFields' +import { dateBasicNames } from './calendarFields' import { getInternals, getTemporalName } from './class' import { Instant } from './instant' import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' diff --git a/packages/temporal-polyfill/src/new/isoFormat.ts b/packages/temporal-polyfill/src/new/isoFormat.ts index da86a996..d9267a59 100644 --- a/packages/temporal-polyfill/src/new/isoFormat.ts +++ b/packages/temporal-polyfill/src/new/isoFormat.ts @@ -1,6 +1,6 @@ import { isoCalendarId } from './calendarConfig' import { CalendarOps } from './calendarOps' -import { DurationInternals, absDurationInternals, durationFieldsToNano, durationFieldsToTimeNano } from './durationFields' +import { DurationInternals, absDurationInternals, durationFieldsToTimeNano } from './durationFields' import { IsoDateFields, IsoDateInternals, IsoDateTimeFields, IsoTimeFields } from './isoFields' import { CalendarDisplay, OffsetDisplay, refineDateDisplayOptions, SubsecDigits, TimeZoneDisplay } from './options' import { TimeZoneOps } from './timeZoneOps' diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/new/options.ts index e2ba6838..3f467841 100644 --- a/packages/temporal-polyfill/src/new/options.ts +++ b/packages/temporal-polyfill/src/new/options.ts @@ -238,9 +238,9 @@ function refineTimeDisplayTuple( } -const refineSmallestUnit = refineUnitOption.bind(undefined, smallestUnitStr) -const refineLargestUnit = refineUnitOption.bind(undefined, largestUnitStr) -const refineTotalUnit = refineUnitOption.bind(undefined, totalUnitStr) +const refineSmallestUnit = refineUnitOption.bind(undefined, 'smallestUnit') +const refineLargestUnit = refineUnitOption.bind(undefined, 'largestUnit') +const refineTotalUnit = refineUnitOption.bind(undefined, 'totalUnit') export enum Overflow { Constrain, diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.ts b/packages/temporal-polyfill/src/new/plainMonthDay.ts index 3c3c065e..c22ed308 100644 --- a/packages/temporal-polyfill/src/new/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/new/plainMonthDay.ts @@ -8,7 +8,7 @@ import { mergePlainMonthDayBag, refinePlainMonthDayBag, } from './convert' -import { IsoDateInternals, generatePublicIsoDateFields, pluckIsoDateInternals } from './isoFields' +import { IsoDateInternals, generatePublicIsoDateFields } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' import { compareIsoDateTimeFields, isoEpochFirstLeapYear, refineIsoDateInternals } from './isoMath' import { parsePlainMonthDay } from './isoParse' From 7448dcd7b7bc68c3d81c3bf91aba1f8099be5276 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 19:24:10 -0400 Subject: [PATCH 172/805] move into old --- packages/temporal-polyfill/src/{ => old}/argParse/calendar.ts | 0 .../temporal-polyfill/src/{ => old}/argParse/calendarDisplay.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/diffOptions.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/disambig.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/fieldStr.ts | 0 .../temporal-polyfill/src/{ => old}/argParse/isoFormatOptions.ts | 0 .../temporal-polyfill/src/{ => old}/argParse/offsetDisplay.ts | 0 .../temporal-polyfill/src/{ => old}/argParse/offsetHandling.ts | 0 .../temporal-polyfill/src/{ => old}/argParse/overflowHandling.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/refine.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/roundingMode.ts | 0 .../temporal-polyfill/src/{ => old}/argParse/roundingOptions.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/timeZone.ts | 0 .../temporal-polyfill/src/{ => old}/argParse/timeZoneDisplay.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/totalOptions.ts | 0 packages/temporal-polyfill/src/{ => old}/argParse/unitStr.ts | 0 packages/temporal-polyfill/src/{ => old}/calendarImpl/bugs.ts | 0 .../temporal-polyfill/src/{ => old}/calendarImpl/calendarImpl.ts | 0 .../src/{ => old}/calendarImpl/calendarImplQuery.ts | 0 .../temporal-polyfill/src/{ => old}/calendarImpl/eraOrigins.ts | 0 .../src/{ => old}/calendarImpl/gregoryCalendarImpl.ts | 0 .../src/{ => old}/calendarImpl/intlCalendarImpl.ts | 0 .../src/{ => old}/calendarImpl/islamicCalendarImpl.ts | 0 .../src/{ => old}/calendarImpl/isoCalendarImpl.ts | 0 .../src/{ => old}/calendarImpl/japaneseCalendarImpl.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/abstract.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/calendar.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/compare.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/constrain.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/dayAndTime.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/diff.ts | 0 .../temporal-polyfill/src/{ => old}/dateUtils/durationFields.ts | 0 .../temporal-polyfill/src/{ => old}/dateUtils/durationSpan.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/epoch.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/fromAndWith.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/intlFormat.ts | 0 .../src/{ => old}/dateUtils/isoFieldValidation.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/isoFields.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/isoFormat.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/localFields.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/mixins.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/offset.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/parse.ts | 0 .../temporal-polyfill/src/{ => old}/dateUtils/parseDuration.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/parseRefine.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/parseRegExp.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/relativeTo.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/rounding.ts | 0 .../temporal-polyfill/src/{ => old}/dateUtils/roundingDuration.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/timeZone.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/totalUnits.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/translate.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/units.ts | 0 packages/temporal-polyfill/src/{ => old}/dateUtils/week.ts | 0 packages/temporal-polyfill/src/{ => old}/global.build.ts | 0 packages/temporal-polyfill/src/{ => old}/global.ts | 0 packages/temporal-polyfill/src/{ => old}/impl.build.ts | 0 packages/temporal-polyfill/src/{ => old}/impl.ts | 0 packages/temporal-polyfill/src/{ => old}/index.build.ts | 0 packages/temporal-polyfill/src/{ => old}/index.ts | 0 packages/temporal-polyfill/src/{ => old}/native/date.ts | 0 packages/temporal-polyfill/src/{ => old}/native/intlFactory.ts | 0 packages/temporal-polyfill/src/{ => old}/native/intlMixins.ts | 0 packages/temporal-polyfill/src/{ => old}/native/intlTemporal.ts | 0 packages/temporal-polyfill/src/{ => old}/native/intlUtils.ts | 0 packages/temporal-polyfill/src/{ => old}/public/calendar.ts | 0 packages/temporal-polyfill/src/{ => old}/public/duration.ts | 0 packages/temporal-polyfill/src/{ => old}/public/instant.ts | 0 packages/temporal-polyfill/src/{ => old}/public/now.ts | 0 packages/temporal-polyfill/src/{ => old}/public/plainDate.ts | 0 packages/temporal-polyfill/src/{ => old}/public/plainDateTime.ts | 0 packages/temporal-polyfill/src/{ => old}/public/plainMonthDay.ts | 0 packages/temporal-polyfill/src/{ => old}/public/plainTime.ts | 0 packages/temporal-polyfill/src/{ => old}/public/plainYearMonth.ts | 0 packages/temporal-polyfill/src/{ => old}/public/temporal.ts | 0 packages/temporal-polyfill/src/{ => old}/public/timeZone.ts | 0 packages/temporal-polyfill/src/{ => old}/public/zonedDateTime.ts | 0 packages/temporal-polyfill/src/{ => old}/shim.ts | 0 .../src/{ => old}/timeZoneImpl/fixedTimeZoneImpl.ts | 0 .../src/{ => old}/timeZoneImpl/intlTimeZoneImpl.ts | 0 .../temporal-polyfill/src/{ => old}/timeZoneImpl/specialCases.ts | 0 .../temporal-polyfill/src/{ => old}/timeZoneImpl/timeZoneImpl.ts | 0 .../src/{ => old}/timeZoneImpl/timeZoneImplQuery.ts | 0 packages/temporal-polyfill/src/{ => old}/utils/dom.ts | 0 packages/temporal-polyfill/src/{ => old}/utils/largeInt.ts | 0 packages/temporal-polyfill/src/{ => old}/utils/math.ts | 0 packages/temporal-polyfill/src/{ => old}/utils/obj.ts | 0 packages/temporal-polyfill/src/{ => old}/utils/string.ts | 0 88 files changed, 0 insertions(+), 0 deletions(-) rename packages/temporal-polyfill/src/{ => old}/argParse/calendar.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/calendarDisplay.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/diffOptions.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/disambig.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/fieldStr.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/isoFormatOptions.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/offsetDisplay.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/offsetHandling.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/overflowHandling.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/refine.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/roundingMode.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/roundingOptions.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/timeZone.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/timeZoneDisplay.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/totalOptions.ts (100%) rename packages/temporal-polyfill/src/{ => old}/argParse/unitStr.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/bugs.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/calendarImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/calendarImplQuery.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/eraOrigins.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/gregoryCalendarImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/intlCalendarImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/islamicCalendarImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/isoCalendarImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/calendarImpl/japaneseCalendarImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/abstract.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/calendar.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/compare.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/constrain.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/dayAndTime.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/diff.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/durationFields.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/durationSpan.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/epoch.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/fromAndWith.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/intlFormat.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/isoFieldValidation.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/isoFields.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/isoFormat.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/localFields.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/mixins.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/offset.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/parse.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/parseDuration.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/parseRefine.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/parseRegExp.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/relativeTo.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/rounding.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/roundingDuration.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/timeZone.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/totalUnits.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/translate.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/units.ts (100%) rename packages/temporal-polyfill/src/{ => old}/dateUtils/week.ts (100%) rename packages/temporal-polyfill/src/{ => old}/global.build.ts (100%) rename packages/temporal-polyfill/src/{ => old}/global.ts (100%) rename packages/temporal-polyfill/src/{ => old}/impl.build.ts (100%) rename packages/temporal-polyfill/src/{ => old}/impl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/index.build.ts (100%) rename packages/temporal-polyfill/src/{ => old}/index.ts (100%) rename packages/temporal-polyfill/src/{ => old}/native/date.ts (100%) rename packages/temporal-polyfill/src/{ => old}/native/intlFactory.ts (100%) rename packages/temporal-polyfill/src/{ => old}/native/intlMixins.ts (100%) rename packages/temporal-polyfill/src/{ => old}/native/intlTemporal.ts (100%) rename packages/temporal-polyfill/src/{ => old}/native/intlUtils.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/calendar.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/duration.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/instant.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/now.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/plainDate.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/plainDateTime.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/plainMonthDay.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/plainTime.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/plainYearMonth.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/temporal.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/timeZone.ts (100%) rename packages/temporal-polyfill/src/{ => old}/public/zonedDateTime.ts (100%) rename packages/temporal-polyfill/src/{ => old}/shim.ts (100%) rename packages/temporal-polyfill/src/{ => old}/timeZoneImpl/fixedTimeZoneImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/timeZoneImpl/intlTimeZoneImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/timeZoneImpl/specialCases.ts (100%) rename packages/temporal-polyfill/src/{ => old}/timeZoneImpl/timeZoneImpl.ts (100%) rename packages/temporal-polyfill/src/{ => old}/timeZoneImpl/timeZoneImplQuery.ts (100%) rename packages/temporal-polyfill/src/{ => old}/utils/dom.ts (100%) rename packages/temporal-polyfill/src/{ => old}/utils/largeInt.ts (100%) rename packages/temporal-polyfill/src/{ => old}/utils/math.ts (100%) rename packages/temporal-polyfill/src/{ => old}/utils/obj.ts (100%) rename packages/temporal-polyfill/src/{ => old}/utils/string.ts (100%) diff --git a/packages/temporal-polyfill/src/argParse/calendar.ts b/packages/temporal-polyfill/src/old/argParse/calendar.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/calendar.ts rename to packages/temporal-polyfill/src/old/argParse/calendar.ts diff --git a/packages/temporal-polyfill/src/argParse/calendarDisplay.ts b/packages/temporal-polyfill/src/old/argParse/calendarDisplay.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/calendarDisplay.ts rename to packages/temporal-polyfill/src/old/argParse/calendarDisplay.ts diff --git a/packages/temporal-polyfill/src/argParse/diffOptions.ts b/packages/temporal-polyfill/src/old/argParse/diffOptions.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/diffOptions.ts rename to packages/temporal-polyfill/src/old/argParse/diffOptions.ts diff --git a/packages/temporal-polyfill/src/argParse/disambig.ts b/packages/temporal-polyfill/src/old/argParse/disambig.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/disambig.ts rename to packages/temporal-polyfill/src/old/argParse/disambig.ts diff --git a/packages/temporal-polyfill/src/argParse/fieldStr.ts b/packages/temporal-polyfill/src/old/argParse/fieldStr.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/fieldStr.ts rename to packages/temporal-polyfill/src/old/argParse/fieldStr.ts diff --git a/packages/temporal-polyfill/src/argParse/isoFormatOptions.ts b/packages/temporal-polyfill/src/old/argParse/isoFormatOptions.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/isoFormatOptions.ts rename to packages/temporal-polyfill/src/old/argParse/isoFormatOptions.ts diff --git a/packages/temporal-polyfill/src/argParse/offsetDisplay.ts b/packages/temporal-polyfill/src/old/argParse/offsetDisplay.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/offsetDisplay.ts rename to packages/temporal-polyfill/src/old/argParse/offsetDisplay.ts diff --git a/packages/temporal-polyfill/src/argParse/offsetHandling.ts b/packages/temporal-polyfill/src/old/argParse/offsetHandling.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/offsetHandling.ts rename to packages/temporal-polyfill/src/old/argParse/offsetHandling.ts diff --git a/packages/temporal-polyfill/src/argParse/overflowHandling.ts b/packages/temporal-polyfill/src/old/argParse/overflowHandling.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/overflowHandling.ts rename to packages/temporal-polyfill/src/old/argParse/overflowHandling.ts diff --git a/packages/temporal-polyfill/src/argParse/refine.ts b/packages/temporal-polyfill/src/old/argParse/refine.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/refine.ts rename to packages/temporal-polyfill/src/old/argParse/refine.ts diff --git a/packages/temporal-polyfill/src/argParse/roundingMode.ts b/packages/temporal-polyfill/src/old/argParse/roundingMode.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/roundingMode.ts rename to packages/temporal-polyfill/src/old/argParse/roundingMode.ts diff --git a/packages/temporal-polyfill/src/argParse/roundingOptions.ts b/packages/temporal-polyfill/src/old/argParse/roundingOptions.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/roundingOptions.ts rename to packages/temporal-polyfill/src/old/argParse/roundingOptions.ts diff --git a/packages/temporal-polyfill/src/argParse/timeZone.ts b/packages/temporal-polyfill/src/old/argParse/timeZone.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/timeZone.ts rename to packages/temporal-polyfill/src/old/argParse/timeZone.ts diff --git a/packages/temporal-polyfill/src/argParse/timeZoneDisplay.ts b/packages/temporal-polyfill/src/old/argParse/timeZoneDisplay.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/timeZoneDisplay.ts rename to packages/temporal-polyfill/src/old/argParse/timeZoneDisplay.ts diff --git a/packages/temporal-polyfill/src/argParse/totalOptions.ts b/packages/temporal-polyfill/src/old/argParse/totalOptions.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/totalOptions.ts rename to packages/temporal-polyfill/src/old/argParse/totalOptions.ts diff --git a/packages/temporal-polyfill/src/argParse/unitStr.ts b/packages/temporal-polyfill/src/old/argParse/unitStr.ts similarity index 100% rename from packages/temporal-polyfill/src/argParse/unitStr.ts rename to packages/temporal-polyfill/src/old/argParse/unitStr.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/bugs.ts b/packages/temporal-polyfill/src/old/calendarImpl/bugs.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/bugs.ts rename to packages/temporal-polyfill/src/old/calendarImpl/bugs.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/calendarImpl.ts b/packages/temporal-polyfill/src/old/calendarImpl/calendarImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/calendarImpl.ts rename to packages/temporal-polyfill/src/old/calendarImpl/calendarImpl.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts b/packages/temporal-polyfill/src/old/calendarImpl/calendarImplQuery.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/calendarImplQuery.ts rename to packages/temporal-polyfill/src/old/calendarImpl/calendarImplQuery.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/eraOrigins.ts b/packages/temporal-polyfill/src/old/calendarImpl/eraOrigins.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/eraOrigins.ts rename to packages/temporal-polyfill/src/old/calendarImpl/eraOrigins.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/gregoryCalendarImpl.ts b/packages/temporal-polyfill/src/old/calendarImpl/gregoryCalendarImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/gregoryCalendarImpl.ts rename to packages/temporal-polyfill/src/old/calendarImpl/gregoryCalendarImpl.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/intlCalendarImpl.ts b/packages/temporal-polyfill/src/old/calendarImpl/intlCalendarImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/intlCalendarImpl.ts rename to packages/temporal-polyfill/src/old/calendarImpl/intlCalendarImpl.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/islamicCalendarImpl.ts b/packages/temporal-polyfill/src/old/calendarImpl/islamicCalendarImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/islamicCalendarImpl.ts rename to packages/temporal-polyfill/src/old/calendarImpl/islamicCalendarImpl.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/isoCalendarImpl.ts b/packages/temporal-polyfill/src/old/calendarImpl/isoCalendarImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/isoCalendarImpl.ts rename to packages/temporal-polyfill/src/old/calendarImpl/isoCalendarImpl.ts diff --git a/packages/temporal-polyfill/src/calendarImpl/japaneseCalendarImpl.ts b/packages/temporal-polyfill/src/old/calendarImpl/japaneseCalendarImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/calendarImpl/japaneseCalendarImpl.ts rename to packages/temporal-polyfill/src/old/calendarImpl/japaneseCalendarImpl.ts diff --git a/packages/temporal-polyfill/src/dateUtils/abstract.ts b/packages/temporal-polyfill/src/old/dateUtils/abstract.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/abstract.ts rename to packages/temporal-polyfill/src/old/dateUtils/abstract.ts diff --git a/packages/temporal-polyfill/src/dateUtils/calendar.ts b/packages/temporal-polyfill/src/old/dateUtils/calendar.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/calendar.ts rename to packages/temporal-polyfill/src/old/dateUtils/calendar.ts diff --git a/packages/temporal-polyfill/src/dateUtils/compare.ts b/packages/temporal-polyfill/src/old/dateUtils/compare.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/compare.ts rename to packages/temporal-polyfill/src/old/dateUtils/compare.ts diff --git a/packages/temporal-polyfill/src/dateUtils/constrain.ts b/packages/temporal-polyfill/src/old/dateUtils/constrain.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/constrain.ts rename to packages/temporal-polyfill/src/old/dateUtils/constrain.ts diff --git a/packages/temporal-polyfill/src/dateUtils/dayAndTime.ts b/packages/temporal-polyfill/src/old/dateUtils/dayAndTime.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/dayAndTime.ts rename to packages/temporal-polyfill/src/old/dateUtils/dayAndTime.ts diff --git a/packages/temporal-polyfill/src/dateUtils/diff.ts b/packages/temporal-polyfill/src/old/dateUtils/diff.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/diff.ts rename to packages/temporal-polyfill/src/old/dateUtils/diff.ts diff --git a/packages/temporal-polyfill/src/dateUtils/durationFields.ts b/packages/temporal-polyfill/src/old/dateUtils/durationFields.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/durationFields.ts rename to packages/temporal-polyfill/src/old/dateUtils/durationFields.ts diff --git a/packages/temporal-polyfill/src/dateUtils/durationSpan.ts b/packages/temporal-polyfill/src/old/dateUtils/durationSpan.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/durationSpan.ts rename to packages/temporal-polyfill/src/old/dateUtils/durationSpan.ts diff --git a/packages/temporal-polyfill/src/dateUtils/epoch.ts b/packages/temporal-polyfill/src/old/dateUtils/epoch.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/epoch.ts rename to packages/temporal-polyfill/src/old/dateUtils/epoch.ts diff --git a/packages/temporal-polyfill/src/dateUtils/fromAndWith.ts b/packages/temporal-polyfill/src/old/dateUtils/fromAndWith.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/fromAndWith.ts rename to packages/temporal-polyfill/src/old/dateUtils/fromAndWith.ts diff --git a/packages/temporal-polyfill/src/dateUtils/intlFormat.ts b/packages/temporal-polyfill/src/old/dateUtils/intlFormat.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/intlFormat.ts rename to packages/temporal-polyfill/src/old/dateUtils/intlFormat.ts diff --git a/packages/temporal-polyfill/src/dateUtils/isoFieldValidation.ts b/packages/temporal-polyfill/src/old/dateUtils/isoFieldValidation.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/isoFieldValidation.ts rename to packages/temporal-polyfill/src/old/dateUtils/isoFieldValidation.ts diff --git a/packages/temporal-polyfill/src/dateUtils/isoFields.ts b/packages/temporal-polyfill/src/old/dateUtils/isoFields.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/isoFields.ts rename to packages/temporal-polyfill/src/old/dateUtils/isoFields.ts diff --git a/packages/temporal-polyfill/src/dateUtils/isoFormat.ts b/packages/temporal-polyfill/src/old/dateUtils/isoFormat.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/isoFormat.ts rename to packages/temporal-polyfill/src/old/dateUtils/isoFormat.ts diff --git a/packages/temporal-polyfill/src/dateUtils/localFields.ts b/packages/temporal-polyfill/src/old/dateUtils/localFields.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/localFields.ts rename to packages/temporal-polyfill/src/old/dateUtils/localFields.ts diff --git a/packages/temporal-polyfill/src/dateUtils/mixins.ts b/packages/temporal-polyfill/src/old/dateUtils/mixins.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/mixins.ts rename to packages/temporal-polyfill/src/old/dateUtils/mixins.ts diff --git a/packages/temporal-polyfill/src/dateUtils/offset.ts b/packages/temporal-polyfill/src/old/dateUtils/offset.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/offset.ts rename to packages/temporal-polyfill/src/old/dateUtils/offset.ts diff --git a/packages/temporal-polyfill/src/dateUtils/parse.ts b/packages/temporal-polyfill/src/old/dateUtils/parse.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/parse.ts rename to packages/temporal-polyfill/src/old/dateUtils/parse.ts diff --git a/packages/temporal-polyfill/src/dateUtils/parseDuration.ts b/packages/temporal-polyfill/src/old/dateUtils/parseDuration.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/parseDuration.ts rename to packages/temporal-polyfill/src/old/dateUtils/parseDuration.ts diff --git a/packages/temporal-polyfill/src/dateUtils/parseRefine.ts b/packages/temporal-polyfill/src/old/dateUtils/parseRefine.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/parseRefine.ts rename to packages/temporal-polyfill/src/old/dateUtils/parseRefine.ts diff --git a/packages/temporal-polyfill/src/dateUtils/parseRegExp.ts b/packages/temporal-polyfill/src/old/dateUtils/parseRegExp.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/parseRegExp.ts rename to packages/temporal-polyfill/src/old/dateUtils/parseRegExp.ts diff --git a/packages/temporal-polyfill/src/dateUtils/relativeTo.ts b/packages/temporal-polyfill/src/old/dateUtils/relativeTo.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/relativeTo.ts rename to packages/temporal-polyfill/src/old/dateUtils/relativeTo.ts diff --git a/packages/temporal-polyfill/src/dateUtils/rounding.ts b/packages/temporal-polyfill/src/old/dateUtils/rounding.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/rounding.ts rename to packages/temporal-polyfill/src/old/dateUtils/rounding.ts diff --git a/packages/temporal-polyfill/src/dateUtils/roundingDuration.ts b/packages/temporal-polyfill/src/old/dateUtils/roundingDuration.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/roundingDuration.ts rename to packages/temporal-polyfill/src/old/dateUtils/roundingDuration.ts diff --git a/packages/temporal-polyfill/src/dateUtils/timeZone.ts b/packages/temporal-polyfill/src/old/dateUtils/timeZone.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/timeZone.ts rename to packages/temporal-polyfill/src/old/dateUtils/timeZone.ts diff --git a/packages/temporal-polyfill/src/dateUtils/totalUnits.ts b/packages/temporal-polyfill/src/old/dateUtils/totalUnits.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/totalUnits.ts rename to packages/temporal-polyfill/src/old/dateUtils/totalUnits.ts diff --git a/packages/temporal-polyfill/src/dateUtils/translate.ts b/packages/temporal-polyfill/src/old/dateUtils/translate.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/translate.ts rename to packages/temporal-polyfill/src/old/dateUtils/translate.ts diff --git a/packages/temporal-polyfill/src/dateUtils/units.ts b/packages/temporal-polyfill/src/old/dateUtils/units.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/units.ts rename to packages/temporal-polyfill/src/old/dateUtils/units.ts diff --git a/packages/temporal-polyfill/src/dateUtils/week.ts b/packages/temporal-polyfill/src/old/dateUtils/week.ts similarity index 100% rename from packages/temporal-polyfill/src/dateUtils/week.ts rename to packages/temporal-polyfill/src/old/dateUtils/week.ts diff --git a/packages/temporal-polyfill/src/global.build.ts b/packages/temporal-polyfill/src/old/global.build.ts similarity index 100% rename from packages/temporal-polyfill/src/global.build.ts rename to packages/temporal-polyfill/src/old/global.build.ts diff --git a/packages/temporal-polyfill/src/global.ts b/packages/temporal-polyfill/src/old/global.ts similarity index 100% rename from packages/temporal-polyfill/src/global.ts rename to packages/temporal-polyfill/src/old/global.ts diff --git a/packages/temporal-polyfill/src/impl.build.ts b/packages/temporal-polyfill/src/old/impl.build.ts similarity index 100% rename from packages/temporal-polyfill/src/impl.build.ts rename to packages/temporal-polyfill/src/old/impl.build.ts diff --git a/packages/temporal-polyfill/src/impl.ts b/packages/temporal-polyfill/src/old/impl.ts similarity index 100% rename from packages/temporal-polyfill/src/impl.ts rename to packages/temporal-polyfill/src/old/impl.ts diff --git a/packages/temporal-polyfill/src/index.build.ts b/packages/temporal-polyfill/src/old/index.build.ts similarity index 100% rename from packages/temporal-polyfill/src/index.build.ts rename to packages/temporal-polyfill/src/old/index.build.ts diff --git a/packages/temporal-polyfill/src/index.ts b/packages/temporal-polyfill/src/old/index.ts similarity index 100% rename from packages/temporal-polyfill/src/index.ts rename to packages/temporal-polyfill/src/old/index.ts diff --git a/packages/temporal-polyfill/src/native/date.ts b/packages/temporal-polyfill/src/old/native/date.ts similarity index 100% rename from packages/temporal-polyfill/src/native/date.ts rename to packages/temporal-polyfill/src/old/native/date.ts diff --git a/packages/temporal-polyfill/src/native/intlFactory.ts b/packages/temporal-polyfill/src/old/native/intlFactory.ts similarity index 100% rename from packages/temporal-polyfill/src/native/intlFactory.ts rename to packages/temporal-polyfill/src/old/native/intlFactory.ts diff --git a/packages/temporal-polyfill/src/native/intlMixins.ts b/packages/temporal-polyfill/src/old/native/intlMixins.ts similarity index 100% rename from packages/temporal-polyfill/src/native/intlMixins.ts rename to packages/temporal-polyfill/src/old/native/intlMixins.ts diff --git a/packages/temporal-polyfill/src/native/intlTemporal.ts b/packages/temporal-polyfill/src/old/native/intlTemporal.ts similarity index 100% rename from packages/temporal-polyfill/src/native/intlTemporal.ts rename to packages/temporal-polyfill/src/old/native/intlTemporal.ts diff --git a/packages/temporal-polyfill/src/native/intlUtils.ts b/packages/temporal-polyfill/src/old/native/intlUtils.ts similarity index 100% rename from packages/temporal-polyfill/src/native/intlUtils.ts rename to packages/temporal-polyfill/src/old/native/intlUtils.ts diff --git a/packages/temporal-polyfill/src/public/calendar.ts b/packages/temporal-polyfill/src/old/public/calendar.ts similarity index 100% rename from packages/temporal-polyfill/src/public/calendar.ts rename to packages/temporal-polyfill/src/old/public/calendar.ts diff --git a/packages/temporal-polyfill/src/public/duration.ts b/packages/temporal-polyfill/src/old/public/duration.ts similarity index 100% rename from packages/temporal-polyfill/src/public/duration.ts rename to packages/temporal-polyfill/src/old/public/duration.ts diff --git a/packages/temporal-polyfill/src/public/instant.ts b/packages/temporal-polyfill/src/old/public/instant.ts similarity index 100% rename from packages/temporal-polyfill/src/public/instant.ts rename to packages/temporal-polyfill/src/old/public/instant.ts diff --git a/packages/temporal-polyfill/src/public/now.ts b/packages/temporal-polyfill/src/old/public/now.ts similarity index 100% rename from packages/temporal-polyfill/src/public/now.ts rename to packages/temporal-polyfill/src/old/public/now.ts diff --git a/packages/temporal-polyfill/src/public/plainDate.ts b/packages/temporal-polyfill/src/old/public/plainDate.ts similarity index 100% rename from packages/temporal-polyfill/src/public/plainDate.ts rename to packages/temporal-polyfill/src/old/public/plainDate.ts diff --git a/packages/temporal-polyfill/src/public/plainDateTime.ts b/packages/temporal-polyfill/src/old/public/plainDateTime.ts similarity index 100% rename from packages/temporal-polyfill/src/public/plainDateTime.ts rename to packages/temporal-polyfill/src/old/public/plainDateTime.ts diff --git a/packages/temporal-polyfill/src/public/plainMonthDay.ts b/packages/temporal-polyfill/src/old/public/plainMonthDay.ts similarity index 100% rename from packages/temporal-polyfill/src/public/plainMonthDay.ts rename to packages/temporal-polyfill/src/old/public/plainMonthDay.ts diff --git a/packages/temporal-polyfill/src/public/plainTime.ts b/packages/temporal-polyfill/src/old/public/plainTime.ts similarity index 100% rename from packages/temporal-polyfill/src/public/plainTime.ts rename to packages/temporal-polyfill/src/old/public/plainTime.ts diff --git a/packages/temporal-polyfill/src/public/plainYearMonth.ts b/packages/temporal-polyfill/src/old/public/plainYearMonth.ts similarity index 100% rename from packages/temporal-polyfill/src/public/plainYearMonth.ts rename to packages/temporal-polyfill/src/old/public/plainYearMonth.ts diff --git a/packages/temporal-polyfill/src/public/temporal.ts b/packages/temporal-polyfill/src/old/public/temporal.ts similarity index 100% rename from packages/temporal-polyfill/src/public/temporal.ts rename to packages/temporal-polyfill/src/old/public/temporal.ts diff --git a/packages/temporal-polyfill/src/public/timeZone.ts b/packages/temporal-polyfill/src/old/public/timeZone.ts similarity index 100% rename from packages/temporal-polyfill/src/public/timeZone.ts rename to packages/temporal-polyfill/src/old/public/timeZone.ts diff --git a/packages/temporal-polyfill/src/public/zonedDateTime.ts b/packages/temporal-polyfill/src/old/public/zonedDateTime.ts similarity index 100% rename from packages/temporal-polyfill/src/public/zonedDateTime.ts rename to packages/temporal-polyfill/src/old/public/zonedDateTime.ts diff --git a/packages/temporal-polyfill/src/shim.ts b/packages/temporal-polyfill/src/old/shim.ts similarity index 100% rename from packages/temporal-polyfill/src/shim.ts rename to packages/temporal-polyfill/src/old/shim.ts diff --git a/packages/temporal-polyfill/src/timeZoneImpl/fixedTimeZoneImpl.ts b/packages/temporal-polyfill/src/old/timeZoneImpl/fixedTimeZoneImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/timeZoneImpl/fixedTimeZoneImpl.ts rename to packages/temporal-polyfill/src/old/timeZoneImpl/fixedTimeZoneImpl.ts diff --git a/packages/temporal-polyfill/src/timeZoneImpl/intlTimeZoneImpl.ts b/packages/temporal-polyfill/src/old/timeZoneImpl/intlTimeZoneImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/timeZoneImpl/intlTimeZoneImpl.ts rename to packages/temporal-polyfill/src/old/timeZoneImpl/intlTimeZoneImpl.ts diff --git a/packages/temporal-polyfill/src/timeZoneImpl/specialCases.ts b/packages/temporal-polyfill/src/old/timeZoneImpl/specialCases.ts similarity index 100% rename from packages/temporal-polyfill/src/timeZoneImpl/specialCases.ts rename to packages/temporal-polyfill/src/old/timeZoneImpl/specialCases.ts diff --git a/packages/temporal-polyfill/src/timeZoneImpl/timeZoneImpl.ts b/packages/temporal-polyfill/src/old/timeZoneImpl/timeZoneImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/timeZoneImpl/timeZoneImpl.ts rename to packages/temporal-polyfill/src/old/timeZoneImpl/timeZoneImpl.ts diff --git a/packages/temporal-polyfill/src/timeZoneImpl/timeZoneImplQuery.ts b/packages/temporal-polyfill/src/old/timeZoneImpl/timeZoneImplQuery.ts similarity index 100% rename from packages/temporal-polyfill/src/timeZoneImpl/timeZoneImplQuery.ts rename to packages/temporal-polyfill/src/old/timeZoneImpl/timeZoneImplQuery.ts diff --git a/packages/temporal-polyfill/src/utils/dom.ts b/packages/temporal-polyfill/src/old/utils/dom.ts similarity index 100% rename from packages/temporal-polyfill/src/utils/dom.ts rename to packages/temporal-polyfill/src/old/utils/dom.ts diff --git a/packages/temporal-polyfill/src/utils/largeInt.ts b/packages/temporal-polyfill/src/old/utils/largeInt.ts similarity index 100% rename from packages/temporal-polyfill/src/utils/largeInt.ts rename to packages/temporal-polyfill/src/old/utils/largeInt.ts diff --git a/packages/temporal-polyfill/src/utils/math.ts b/packages/temporal-polyfill/src/old/utils/math.ts similarity index 100% rename from packages/temporal-polyfill/src/utils/math.ts rename to packages/temporal-polyfill/src/old/utils/math.ts diff --git a/packages/temporal-polyfill/src/utils/obj.ts b/packages/temporal-polyfill/src/old/utils/obj.ts similarity index 100% rename from packages/temporal-polyfill/src/utils/obj.ts rename to packages/temporal-polyfill/src/old/utils/obj.ts diff --git a/packages/temporal-polyfill/src/utils/string.ts b/packages/temporal-polyfill/src/old/utils/string.ts similarity index 100% rename from packages/temporal-polyfill/src/utils/string.ts rename to packages/temporal-polyfill/src/old/utils/string.ts From 7b7d9657b5dd378f9ec413250dc0bab831ca8465 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 19:25:09 -0400 Subject: [PATCH 173/805] move new into root --- packages/temporal-polyfill/src/{new => }/calendar.ts | 0 packages/temporal-polyfill/src/{new => }/calendarConfig.ts | 0 packages/temporal-polyfill/src/{new => }/calendarFields.ts | 0 packages/temporal-polyfill/src/{new => }/calendarImpl.ts | 0 packages/temporal-polyfill/src/{new => }/calendarOps.ts | 0 packages/temporal-polyfill/src/{new => }/class.ts | 0 packages/temporal-polyfill/src/{new => }/convert.ts | 0 packages/temporal-polyfill/src/{new => }/diff.ts | 0 packages/temporal-polyfill/src/{new => }/duration.ts | 0 packages/temporal-polyfill/src/{new => }/durationFields.ts | 0 packages/temporal-polyfill/src/{new => }/global.ts | 0 packages/temporal-polyfill/src/{new => }/impl.ts | 0 packages/temporal-polyfill/src/{new => }/index.ts | 0 packages/temporal-polyfill/src/{new => }/instant.ts | 0 packages/temporal-polyfill/src/{new => }/intlFormat.ts | 0 packages/temporal-polyfill/src/{new => }/isoFields.ts | 0 packages/temporal-polyfill/src/{new => }/isoFormat.ts | 0 packages/temporal-polyfill/src/{new => }/isoMath.ts | 0 packages/temporal-polyfill/src/{new => }/isoParse.ts | 0 packages/temporal-polyfill/src/{new => }/largeInt.ts | 0 packages/temporal-polyfill/src/{new => }/move.ts | 0 packages/temporal-polyfill/src/{new => }/now.ts | 0 packages/temporal-polyfill/src/{new => }/options.ts | 0 packages/temporal-polyfill/src/{new => }/plainDate.ts | 0 packages/temporal-polyfill/src/{new => }/plainDateTime.ts | 0 packages/temporal-polyfill/src/{new => }/plainMonthDay.ts | 0 packages/temporal-polyfill/src/{new => }/plainTime.ts | 0 packages/temporal-polyfill/src/{new => }/plainYearMonth.ts | 0 packages/temporal-polyfill/src/{new => }/round.ts | 0 packages/temporal-polyfill/src/{new => }/temporal.ts | 0 packages/temporal-polyfill/src/{new => }/timeZone.ts | 0 packages/temporal-polyfill/src/{new => }/timeZoneImpl.ts | 0 packages/temporal-polyfill/src/{new => }/timeZoneOps.ts | 0 packages/temporal-polyfill/src/{new => }/units.ts | 0 packages/temporal-polyfill/src/{new => }/utils.ts | 0 packages/temporal-polyfill/src/{new => }/zonedDateTime.ts | 0 36 files changed, 0 insertions(+), 0 deletions(-) rename packages/temporal-polyfill/src/{new => }/calendar.ts (100%) rename packages/temporal-polyfill/src/{new => }/calendarConfig.ts (100%) rename packages/temporal-polyfill/src/{new => }/calendarFields.ts (100%) rename packages/temporal-polyfill/src/{new => }/calendarImpl.ts (100%) rename packages/temporal-polyfill/src/{new => }/calendarOps.ts (100%) rename packages/temporal-polyfill/src/{new => }/class.ts (100%) rename packages/temporal-polyfill/src/{new => }/convert.ts (100%) rename packages/temporal-polyfill/src/{new => }/diff.ts (100%) rename packages/temporal-polyfill/src/{new => }/duration.ts (100%) rename packages/temporal-polyfill/src/{new => }/durationFields.ts (100%) rename packages/temporal-polyfill/src/{new => }/global.ts (100%) rename packages/temporal-polyfill/src/{new => }/impl.ts (100%) rename packages/temporal-polyfill/src/{new => }/index.ts (100%) rename packages/temporal-polyfill/src/{new => }/instant.ts (100%) rename packages/temporal-polyfill/src/{new => }/intlFormat.ts (100%) rename packages/temporal-polyfill/src/{new => }/isoFields.ts (100%) rename packages/temporal-polyfill/src/{new => }/isoFormat.ts (100%) rename packages/temporal-polyfill/src/{new => }/isoMath.ts (100%) rename packages/temporal-polyfill/src/{new => }/isoParse.ts (100%) rename packages/temporal-polyfill/src/{new => }/largeInt.ts (100%) rename packages/temporal-polyfill/src/{new => }/move.ts (100%) rename packages/temporal-polyfill/src/{new => }/now.ts (100%) rename packages/temporal-polyfill/src/{new => }/options.ts (100%) rename packages/temporal-polyfill/src/{new => }/plainDate.ts (100%) rename packages/temporal-polyfill/src/{new => }/plainDateTime.ts (100%) rename packages/temporal-polyfill/src/{new => }/plainMonthDay.ts (100%) rename packages/temporal-polyfill/src/{new => }/plainTime.ts (100%) rename packages/temporal-polyfill/src/{new => }/plainYearMonth.ts (100%) rename packages/temporal-polyfill/src/{new => }/round.ts (100%) rename packages/temporal-polyfill/src/{new => }/temporal.ts (100%) rename packages/temporal-polyfill/src/{new => }/timeZone.ts (100%) rename packages/temporal-polyfill/src/{new => }/timeZoneImpl.ts (100%) rename packages/temporal-polyfill/src/{new => }/timeZoneOps.ts (100%) rename packages/temporal-polyfill/src/{new => }/units.ts (100%) rename packages/temporal-polyfill/src/{new => }/utils.ts (100%) rename packages/temporal-polyfill/src/{new => }/zonedDateTime.ts (100%) diff --git a/packages/temporal-polyfill/src/new/calendar.ts b/packages/temporal-polyfill/src/calendar.ts similarity index 100% rename from packages/temporal-polyfill/src/new/calendar.ts rename to packages/temporal-polyfill/src/calendar.ts diff --git a/packages/temporal-polyfill/src/new/calendarConfig.ts b/packages/temporal-polyfill/src/calendarConfig.ts similarity index 100% rename from packages/temporal-polyfill/src/new/calendarConfig.ts rename to packages/temporal-polyfill/src/calendarConfig.ts diff --git a/packages/temporal-polyfill/src/new/calendarFields.ts b/packages/temporal-polyfill/src/calendarFields.ts similarity index 100% rename from packages/temporal-polyfill/src/new/calendarFields.ts rename to packages/temporal-polyfill/src/calendarFields.ts diff --git a/packages/temporal-polyfill/src/new/calendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/new/calendarImpl.ts rename to packages/temporal-polyfill/src/calendarImpl.ts diff --git a/packages/temporal-polyfill/src/new/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts similarity index 100% rename from packages/temporal-polyfill/src/new/calendarOps.ts rename to packages/temporal-polyfill/src/calendarOps.ts diff --git a/packages/temporal-polyfill/src/new/class.ts b/packages/temporal-polyfill/src/class.ts similarity index 100% rename from packages/temporal-polyfill/src/new/class.ts rename to packages/temporal-polyfill/src/class.ts diff --git a/packages/temporal-polyfill/src/new/convert.ts b/packages/temporal-polyfill/src/convert.ts similarity index 100% rename from packages/temporal-polyfill/src/new/convert.ts rename to packages/temporal-polyfill/src/convert.ts diff --git a/packages/temporal-polyfill/src/new/diff.ts b/packages/temporal-polyfill/src/diff.ts similarity index 100% rename from packages/temporal-polyfill/src/new/diff.ts rename to packages/temporal-polyfill/src/diff.ts diff --git a/packages/temporal-polyfill/src/new/duration.ts b/packages/temporal-polyfill/src/duration.ts similarity index 100% rename from packages/temporal-polyfill/src/new/duration.ts rename to packages/temporal-polyfill/src/duration.ts diff --git a/packages/temporal-polyfill/src/new/durationFields.ts b/packages/temporal-polyfill/src/durationFields.ts similarity index 100% rename from packages/temporal-polyfill/src/new/durationFields.ts rename to packages/temporal-polyfill/src/durationFields.ts diff --git a/packages/temporal-polyfill/src/new/global.ts b/packages/temporal-polyfill/src/global.ts similarity index 100% rename from packages/temporal-polyfill/src/new/global.ts rename to packages/temporal-polyfill/src/global.ts diff --git a/packages/temporal-polyfill/src/new/impl.ts b/packages/temporal-polyfill/src/impl.ts similarity index 100% rename from packages/temporal-polyfill/src/new/impl.ts rename to packages/temporal-polyfill/src/impl.ts diff --git a/packages/temporal-polyfill/src/new/index.ts b/packages/temporal-polyfill/src/index.ts similarity index 100% rename from packages/temporal-polyfill/src/new/index.ts rename to packages/temporal-polyfill/src/index.ts diff --git a/packages/temporal-polyfill/src/new/instant.ts b/packages/temporal-polyfill/src/instant.ts similarity index 100% rename from packages/temporal-polyfill/src/new/instant.ts rename to packages/temporal-polyfill/src/instant.ts diff --git a/packages/temporal-polyfill/src/new/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts similarity index 100% rename from packages/temporal-polyfill/src/new/intlFormat.ts rename to packages/temporal-polyfill/src/intlFormat.ts diff --git a/packages/temporal-polyfill/src/new/isoFields.ts b/packages/temporal-polyfill/src/isoFields.ts similarity index 100% rename from packages/temporal-polyfill/src/new/isoFields.ts rename to packages/temporal-polyfill/src/isoFields.ts diff --git a/packages/temporal-polyfill/src/new/isoFormat.ts b/packages/temporal-polyfill/src/isoFormat.ts similarity index 100% rename from packages/temporal-polyfill/src/new/isoFormat.ts rename to packages/temporal-polyfill/src/isoFormat.ts diff --git a/packages/temporal-polyfill/src/new/isoMath.ts b/packages/temporal-polyfill/src/isoMath.ts similarity index 100% rename from packages/temporal-polyfill/src/new/isoMath.ts rename to packages/temporal-polyfill/src/isoMath.ts diff --git a/packages/temporal-polyfill/src/new/isoParse.ts b/packages/temporal-polyfill/src/isoParse.ts similarity index 100% rename from packages/temporal-polyfill/src/new/isoParse.ts rename to packages/temporal-polyfill/src/isoParse.ts diff --git a/packages/temporal-polyfill/src/new/largeInt.ts b/packages/temporal-polyfill/src/largeInt.ts similarity index 100% rename from packages/temporal-polyfill/src/new/largeInt.ts rename to packages/temporal-polyfill/src/largeInt.ts diff --git a/packages/temporal-polyfill/src/new/move.ts b/packages/temporal-polyfill/src/move.ts similarity index 100% rename from packages/temporal-polyfill/src/new/move.ts rename to packages/temporal-polyfill/src/move.ts diff --git a/packages/temporal-polyfill/src/new/now.ts b/packages/temporal-polyfill/src/now.ts similarity index 100% rename from packages/temporal-polyfill/src/new/now.ts rename to packages/temporal-polyfill/src/now.ts diff --git a/packages/temporal-polyfill/src/new/options.ts b/packages/temporal-polyfill/src/options.ts similarity index 100% rename from packages/temporal-polyfill/src/new/options.ts rename to packages/temporal-polyfill/src/options.ts diff --git a/packages/temporal-polyfill/src/new/plainDate.ts b/packages/temporal-polyfill/src/plainDate.ts similarity index 100% rename from packages/temporal-polyfill/src/new/plainDate.ts rename to packages/temporal-polyfill/src/plainDate.ts diff --git a/packages/temporal-polyfill/src/new/plainDateTime.ts b/packages/temporal-polyfill/src/plainDateTime.ts similarity index 100% rename from packages/temporal-polyfill/src/new/plainDateTime.ts rename to packages/temporal-polyfill/src/plainDateTime.ts diff --git a/packages/temporal-polyfill/src/new/plainMonthDay.ts b/packages/temporal-polyfill/src/plainMonthDay.ts similarity index 100% rename from packages/temporal-polyfill/src/new/plainMonthDay.ts rename to packages/temporal-polyfill/src/plainMonthDay.ts diff --git a/packages/temporal-polyfill/src/new/plainTime.ts b/packages/temporal-polyfill/src/plainTime.ts similarity index 100% rename from packages/temporal-polyfill/src/new/plainTime.ts rename to packages/temporal-polyfill/src/plainTime.ts diff --git a/packages/temporal-polyfill/src/new/plainYearMonth.ts b/packages/temporal-polyfill/src/plainYearMonth.ts similarity index 100% rename from packages/temporal-polyfill/src/new/plainYearMonth.ts rename to packages/temporal-polyfill/src/plainYearMonth.ts diff --git a/packages/temporal-polyfill/src/new/round.ts b/packages/temporal-polyfill/src/round.ts similarity index 100% rename from packages/temporal-polyfill/src/new/round.ts rename to packages/temporal-polyfill/src/round.ts diff --git a/packages/temporal-polyfill/src/new/temporal.ts b/packages/temporal-polyfill/src/temporal.ts similarity index 100% rename from packages/temporal-polyfill/src/new/temporal.ts rename to packages/temporal-polyfill/src/temporal.ts diff --git a/packages/temporal-polyfill/src/new/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts similarity index 100% rename from packages/temporal-polyfill/src/new/timeZone.ts rename to packages/temporal-polyfill/src/timeZone.ts diff --git a/packages/temporal-polyfill/src/new/timeZoneImpl.ts b/packages/temporal-polyfill/src/timeZoneImpl.ts similarity index 100% rename from packages/temporal-polyfill/src/new/timeZoneImpl.ts rename to packages/temporal-polyfill/src/timeZoneImpl.ts diff --git a/packages/temporal-polyfill/src/new/timeZoneOps.ts b/packages/temporal-polyfill/src/timeZoneOps.ts similarity index 100% rename from packages/temporal-polyfill/src/new/timeZoneOps.ts rename to packages/temporal-polyfill/src/timeZoneOps.ts diff --git a/packages/temporal-polyfill/src/new/units.ts b/packages/temporal-polyfill/src/units.ts similarity index 100% rename from packages/temporal-polyfill/src/new/units.ts rename to packages/temporal-polyfill/src/units.ts diff --git a/packages/temporal-polyfill/src/new/utils.ts b/packages/temporal-polyfill/src/utils.ts similarity index 100% rename from packages/temporal-polyfill/src/new/utils.ts rename to packages/temporal-polyfill/src/utils.ts diff --git a/packages/temporal-polyfill/src/new/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts similarity index 100% rename from packages/temporal-polyfill/src/new/zonedDateTime.ts rename to packages/temporal-polyfill/src/zonedDateTime.ts From 93aa9c60e2211ccb7fd17432f91a22520e374081 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 19:32:15 -0400 Subject: [PATCH 174/805] small fixes --- packages/temporal-polyfill/package.json | 2 +- packages/temporal-polyfill/src/calendarConfig.ts | 2 +- packages/temporal-polyfill/src/diff.ts | 2 +- packages/temporal-polyfill/src/isoMath.ts | 5 ++--- packages/temporal-polyfill/src/isoParse.ts | 8 ++++---- packages/temporal-polyfill/src/now.ts | 2 +- packages/temporal-polyfill/tsconfig.json | 3 +++ 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index f47d2d79..6629e4ea 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -25,7 +25,7 @@ "build": "pnpm run types && pnpm run bundle", "build:dev": "pnpm run types && NO_MIN=1 pnpm run bundle", "watch": "concurrently npm:types:watch npm:bundle:watch", - "types": "tsc --build --preserveWatchOutput", + "types": "tsc --build", "types:watch": "tsc --build --preserveWatchOutput --watch", "bundle": "rollup -c ../../scripts/config/pkgBundle.cjs", "bundle:watch": "rollup -c ../../scripts/config/pkgBundle.cjs --watch", diff --git a/packages/temporal-polyfill/src/calendarConfig.ts b/packages/temporal-polyfill/src/calendarConfig.ts index 05701793..ad594816 100644 --- a/packages/temporal-polyfill/src/calendarConfig.ts +++ b/packages/temporal-polyfill/src/calendarConfig.ts @@ -1,4 +1,4 @@ -import { CalendarOps } from "./calendarOps" +import { CalendarOps } from './calendarOps' export const isoCalendarId = 'iso8601' export const gregoryCalendarId = 'gregory' diff --git a/packages/temporal-polyfill/src/diff.ts b/packages/temporal-polyfill/src/diff.ts index 186587d9..4241bca6 100644 --- a/packages/temporal-polyfill/src/diff.ts +++ b/packages/temporal-polyfill/src/diff.ts @@ -1,4 +1,4 @@ -import { TimeZoneImpl } from '../timeZoneImpl/timeZoneImpl' +import { TimeZoneImpl } from './timeZoneImpl' import { CalendarImpl } from './calendarImpl' import { CalendarOps } from './calendarOps' import { diff --git a/packages/temporal-polyfill/src/isoMath.ts b/packages/temporal-polyfill/src/isoMath.ts index bd779445..8b4a1412 100644 --- a/packages/temporal-polyfill/src/isoMath.ts +++ b/packages/temporal-polyfill/src/isoMath.ts @@ -1,4 +1,3 @@ -import { isoFieldsToEpochMilli } from '../dateUtils/epoch' import { CalendarArg } from './calendar' import { diffEpochMilliByDay } from './diff' import { @@ -69,8 +68,8 @@ export function computeIsoIsLeapYear(isoYear: number): boolean { export function computeIsoDayOfYear(isoDateFields: IsoDateFields): number { return diffEpochMilliByDay( - isoFieldsToEpochMilli(isoDateMonthStart(isoDateFields)), - isoFieldsToEpochMilli(isoDateFields), + isoToEpochMilli(isoDateMonthStart(isoDateFields))!, + isoToEpochMilli(isoDateFields)!, ) } diff --git a/packages/temporal-polyfill/src/isoParse.ts b/packages/temporal-polyfill/src/isoParse.ts index 7378dbd5..3fcaa535 100644 --- a/packages/temporal-polyfill/src/isoParse.ts +++ b/packages/temporal-polyfill/src/isoParse.ts @@ -1,4 +1,4 @@ -import { nanoIn, nanoInSecond } from '../dateUtils/units' +import { unitNanoMap, nanoInSec } from './units' import { isoCalendarId } from './calendarConfig' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { @@ -388,7 +388,7 @@ function parseOffsetParts(parts: string[]): number { return parseSign(parts[0]) * ( parseInt0(parts[0]) * nanoInHour + parseInt0(parts[2]) * nanoInMinute + - parseInt0(parts[4]) * nanoInSecond + + parseInt0(parts[4]) * nanoInSec + parseSubsecNano(parts[6] || '') ) } @@ -425,7 +425,7 @@ function parseDurationParts(parts: string[]): DurationInternals { let wholeUnits = 0 if (timeUnit) { - [leftoverUnits, leftoverNano] = divFloorMod(leftoverNano, nanoIn[timeUnit]) + [leftoverUnits, leftoverNano] = divFloorMod(leftoverNano, unitNanoMap[timeUnit]) } if (wholeStr !== undefined) { @@ -438,7 +438,7 @@ function parseDurationParts(parts: string[]): DurationInternals { if (fracStr) { // convert seconds to other units, abusing parseSubsecNano - leftoverNano = parseSubsecNano(fracStr) * (nanoIn[timeUnit!] / nanoInSecond) + leftoverNano = parseSubsecNano(fracStr) * (unitNanoMap[timeUnit!] / nanoInSec) hasAnyFrac = true } } diff --git a/packages/temporal-polyfill/src/now.ts b/packages/temporal-polyfill/src/now.ts index 28c2423b..4a3cf0d7 100644 --- a/packages/temporal-polyfill/src/now.ts +++ b/packages/temporal-polyfill/src/now.ts @@ -1,4 +1,4 @@ -import { nanoInMilli } from '../dateUtils/units' +import { nanoInMilli } from './units' import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' diff --git a/packages/temporal-polyfill/tsconfig.json b/packages/temporal-polyfill/tsconfig.json index 5005d809..6bb08d54 100644 --- a/packages/temporal-polyfill/tsconfig.json +++ b/packages/temporal-polyfill/tsconfig.json @@ -13,5 +13,8 @@ }, "include": [ "src/**/*" + ], + "exclude": [ + "src/old/**/*" ] } From e270906f4cba242d7cd5e968d0886561f3336e43 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 19:49:30 -0400 Subject: [PATCH 175/805] temporary stuff to get bundling --- packages/temporal-polyfill/package.json | 5 ----- scripts/lib/pkgBundle.cjs | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 6629e4ea..5dc7bc97 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -50,11 +50,6 @@ "require": "./dist/impl.cjs", "import": "./dist/impl.mjs" }, - "./shim": { - "types": "./dist/shim.d.ts", - "require": "./dist/shim.cjs", - "import": "./dist/shim.mjs" - }, "./global": { "types": "./dist/global.d.ts", "require": "./dist/global.cjs", diff --git a/scripts/lib/pkgBundle.cjs b/scripts/lib/pkgBundle.cjs index a5fc2f5d..409cf488 100644 --- a/scripts/lib/pkgBundle.cjs +++ b/scripts/lib/pkgBundle.cjs @@ -46,6 +46,7 @@ async function buildPkgBundleConfigs(pkgDir, commandLineArgs) { }) } + /* if (entryPointTypes.length && !watch) { configs.push({ input: createTypeInputHash(entryPointTypes.map((f) => path.join(pkgDir, f))), @@ -54,6 +55,7 @@ async function buildPkgBundleConfigs(pkgDir, commandLineArgs) { plugins: [dts(), typePreparing(pkgDir)], }) } + */ return configs } From 4dfd3dfab2ffddcbea3c1c48e829605f78d53ab7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 20:15:20 -0400 Subject: [PATCH 176/805] upgrade terser --- package.json | 2 +- pnpm-lock.yaml | 430 +++++++++++++++++++++++++------------------------ 2 files changed, 221 insertions(+), 211 deletions(-) diff --git a/package.json b/package.json index 9ac92918..8405737b 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@typescript-eslint/parser": "^4.22.1", "colors": "^1.4.0", "deepmerge": "^4.2.2", - "esbuild": "^0.14.38", + "esbuild": "^0.18.17", "eslint": "^7.25.0", "eslint-config-standard": "^16.0.3", "eslint-import-resolver-node": "^0.3.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1979f85..ba93a9ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,8 +41,8 @@ importers: specifier: ^4.2.2 version: 4.3.0 esbuild: - specifier: ^0.14.38 - version: 0.14.54 + specifier: ^0.18.17 + version: 0.18.17 eslint: specifier: ^7.25.0 version: 7.32.0 @@ -75,7 +75,7 @@ importers: version: 3.0.2(rollup@2.79.1)(typescript@5.1.6) rollup-plugin-esbuild: specifier: ^4.9.1 - version: 4.10.3(esbuild@0.14.54)(rollup@2.79.1) + version: 4.10.3(esbuild@0.18.17)(rollup@2.79.1) rollup-plugin-terser: specifier: ^7.0.2 version: 7.0.2(rollup@2.79.1) @@ -1412,8 +1412,98 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@esbuild/linux-loong64@0.14.54: - resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} + /@esbuild/android-arm64@0.18.17: + resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.17: + resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.17: + resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.17: + resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.17: + resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.17: + resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.17: + resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.17: + resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.17: + resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.17: + resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.17: + resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -1421,6 +1511,105 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.18.17: + resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.17: + resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.17: + resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.17: + resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.17: + resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.17: + resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.17: + resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.17: + resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.17: + resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.17: + resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.17: + resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint/eslintrc@0.4.3: resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2752,213 +2941,34 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild-android-64@0.14.54: - resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-android-arm64@0.14.54: - resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-64@0.14.54: - resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-arm64@0.14.54: - resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-64@0.14.54: - resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-arm64@0.14.54: - resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-32@0.14.54: - resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-64@0.14.54: - resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm64@0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm@0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-mips64le@0.14.54: - resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-ppc64le@0.14.54: - resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-riscv64@0.14.54: - resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-s390x@0.14.54: - resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-netbsd-64@0.14.54: - resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-openbsd-64@0.14.54: - resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-sunos-64@0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-32@0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-64@0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-arm64@0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild@0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} + /esbuild@0.18.17: + resolution: {integrity: sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/linux-loong64': 0.14.54 - esbuild-android-64: 0.14.54 - esbuild-android-arm64: 0.14.54 - esbuild-darwin-64: 0.14.54 - esbuild-darwin-arm64: 0.14.54 - esbuild-freebsd-64: 0.14.54 - esbuild-freebsd-arm64: 0.14.54 - esbuild-linux-32: 0.14.54 - esbuild-linux-64: 0.14.54 - esbuild-linux-arm: 0.14.54 - esbuild-linux-arm64: 0.14.54 - esbuild-linux-mips64le: 0.14.54 - esbuild-linux-ppc64le: 0.14.54 - esbuild-linux-riscv64: 0.14.54 - esbuild-linux-s390x: 0.14.54 - esbuild-netbsd-64: 0.14.54 - esbuild-openbsd-64: 0.14.54 - esbuild-sunos-64: 0.14.54 - esbuild-windows-32: 0.14.54 - esbuild-windows-64: 0.14.54 - esbuild-windows-arm64: 0.14.54 + '@esbuild/android-arm': 0.18.17 + '@esbuild/android-arm64': 0.18.17 + '@esbuild/android-x64': 0.18.17 + '@esbuild/darwin-arm64': 0.18.17 + '@esbuild/darwin-x64': 0.18.17 + '@esbuild/freebsd-arm64': 0.18.17 + '@esbuild/freebsd-x64': 0.18.17 + '@esbuild/linux-arm': 0.18.17 + '@esbuild/linux-arm64': 0.18.17 + '@esbuild/linux-ia32': 0.18.17 + '@esbuild/linux-loong64': 0.18.17 + '@esbuild/linux-mips64el': 0.18.17 + '@esbuild/linux-ppc64': 0.18.17 + '@esbuild/linux-riscv64': 0.18.17 + '@esbuild/linux-s390x': 0.18.17 + '@esbuild/linux-x64': 0.18.17 + '@esbuild/netbsd-x64': 0.18.17 + '@esbuild/openbsd-x64': 0.18.17 + '@esbuild/sunos-x64': 0.18.17 + '@esbuild/win32-arm64': 0.18.17 + '@esbuild/win32-ia32': 0.18.17 + '@esbuild/win32-x64': 0.18.17 dev: true /escalade@3.1.1: @@ -4978,7 +4988,7 @@ packages: '@babel/code-frame': 7.18.6 dev: true - /rollup-plugin-esbuild@4.10.3(esbuild@0.14.54)(rollup@2.79.1): + /rollup-plugin-esbuild@4.10.3(esbuild@0.18.17)(rollup@2.79.1): resolution: {integrity: sha512-RILwUCgnCL5vo8vyZ/ZpwcqRuE5KmLizEv6BujBQfgXFZ6ggcS0FiYvQN+gsTJfWCMaU37l0Fosh4eEufyO97Q==} engines: {node: '>=12'} peerDependencies: @@ -4988,7 +4998,7 @@ packages: '@rollup/pluginutils': 4.2.1 debug: 4.3.4 es-module-lexer: 0.9.3 - esbuild: 0.14.54 + esbuild: 0.18.17 joycon: 3.1.1 jsonc-parser: 3.2.0 rollup: 2.79.1 From d5e3d43344ac96d328526eb9435551a2e89f4930 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 26 Jul 2023 20:39:17 -0400 Subject: [PATCH 177/805] modify size script --- scripts/pkgSize.cjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/pkgSize.cjs b/scripts/pkgSize.cjs index a521945b..db1a21f5 100644 --- a/scripts/pkgSize.cjs +++ b/scripts/pkgSize.cjs @@ -20,10 +20,12 @@ async function printPkgSize(pkgDir) { for (const filename of filenames) { if ( - !filename.match(/\.map$/) && - !filename.match(/\.cjs$/) + // !filename.match(/\.map$/) && + // !filename.match(/\.cjs$/) + filename.match(/\.js$/) ) { const filePath = path.join(distDir, filename) + console.log(filename) const { stdout } = await exec(`gzip -c -r ${filePath} | wc -c`) const fileBytes = parseInt(stdout.trim()) bytes = Math.max(bytes, fileBytes) From a8a06cf9c6b7ea43127fbb747df65cc2f8f08508 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Fri, 28 Jul 2023 00:23:20 -0400 Subject: [PATCH 178/805] many more ts corrections --- packages/temporal-polyfill/src/calendar.ts | 40 ++++++++--------- .../temporal-polyfill/src/calendarFields.ts | 15 ++++--- .../temporal-polyfill/src/calendarImpl.ts | 32 +++++++++----- packages/temporal-polyfill/src/calendarOps.ts | 30 ++++++------- packages/temporal-polyfill/src/class.ts | 19 ++++---- packages/temporal-polyfill/src/convert.ts | 40 ++++++++++------- packages/temporal-polyfill/src/diff.ts | 4 +- packages/temporal-polyfill/src/duration.ts | 43 ++++++++++++------- .../temporal-polyfill/src/durationFields.ts | 14 +++--- packages/temporal-polyfill/src/instant.ts | 28 +++++++----- packages/temporal-polyfill/src/isoMath.ts | 35 ++++++++++++--- packages/temporal-polyfill/src/move.ts | 9 ++-- packages/temporal-polyfill/src/options.ts | 15 ++++--- packages/temporal-polyfill/src/plainDate.ts | 28 ++++++------ packages/temporal-polyfill/src/units.ts | 3 ++ packages/temporal-polyfill/src/utils.ts | 17 +------- 16 files changed, 223 insertions(+), 149 deletions(-) diff --git a/packages/temporal-polyfill/src/calendar.ts b/packages/temporal-polyfill/src/calendar.ts index 35d6e1fd..9c3dc427 100644 --- a/packages/temporal-polyfill/src/calendar.ts +++ b/packages/temporal-polyfill/src/calendar.ts @@ -1,4 +1,4 @@ -import { dateGetterNames } from './calendarFields' +import { DateGetterFields, dateGetterNames } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { TemporalInstance, createTemporalClass, getInternals, getObjId, getTemporalName, idGetters } from './class' import { @@ -8,6 +8,7 @@ import { refinePlainYearMonthBag, } from './convert' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' +import { IsoDateFields } from './isoFields' import { parseCalendarId } from './isoParse' import { ensureObjectlike, @@ -16,6 +17,7 @@ import { refineOverflowOptions, } from './options' import { PlainDate, PlainDateArg, createPlainDate, toPlainDateInternals } from './plainDate' +import { PlainDateTime } from './plainDateTime' import { PlainMonthDay, createPlainMonthDay } from './plainMonthDay' import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' import { TimeZone } from './timeZone' @@ -53,7 +55,7 @@ export interface CalendarProtocol extends CalendarProtocolMethods{ } // TODO: compress this somehow -const dateArgWhitelist = { +const dateArgWhitelist: Record = { era: 'PlainYearMonth', eraYear: 'PlainYearMonth', year: 'PlainYearMonth', @@ -66,19 +68,25 @@ const dateArgWhitelist = { day: 'PlainMonthDay', } -// the *required* protocol methods +type DateArg = PlainYearMonth | PlainMonthDay | PlainDateTime | PlainDateArg + +/* +the *required* protocol methods +*/ export const calendarProtocolMethods = { - ...mapPropNames((propName) => { - const whitelistName = dateArgWhitelist[propName as keyof typeof dateArgWhitelist] + ...mapPropNames((propName: keyof DateGetterFields) => { + const whitelistName = dateArgWhitelist[propName] - return ((impl: CalendarImpl, dateArg: any) => { - const isoFields = whitelistName && (getTemporalName(dateArg) || '').includes(whitelistName) - ? getInternals(dateArg) - : toPlainDateInternals(dateArg) + return (impl: CalendarImpl, dateArg: DateArg) => { + const inWhitelist = whitelistName && (getTemporalName(dateArg) || '').includes(whitelistName) + const getInternalsFunc = inWhitelist ? getInternals : toPlainDateInternals + const isoFields = getInternalsFunc(dateArg) as IsoDateFields return impl[propName](isoFields) - }) as any - }, dateGetterNames), + } + }, dateGetterNames) as { + [K in keyof DateGetterFields]: (impl: CalendarImpl, dateArg: any) => DateGetterFields[K] + }, dateAdd( impl: CalendarImpl, @@ -147,15 +155,7 @@ export const calendarProtocolMethods = { }, } -// TODO: move elsewhere -// TODO: use TS `satisfies` on main class? -type Unmethodize = F extends ((...args: infer A) => infer R) - ? (impl: CalendarImpl, ...args: A) => R - : never - -const calendarMethods: { - [K in keyof CalendarProtocolMethods]: Unmethodize -} = { +const calendarMethods = { ...calendarProtocolMethods, toString: getObjId, } diff --git a/packages/temporal-polyfill/src/calendarFields.ts b/packages/temporal-polyfill/src/calendarFields.ts index 21bd7a08..0b96d8a1 100644 --- a/packages/temporal-polyfill/src/calendarFields.ts +++ b/packages/temporal-polyfill/src/calendarFields.ts @@ -199,12 +199,17 @@ export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) as export const dateStatNames = Object.keys(dateStatRefiners) as (keyof DateStats)[] +export type DateGetterFields = EraYearFields & DateFields & DateStats + +export const dateGetterRefiners = { + ...eraYearFieldRefiners, + ...dateFieldRefiners, + ...dateStatRefiners, +} + // unordered -export const dateGetterNames = [ - ...eraYearFieldNames, - ...dateFieldNames, - ...dateStatNames, -] +export const dateGetterNames = Object.keys(dateGetterRefiners) as + (keyof DateGetterFields)[] // unordered export const yearMonthGetterNames = [ diff --git a/packages/temporal-polyfill/src/calendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl.ts index 70488e89..54fa012e 100644 --- a/packages/temporal-polyfill/src/calendarImpl.ts +++ b/packages/temporal-polyfill/src/calendarImpl.ts @@ -9,6 +9,7 @@ import { leapYearMetas, } from './calendarConfig' import { + AllYearFields, allYearFieldNames, eraYearFieldNames, monthDayFieldNames, @@ -41,7 +42,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { Overflow } from './options' import { Unit, milliInDay } from './units' -import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './utils' +import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2, remapProps } from './utils' import { CalendarOps } from './calendarOps' import { DurationInternals } from './durationFields' @@ -173,7 +174,7 @@ export class CalendarImpl implements CalendarOps { const dayEpochMilli = isoToEpochMilli({ ...isoDateFields, ...isoTimeFieldDefaults, - }) + })! const yearStartEpochMilli = this.queryDateStart(this.year(isoDateFields)) return diffEpochMilliByDay(yearStartEpochMilli, dayEpochMilli) } @@ -280,15 +281,19 @@ interface YearMethods { monthsInYear(isoFields: IsoDateFields): number } +type VeryGeneric = any + const yearMethods = {} as YearMethods -Object.keys(yearComputeMethods).forEach((queryMethodName, i) => { +( + Object.keys(yearComputeMethods) as (keyof YearComputeMethods)[] +).forEach((computeMethodName, i) => { yearMethods[yearStatNames[i]] = function( this: CalendarImpl, isoDateFields: IsoDateFields, ) { - return this[queryMethodName as keyof YearMethods](this.year(isoDateFields)) - } as any + return this[computeMethodName](this.year(isoDateFields)) + } as VeryGeneric }) // Base Calendar Implementation :: Week Methods @@ -573,14 +578,21 @@ class IntlCalendarImpl extends CalendarImpl { // IntlCalendarImpl - Prototype Trickery // ------------------------------------------------------------------------------------------------- -// era/eraYear/year/day -[...allYearFieldNames, 'day'].forEach((dateFieldName) => { - (IntlCalendarImpl as any).prototype[dateFieldName] = function( +type EasyIntlMethodName = keyof AllYearFields | 'day' + +/* +era/eraYear/year/day +Fields that are easily-extractable from IntlFields (non-month fields) +*/ +( + [...allYearFieldNames, 'day'] as EasyIntlMethodName[] +).forEach((dateFieldName) => { + IntlCalendarImpl.prototype[dateFieldName] = function( this: IntlCalendarImpl, isoDateFields: IsoDateFields, ) { - return (this.isoDateFieldsToIntl(isoDateFields) as any)[dateFieldName] - } + return this.isoDateFieldsToIntl(isoDateFields)[dateFieldName as EasyIntlMethodName] + } as VeryGeneric }) // CalendarImpl Querying diff --git a/packages/temporal-polyfill/src/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts index 1bc899e5..0cfe1769 100644 --- a/packages/temporal-polyfill/src/calendarOps.ts +++ b/packages/temporal-polyfill/src/calendarOps.ts @@ -1,5 +1,5 @@ import { Calendar, CalendarArg, CalendarProtocol, calendarProtocolMethods, createCalendar } from './calendar' -import { dateFieldRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' +import { DateGetterFields, dateFieldRefiners, dateGetterRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { createProtocolChecker, @@ -42,9 +42,9 @@ export interface CalendarOps { dateFromFields(fields: any, overflow: Overflow): IsoDateInternals yearMonthFromFields(fields: any, overflow: Overflow): IsoDateInternals monthDayFromFields(fields: any, overflow: Overflow): IsoDateInternals - dateAdd(isoFields: IsoDateFields, durationInternals: DurationInternals, overflow: Overflow): IsoDateFields + dateAdd(isoFields: IsoDateFields, durationInternals: DurationInternals, overflow: Overflow): IsoDateInternals dateUntil(isoFields0: IsoDateFields, isoFields1: IsoDateFields, options: any): DurationInternals - fields(fieldNames: Iterable): Iterable + fields(fieldNames: string[]): string[] mergeFields(fields0: any, fields1: any): any } @@ -55,7 +55,7 @@ const checkCalendarProtocol = createProtocolChecker(calendarProtocolMethods) export function queryCalendarOps(calendarArg: CalendarArg): CalendarOps { if (typeof calendarArg === 'object') { if (calendarArg instanceof Calendar) { - return getInternals(calendarArg) + return getInternals(calendarArg as Calendar) } checkCalendarProtocol(calendarArg) @@ -107,15 +107,13 @@ const getDurationInternals = getStrictInternals.bind< const calendarOpsAdapterMethods = { ...mapProps((refiner, propName) => { - return ((calendar: CalendarProtocol, isoDateFields: IsoDateInternals) => { - return refiner(calendar[propName](createPlainDate(isoDateFields)) as any) - }) as any - }, { - // TODO: more DRY with DateGetters or something? - ...eraYearFieldRefiners, - ...dateFieldRefiners, - ...dateStatRefiners, - }), + return ((calendar: CalendarProtocol, isoDateFields: IsoDateFields) => { + // TODO: fix type error by having more specific refiner inputs + return refiner(calendar[propName](createPlainDate(isoDateFields))) + }) + }, dateGetterRefiners) as { + [K in keyof DateGetterFields]: (calendar: CalendarProtocol, isoFields: IsoDateFields) => DateGetterFields[K] + }, dateAdd( calendar: CalendarProtocol, @@ -140,8 +138,8 @@ const calendarOpsAdapterMethods = { ): DurationInternals { return getDurationInternals( calendar.dateUntil( - createPlainDate(isoDateFields0), - createPlainDate(isoDateFields1), + createPlainDate(isoDateFields0 as IsoDateInternals), // hopefully internal calendar never used + createPlainDate(isoDateFields1 as IsoDateInternals), // " { largestUnit: unitNamesAsc[largestUnit] }, ) ) @@ -159,7 +157,7 @@ const calendarOpsAdapterMethods = { return getPlainMonthDayInternals(calendar.monthDayFromFields(fields, { overflow })) }, - fields(calendar: CalendarProtocol, fieldNames: Iterable): Iterable { + fields(calendar: CalendarProtocol, fieldNames: string[]): string[] { return [...calendar.fields(fieldNames)].map(ensureString) // TODO: kill ensureArray elsewhere? }, diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index e9639447..fd22e443 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -148,14 +148,14 @@ export function createTemporalClass< A extends any[], I, O, - G extends { [propName: string]: (internals: I) => unknown }, - M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, + G extends { [propName: string]: (this: TemporalInstance, internals: I) => unknown }, + M extends { [methodName: string]: (this: TemporalInstance, internals: I, ...args: any[]) => unknown }, S extends {} >( temporalName: string, constructorToInternals: (...args: A) => I = (identityFunc as any), internalsConversionMap: { [typeName: string]: (otherInternal: any) => I }, - bagToInternals: (bag: B, options?: O) => I, + bagToInternals: (bag: B, options?: O) => I | void, // void opts-out of bag processing stringToInternals: (str: string) => I, handleUnusedOptions: (options?: O) => void, getters: G, @@ -233,14 +233,17 @@ export function neverValueOf() { // Complex Objects with IDs // ------------------------------------------------------------------------------------------------- -// any - Record unknown> -export function createProtocolChecker(protocolMethods: any) { - const propNames = Object.keys(protocolMethods) +export function createProtocolChecker

( + protocolMethods: P +): ( + (obj: { [K in keyof P]: any } & { id: string }) => void +) { + const propNames = Object.keys(protocolMethods) as (keyof (P & { id: string }))[] propNames.push('id') propNames.sort() // TODO: order matters? - return (obj: Record) => { - if (!hasAllPropsByName(obj, propNames)) { + return (obj) => { + if (!hasAllPropsByName

(obj, propNames)) { throw new TypeError('Invalid protocol') } } diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index ebedfa42..3c9041de 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -6,6 +6,7 @@ import { } from './calendarConfig' import { DateFields, + TimeFields, dateFieldNames, dateTimeFieldNames, dateTimeFieldRefiners, @@ -19,7 +20,7 @@ import { } from './calendarFields' import { queryCalendarImpl } from './calendarImpl' import { CalendarOps, queryCalendarOps } from './calendarOps' -import { getInternals } from './class' +import { TemporalInstance, getInternals } from './class' import { DurationBag, DurationMod } from './duration' import { DurationInternals, @@ -27,7 +28,7 @@ import { durationFieldRefiners, updateDurationFieldsSign, } from './durationFields' -import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields } from './isoFields' +import { CalendarInternals, IsoDateInternals, IsoDateTimeInternals, IsoTimeFields } from './isoFields' import { constrainIsoTimeFields, isoEpochFirstLeapYear } from './isoMath' import { parseOffsetNano } from './isoParse' import { @@ -46,7 +47,7 @@ import { PlainMonthDay, createPlainMonthDay } from './plainMonthDay' import { PlainTime } from './plainTime' import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' +import { Reused, excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' import { ZonedDateTime, ZonedDateTimeBag, ZonedInternals, createZonedDateTime } from './zonedDateTime' /* @@ -258,7 +259,7 @@ export function mergePlainDateBag( } function convertToIso( - input: any, + input: PlainYearMonth | PlainMonthDay, inputFieldNames: string[], extra: any, extraFieldNames: string[], @@ -266,7 +267,7 @@ function convertToIso( const { calendar } = getInternals(input) inputFieldNames = calendar.fields(inputFieldNames) - input = pluckProps(inputFieldNames, input) + input = pluckProps(inputFieldNames, input as Record) as Reused extraFieldNames = calendar.fields(extraFieldNames) extra = refineFields(extra, extraFieldNames, getRequiredDateFields(calendar)) @@ -275,7 +276,7 @@ function convertToIso( const mergedFieldNames = excludeArrayDuplicates([...inputFieldNames, ...extraFieldNames]) mergedFields = refineFields(mergedFields, mergedFieldNames, []) - return calendar.dateFromFields(mergedFields) + return calendar.dateFromFields(mergedFields, Overflow.Constrain) } // PlainYearMonth @@ -420,7 +421,7 @@ export function refinePlainTimeBag(bag: any, options: any): IsoTimeFields { } export function mergePlainTimeBag(plainTime: PlainTime, bag: any, options: any): IsoTimeFields { - const fields = pluckProps(timeFieldNames, plainTime) + const fields = pluckProps(timeFieldNames, plainTime as unknown as TimeFields) // TODO: wish PlainTime had real TS methods const partialFields = refineFields(bag, timeFieldNames) const mergeFields = { ...fields, ...partialFields } @@ -485,13 +486,16 @@ function getBagCalendarOps(bag: any): CalendarOps { return extractBagCalendarOps(bag) || queryCalendarImpl(isoCalendarId) } -function extractBagCalendarOps(bag: any): CalendarOps | undefined { - let { calendar } = getInternals(bag) || {} +function extractBagCalendarOps( + bag: TemporalInstance | { calendar: string }, +): CalendarOps | undefined { + let calendar: CalendarOps | string | undefined = (getInternals(bag) || {}).calendar + if (calendar) { return calendar // CalendarOps } - ({ calendar } = bag) + calendar = (bag as { calendar: string }).calendar if (calendar) { return queryCalendarOps(calendar) } @@ -536,8 +540,8 @@ function refineFields( if (fieldVal !== undefined) { any = true - if (builtinRefiners[fieldName]) { - fieldVal = builtinRefiners[fieldName] + if (builtinRefiners[fieldName as keyof typeof builtinRefiners]) { + fieldVal = builtinRefiners[fieldName as keyof typeof builtinRefiners](fieldVal) } res[fieldName] = fieldVal @@ -546,7 +550,7 @@ function refineFields( throw new TypeError('Missing required field name') } - res[fieldName] = builtinDefaults[fieldName] + res[fieldName] = builtinDefaults[fieldName as keyof typeof builtinDefaults] } } @@ -557,8 +561,12 @@ function refineFields( return res } -export function refineComplexBag(key: string, ForbiddenClass: any, bag: any): any { - const internalArg = getInternals(bag)?.[key] +export function refineComplexBag( + key: K, + ForbiddenClass: unknown, + bag: TemporalInstance> | Record, +): unknown { + const internalArg = getInternals(bag as TemporalInstance>)?.[key] if (internalArg) { return internalArg } @@ -568,7 +576,7 @@ export function refineComplexBag(key: string, ForbiddenClass: any, bag: any): an if (!(key in bag)) { return bag } else { - bag = bag[key] + bag = (bag as Record)[key] forbidInstanceClass(bag, ForbiddenClass) diff --git a/packages/temporal-polyfill/src/diff.ts b/packages/temporal-polyfill/src/diff.ts index 4241bca6..e44a7394 100644 --- a/packages/temporal-polyfill/src/diff.ts +++ b/packages/temporal-polyfill/src/diff.ts @@ -112,13 +112,13 @@ export function diffDates( return roundRelativeDuration( dateDiff, - isoToEpochNano(endIsoFields), + isoToEpochNano(endIsoFields)!, largestUnit, smallestUnit, roundingInc, roundingMode, startIsoFields, // marker - isoToEpochNano, // markerToEpochNano + isoToEpochNano, // markerToEpochNano // TODO --- stop doing isoToEpochNano*!* calendar.dateAdd.bind(calendar), // moveMarker ) } diff --git a/packages/temporal-polyfill/src/duration.ts b/packages/temporal-polyfill/src/duration.ts index e2a4a7c4..e39433b0 100644 --- a/packages/temporal-polyfill/src/duration.ts +++ b/packages/temporal-polyfill/src/duration.ts @@ -15,7 +15,7 @@ import { } from './durationFields' import { formatDurationInternals } from './isoFormat' import { parseDuration } from './isoParse' -import { compareLargeInts } from './largeInt' +import { LargeInt, compareLargeInts } from './largeInt' import { SubsecDigits, refineDurationRoundOptions, @@ -133,7 +133,9 @@ export const [ if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { // TODO: check internals doesn't have large fields return createDuration( - roundDayTimeDuration(internals, smallestUnit, roundingInc, roundingMode), + updateDurationFieldsSign( + roundDayTimeDuration(internals, smallestUnit as DayTimeUnit, roundingInc, roundingMode), + ) ) } @@ -144,23 +146,28 @@ export const [ const markerSystem = createMarkerSystem(markerInternals) return createDuration( - roundRelativeDuration( - ...spanDuration(internals, largestUnit, ...markerSystem), - largestUnit, - smallestUnit, - roundingInc, - roundingMode, - ...(markerSystem as unknown as [Marker, MarkerToEpochNano, MoveMarker]), + updateDurationFieldsSign( + roundRelativeDuration( + ...spanDuration(internals, largestUnit, ...markerSystem), + largestUnit, + smallestUnit, + roundingInc, + roundingMode, + ...(markerSystem as unknown as [Marker, MarkerToEpochNano, MoveMarker]), + ), ), ) }, total(internals: DurationInternals, options): number { - const [totalUnitIndex, markerInternals] = refineTotalOptions(options) - const largestUnit = getLargestDurationUnit(internals) + const [totalUnit, markerInternals] = refineTotalOptions(options) + const largestUnit = Math.max( + getLargestDurationUnit(internals), + totalUnit, + ) as Unit if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { - return totalDayTimeDuration(internals, totalUnitIndex) + return totalDayTimeDuration(internals, totalUnit as DayTimeUnit) } if (!markerInternals) { @@ -171,7 +178,7 @@ export const [ return totalRelativeDuration( ...spanDuration(internals, largestUnit, ...markerSystem), - totalUnitIndex, + totalUnit, ...(markerSystem as unknown as [Marker, MarkerToEpochNano, MoveMarker]), ) }, @@ -180,7 +187,7 @@ export const [ const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options, Unit.Second) return formatDurationInternals( - roundDurationToNano(internals, nanoInc, roundingMode), + updateDurationFieldsSign(roundDurationToNano(internals, nanoInc, roundingMode)), subsecDigits as (SubsecDigits | undefined), // -1 won't happen (units can't be minutes) ) }, @@ -199,7 +206,7 @@ export const [ const largestUnit = Math.max( getLargestDurationUnit(durationFields0), getLargestDurationUnit(durationFields1), - ) + ) as Unit if (largestUnit < Unit.Day || (largestUnit === Unit.Day && !markerInternals)) { return compareLargeInts( @@ -244,6 +251,10 @@ function addToDuration( return balanceDurationDayTime(addedDurationFields, largestUnit as DayTimeUnit) } + if (!markerInternals) { + throw new RangeError('relativeTo is required for years, months, or weeks arithmetic') + } + const markerSystem = createMarkerSystem(markerInternals) return createDuration(spanDuration(internals, largestUnit, ...markerSystem)[0]) } @@ -258,7 +269,7 @@ function spanDuration( diffMarkers: DiffMarkers, ): [ DurationInternals, - Marker, + LargeInt, ] { const endMarker = markerToEpochNano(moveMarker(marker, durationFields)) const balancedDuration = diffMarkers(marker, endMarker, largestUnit) diff --git a/packages/temporal-polyfill/src/durationFields.ts b/packages/temporal-polyfill/src/durationFields.ts index 573d4a3e..505aa88b 100644 --- a/packages/temporal-polyfill/src/durationFields.ts +++ b/packages/temporal-polyfill/src/durationFields.ts @@ -137,6 +137,7 @@ export function nanoToDurationFields( const [largeUnitNum, remainder] = largeNano.divTruncMod(divisor) return { + ...durationFieldDefaults, [durationFieldNamesAsc[largestUnit]]: largeUnitNum.toNumber(), ...nanoToGivenFields(remainder, largestUnit - 1, durationFieldNamesAsc), } @@ -146,11 +147,14 @@ export function timeNanoToDurationFields( nano: number, largestUnit: TimeUnit = Unit.Hour, ): DurationFields { - return nanoToGivenFields( - nano, - largestUnit, - durationFieldNamesAsc, - ) + return { + ...durationFieldDefaults, + ...nanoToGivenFields( + nano, + largestUnit, + durationFieldNamesAsc, + ) + } } // Field Math diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index ca5320f5..dd194e1a 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -3,7 +3,7 @@ import { queryCalendarOps } from './calendarOps' import { TemporalInstance, createTemporalClass, neverValueOf } from './class' import { diffEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' -import { negateDurationInternals } from './durationFields' +import { negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { formatIsoDateTimeFields, formatOffsetNano } from './isoFormat' import { epochGetters, @@ -17,6 +17,7 @@ import { parseInstant } from './isoParse' import { LargeInt, compareLargeInts } from './largeInt' import { moveEpochNano } from './move' import { + RoundingMode, ensureObjectlike, refineDiffOptions, refineInstantDisplayOptions, @@ -27,7 +28,7 @@ import { computeNanoInc, roundByIncLarge } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { noop } from './utils' import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' -import { Unit } from './units' +import { TimeUnit, Unit } from './units' import { TimeZoneArg } from './timeZone' export type InstantArg = Instant | string @@ -75,7 +76,7 @@ export const [ return createZonedDateTime({ epochNanoseconds: epochNano, timeZone: queryTimeZoneOps(timeZoneArg), - calendar: isoCalendarId, + calendar: queryCalendarOps(isoCalendarId), }) }, @@ -116,10 +117,10 @@ export const [ }, round(epochNano: LargeInt, options): Instant { - const [smallestUnitI, roundingInc, roundingModeI] = refineRoundOptions(options, Unit.Hour) + const [smallestUnit, roundingInc, roundingModeI] = refineRoundOptions(options, Unit.Hour) return createInstant( - roundByIncLarge(epochNano, computeNanoInc(smallestUnitI, roundingInc), roundingModeI), + roundByIncLarge(epochNano, computeNanoInc(smallestUnit as TimeUnit, roundingInc), roundingModeI), ) }, @@ -134,12 +135,12 @@ export const [ const [ timeZoneArg, nanoInc, - roundingModeI, + roundingMode, subsecDigits, ] = refineInstantDisplayOptions(options) const timeZone = queryTimeZoneOps(timeZoneArg || utcTimeZoneId) - epochNano = roundByIncLarge(epochNano, nanoInc, roundingModeI) + epochNano = roundByIncLarge(epochNano, nanoInc, roundingMode) const offsetNano = timeZone.getOffsetNanosecondsFor(epochNano) const isoFields = epochNanoToIso(epochNano.addNumber(offsetNano)) @@ -184,10 +185,15 @@ function diffInstants( roundingModeInvert?: boolean ): Duration { return createDuration( - diffEpochNano( - epochNano0, - epochNano1, - ...refineDiffOptions(roundingModeInvert, options, secondsIndex, hourIndex), + updateDurationFieldsSign( + diffEpochNano( + epochNano0, + epochNano1, + ...( + refineDiffOptions(roundingModeInvert, options, Unit.Second, Unit.Hour) as + [TimeUnit, TimeUnit, number, RoundingMode] + ), + ), ), ) } diff --git a/packages/temporal-polyfill/src/isoMath.ts b/packages/temporal-polyfill/src/isoMath.ts index 8b4a1412..7f167440 100644 --- a/packages/temporal-polyfill/src/isoMath.ts +++ b/packages/temporal-polyfill/src/isoMath.ts @@ -27,7 +27,7 @@ import { nanoToGivenFields, secInDay, } from './units' -import { compareProps, divFloorMod, mapPropsWithRefiners } from './utils' +import { NumSign, compareNumbers, divFloorMod, mapPropsWithRefiners } from './utils' // ISO Calendar // ------------------------------------------------------------------------------------------------- @@ -251,8 +251,8 @@ export function isoTimeFieldsToNano(isoTimeFields: IsoTimeFields): number { export function nanoToIsoTimeAndDay(nano: number): [IsoTimeFields, number] { const [dayDelta, timeNano] = divFloorMod(nano, nanoInUtcDay) - const isoTimeFields = nanoToGivenFields(timeNano, Unit.Hour, isoTimeFieldNamesAsc) - return [isoTimeFields as IsoTimeFields, dayDelta] + const isoTimeFields = nanoToGivenFields(timeNano, Unit.Hour, isoTimeFieldNamesAsc) as IsoTimeFields + return [isoTimeFields, dayDelta] } // Epoch Unit Conversion @@ -431,5 +431,30 @@ export function epochMilliToIso(epochMilli: number): { // Comparison // ------------------------------------------------------------------------------------------------- -export const compareIsoDateTimeFields = compareProps.bind(undefined, isoDateTimeFieldNamesAsc) -export const compareIsoTimeFields = compareProps.bind(undefined, isoTimeFieldNamesAsc) +export function compareIsoDateTimeFields( + isoFields0: IsoDateTimeFields, + isoFields1: IsoDateTimeFields, +): NumSign { + return compareIsoDateFields(isoFields0, isoFields1) || + compareIsoTimeFields(isoFields0, isoFields1) +} + +export function compareIsoDateFields( + isoFields0: IsoDateFields, + isoFields1: IsoDateFields, +): NumSign { + return compareNumbers( + isoToEpochMilli(isoFields0)!, + isoToEpochMilli(isoFields1)!, + ) +} + +export function compareIsoTimeFields( + isoFields0: IsoTimeFields, + isoFields1: IsoTimeFields, +): NumSign { + return compareNumbers( + isoTimeFieldsToNano(isoFields0), + isoTimeFieldsToNano(isoFields1) + ) +} diff --git a/packages/temporal-polyfill/src/move.ts b/packages/temporal-polyfill/src/move.ts index 054576c0..5d6fcde7 100644 --- a/packages/temporal-polyfill/src/move.ts +++ b/packages/temporal-polyfill/src/move.ts @@ -9,7 +9,7 @@ import { durationTimeFieldsToIsoStrict, updateDurationFieldsSign, } from './durationFields' -import { IsoDateFields, IsoDateTimeFields, IsoTimeFields } from './isoFields' +import { IsoDateFields, IsoDateInternals, IsoDateTimeFields, IsoTimeFields } from './isoFields' import { epochMilliToIso, isoDaysInWeek, @@ -99,7 +99,7 @@ export function moveDate( isoDateFields: IsoDateFields, durationFields: DurationFields, overflowHandling: Overflow, -) { +): IsoDateInternals { let { years, months, weeks, days } = durationFields let epochMilli: number | undefined @@ -124,7 +124,10 @@ export function moveDate( } else if (weeks || days) { epochMilli = isoToEpochMilli(isoDateFields) } else { - return isoDateFields + return { // TODO: not nice + calendar, + ...isoDateFields + } } epochMilli! += (weeks * isoDaysInWeek + days) * milliInDay diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index 3f467841..cab1e576 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -6,6 +6,7 @@ import { parseMaybeZonedDateTime } from './isoParse' import { LargeInt, bigIntToLargeInt } from './largeInt' import { PlainDate } from './plainDate' import { PlainDateTime } from './plainDateTime' +import { TimeZoneArg } from './timeZone' import { DayTimeUnit, TimeUnit, Unit, UnitName, unitNameMap, unitNanoMap } from './units' import { FilterPropValues, @@ -95,6 +96,10 @@ export type RoundTuple = [ RoundingMode, ] +const smallestUnitStr = 'smallestUnit' +const largestUnitStr = 'largestUnit' +const totalUnitStr = 'unit' + /* Always related to time */ @@ -148,14 +153,14 @@ export function refineRelativeToOptions(options: Options | undefined): RelativeT } export type InstantDisplayTuple = [ - string, // TimeZoneArg + TimeZoneArg, ...TimeDisplayTuple, ] export function refineInstantDisplayOptions(options: Options | undefined): InstantDisplayTuple { options = normalizeOptions(options) return [ - options.timeZone, + options.timeZone as TimeZoneArg, // TODO: possibly not needed after moving away from Record ...refineTimeDisplayTuple(options), ] } @@ -238,9 +243,9 @@ function refineTimeDisplayTuple( } -const refineSmallestUnit = refineUnitOption.bind(undefined, 'smallestUnit') -const refineLargestUnit = refineUnitOption.bind(undefined, 'largestUnit') -const refineTotalUnit = refineUnitOption.bind(undefined, 'totalUnit') +const refineSmallestUnit = refineUnitOption.bind(undefined, smallestUnitStr) +const refineLargestUnit = refineUnitOption.bind(undefined, largestUnitStr) +const refineTotalUnit = refineUnitOption.bind(undefined, totalUnitStr) export enum Overflow { Constrain, diff --git a/packages/temporal-polyfill/src/plainDate.ts b/packages/temporal-polyfill/src/plainDate.ts index e8152dbd..39b11bb7 100644 --- a/packages/temporal-polyfill/src/plainDate.ts +++ b/packages/temporal-polyfill/src/plainDate.ts @@ -16,7 +16,7 @@ import { } from './convert' import { diffDates } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' -import { negateDurationInternals } from './durationFields' +import { negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { IsoDateInternals, IsoTimeFields, @@ -25,7 +25,7 @@ import { pluckIsoDateInternals, } from './isoFields' import { formatCalendar, formatIsoDateFields } from './isoFormat' -import { compareIsoDateTimeFields, refineIsoDateInternals } from './isoMath' +import { compareIsoDateFields, refineIsoDateInternals } from './isoMath' import { parsePlainDate } from './isoParse' import { refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' import { PlainDateTime, createPlainDateTime } from './plainDateTime' @@ -104,18 +104,22 @@ export const [ }, add(internals: IsoDateInternals, durationArg: DurationArg, options): PlainDate { - return internals.calendar.dateAdd( - internals, - toDurationInternals(durationArg), - options, + return createPlainDate( + internals.calendar.dateAdd( + internals, + toDurationInternals(durationArg), + options, + ), ) }, subtract(internals: IsoDateInternals, durationArg: DurationArg, options): PlainDate { - return internals.calendar.dateAdd( - internals, - negateDurationInternals(toDurationInternals(durationArg)), - options, + return createPlainDate( + internals.calendar.dateAdd( + internals, + negateDurationInternals(toDurationInternals(durationArg)), + options, + ), ) }, @@ -129,7 +133,7 @@ export const [ equals(internals: IsoDateInternals, otherArg: PlainDateArg): boolean { const otherInternals = toPlainDateInternals(otherArg) - return !compareIsoDateTimeFields(internals, otherInternals) && + return !compareIsoDateFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) }, @@ -171,7 +175,7 @@ export const [ { compare(arg0: PlainDateArg, arg1: PlainDateArg): NumSign { - return compareIsoDateTimeFields( + return compareIsoDateFields( toPlainDateInternals(arg0), toPlainDateInternals(arg1), ) diff --git a/packages/temporal-polyfill/src/units.ts b/packages/temporal-polyfill/src/units.ts index 8e6c0512..2064ee5c 100644 --- a/packages/temporal-polyfill/src/units.ts +++ b/packages/temporal-polyfill/src/units.ts @@ -106,6 +106,9 @@ export function givenFieldsToNano( return nano } +/* +Whatever unit you want, it might not populate all fields +*/ export function nanoToGivenFields( nano: number, unit: DayTimeUnit, // largestUnit diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index a3ab2113..d1e98e87 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -1,3 +1,4 @@ +import { IsoDateFields, IsoDateInternals } from './isoFields' import { Overflow } from './options' export type Reused = any @@ -256,20 +257,6 @@ export function compareNumbers(a: number, b: number): NumSign { // TODO: rename return Math.sign(a - b) as NumSign } -export function compareProps>( - propNames: (keyof Props)[], - props0: Props, - props1: Props, -): NumSign { - for (const propName of propNames) { - const cmp = compareNumbers(props0[propName], props1[propName]) - if (cmp) { - return cmp - } - } - return 0 -} - /* min/max are inclusive */ @@ -351,5 +338,5 @@ function hasHalf(num: number): boolean { // types export type FilterPropValues = { - [K in keyof P as P[K] extends F ? K : never]: P[K] + [K in keyof P as (P[K] extends F ? K : never)]: P[K] } From 76453e006263b93991f4695be58af1bec7cbb0ca Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 11:30:59 -0400 Subject: [PATCH 179/805] lots of types --- .../temporal-polyfill/src/calendarImpl.ts | 6 +-- packages/temporal-polyfill/src/calendarOps.ts | 2 +- packages/temporal-polyfill/src/convert.ts | 4 +- packages/temporal-polyfill/src/diff.ts | 48 ++++++++----------- .../temporal-polyfill/src/durationFields.ts | 1 + packages/temporal-polyfill/src/instant.ts | 14 ++---- packages/temporal-polyfill/src/intlFormat.ts | 2 +- packages/temporal-polyfill/src/isoMath.ts | 1 + packages/temporal-polyfill/src/plainDate.ts | 19 +++++--- .../temporal-polyfill/src/plainDateTime.ts | 21 ++++---- .../temporal-polyfill/src/plainMonthDay.ts | 5 +- packages/temporal-polyfill/src/plainTime.ts | 24 ++++++---- .../temporal-polyfill/src/plainYearMonth.ts | 25 +++++----- packages/temporal-polyfill/src/round.ts | 38 ++++++++------- packages/temporal-polyfill/src/timeZone.ts | 13 +++-- .../temporal-polyfill/src/timeZoneImpl.ts | 7 +-- packages/temporal-polyfill/src/timeZoneOps.ts | 7 ++- .../temporal-polyfill/src/zonedDateTime.ts | 44 +++++++++-------- 18 files changed, 154 insertions(+), 127 deletions(-) diff --git a/packages/temporal-polyfill/src/calendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl.ts index 54fa012e..a0151010 100644 --- a/packages/temporal-polyfill/src/calendarImpl.ts +++ b/packages/temporal-polyfill/src/calendarImpl.ts @@ -22,7 +22,7 @@ import { diffDatesExact, diffEpochMilliByDay, } from './diff' -import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' +import { IntlDateTimeFormat, hashIntlFormatParts, standardLocaleId } from './intlFormat' import { IsoDateFields, IsoDateInternals, isoTimeFieldDefaults } from './isoFields' import { computeIsoDayOfWeek, @@ -710,7 +710,7 @@ export function parseIntlYear( } function buildIntlFormat(calendarId: string): Intl.DateTimeFormat { - return new IntlDateTimeFormat(standardCalendarId, { + return new IntlDateTimeFormat(standardLocaleId, { calendar: calendarId, timeZone: 'UTC', era: 'short', // 'narrow' is too terse for japanese months @@ -776,7 +776,7 @@ function createIntlMonthCache( // Era Utils // ------------------------------------------------------------------------------------------------- -function getEraOrigins(calendarId: string): Record { +function getEraOrigins(calendarId: string): Record | undefined { return eraOriginsByCalendarId[getCalendarIdBase(calendarId)] } diff --git a/packages/temporal-polyfill/src/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts index 0cfe1769..d58caa8a 100644 --- a/packages/temporal-polyfill/src/calendarOps.ts +++ b/packages/temporal-polyfill/src/calendarOps.ts @@ -1,5 +1,5 @@ import { Calendar, CalendarArg, CalendarProtocol, calendarProtocolMethods, createCalendar } from './calendar' -import { DateGetterFields, dateFieldRefiners, dateGetterRefiners, dateStatRefiners, eraYearFieldRefiners } from './calendarFields' +import { DateGetterFields, dateGetterRefiners } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { createProtocolChecker, diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index 3c9041de..5875787f 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -171,7 +171,9 @@ export function createZonedDateTimeConverter( (internals: any, options: any) => ZonedDateTime ) { return (internals, options) => { - const { calendar, timeZone } = internals + const { calendar } = internals + const timeZone = queryTimeZoneOps(options.timeZone) + const epochNanoseconds = getSingleInstantFor(timeZone, { ...internals, ...getExtraIsoFields(normalizeOptions(options)), diff --git a/packages/temporal-polyfill/src/diff.ts b/packages/temporal-polyfill/src/diff.ts index e44a7394..e985a270 100644 --- a/packages/temporal-polyfill/src/diff.ts +++ b/packages/temporal-polyfill/src/diff.ts @@ -19,8 +19,8 @@ import { import { LargeInt, compareLargeInts } from './largeInt' import { moveDateByDays, moveDateTime, moveZonedEpochNano } from './move' import { RoundingMode } from './options' -import { computeNanoInc, roundByInc, roundByIncLarge, roundRelativeDuration } from './round' -import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' +import { MarkerToEpochNano, MoveMarker, computeNanoInc, roundByInc, roundByIncLarge, roundRelativeDuration } from './round' +import { TimeZoneOps, getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { DayTimeUnit, TimeUnit, @@ -34,7 +34,7 @@ import { NumSign, identityFunc } from './utils' // ------------------------------------------------------------------------------------------------- export function diffDateTimes( - calendar: CalendarOps, // calendarOps + calendar: CalendarOps, startIsoFields: IsoDateTimeFields, endIsoFields: IsoDateTimeFields, largestUnit: Unit, @@ -76,38 +76,27 @@ export function diffDateTimes( const timeDiff = timeNanoToDurationFields(timeNano) return roundRelativeDuration( - { ...dateDiff, ...timeDiff, sign }, + { ...dateDiff, ...timeDiff }, endEpochNano, largestUnit, smallestUnit, roundingInc, roundingMode, startIsoFields, // marker - isoToEpochNano, // markerToEpochNano - moveDateTime.bind(undefined, calendar), // moveMarker + isoToEpochNano as MarkerToEpochNano, // markerToEpochNano + moveDateTime.bind(undefined, calendar) as MoveMarker, // moveMarker ) } export function diffDates( - calendar: CalendarImpl, + calendar: CalendarOps, startIsoFields: IsoDateFields, endIsoFields: IsoDateFields, - largestUnit: Unit, - smallestUnit: Unit, + largestUnit: Unit, // TODO: large field + smallestUnit: Unit, // TODO: large field roundingInc: number, roundingMode: RoundingMode, ): DurationFields { - if (largestUnit < Unit.Day) { - return diffEpochNano( - isoToEpochNano(startIsoFields)!, - isoToEpochNano(endIsoFields)!, - largestUnit as TimeUnit, - smallestUnit as TimeUnit, - roundingInc, - roundingMode, - ) - } - const dateDiff = calendar.dateUntil(startIsoFields, endIsoFields, largestUnit) return roundRelativeDuration( @@ -118,11 +107,14 @@ export function diffDates( roundingInc, roundingMode, startIsoFields, // marker - isoToEpochNano, // markerToEpochNano // TODO --- stop doing isoToEpochNano*!* + isoToEpochNano as MarkerToEpochNano, // markerToEpochNano calendar.dateAdd.bind(calendar), // moveMarker ) } +/* +Used internally by Calendar! +*/ export function diffDatesExact( calendar: CalendarImpl, startIsoFields: IsoDateFields, @@ -184,14 +176,14 @@ export function diffTimes( // ------------------------------------------------------------------------------------------------- export function diffZonedEpochNano( - calendar: CalendarImpl, - timeZone: TimeZoneImpl, + calendar: CalendarOps, + timeZone: TimeZoneOps, startEpochNano: LargeInt, endEpochNano: LargeInt, largestUnit: Unit, - smallestUnit?: Unit, // internally will default to 'nanoseconds' - roundingInc?: number, // internally will default to 1 - roundingMode?: RoundingMode, // internally will default to 'halfExpand' + smallestUnit: Unit = Unit.Nanosecond, + roundingInc: number = 1, + roundingMode: RoundingMode = RoundingMode.HalfExpand, ): DurationFields { if (largestUnit < Unit.Day) { return diffEpochNano( @@ -226,14 +218,14 @@ export function diffZonedEpochNano( const timeDiff = timeNanoToDurationFields(timeDiffNano) return roundRelativeDuration( - { ...dateDiff, ...timeDiff, sign }, + { ...dateDiff, ...timeDiff }, endEpochNano, largestUnit, smallestUnit, roundingInc, roundingMode, startEpochNano, // marker - identityFunc, // markerToEpochNano + identityFunc as MarkerToEpochNano, // markerToEpochNano moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker ) } diff --git a/packages/temporal-polyfill/src/durationFields.ts b/packages/temporal-polyfill/src/durationFields.ts index 505aa88b..d8ee8d5e 100644 --- a/packages/temporal-polyfill/src/durationFields.ts +++ b/packages/temporal-polyfill/src/durationFields.ts @@ -162,6 +162,7 @@ export function timeNanoToDurationFields( /* Mutates `fields` +TODO: crazy-overused */ export function updateDurationFieldsSign(fields: DurationFields): DurationInternals { (fields as DurationInternals).sign = computeDurationFieldsSign(fields) diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index dd194e1a..5536d538 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -1,6 +1,6 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' -import { TemporalInstance, createTemporalClass, neverValueOf } from './class' +import { TemporalInstance, createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { diffEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { negateDurationInternals, updateDurationFieldsSign } from './durationFields' @@ -72,6 +72,9 @@ export const [ // ----------------------------------------------------------------------------------------------- { + /* + TODO: doesn't accept timeZoneArg anymore??? + */ toZonedDateTimeISO(epochNano: LargeInt, timeZoneArg: TimeZoneArg): ZonedDateTime { return createZonedDateTime({ epochNanoseconds: epochNano, @@ -148,14 +151,7 @@ export const [ formatOffsetNano(offsetNano) }, - toLocaleString( - epochNano: LargeInt, - locales: string | string[], - options: any, - ): string { - // TODO - return '' - }, + toLocaleString: toLocaleStringMethod, valueOf: neverValueOf, }, diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index e0d79603..084b607f 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -19,7 +19,7 @@ import { } from './utils' import { ZonedDateTime, ZonedInternals } from './zonedDateTime' -export const standardCalendarId = 'en-GB' // gives 24-hour clock +export const standardLocaleId = 'en-GB' // gives 24-hour clock export function hashIntlFormatParts( intlFormat: Intl.DateTimeFormat, diff --git a/packages/temporal-polyfill/src/isoMath.ts b/packages/temporal-polyfill/src/isoMath.ts index 7f167440..b2f12380 100644 --- a/packages/temporal-polyfill/src/isoMath.ts +++ b/packages/temporal-polyfill/src/isoMath.ts @@ -340,6 +340,7 @@ export function isoToEpochMilli( /* If out-of-bounds, returns undefined +TODO: rethink all this ! bs */ export function isoToEpochNano( isoFields: IsoDateTimeFields | IsoDateFields, diff --git a/packages/temporal-polyfill/src/plainDate.ts b/packages/temporal-polyfill/src/plainDate.ts index 39b11bb7..83c5a2a5 100644 --- a/packages/temporal-polyfill/src/plainDate.ts +++ b/packages/temporal-polyfill/src/plainDate.ts @@ -133,6 +133,7 @@ export const [ equals(internals: IsoDateInternals, otherArg: PlainDateArg): boolean { const otherInternals = toPlainDateInternals(otherArg) + return !compareIsoDateFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) }, @@ -147,7 +148,7 @@ export const [ valueOf: neverValueOf, toZonedDateTime: createZonedDateTimeConverter((options: any) => { - return optionalToPlainTimeFields(options.time) + return optionalToPlainTimeFields(options.plainTime) }), toPlainDateTime(internals, timeArg): PlainDateTime { @@ -192,13 +193,17 @@ function diffPlainDates( options: any, roundingModeInvert?: boolean, ): Duration { + const calendarOps = getCommonCalendarOps(internals0, internals1) + return createDuration( - diffDates( - getCommonCalendarOps(internals0, internals1), - internals0, - internals1, - ...refineDiffOptions(roundingModeInvert, options, Unit.Day, Unit.Year, Unit.Day), - ), + updateDurationFieldsSign( + diffDates( + calendarOps, + internals0, + internals1, + ...refineDiffOptions(roundingModeInvert, options, Unit.Day, Unit.Year, Unit.Day), + ) + ) ) } diff --git a/packages/temporal-polyfill/src/plainDateTime.ts b/packages/temporal-polyfill/src/plainDateTime.ts index 2f24efc4..6700475a 100644 --- a/packages/temporal-polyfill/src/plainDateTime.ts +++ b/packages/temporal-polyfill/src/plainDateTime.ts @@ -11,7 +11,7 @@ import { } from './convert' import { diffDateTimes } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' -import { DurationInternals, negateDurationInternals } from './durationFields' +import { DurationInternals, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { IsoDateTimeInternals, generatePublicIsoDateTimeFields, @@ -25,6 +25,7 @@ import { compareIsoDateTimeFields, refineIsoDateTimeInternals } from './isoMath' import { parsePlainDateTime } from './isoParse' import { moveDateTime } from './move' import { + RoundingMode, refineDateTimeDisplayOptions, refineDiffOptions, refineEpochDisambigOptions, @@ -38,7 +39,7 @@ import { PlainYearMonth } from './plainYearMonth' import { roundDateTime, roundDateTimeToNano } from './round' import { TimeZoneArg } from './timeZone' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' -import { Unit } from './units' +import { DayTimeUnit, Unit } from './units' import { NumSign } from './utils' import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' @@ -158,7 +159,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr round(internals: IsoDateTimeInternals, options): PlainDateTime { const isoDateTimeFields = roundDateTime( internals, - ...refineRoundOptions(options), + ...(refineRoundOptions(options) as [DayTimeUnit, number, RoundingMode]), ) return createPlainDateTime({ @@ -267,11 +268,13 @@ function diffPlainDateTimes( roundingModeInvert?: boolean ): Duration { return createDuration( - diffDateTimes( - getCommonCalendarOps(internals0, internals1), - internals0, - internals1, - ...refineDiffOptions(roundingModeInvert, options, Unit.Day), - ), + updateDurationFieldsSign( + diffDateTimes( + getCommonCalendarOps(internals0, internals1), + internals0, + internals1, + ...refineDiffOptions(roundingModeInvert, options, Unit.Day), + ), + ) ) } diff --git a/packages/temporal-polyfill/src/plainMonthDay.ts b/packages/temporal-polyfill/src/plainMonthDay.ts index c22ed308..5e2a50a7 100644 --- a/packages/temporal-polyfill/src/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/plainMonthDay.ts @@ -10,7 +10,7 @@ import { } from './convert' import { IsoDateInternals, generatePublicIsoDateFields } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' -import { compareIsoDateTimeFields, isoEpochFirstLeapYear, refineIsoDateInternals } from './isoMath' +import { compareIsoDateFields, isoEpochFirstLeapYear, refineIsoDateInternals } from './isoMath' import { parsePlainMonthDay } from './isoParse' import { refineOverflowOptions } from './options' import { PlainDate } from './plainDate' @@ -73,7 +73,8 @@ export const [ equals(internals: IsoDateInternals, otherArg: PlainMonthDayArg): boolean { const otherInternals = toPlainMonthDayInternals(otherArg) - return !compareIsoDateTimeFields(internals, otherInternals) && + + return !compareIsoDateFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) }, diff --git a/packages/temporal-polyfill/src/plainTime.ts b/packages/temporal-polyfill/src/plainTime.ts index 2f754bd2..fdd647d4 100644 --- a/packages/temporal-polyfill/src/plainTime.ts +++ b/packages/temporal-polyfill/src/plainTime.ts @@ -7,13 +7,14 @@ import { } from './convert' import { diffTimes } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' -import { DurationInternals, negateDurationInternals } from './durationFields' +import { DurationInternals, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { IsoTimeFields, pluckIsoTimeFields } from './isoFields' import { formatIsoTimeFields } from './isoFormat' import { compareIsoTimeFields, refineIsoTimeInternals } from './isoMath' import { parsePlainTime } from './isoParse' import { moveTime } from './move' import { + RoundingMode, refineDiffOptions, refineOverflowOptions, refineRoundOptions, @@ -23,7 +24,7 @@ import { PlainDateArg, toPlainDateInternals } from './plainDate' import { PlainDateTime, createPlainDateTime } from './plainDateTime' import { roundTime, roundTimeToNano } from './round' import { zonedInternalsToIso } from './timeZoneOps' -import { Unit } from './units' +import { TimeUnit, Unit } from './units' import { NumSign } from './utils' export type PlainTimeArg = PlainTime | PlainTimeBag | string @@ -108,7 +109,10 @@ export const [ round(fields: IsoTimeFields, options): PlainTime { return createPlainTime( - roundTime(fields, ...refineRoundOptions(options, Unit.Hour)), + roundTime( + fields, + ...(refineRoundOptions(options, Unit.Hour) as [TimeUnit, number, RoundingMode]) + ), ) }, @@ -121,7 +125,7 @@ export const [ const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatIsoTimeFields( - roundTimeToNano(fields, nanoInc, roundingMode), + roundTimeToNano(fields, nanoInc, roundingMode)[0], subsecDigits, ) }, @@ -171,10 +175,12 @@ function diffPlainTimes( roundingModeInvert?: boolean ): Duration { return createDuration( - diffTimes( - internals0, - internals1, - ...refineDiffOptions(roundingModeInvert, options, hourIndex, hourIndex), - ), + updateDurationFieldsSign( + diffTimes( + internals0, + internals1, + ...(refineDiffOptions(roundingModeInvert, options, Unit.Hour, Unit.Hour) as [TimeUnit, TimeUnit, number, RoundingMode]), + ), + ) ) } diff --git a/packages/temporal-polyfill/src/plainYearMonth.ts b/packages/temporal-polyfill/src/plainYearMonth.ts index 24075764..cfcee210 100644 --- a/packages/temporal-polyfill/src/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/plainYearMonth.ts @@ -10,10 +10,10 @@ import { } from './convert' import { diffDates } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' -import { DurationInternals, negateDurationInternals } from './durationFields' +import { DurationInternals, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { IsoDateFields, IsoDateInternals, generatePublicIsoDateFields } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' -import { compareIsoDateTimeFields, refineIsoDateInternals } from './isoMath' +import { compareIsoDateFields, refineIsoDateInternals } from './isoMath' import { parsePlainYearMonth } from './isoParse' import { moveDateByDays } from './move' import { refineDiffOptions, refineOverflowOptions } from './options' @@ -74,7 +74,7 @@ export const [ { with(internals: IsoDateInternals, mod: PlainYearMonthMod, options): PlainYearMonth { - return createPlainYearMonth(mergePlainYearMonthBag(internals, mod, options)) + return createPlainYearMonth(mergePlainYearMonthBag(this, mod, options)) }, add(internals: IsoDateInternals, durationArg: DurationArg, options): PlainYearMonth { @@ -103,7 +103,8 @@ export const [ equals(internals: IsoDateInternals, otherArg: PlainYearMonthArg): boolean { const otherInternals = toPlainYearMonthInternals(otherArg) - return !compareIsoDateTimeFields(internals, otherInternals) && + + return !compareIsoDateFields(internals, otherInternals) && isObjIdsEqual(internals.calendar, otherInternals.calendar) }, @@ -127,7 +128,7 @@ export const [ { compare(arg0: PlainYearMonthArg, arg1: PlainYearMonthArg): NumSign { - return compareIsoDateTimeFields( + return compareIsoDateFields( toPlainYearMonthInternals(arg0), toPlainYearMonthInternals(arg1), ) @@ -145,12 +146,14 @@ function diffPlainYearMonths( roundingModeInvert?: boolean ): Duration { return createDuration( - diffDates( - getCommonCalendarOps(internals0, internals1), - movePlainYearMonthToDay(internals0), - movePlainYearMonthToDay(internals1), - ...refineDiffOptions(roundingModeInvert, options, Unit.Year, Unit.Year, Unit.Day), - ), + updateDurationFieldsSign( + diffDates( + getCommonCalendarOps(internals0, internals1), + movePlainYearMonthToDay(internals0), + movePlainYearMonthToDay(internals1), + ...refineDiffOptions(roundingModeInvert, options, Unit.Year, Unit.Year, Unit.Day), + ), + ) ) } diff --git a/packages/temporal-polyfill/src/round.ts b/packages/temporal-polyfill/src/round.ts index e2957822..0324b289 100644 --- a/packages/temporal-polyfill/src/round.ts +++ b/packages/temporal-polyfill/src/round.ts @@ -9,9 +9,10 @@ import { durationTimeFieldDefaults, nanoToDurationFields, timeNanoToDurationFields, + updateDurationFieldsSign, } from './durationFields' import { IsoDateFields, IsoDateInternals, IsoDateTimeFields, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' -import { isoTimeFieldsToNano, nanoToIsoTimeAndDay } from './isoMath' +import { isoTimeFieldsToNano, isoToEpochNano, nanoToIsoTimeAndDay } from './isoMath' import { LargeInt } from './largeInt' import { moveDateByDays, moveZonedEpochNano } from './move' import { RoundingMode, roundingModeFuncs } from './options' @@ -39,7 +40,7 @@ export function roundDateTime( smallestUnit: DayTimeUnit, roundingInc: number, roundingMode: RoundingMode, - timeZoneOps: TimeZoneOps | undefined = undefined, + timeZoneOps?: TimeZoneOps | undefined, ) { if (smallestUnit === Unit.Day) { return roundDateTimeToDay(isoFields, timeZoneOps, roundingMode) @@ -164,14 +165,16 @@ export function roundRelativeDuration( return durationFields } - let [roundedDurationFields, roundedEpochNanoseconds, grew] = ( + const nudgeFunc = ( smallestUnit >= Unit.Day ? nudgeRelativeDuration : markerToEpochNano === identityFunc // marker is ZonedDateTime's epochNanoseconds? ? nudgeRelativeDurationTime : nudgeDurationTime - )( - durationFields, + ) as typeof nudgeRelativeDuration // accept all units + + let [roundedDurationFields, roundedEpochNano, grew] = nudgeFunc( + updateDurationFieldsSign(durationFields), endEpochNano, smallestUnit, roundingInc, @@ -185,8 +188,8 @@ export function roundRelativeDuration( // grew a day/week/month/year? if (grew) { roundedDurationFields = bubbleRelativeDuration( - roundedDurationFields, - roundedEpochNanoseconds, + updateDurationFieldsSign(roundedDurationFields), + roundedEpochNano, largestUnit, smallestUnit, // marker system... @@ -241,7 +244,7 @@ export function totalDayTimeDuration( // assumes iso-length days } export function totalRelativeDuration( - durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, totalUnit: Unit, // marker system... @@ -305,7 +308,7 @@ function nudgeDurationTime( } function nudgeRelativeDurationTime( - durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, // NOT NEEDED, just for conformance smallestUnit: TimeUnit, roundingInc: number, @@ -357,7 +360,7 @@ function nudgeRelativeDurationTime( } function nudgeRelativeDuration( - durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, smallestUnit: Unit, roundingInc: number, @@ -372,10 +375,11 @@ function nudgeRelativeDuration( grew: NumSign, ] { const { sign } = durationFields + const smallestUnitFieldName = durationFieldNamesAsc[smallestUnit] const baseDurationFields = clearDurationFields(durationFields, smallestUnit - 1) - baseDurationFields[smallestUnit] = Math.trunc( - durationInternals[smallestUnit] / roundingInc, + baseDurationFields[smallestUnitFieldName] = Math.trunc( + durationFields[smallestUnitFieldName] / roundingInc, ) const [epochNano0, epochNano1] = clampRelativeDuration( @@ -395,7 +399,7 @@ function nudgeRelativeDuration( const roundedPortion = roundWithMode(portion * sign, roundingMode) // -1/0/1 if (roundedPortion) { // enlarged? - baseDurationFields[smallestUnit] += roundingInc * sign + baseDurationFields[smallestUnitFieldName] += roundingInc * sign return [baseDurationFields, epochNano1, roundedPortion as NumSign] } else { @@ -426,14 +430,14 @@ export function createMarkerSystem( if (epochNanoseconds) { return [ epochNanoseconds, // marker - identityFunc, // markerToEpochNano + identityFunc as MarkerToEpochNano, // markerToEpochNano moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker diffZonedEpochNano.bind(undefined, calendar, timeZone), // diffMarkers ] } else { return [ markerInternals as IsoDateFields, // marker (IsoDateFields) - isoToEpochNano as (marker: Marker) => LargeInt, // markerToEpochNano + isoToEpochNano as MarkerToEpochNano, calendar.dateAdd.bind(calendar), // moveMarker calendar.dateUntil.bind(calendar), // diffMarkers ] @@ -444,7 +448,7 @@ export function createMarkerSystem( // ------------------------------------------------------------------------------------------------- function bubbleRelativeDuration( - durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) + durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, largestUnit: Unit, smallestUnit: Unit, @@ -473,7 +477,7 @@ function bubbleRelativeDuration( const beyondThreshold = endEpochNano.addLargeInt(thresholdEpochNano, -1).toNumber() if (!beyondThreshold || Math.sign(beyondThreshold) === sign) { - durationFields = baseDurationFields + durationFields = updateDurationFieldsSign(baseDurationFields) } else { break } diff --git a/packages/temporal-polyfill/src/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts index 5754aa2f..8c6405ba 100644 --- a/packages/temporal-polyfill/src/timeZone.ts +++ b/packages/temporal-polyfill/src/timeZone.ts @@ -10,11 +10,12 @@ import { refineEpochDisambigOptions } from './options' import { PlainDateTime, PlainDateTimeArg, createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { noop } from './utils' +import { isoCalendarId } from './calendarConfig' interface TimeZoneProtocolMethods { getOffsetNanosecondsFor(instant: InstantArg): number getOffsetStringFor?(instant: InstantArg): string - getPlainDateTimeFor?(instant: InstantArg, calendar?: CalendarArg): PlainDateTime + getPlainDateTimeFor?(instant: InstantArg, calendarArg?: CalendarArg): PlainDateTime getInstantFor?(dateTime: PlainDateTimeArg, options?: any): Instant getNextTransition?(startingPoint: InstantArg): Instant | null getPreviousTransition?(startingPoint: InstantArg): Instant | null @@ -52,12 +53,16 @@ const timeZoneMethods: { return formatOffsetNano(getImplOffsetNanosecondsFor(impl, instantArg)) }, - getPlainDateTimeFor(impl: TimeZoneImpl, instantArg: InstantArg, calendarArg?: CalendarArg): PlainDateTime { - const epochNanoseconds = toInstantEpochNano(instantArg) + getPlainDateTimeFor( + impl: TimeZoneImpl, + instantArg: InstantArg, + calendarArg: CalendarArg = isoCalendarId + ): PlainDateTime { + const epochNano = toInstantEpochNano(instantArg) return createPlainDateTime({ calendar: queryCalendarOps(calendarArg), - ...zonedEpochNanoToIso(impl, epochNanoseconds), + ...zonedEpochNanoToIso(impl, epochNano), }) }, diff --git a/packages/temporal-polyfill/src/timeZoneImpl.ts b/packages/temporal-polyfill/src/timeZoneImpl.ts index 96859f19..c02ecc37 100644 --- a/packages/temporal-polyfill/src/timeZoneImpl.ts +++ b/packages/temporal-polyfill/src/timeZoneImpl.ts @@ -1,5 +1,6 @@ +import { isoCalendarId } from './calendarConfig' import { parseIntlYear } from './calendarImpl' -import { IntlDateTimeFormat, hashIntlFormatParts, standardCalendarId } from './intlFormat' +import { IntlDateTimeFormat, hashIntlFormatParts, standardLocaleId } from './intlFormat' import { IsoDateTimeFields } from './isoFields' import { epochNanoToSec, @@ -251,7 +252,7 @@ function createComputeOffsetSec(timeZoneId: string): ( return (epochSec: number) => { const intlParts = hashIntlFormatParts(format, epochSec * milliInSec) const zonedEpochSec = isoArgsToEpochSec( - parseIntlYear(intlParts).year, + parseIntlYear(intlParts, isoCalendarId).year, parseInt(intlParts.month), parseInt(intlParts.day), parseInt(intlParts.hour), @@ -264,7 +265,7 @@ function createComputeOffsetSec(timeZoneId: string): ( function buildIntlFormat(timeZoneId: string): Intl.DateTimeFormat { // format will ALWAYS do gregorian. need to parse year - return new IntlDateTimeFormat(standardCalendarId, { + return new IntlDateTimeFormat(standardLocaleId, { timeZone: timeZoneId, era: 'short', year: 'numeric', diff --git a/packages/temporal-polyfill/src/timeZoneOps.ts b/packages/temporal-polyfill/src/timeZoneOps.ts index 52b06f47..4396cc8a 100644 --- a/packages/temporal-polyfill/src/timeZoneOps.ts +++ b/packages/temporal-polyfill/src/timeZoneOps.ts @@ -42,7 +42,7 @@ const checkTimeZoneProtocol = createProtocolChecker(timeZoneProtocolMethods) export function queryTimeZoneOps(timeZoneArg: TimeZoneArg): TimeZoneOps { if (typeof timeZoneArg === 'object') { if (timeZoneArg instanceof TimeZone) { - return getInternals(timeZoneArg) + return getInternals(timeZoneArg as TimeZone) } checkTimeZoneProtocol(timeZoneArg) @@ -73,8 +73,11 @@ export function computeNanosecondsInDay( isoDateFields: IsoDateFields, // could contain time fields though ): number { isoDateFields = { ...isoDateFields, ...isoTimeFieldDefaults } + + // TODO: have getSingleInstantFor accept IsoDateFields? const epochNano0 = getSingleInstantFor(timeZoneOps, { ...isoTimeFieldDefaults, ...isoDateFields }) - const epochNano1 = getSingleInstantFor(timeZoneOps, moveDateByDays(isoDateFields, 1)) + const epochNano1 = getSingleInstantFor(timeZoneOps, { ...isoTimeFieldDefaults, ...moveDateByDays(isoDateFields, 1) }) + return epochNano1.addLargeInt(epochNano0, -1).toNumber() } diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index a10bcf2d..a3dbc522 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -11,7 +11,7 @@ import { } from './convert' import { diffZonedEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' -import { DurationFields, negateDurationInternals } from './durationFields' +import { DurationFields, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { Instant, createInstant } from './instant' import { resolveZonedFormattable } from './intlFormat' import { @@ -40,6 +40,7 @@ import { EpochDisambig, OffsetDisambig, Overflow, + RoundingMode, refineDiffOptions, refineOverflowOptions, refineRoundOptions, @@ -62,7 +63,7 @@ import { queryTimeZoneOps, zonedInternalsToIso, } from './timeZoneOps' -import { Unit, nanoInHour } from './units' +import { DayTimeUnit, Unit, nanoInHour } from './units' import { NumSign, mapProps } from './utils' export type ZonedDateTimeArg = ZonedDateTime | ZonedDateTimeBag | string @@ -137,8 +138,7 @@ export const [ ) / nanoInHour }, - // TODO: make this a getter? - offsetNanoseconds(internals: ZonedInternals): LargeInt { + offsetNanoseconds(internals: ZonedInternals): number { // TODO: more DRY return zonedInternalsToIso(internals).offsetNanoseconds }, @@ -261,7 +261,7 @@ export const [ isoDateTimeFields = roundDateTime( isoDateTimeFields, - ...refineRoundOptions(options), + ...(refineRoundOptions(options) as [DayTimeUnit, number, RoundingMode]), timeZone, ) epochNanoseconds = getMatchingInstantFor( @@ -422,15 +422,17 @@ function moveZonedDateTime( durationFields: DurationFields, overflowHandling: Overflow ): ZonedDateTime { - return createZonedDateTime( - moveZonedEpochNano( - internals.calendar, - internals.timeZone, - internals.epochNanoseconds, - durationFields, - overflowHandling, - ), + const epochNano = moveZonedEpochNano( + internals.calendar, + internals.timeZone, + internals.epochNanoseconds, + durationFields, + overflowHandling, ) + return createZonedDateTime({ + ...internals, + epochNanoseconds: epochNano, + }) } function diffZonedDateTimes( @@ -440,12 +442,14 @@ function diffZonedDateTimes( roundingModeInvert?: boolean ): Duration { return createDuration( - diffZonedEpochNano( - getCommonCalendarOps(internals, otherInternals), - getCommonTimeZoneOps(internals, otherInternals), - internals.epochNanoseconds, - otherInternals.epochNanoseconds, - ...refineDiffOptions(roundingModeInvert, options, Unit.Hour), - ), + updateDurationFieldsSign( + diffZonedEpochNano( + getCommonCalendarOps(internals, otherInternals), + getCommonTimeZoneOps(internals, otherInternals), + internals.epochNanoseconds, + otherInternals.epochNanoseconds, + ...refineDiffOptions(roundingModeInvert, options, Unit.Hour), + ), + ) ) } From 5668dc6166347ad3f506508a706252a0f1564f55 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 11:37:08 -0400 Subject: [PATCH 180/805] update typescript in subpackage --- packages/temporal-polyfill/package.json | 2 +- pnpm-lock.yaml | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 5dc7bc97..56a77a1d 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -82,6 +82,6 @@ "progress": "^2.0.3", "rollup": "^2.55.1", "tiny-glob": "^0.2.9", - "typescript": "^4.3.5" + "typescript": "^5.1.6" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba93a9ce..017385aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -185,8 +185,8 @@ importers: specifier: ^0.2.9 version: 0.2.9 typescript: - specifier: ^4.3.5 - version: 4.9.5 + specifier: ^5.1.6 + version: 5.1.6 packages/temporal-spec: {} @@ -5424,12 +5424,6 @@ packages: is-typedarray: 1.0.0 dev: true - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - /typescript@5.1.6: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} From 6c07524ab06b1a51d77e4abe736fb38c23530c3c Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 15:34:00 -0400 Subject: [PATCH 181/805] more/better types --- packages/temporal-polyfill/src/calendar.ts | 2 +- packages/temporal-polyfill/src/calendarOps.ts | 3 +- packages/temporal-polyfill/src/diff.ts | 19 ++-- packages/temporal-polyfill/src/duration.ts | 26 ++--- packages/temporal-polyfill/src/options.ts | 1 + packages/temporal-polyfill/src/round.ts | 94 ++++++++++--------- packages/temporal-polyfill/src/timeZone.ts | 2 +- 7 files changed, 81 insertions(+), 66 deletions(-) diff --git a/packages/temporal-polyfill/src/calendar.ts b/packages/temporal-polyfill/src/calendar.ts index 9c3dc427..7b9d0b78 100644 --- a/packages/temporal-polyfill/src/calendar.ts +++ b/packages/temporal-polyfill/src/calendar.ts @@ -192,7 +192,7 @@ export const [Calendar, createCalendar] = createTemporalClass( // Getters // ----------------------------------------------------------------------------------------------- - idGetters, + idGetters as { id: (this: Calendar, impl: CalendarImpl) => string }, // Methods // ----------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts index d58caa8a..aaba1c6f 100644 --- a/packages/temporal-polyfill/src/calendarOps.ts +++ b/packages/temporal-polyfill/src/calendarOps.ts @@ -13,6 +13,7 @@ import { import { Duration, createDuration } from './duration' import { DurationInternals } from './durationFields' import { CalendarInternals, IsoDateFields, IsoDateInternals } from './isoFields' +import { LargeInt } from './largeInt' import { Overflow, ensureObjectlike, ensureString, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' @@ -43,7 +44,7 @@ export interface CalendarOps { yearMonthFromFields(fields: any, overflow: Overflow): IsoDateInternals monthDayFromFields(fields: any, overflow: Overflow): IsoDateInternals dateAdd(isoFields: IsoDateFields, durationInternals: DurationInternals, overflow: Overflow): IsoDateInternals - dateUntil(isoFields0: IsoDateFields, isoFields1: IsoDateFields, options: any): DurationInternals + dateUntil(isoFields0: IsoDateFields, isoFields1: IsoDateFields, largestUnit: Unit): DurationInternals fields(fieldNames: string[]): string[] mergeFields(fields0: any, fields1: any): any } diff --git a/packages/temporal-polyfill/src/diff.ts b/packages/temporal-polyfill/src/diff.ts index e985a270..58e327fc 100644 --- a/packages/temporal-polyfill/src/diff.ts +++ b/packages/temporal-polyfill/src/diff.ts @@ -1,4 +1,3 @@ -import { TimeZoneImpl } from './timeZoneImpl' import { CalendarImpl } from './calendarImpl' import { CalendarOps } from './calendarOps' import { @@ -7,6 +6,7 @@ import { durationFieldDefaults, nanoToDurationFields, timeNanoToDurationFields, + updateDurationFieldsSign, } from './durationFields' import { IsoDateFields, IsoDateTimeFields, IsoTimeFields, pluckIsoTimeFields } from './isoFields' import { @@ -18,7 +18,7 @@ import { } from './isoMath' import { LargeInt, compareLargeInts } from './largeInt' import { moveDateByDays, moveDateTime, moveZonedEpochNano } from './move' -import { RoundingMode } from './options' +import { Overflow, RoundingMode } from './options' import { MarkerToEpochNano, MoveMarker, computeNanoInc, roundByInc, roundByIncLarge, roundRelativeDuration } from './round' import { TimeZoneOps, getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { @@ -83,8 +83,9 @@ export function diffDateTimes( roundingInc, roundingMode, startIsoFields, // marker - isoToEpochNano as MarkerToEpochNano, // markerToEpochNano - moveDateTime.bind(undefined, calendar) as MoveMarker, // moveMarker + isoToEpochNano as (isoFields: IsoDateTimeFields) => LargeInt, // markerToEpochNano -- TODO: better after removing `!` + // TODO: better way to bind w/o specifying Overflow + (m: IsoDateTimeFields, d: DurationFields) => moveDateTime(calendar, m, d, Overflow.Constrain), ) } @@ -107,8 +108,9 @@ export function diffDates( roundingInc, roundingMode, startIsoFields, // marker - isoToEpochNano as MarkerToEpochNano, // markerToEpochNano - calendar.dateAdd.bind(calendar), // moveMarker + isoToEpochNano as (isoFields: IsoDateFields) => LargeInt, // markerToEpochNano + // TODO: better way to bind w/o specifying Overflow + (m: IsoDateFields, d: DurationFields) => calendar.dateAdd(m, updateDurationFieldsSign(d), Overflow.Constrain), ) } @@ -225,8 +227,9 @@ export function diffZonedEpochNano( roundingInc, roundingMode, startEpochNano, // marker - identityFunc as MarkerToEpochNano, // markerToEpochNano - moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker + identityFunc, // markerToEpochNano + // TODO: better way to bind + (m: LargeInt, d: DurationFields) => moveZonedEpochNano(calendar, timeZone, m, d, Overflow.Constrain), ) } diff --git a/packages/temporal-polyfill/src/duration.ts b/packages/temporal-polyfill/src/duration.ts index e39433b0..632c5864 100644 --- a/packages/temporal-polyfill/src/duration.ts +++ b/packages/temporal-polyfill/src/duration.ts @@ -24,6 +24,8 @@ import { refineTotalOptions, } from './options' import { + MarkerSystem, + SimpleMarkerSystem, roundDayTimeDuration, roundDurationToNano, roundRelativeDuration, @@ -32,7 +34,7 @@ import { } from './round' import { NumSign, noop } from './utils' import { DayTimeUnit, Unit } from './units' -import { Marker, MarkerToEpochNano, MoveMarker, DiffMarkers, createMarkerSystem } from './round' +import { MarkerToEpochNano, MoveMarker, DiffMarkers, createMarkerSystem } from './round' export type DurationArg = Duration | DurationBag | string export type DurationBag = Partial @@ -143,7 +145,7 @@ export const [ throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals) + const markerSystem = createMarkerSystem(markerInternals) as MarkerSystem return createDuration( updateDurationFieldsSign( @@ -153,7 +155,7 @@ export const [ smallestUnit, roundingInc, roundingMode, - ...(markerSystem as unknown as [Marker, MarkerToEpochNano, MoveMarker]), + ...(markerSystem as unknown as SimpleMarkerSystem), ), ), ) @@ -174,12 +176,12 @@ export const [ throw new RangeError('need relativeTo') } - const markerSystem = createMarkerSystem(markerInternals) + const markerSystem = createMarkerSystem(markerInternals) as MarkerSystem return totalRelativeDuration( ...spanDuration(internals, largestUnit, ...markerSystem), totalUnit, - ...(markerSystem as unknown as [Marker, MarkerToEpochNano, MoveMarker]), + ...(markerSystem as unknown as SimpleMarkerSystem), ) }, @@ -219,7 +221,7 @@ export const [ throw new RangeError('need relativeTo') } - const [marker, markerToEpochNano, moveMarker] = createMarkerSystem(markerInternals) + const [marker, markerToEpochNano, moveMarker] = createMarkerSystem(markerInternals) as MarkerSystem return compareLargeInts( markerToEpochNano(moveMarker(marker, durationFields0)), @@ -255,18 +257,18 @@ function addToDuration( throw new RangeError('relativeTo is required for years, months, or weeks arithmetic') } - const markerSystem = createMarkerSystem(markerInternals) + const markerSystem = createMarkerSystem(markerInternals) as MarkerSystem return createDuration(spanDuration(internals, largestUnit, ...markerSystem)[0]) } -function spanDuration( +function spanDuration( durationFields: DurationFields, largestUnit: Unit, // TODO: more descrimination? // marker system... - marker: Marker, - markerToEpochNano: MarkerToEpochNano, - moveMarker: MoveMarker, - diffMarkers: DiffMarkers, + marker: M, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, + diffMarkers: DiffMarkers, ): [ DurationInternals, LargeInt, diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index cab1e576..b2c458fc 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -401,6 +401,7 @@ function refineSubsecDigits(options: Options): SubsecDigits | undefined { // undefind means 'auto' } +// TODO: use in definition of `createMarkerSystem` ? type RelativeToInternals = ZonedInternals | IsoDateInternals function refineRelativeTo(options: Options): RelativeToInternals | undefined { diff --git a/packages/temporal-polyfill/src/round.ts b/packages/temporal-polyfill/src/round.ts index 0324b289..fec1aadf 100644 --- a/packages/temporal-polyfill/src/round.ts +++ b/packages/temporal-polyfill/src/round.ts @@ -15,7 +15,7 @@ import { IsoDateFields, IsoDateInternals, IsoDateTimeFields, IsoTimeFields, isoT import { isoTimeFieldsToNano, isoToEpochNano, nanoToIsoTimeAndDay } from './isoMath' import { LargeInt } from './largeInt' import { moveDateByDays, moveZonedEpochNano } from './move' -import { RoundingMode, roundingModeFuncs } from './options' +import { Overflow, RoundingMode, roundingModeFuncs } from './options' import { TimeZoneOps, computeNanosecondsInDay } from './timeZoneOps' import { nanoInMinute, @@ -148,7 +148,7 @@ export function roundDurationToNano( } } -export function roundRelativeDuration( +export function roundRelativeDuration( durationFields: DurationFields, // must be balanced & top-heavy in day or larger (so, small time-fields) // ^has sign endEpochNano: LargeInt, @@ -157,9 +157,9 @@ export function roundRelativeDuration( roundingInc: number, roundingMode: RoundingMode, // marker system... - marker: Marker, - markerToEpochNano: MarkerToEpochNano, - moveMarker: MoveMarker, + marker: M, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, ): DurationFields { if (smallestUnit === Unit.Nanosecond && roundingInc === 1) { return durationFields @@ -243,14 +243,14 @@ export function totalDayTimeDuration( // assumes iso-length days return fullUnits.toNumber() + (remainder / divisor) } -export function totalRelativeDuration( +export function totalRelativeDuration( durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, totalUnit: Unit, // marker system... - marker: Marker, - markerToEpochNano: MarkerToEpochNano, - moveMarker: MoveMarker, + marker: M, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, ): number { const { sign } = durationFields @@ -307,16 +307,16 @@ function nudgeDurationTime( ] } -function nudgeRelativeDurationTime( +function nudgeRelativeDurationTime( durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, // NOT NEEDED, just for conformance smallestUnit: TimeUnit, roundingInc: number, roundingMode: RoundingMode, // marker system... - marker: Marker, - markerToEpochNano: MarkerToEpochNano, - moveMarker: MoveMarker, + marker: M, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, ): [ nudgedDurationFields: DurationFields, nudgedEpochNano: LargeInt, @@ -359,16 +359,16 @@ function nudgeRelativeDurationTime( return [nudgedDurationFields, endEpochNano, dayDelta] } -function nudgeRelativeDuration( +function nudgeRelativeDuration( durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, smallestUnit: Unit, roundingInc: number, roundingMode: RoundingMode, // marker system... - marker: Marker, - markerToEpochNano: MarkerToEpochNano, - moveMarker: MoveMarker, + marker: M, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, ): [ durationFields: DurationFields, movedEpochNano: LargeInt, @@ -411,35 +411,43 @@ function nudgeRelativeDuration( // ------------------------------------------------------------------------------------------------- // TODO: best place for this? -export type Marker = LargeInt | IsoDateFields -export type MarkerToEpochNano = (marker: Marker) => LargeInt -export type MoveMarker = (marker: Marker, durationFields: DurationFields) => Marker -export type DiffMarkers = (marker0: Marker, marker1: Marker, largeUnit: Unit) => DurationInternals -export type MarkerSystem = [ - Marker, - MarkerToEpochNano, - MoveMarker, - DiffMarkers, +export type MarkerToEpochNano = (marker: M) => LargeInt +export type MoveMarker = (marker: M, durationFields: DurationFields) => M +export type DiffMarkers = (marker0: M, marker1: M, largeUnit: Unit) => DurationInternals +export type MarkerSystem = [ + M, + MarkerToEpochNano, + MoveMarker, + DiffMarkers, +] +export type SimpleMarkerSystem = [ + M, + MarkerToEpochNano, + MoveMarker, ] +/* +Okay that callers frequently cast to `unknown`? +*/ export function createMarkerSystem( markerInternals: ZonedInternals | IsoDateInternals -): MarkerSystem { +): MarkerSystem | MarkerSystem { const { calendar, timeZone, epochNanoseconds } = markerInternals as ZonedInternals if (epochNanoseconds) { return [ - epochNanoseconds, // marker - identityFunc as MarkerToEpochNano, // markerToEpochNano - moveZonedEpochNano.bind(undefined, calendar, timeZone), // moveMarker - diffZonedEpochNano.bind(undefined, calendar, timeZone), // diffMarkers + epochNanoseconds, + identityFunc as MarkerToEpochNano, + moveZonedEpochNano.bind(undefined, calendar, timeZone) as MoveMarker, + diffZonedEpochNano.bind(undefined, calendar, timeZone) as DiffMarkers, ] } else { return [ - markerInternals as IsoDateFields, // marker (IsoDateFields) - isoToEpochNano as MarkerToEpochNano, - calendar.dateAdd.bind(calendar), // moveMarker - calendar.dateUntil.bind(calendar), // diffMarkers + markerInternals as IsoDateFields, + isoToEpochNano as MarkerToEpochNano, + // TODO: better way to .bind to Calendar, without specifying overflow/largeUnit? + (m: IsoDateFields, d: DurationFields) => calendar.dateAdd(m, updateDurationFieldsSign(d), Overflow.Constrain), + (m0: IsoDateFields, m1: IsoDateFields, largeUnit: Unit) => calendar.dateUntil(m0, m1, largeUnit), ] } } @@ -447,15 +455,15 @@ export function createMarkerSystem( // Utils // ------------------------------------------------------------------------------------------------- -function bubbleRelativeDuration( +function bubbleRelativeDuration( durationFields: DurationInternals, // must be balanced & top-heavy in day or larger (so, small time-fields) endEpochNano: LargeInt, largestUnit: Unit, smallestUnit: Unit, // marker system... - marker: Marker, - markerToEpochNano: MarkerToEpochNano, - moveMarker: MoveMarker, + marker: M, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, ): DurationFields { const { sign } = durationFields @@ -486,14 +494,14 @@ function bubbleRelativeDuration( return durationFields } -function clampRelativeDuration( +function clampRelativeDuration( durationFields: DurationFields, clampUnit: Unit, clampDistance: number, // marker system... - marker: Marker, - markerToEpochNano: MarkerToEpochNano, - moveMarker: MoveMarker, + marker: M, + markerToEpochNano: MarkerToEpochNano, + moveMarker: MoveMarker, ) { const clampDurationFields = { ...durationFieldDefaults, diff --git a/packages/temporal-polyfill/src/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts index 8c6405ba..f9051021 100644 --- a/packages/temporal-polyfill/src/timeZone.ts +++ b/packages/temporal-polyfill/src/timeZone.ts @@ -115,7 +115,7 @@ export const [TimeZone, createTimeZone] = createTemporalClass( // Getters // ----------------------------------------------------------------------------------------------- - idGetters, + idGetters as { id: (this: TimeZone, impl: TimeZoneImpl) => string }, // Methods // ----------------------------------------------------------------------------------------------- From 2ab3d4ce6370293b6738b396f74b19847265c24b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 17:35:45 -0400 Subject: [PATCH 182/805] changes to classes and timeZone/calendar obj processing --- packages/temporal-polyfill/src/calendar.ts | 34 +++++----- packages/temporal-polyfill/src/calendarOps.ts | 44 ++++++++++--- packages/temporal-polyfill/src/class.ts | 62 ++++++++++++++----- packages/temporal-polyfill/src/convert.ts | 31 ---------- packages/temporal-polyfill/src/timeZone.ts | 35 +++++------ packages/temporal-polyfill/src/timeZoneOps.ts | 43 ++++++++++--- packages/temporal-polyfill/src/utils.ts | 2 +- 7 files changed, 145 insertions(+), 106 deletions(-) diff --git a/packages/temporal-polyfill/src/calendar.ts b/packages/temporal-polyfill/src/calendar.ts index 7b9d0b78..fb677237 100644 --- a/packages/temporal-polyfill/src/calendar.ts +++ b/packages/temporal-polyfill/src/calendar.ts @@ -1,15 +1,14 @@ import { DateGetterFields, dateGetterNames } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' -import { TemporalInstance, createTemporalClass, getInternals, getObjId, getTemporalName, idGetters } from './class' +import { queryCalendarPublic } from './calendarOps' +import { TemporalInstance, createSimpleTemporalClass, getInternals, getObjId, getTemporalName, idGetters } from './class' import { - refineComplexBag, refinePlainDateBag, refinePlainMonthDayBag, refinePlainYearMonthBag, } from './convert' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { IsoDateFields } from './isoFields' -import { parseCalendarId } from './isoParse' import { ensureObjectlike, ensureString, @@ -20,8 +19,8 @@ import { PlainDate, PlainDateArg, createPlainDate, toPlainDateInternals } from ' import { PlainDateTime } from './plainDateTime' import { PlainMonthDay, createPlainMonthDay } from './plainMonthDay' import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' -import { TimeZone } from './timeZone' -import { excludeUndefinedProps, mapPropNames, noop } from './utils' +import { excludeUndefinedProps, mapPropNames } from './utils' +import { ZonedDateTime } from './zonedDateTime' interface CalendarProtocolMethods { year(dateArg: PlainYearMonth | PlainDateArg): number @@ -160,7 +159,7 @@ const calendarMethods = { toString: getObjId, } -export type CalendarArg = CalendarProtocol | string +export type CalendarArg = CalendarProtocol | string | PlainDate | PlainDateTime | ZonedDateTime | PlainMonthDay | PlainYearMonth export type Calendar = TemporalInstance< CalendarImpl, // internals @@ -168,7 +167,7 @@ export type Calendar = TemporalInstance< typeof calendarMethods // methods > -export const [Calendar, createCalendar] = createTemporalClass( +export const [Calendar, createCalendar] = createSimpleTemporalClass( 'Calendar', // Creation @@ -177,25 +176,20 @@ export const [Calendar, createCalendar] = createTemporalClass( // constructorToInternals queryCalendarImpl, - // internalsConversionMap - {}, - - // bagToInternals - refineComplexBag.bind(undefined, 'calendar', TimeZone), - - // stringToInternals - (str) => queryCalendarImpl(parseCalendarId(str)), - - // handleUnusedOptions - noop, - // Getters // ----------------------------------------------------------------------------------------------- - idGetters as { id: (this: Calendar, impl: CalendarImpl) => string }, + idGetters, // Methods // ----------------------------------------------------------------------------------------------- calendarMethods, + + // Static + // ----------------------------------------------------------------------------------------------- + + { + from: queryCalendarPublic, + } ) diff --git a/packages/temporal-polyfill/src/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts index aaba1c6f..bacc6ec6 100644 --- a/packages/temporal-polyfill/src/calendarOps.ts +++ b/packages/temporal-polyfill/src/calendarOps.ts @@ -8,18 +8,19 @@ import { getInternals, getStrictInternals, idGettersStrict, + TemporalInstance, WrapperInstance, } from './class' import { Duration, createDuration } from './duration' import { DurationInternals } from './durationFields' import { CalendarInternals, IsoDateFields, IsoDateInternals } from './isoFields' -import { LargeInt } from './largeInt' +import { parseCalendarId } from './isoParse' import { Overflow, ensureObjectlike, ensureString, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' import { Unit, unitNamesAsc } from './units' -import { mapProps } from './utils' +import { isObjectlike, mapProps } from './utils' // types @@ -54,23 +55,48 @@ export interface CalendarOps { const checkCalendarProtocol = createProtocolChecker(calendarProtocolMethods) export function queryCalendarOps(calendarArg: CalendarArg): CalendarOps { - if (typeof calendarArg === 'object') { + if (isObjectlike(calendarArg)) { if (calendarArg instanceof Calendar) { return getInternals(calendarArg as Calendar) } - checkCalendarProtocol(calendarArg) - return new CalendarOpsAdapter(calendarArg) + const { calendar } = getInternals(calendarArg as TemporalInstance<{ calendar: CalendarOps }>) || {} + + return calendar || ( + checkCalendarProtocol(calendarArg as CalendarProtocol), + new CalendarOpsAdapter(calendarArg as CalendarProtocol) + ) + } + + return queryCalendarImpl(parseCalendarId(toString(calendarArg))) +} + +export function queryCalendarPublic(calendarArg: CalendarArg): CalendarProtocol { + if (isObjectlike(calendarArg)) { + if (calendarArg instanceof Calendar) { + return calendarArg + } + + const { calendar } = getInternals(calendarArg as TemporalInstance<{ calendar: CalendarOps }>) || {} + + return calendar + ? calendarOpsToPublic(calendar) + : ( + checkCalendarProtocol(calendarArg as CalendarProtocol), + calendarArg as CalendarProtocol + ) } - return queryCalendarImpl(toString(calendarArg)) + return createCalendar(queryCalendarImpl(parseCalendarId(toString(calendarArg)))) } export function getPublicCalendar(internals: { calendar: CalendarOps }): CalendarProtocol { - const { calendar } = internals + return calendarOpsToPublic(internals.calendar) +} - return getInternals(calendar as CalendarOpsAdapter) || - createCalendar(calendar as CalendarImpl) +function calendarOpsToPublic(calendarOps: CalendarOps): CalendarProtocol { + return getInternals(calendarOps as CalendarOpsAdapter) || + createCalendar(calendarOps as CalendarImpl) } export const getCommonCalendarOps = getCommonInnerObj.bind< diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index fd22e443..cb0d02d3 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -143,7 +143,7 @@ const temporaNameMap = new WeakMap, string>() export const getTemporalName = temporaNameMap.get.bind(temporaNameMap) as (arg: unknown) => string | undefined -export function createTemporalClass< +export function createSimpleTemporalClass< B, A extends any[], I, @@ -154,26 +154,17 @@ export function createTemporalClass< >( temporalName: string, constructorToInternals: (...args: A) => I = (identityFunc as any), - internalsConversionMap: { [typeName: string]: (otherInternal: any) => I }, - bagToInternals: (bag: B, options?: O) => I | void, // void opts-out of bag processing - stringToInternals: (str: string) => I, - handleUnusedOptions: (options?: O) => void, getters: G, methods: M, - staticMembers: S = {} as any, + staticMembers: S = {} as any, // need this to be optional? ): [ Class: TemporalClass, - createInstance: (internals: I) => TemporalInstance, - toInternals: (arg: TemporalInstance | B | string, options?: O) => I + createInstance: (internals: I) => TemporalInstance, ] { ;(methods as unknown as ToJsonMethods).toJSON = function() { return String(this) } - ;(staticMembers as any).from = function(arg: TemporalInstance | B | string, options: O) { - return createInstance(toInternals(arg, options)) - } - const TemporalClass = createWrapperClass( getters, methods, @@ -190,6 +181,49 @@ export function createTemporalClass< return instance } + function setTemporalName(instance: TemporalInstance) { + temporaNameMap.set(instance, temporalName) + } + + return [TemporalClass as any, createInstance] +} + +export function createTemporalClass< + B, + A extends any[], + I, + O, + G extends { [propName: string]: (this: TemporalInstance, internals: I) => unknown }, + M extends { [methodName: string]: (this: TemporalInstance, internals: I, ...args: any[]) => unknown }, + S extends {} +>( + temporalName: string, + constructorToInternals: (...args: A) => I = (identityFunc as any), + internalsConversionMap: { [typeName: string]: (otherInternal: any) => I }, + bagToInternals: (bag: B, options?: O) => I | void, // void opts-out of bag processing + stringToInternals: (str: string) => I, + handleUnusedOptions: (options?: O) => void, + getters: G, + methods: M, + staticMembers: S = {} as any, +): [ + Class: TemporalClass, + createInstance: (internals: I) => TemporalInstance, + toInternals: (arg: TemporalInstance | B | string, options?: O) => I +] { + // TODO: cast to better type + ;(staticMembers as any).from = function(arg: TemporalInstance | B | string, options: O) { + return createInstance(toInternals(arg, options)) + } + + const [TemporalClass, createInstance] = createSimpleTemporalClass( + temporalName, + constructorToInternals, + getters, + methods, + staticMembers, + ) + function toInternals(arg: TemporalInstance | B | string, options?: O): I { let argInternals = getInternals(arg) as Reused let argTemporalName @@ -202,10 +236,6 @@ export function createTemporalClass< (handleUnusedOptions(options), (argInternals as I) || stringToInternals(toString(arg))) } - function setTemporalName(instance: TemporalInstance) { - temporaNameMap.set(instance, temporalName) - } - return [TemporalClass as any, createInstance, toInternals] } diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index 5875787f..cd603528 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -562,34 +562,3 @@ function refineFields( return res } - -export function refineComplexBag( - key: K, - ForbiddenClass: unknown, - bag: TemporalInstance> | Record, -): unknown { - const internalArg = getInternals(bag as TemporalInstance>)?.[key] - if (internalArg) { - return internalArg - } - - forbidInstanceClass(bag, ForbiddenClass) - - if (!(key in bag)) { - return bag - } else { - bag = (bag as Record)[key] - - forbidInstanceClass(bag, ForbiddenClass) - - if (isObjectlike(bag) && !(key in bag)) { - return bag - } - } -} - -function forbidInstanceClass(obj: any, Class: any): void { - if (obj instanceof Class) { - throw new RangeError(`Unexpected ${Class.prototype[Symbol.toStringTag]}`) - } -} diff --git a/packages/temporal-polyfill/src/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts index f9051021..cb523711 100644 --- a/packages/temporal-polyfill/src/timeZone.ts +++ b/packages/temporal-polyfill/src/timeZone.ts @@ -1,16 +1,14 @@ import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' -import { Calendar, CalendarArg } from './calendar' +import { CalendarArg } from './calendar' import { queryCalendarOps } from './calendarOps' -import { TemporalInstance, createTemporalClass, getObjId, idGetters } from './class' -import { refineComplexBag } from './convert' +import { TemporalInstance, createSimpleTemporalClass, getObjId, idGetters } from './class' import { Instant, InstantArg, createInstant, toInstantEpochNano } from './instant' import { formatOffsetNano } from './isoFormat' -import { parseTimeZoneId } from './isoParse' import { refineEpochDisambigOptions } from './options' import { PlainDateTime, PlainDateTimeArg, createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' -import { getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' -import { noop } from './utils' +import { getSingleInstantFor, queryTimeZonePublic, zonedEpochNanoToIso } from './timeZoneOps' import { isoCalendarId } from './calendarConfig' +import { ZonedDateTime } from './zonedDateTime' interface TimeZoneProtocolMethods { getOffsetNanosecondsFor(instant: InstantArg): number @@ -83,7 +81,7 @@ const timeZoneMethods: { toString: getObjId, } -export type TimeZoneArg = TimeZoneProtocol | string +export type TimeZoneArg = TimeZoneProtocol | string | ZonedDateTime export type TimeZone = TemporalInstance< TimeZoneImpl, // internals @@ -91,7 +89,7 @@ export type TimeZone = TemporalInstance< typeof timeZoneMethods // methods > -export const [TimeZone, createTimeZone] = createTemporalClass( +export const [TimeZone, createTimeZone] = createSimpleTemporalClass( 'TimeZone', // Creation @@ -100,27 +98,22 @@ export const [TimeZone, createTimeZone] = createTemporalClass( // constructorToInternals queryTimeZoneImpl, - // internalsConversionMap - {}, - - // bagToInternals - refineComplexBag.bind(undefined, 'timeZone', Calendar), - - // stringToInternals - (str) => queryTimeZoneImpl(parseTimeZoneId(str)), - - // handleUnusedOptions - noop, - // Getters // ----------------------------------------------------------------------------------------------- - idGetters as { id: (this: TimeZone, impl: TimeZoneImpl) => string }, + idGetters as { id: (impl: TimeZoneImpl) => string }, // type needed? // Methods // ----------------------------------------------------------------------------------------------- timeZoneMethods, + + // Abstract + // ----------------------------------------------------------------------------------------------- + + { + from: queryTimeZonePublic, + } ) function getImplOffsetNanosecondsFor(impl: TimeZoneImpl, instantArg: InstantArg): number { diff --git a/packages/temporal-polyfill/src/timeZoneOps.ts b/packages/temporal-polyfill/src/timeZoneOps.ts index 4396cc8a..bf8131cf 100644 --- a/packages/temporal-polyfill/src/timeZoneOps.ts +++ b/packages/temporal-polyfill/src/timeZoneOps.ts @@ -1,4 +1,5 @@ import { + TemporalInstance, WrapperInstance, createProtocolChecker, createWrapperClass, @@ -13,6 +14,7 @@ import { epochNanoToIso, isoToEpochNano, } from './isoMath' +import { parseTimeZoneId } from './isoParse' import { LargeInt } from './largeInt' import { moveDateByDays } from './move' import { EpochDisambig, OffsetDisambig, ensureArray, toString } from './options' @@ -21,7 +23,7 @@ import { roundToMinute } from './round' import { TimeZone, TimeZoneArg, TimeZoneProtocol, createTimeZone, timeZoneProtocolMethods } from './timeZone' import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' import { nanoInUtcDay } from './units' -import { createLazyGenerator } from './utils' +import { createLazyGenerator, isObjectlike } from './utils' import { ZonedInternals } from './zonedDateTime' export interface TimeZoneOps { @@ -40,23 +42,48 @@ export const utcTimeZoneId = 'UTC' const checkTimeZoneProtocol = createProtocolChecker(timeZoneProtocolMethods) export function queryTimeZoneOps(timeZoneArg: TimeZoneArg): TimeZoneOps { - if (typeof timeZoneArg === 'object') { + if (isObjectlike(timeZoneArg)) { if (timeZoneArg instanceof TimeZone) { return getInternals(timeZoneArg as TimeZone) } - checkTimeZoneProtocol(timeZoneArg) - return new TimeZoneOpsAdapter(timeZoneArg) + const { timeZone } = getInternals(timeZoneArg as TemporalInstance<{ timeZone: TimeZoneOps }>) || {} + + return timeZone || ( + checkTimeZoneProtocol(timeZoneArg as TimeZoneProtocol), + new TimeZoneOpsAdapter(timeZoneArg as TimeZoneProtocol) + ) } - return queryTimeZoneImpl(toString(timeZoneArg)) + return queryTimeZoneImpl(parseTimeZoneId(toString(timeZoneArg))) +} + +export function queryTimeZonePublic(timeZoneArg: TimeZoneArg): TimeZoneProtocol { + if (isObjectlike(timeZoneArg)) { + if (timeZoneArg instanceof TimeZone) { + return timeZoneArg + } + + const { timeZone } = getInternals(timeZoneArg as TemporalInstance<{ timeZone: TimeZoneOps }>) || {} + + return timeZone + ? timeZoneOpsToPublic(timeZone) + : ( + checkTimeZoneProtocol(timeZoneArg as TimeZoneProtocol), + timeZoneArg as TimeZoneProtocol + ) + } + + return createTimeZone(queryTimeZoneImpl(parseTimeZoneId(toString(timeZoneArg)))) } export function getPublicTimeZone(internals: { timeZone: TimeZoneOps }): TimeZoneProtocol { - const { timeZone } = internals + return timeZoneOpsToPublic(internals.timeZone) +} - return getInternals(timeZone as TimeZoneOpsAdapter) || - createTimeZone(timeZone as TimeZoneImpl) +function timeZoneOpsToPublic(timeZoneOps: TimeZoneOps): TimeZoneProtocol { + return getInternals(timeZoneOps as TimeZoneOpsAdapter) || + createTimeZone(timeZoneOps as TimeZoneImpl) } export const getCommonTimeZoneOps = getCommonInnerObj.bind< diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index d1e98e87..48423859 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -6,7 +6,7 @@ export type Reused = any const objectlikeRE = /object|function/ // TODO: Record -export function isObjectlike(arg: unknown): arg is Record { +export function isObjectlike(arg: unknown): arg is {} { return arg !== null && objectlikeRE.test(typeof arg) } From 44c2a74e398e21b613820dcc47378153d27cbfd0 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 17:41:44 -0400 Subject: [PATCH 183/805] fix marker bugs --- packages/temporal-polyfill/src/duration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/temporal-polyfill/src/duration.ts b/packages/temporal-polyfill/src/duration.ts index 632c5864..fde4da07 100644 --- a/packages/temporal-polyfill/src/duration.ts +++ b/packages/temporal-polyfill/src/duration.ts @@ -273,9 +273,9 @@ function spanDuration( DurationInternals, LargeInt, ] { - const endMarker = markerToEpochNano(moveMarker(marker, durationFields)) + const endMarker = moveMarker(marker, durationFields) const balancedDuration = diffMarkers(marker, endMarker, largestUnit) - return [balancedDuration, endMarker] + return [balancedDuration, markerToEpochNano(endMarker)] } function balanceDurationDayTime( From 09b29e6b4353054583cc9b6c5171597c219bc8c2 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 19:42:25 -0400 Subject: [PATCH 184/805] real options types --- packages/temporal-polyfill/src/convert.ts | 36 +- packages/temporal-polyfill/src/duration.ts | 17 +- packages/temporal-polyfill/src/instant.ts | 9 +- packages/temporal-polyfill/src/intlFormat.ts | 4 +- packages/temporal-polyfill/src/isoFormat.ts | 4 +- packages/temporal-polyfill/src/options.ts | 315 ++++++++++++++---- packages/temporal-polyfill/src/plainDate.ts | 20 +- .../temporal-polyfill/src/plainDateTime.ts | 27 +- packages/temporal-polyfill/src/plainTime.ts | 17 +- .../temporal-polyfill/src/plainYearMonth.ts | 16 +- packages/temporal-polyfill/src/timeZone.ts | 4 +- packages/temporal-polyfill/src/units.ts | 1 + .../temporal-polyfill/src/zonedDateTime.ts | 28 +- 13 files changed, 356 insertions(+), 142 deletions(-) diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index cd603528..95201d0a 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -35,6 +35,8 @@ import { EpochDisambig, OffsetDisambig, Overflow, + OverflowOptions, + ZonedFieldOptions, ensureObjectlike, normalizeOptions, refineOverflowOptions, @@ -98,7 +100,7 @@ export function refineMaybeZonedDateTimeBag(bag: any): ZonedInternals | IsoDateI // ZonedDateTime // ------------------------------------------------------------------------------------------------- -export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: any): ZonedInternals { +export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: ZonedFieldOptions | undefined): ZonedInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, @@ -133,7 +135,7 @@ export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: any): Zon export function mergeZonedDateTimeBag( zonedDateTime: ZonedDateTime, bag: any, - options: any, + options: ZonedFieldOptions, ): ZonedInternals { const { calendar, timeZone } = getInternals(zonedDateTime) const fields = mergeCalendarFields( @@ -190,7 +192,10 @@ export function createZonedDateTimeConverter( // PlainDateTime // ------------------------------------------------------------------------------------------------- -export function refinePlainDateTimeBag(bag: PlainDateTimeBag, options: any): IsoDateTimeInternals { +export function refinePlainDateTimeBag( + bag: PlainDateTimeBag, + options: OverflowOptions | undefined, +): IsoDateTimeInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, @@ -209,7 +214,7 @@ export function refinePlainDateTimeBag(bag: PlainDateTimeBag, options: any): Iso export function mergePlainDateTimeBag( plainDateTime: PlainDateTime, bag: any, - options: any, + options: OverflowOptions | undefined, ): IsoDateTimeInternals { const { calendar } = getInternals(plainDateTime) const fields = mergeCalendarFields( @@ -231,7 +236,7 @@ export function mergePlainDateTimeBag( export function refinePlainDateBag( bag: DateFields, - options: any, + options: OverflowOptions | undefined, calendar: CalendarOps | undefined = getBagCalendarOps(bag) ): IsoDateInternals { const fields = refineCalendarFields( @@ -247,7 +252,7 @@ export function refinePlainDateBag( export function mergePlainDateBag( plainDate: PlainDate, bag: any, - options: any + options: OverflowOptions | undefined, ): IsoDateInternals { const { calendar } = getInternals(plainDate) const fields = mergeCalendarFields( @@ -286,7 +291,7 @@ function convertToIso( export function refinePlainYearMonthBag( bag: any, - options: any, + options: OverflowOptions | undefined, calendar: CalendarOps | undefined = getBagCalendarOps(bag) ): IsoDateInternals { const fields = refineCalendarFields( @@ -302,7 +307,7 @@ export function refinePlainYearMonthBag( export function mergePlainYearMonthBag( plainYearMonth: PlainYearMonth, bag: any, - options: any, + options: OverflowOptions | undefined, ): IsoDateInternals { const { calendar } = getInternals(plainYearMonth) const fields = mergeCalendarFields( @@ -345,7 +350,7 @@ export function convertToPlainYearMonth( export function refinePlainMonthDayBag( bag: any, - options: any, + options: OverflowOptions | undefined, calendar: CalendarOps | undefined = extractBagCalendarOps(bag), ): IsoDateInternals { const calendarAbsent = !calendar @@ -375,7 +380,7 @@ export function refinePlainMonthDayBag( export function mergePlainMonthDayBag( plainMonthDay: PlainMonthDay, bag: any, - options: any, + options: OverflowOptions | undefined, ): IsoDateInternals { const { calendar } = getInternals(plainMonthDay) const fields = mergeCalendarFields( @@ -416,13 +421,20 @@ export function convertPlainMonthDayToDate( // PlainTime // ------------------------------------------------------------------------------------------------- -export function refinePlainTimeBag(bag: any, options: any): IsoTimeFields { +export function refinePlainTimeBag( + bag: any, + options: OverflowOptions | undefined, +): IsoTimeFields { const fields = refineFields(bag, timeFieldNames, []) return refineTimeFields(fields, refineOverflowOptions(options)) } -export function mergePlainTimeBag(plainTime: PlainTime, bag: any, options: any): IsoTimeFields { +export function mergePlainTimeBag( + plainTime: PlainTime, + bag: any, + options: OverflowOptions | undefined, +): IsoTimeFields { const fields = pluckProps(timeFieldNames, plainTime as unknown as TimeFields) // TODO: wish PlainTime had real TS methods const partialFields = refineFields(bag, timeFieldNames) const mergeFields = { ...fields, ...partialFields } diff --git a/packages/temporal-polyfill/src/duration.ts b/packages/temporal-polyfill/src/duration.ts index fde4da07..4ad9d8e8 100644 --- a/packages/temporal-polyfill/src/duration.ts +++ b/packages/temporal-polyfill/src/duration.ts @@ -17,7 +17,10 @@ import { formatDurationInternals } from './isoFormat' import { parseDuration } from './isoParse' import { LargeInt, compareLargeInts } from './largeInt' import { + RelativeToOptions, SubsecDigits, + TimeDisplayOptions, + TotalUnitOptionsWithRel, refineDurationRoundOptions, refineRelativeToOptions, refineTimeDisplayOptions, @@ -33,7 +36,7 @@ import { totalRelativeDuration, } from './round' import { NumSign, noop } from './utils' -import { DayTimeUnit, Unit } from './units' +import { DayTimeUnit, Unit, UnitName } from './units' import { MarkerToEpochNano, MoveMarker, DiffMarkers, createMarkerSystem } from './round' export type DurationArg = Duration | DurationBag | string @@ -161,7 +164,7 @@ export const [ ) }, - total(internals: DurationInternals, options): number { + total(internals: DurationInternals, options: TotalUnitOptionsWithRel | UnitName): number { const [totalUnit, markerInternals] = refineTotalOptions(options) const largestUnit = Math.max( getLargestDurationUnit(internals), @@ -185,7 +188,7 @@ export const [ ) }, - toString(internals: DurationInternals, options: any): string { + toString(internals: DurationInternals, options?: TimeDisplayOptions): string { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options, Unit.Second) return formatDurationInternals( @@ -201,7 +204,11 @@ export const [ // ----------------------------------------------------------------------------------------------- { - compare(durationArg0: DurationArg, durationArg1: DurationArg, options: any): NumSign { + compare( + durationArg0: DurationArg, + durationArg1: DurationArg, + options?: RelativeToOptions, + ): NumSign { const durationFields0 = toDurationInternals(durationArg0) const durationFields1 = toDurationInternals(durationArg1) const markerInternals = refineRelativeToOptions(options) @@ -238,7 +245,7 @@ function addToDuration( direction: -1 | 1, internals: DurationInternals, otherArg: DurationArg, - options: any, // !!! + options: RelativeToOptions | undefined, ): Duration { const otherFields = toDurationInternals(otherArg) const markerInternals = refineRelativeToOptions(options) // optional diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index 5536d538..daeab0b1 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -17,6 +17,8 @@ import { parseInstant } from './isoParse' import { LargeInt, compareLargeInts } from './largeInt' import { moveEpochNano } from './move' import { + DiffOptions, + InstantDisplayOptions, RoundingMode, ensureObjectlike, refineDiffOptions, @@ -134,7 +136,10 @@ export const [ ) }, - toString(epochNano: LargeInt, options: any): string { + toString( + epochNano: LargeInt, + options?: InstantDisplayOptions + ): string { const [ timeZoneArg, nanoInc, @@ -177,7 +182,7 @@ export const [ function diffInstants( epochNano0: LargeInt, epochNano1: LargeInt, - options: any, + options?: DiffOptions, roundingModeInvert?: boolean ): Duration { return createDuration( diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 084b607f..53ae7d10 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -138,8 +138,8 @@ function resolveRangeFormattables( export function resolveZonedFormattable( internals: ZonedInternals, - locales: string | string[], - options: Intl.DateTimeFormatOptions, // NOT resolved yet (does not include locale) + locales?: string | string[], + options?: Intl.DateTimeFormatOptions, // NOT resolved yet (does not include locale) ): [ number, Intl.DateTimeFormat, diff --git a/packages/temporal-polyfill/src/isoFormat.ts b/packages/temporal-polyfill/src/isoFormat.ts index d9267a59..a6284df1 100644 --- a/packages/temporal-polyfill/src/isoFormat.ts +++ b/packages/temporal-polyfill/src/isoFormat.ts @@ -2,7 +2,7 @@ import { isoCalendarId } from './calendarConfig' import { CalendarOps } from './calendarOps' import { DurationInternals, absDurationInternals, durationFieldsToTimeNano } from './durationFields' import { IsoDateFields, IsoDateInternals, IsoDateTimeFields, IsoTimeFields } from './isoFields' -import { CalendarDisplay, OffsetDisplay, refineDateDisplayOptions, SubsecDigits, TimeZoneDisplay } from './options' +import { CalendarDisplay, DateTimeDisplayOptions, OffsetDisplay, refineDateDisplayOptions, SubsecDigits, TimeZoneDisplay } from './options' import { TimeZoneOps } from './timeZoneOps' import { nanoInHour, @@ -20,7 +20,7 @@ High-level. Refined options export function formatPossibleDate( formatSimple: (internals: IsoDateInternals) => string, internals: IsoDateInternals, - options: any, + options?: DateTimeDisplayOptions, ) { const calendarDisplay = refineDateDisplayOptions(options) const showCalendar = diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index b2c458fc..e0ce2a9b 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -21,23 +21,23 @@ import { } from './utils' import { ZonedDateTime, ZonedInternals } from './zonedDateTime' -type Options = Record - // Compound Options // ------------------------------------------------------------------------------------------------- // TODO: always good to spread options tuples? better to nest? -export function refineOverflowOptions(options: Options | undefined): Overflow { +export function refineOverflowOptions(options: OverflowOptions | undefined): Overflow { return refineOverflow(normalizeOptions(options)) } +export type ZonedFieldOptions = OverflowOptions & EpochDisambigOptions & OffsetDisambigOptions + export type ZonedFieldTuple = [ Overflow, EpochDisambig, OffsetDisambig, ] -export function refineZonedFieldOptions(options: Options | undefined): ZonedFieldTuple { +export function refineZonedFieldOptions(options: ZonedFieldOptions | undefined): ZonedFieldTuple { options = normalizeOptions(options) return [ refineOverflow(options), @@ -46,10 +46,12 @@ export function refineZonedFieldOptions(options: Options | undefined): ZonedFiel ] } -export function refineEpochDisambigOptions(options: Options | undefined): EpochDisambig { +export function refineEpochDisambigOptions(options: EpochDisambigOptions | undefined): EpochDisambig { return refineEpochDisambig(normalizeOptions(options)) } +export type DiffOptions = LargestUnitOptions & SmallestUnitOptions & RoundingIncOptions & RoundingModeOptions + export type DiffTuple = [ Unit, // largestUnit Unit, // smallestUnit @@ -59,7 +61,7 @@ export type DiffTuple = [ export function refineDiffOptions( roundingModeInvert: boolean | undefined, - options: Options | undefined, + options: DiffOptions | undefined, defaultLargestUnit: Unit, maxUnit = Unit.Year, minUnit = Unit.Nanosecond, @@ -84,7 +86,7 @@ export function refineDiffOptions( } export function refineCalendarDiffOptions( - options: Options | undefined, + options: LargestUnitOptions | undefined, // TODO: definitely make large-unit type via generics ): Unit { // TODO: only year/month/week/day??? options = normalizeOptions(options) return refineLargestUnit(options, Unit.Year, Unit.Day, Unit.Day) @@ -100,11 +102,14 @@ const smallestUnitStr = 'smallestUnit' const largestUnitStr = 'largestUnit' const totalUnitStr = 'unit' +// TODO: DRY with DiffOptions? +export type RoundingOptions = SmallestUnitOptions & RoundingIncOptions & RoundingModeOptions + /* Always related to time */ export function refineRoundOptions( - options: Options | undefined, + options: RoundingOptions | UnitName, maxUnit: DayTimeUnit = Unit.Day, ): RoundTuple { options = normalizeUnitNameOptions(options, smallestUnitStr) @@ -116,13 +121,15 @@ export function refineRoundOptions( ] } +export type DurationRoundOptions = DiffOptions & RelativeToOptions + export type DurationRoundTuple = [ ...DiffTuple, - RelativeToInternals | undefined, + RelativeToInternals?, ] export function refineDurationRoundOptions( - options: Options | undefined, + options: DurationRoundOptions, defaultLargestUnit: Unit ): DurationRoundTuple { options = normalizeUnitNameOptions(options, smallestUnitStr) @@ -135,8 +142,10 @@ export function refineDurationRoundOptions( ] } +export type TotalUnitOptionsWithRel = TotalUnitOptions & RelativeToOptions + export function refineTotalOptions( - options: Options | undefined + options: TotalUnitOptionsWithRel | UnitName ): [ Unit, RelativeToInternals | undefined, @@ -148,16 +157,20 @@ export function refineTotalOptions( ] } -export function refineRelativeToOptions(options: Options | undefined): RelativeToInternals | undefined { +export function refineRelativeToOptions(options: RelativeToOptions | undefined): RelativeToInternals | undefined { return refineRelativeTo(normalizeOptions(options)) } +export type InstantDisplayOptions = + { timeZone: TimeZoneArg } & + TimeDisplayOptions + export type InstantDisplayTuple = [ TimeZoneArg, ...TimeDisplayTuple, ] -export function refineInstantDisplayOptions(options: Options | undefined): InstantDisplayTuple { +export function refineInstantDisplayOptions(options: InstantDisplayOptions | undefined): InstantDisplayTuple { options = normalizeOptions(options) return [ options.timeZone as TimeZoneArg, // TODO: possibly not needed after moving away from Record @@ -165,6 +178,12 @@ export function refineInstantDisplayOptions(options: Options | undefined): Insta ] } +export type ZonedDateTimeDisplayOptions = + & CalendarDisplayOptions + & TimeZoneDisplayOptions + & OffsetDisplayOptions + & TimeDisplayOptions + export type ZonedDateTimeDisplayTuple = [ CalendarDisplay, TimeZoneDisplay, @@ -172,7 +191,7 @@ export type ZonedDateTimeDisplayTuple = [ ...TimeDisplayTuple, ] -export function refineZonedDateTimeDisplayOptions(options: Options | undefined): ZonedDateTimeDisplayTuple { +export function refineZonedDateTimeDisplayOptions(options: ZonedDateTimeDisplayOptions | undefined): ZonedDateTimeDisplayTuple { options = normalizeOptions(options) return [ refineCalendarDisplay(options), @@ -182,12 +201,14 @@ export function refineZonedDateTimeDisplayOptions(options: Options | undefined): ] } +export type DateTimeDisplayOptions = CalendarDisplayOptions & TimeDisplayOptions + export type DateTimeDisplayTuple = [ CalendarDisplay, ...TimeDisplayTuple, ] -export function refineDateTimeDisplayOptions(options: Options | undefined): DateTimeDisplayTuple { +export function refineDateTimeDisplayOptions(options: DateTimeDisplayOptions | undefined): DateTimeDisplayTuple { options = normalizeOptions(options) return [ refineCalendarDisplay(options), @@ -195,7 +216,7 @@ export function refineDateTimeDisplayOptions(options: Options | undefined): Date ] } -export function refineDateDisplayOptions(options: Options | undefined): CalendarDisplay { +export function refineDateDisplayOptions(options: CalendarDisplayOptions | undefined): CalendarDisplay { return refineCalendarDisplay(normalizeOptions(options)) } @@ -205,22 +226,18 @@ export type TimeDisplayTuple = [ subsecDigits: SubsecDigits | -1 | undefined ] +// TODO: lock-down subset of Unit here? +export type TimeDisplayOptions = SmallestUnitOptions & RoundingModeOptions & SubsecDigitsOptions + export function refineTimeDisplayOptions( - options: Options | undefined, + options: TimeDisplayOptions | undefined, maxSmallestUnit?: TimeUnit ): TimeDisplayTuple { return refineTimeDisplayTuple(normalizeOptions(options), maxSmallestUnit) } -/* -addons: - -1 means hide seconds - undefined means 'auto' (display all digits but no trailing zeros) -*/ -export type SubsecDigits = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 - function refineTimeDisplayTuple( - options: Options, + options: TimeDisplayOptions, maxSmallestUnit: TimeUnit = Unit.Minute ): TimeDisplayTuple { const smallestUnit = refineSmallestUnit(options, maxSmallestUnit, Unit.Nanosecond, -1 as number) @@ -242,19 +259,67 @@ function refineTimeDisplayTuple( ] } +// +// TODO: generic for DayTimeUnit/TimeUnit? + +interface SmallestUnitOptions { + smallestUnit?: UnitName | keyof DurationFields +} + +interface LargestUnitOptions { + largestUnit?: UnitName | keyof DurationFields +} + +interface TotalUnitOptions { + unit: UnitName | keyof DurationFields +} + +// + +const refineSmallestUnit = refineUnitOption.bind< + any, [any], // bound + [SmallestUnitOptions, Unit?, Unit?, Unit?], // unbound + Unit // return +>(undefined, smallestUnitStr) -const refineSmallestUnit = refineUnitOption.bind(undefined, smallestUnitStr) -const refineLargestUnit = refineUnitOption.bind(undefined, largestUnitStr) -const refineTotalUnit = refineUnitOption.bind(undefined, totalUnitStr) +const refineLargestUnit = refineUnitOption.bind< + any, [any], // bound + [LargestUnitOptions, Unit?, Unit?, Unit?], // unbound + Unit +>(undefined, largestUnitStr) + +// TODO: get totalUnitStr closer to this! etc +const refineTotalUnit = refineUnitOption.bind< + any, [any], // bound + [TotalUnitOptions, Unit?, Unit?, Unit?], // unbound + Unit +>(undefined, totalUnitStr) + +// Overflow +// ------------------------------------------------------------------------------------------------- export enum Overflow { Constrain, Reject, } -const refineOverflow = refineChoiceOption.bind(undefined, 'overflow', { + +export interface OverflowOptions { + overflow?: keyof typeof overflowMap +} + +const overflowMap = { constrain: Overflow.Constrain, reject: Overflow.Reject, -}) as (options: Options) => Overflow +} + +const refineOverflow = refineChoiceOption.bind< + any, [any, any], // bound + [OverflowOptions, Overflow?], // unbound + Overflow // return +>(undefined, 'overflow', overflowMap) + +// Epoch Disambig +// ------------------------------------------------------------------------------------------------- export enum EpochDisambig { Compat, @@ -262,12 +327,26 @@ export enum EpochDisambig { Earlier, Later, } -const refineEpochDisambig = refineChoiceOption.bind(undefined, 'disambiguation', { + +export interface EpochDisambigOptions { + disambiguation?: keyof typeof epochDisambigMap +} + +const epochDisambigMap = { compatible: EpochDisambig.Compat, reject: EpochDisambig.Reject, earlier: EpochDisambig.Earlier, later: EpochDisambig.Later, -}) as (options: Options) => EpochDisambig +} + +const refineEpochDisambig = refineChoiceOption.bind< + any, [any, any], // bound + [EpochDisambigOptions, EpochDisambig?], // unbound + EpochDisambig // return +>(undefined, 'disambiguation', epochDisambigMap) + +// Offset Disambig +// ------------------------------------------------------------------------------------------------- export enum OffsetDisambig { Use, @@ -275,12 +354,26 @@ export enum OffsetDisambig { Prefer, Ignore, } -const refineOffsetDisambig = refineChoiceOption.bind(undefined, 'offset', { + +export interface OffsetDisambigOptions { + offset?: keyof typeof offsetDisambigMap +} + +const offsetDisambigMap = { use: OffsetDisambig.Use, reject: OffsetDisambig.Reject, prefer: OffsetDisambig.Prefer, ignore: OffsetDisambig.Ignore, -}) as (options: Options) => OffsetDisambig +} + +const refineOffsetDisambig = refineChoiceOption.bind< + any, [any, any], // bound + [OffsetDisambigOptions, OffsetDisambig?], // unbound + OffsetDisambig // return +>(undefined, 'offset', offsetDisambigMap) + +// Calendar Display +// ------------------------------------------------------------------------------------------------- export enum CalendarDisplay { Auto, @@ -288,32 +381,74 @@ export enum CalendarDisplay { Critical, Always, } -const refineCalendarDisplay = refineChoiceOption.bind(undefined, 'calendarName', { + +export interface CalendarDisplayOptions { + calendarName?: keyof typeof calendarDisplayMap +} + +const calendarDisplayMap = { auto: CalendarDisplay.Auto, never: CalendarDisplay.Never, critical: CalendarDisplay.Critical, always: CalendarDisplay.Always, -}) as (options: Options) => CalendarDisplay +} + +const refineCalendarDisplay = refineChoiceOption.bind< + any, [any, any], // bound + [CalendarDisplayOptions, CalendarDisplay?], // unbound + CalendarDisplay // return +>(undefined, 'calendarName', calendarDisplayMap) + +// TimeZone Display +// ------------------------------------------------------------------------------------------------- export enum TimeZoneDisplay { Auto, Never, Critical, } -const refineTimeZoneDisplay = refineChoiceOption.bind(undefined, 'timeZoneName', { + +export interface TimeZoneDisplayOptions { + timeZoneName?: keyof typeof timeZoneDisplayMap +} + +const timeZoneDisplayMap = { auto: TimeZoneDisplay.Auto, never: TimeZoneDisplay.Never, critical: TimeZoneDisplay.Critical, -}) as (options: Options) => TimeZoneDisplay +} + +const refineTimeZoneDisplay = refineChoiceOption.bind< + any, [any, any], // bound + [TimeZoneDisplayOptions, TimeZoneDisplay?], // unbound + TimeZoneDisplay // return +>(undefined, 'timeZoneName', timeZoneDisplayMap) + +// Offset Display +// ------------------------------------------------------------------------------------------------- export enum OffsetDisplay { Auto, Never, } -const refineOffsetDisplay = refineChoiceOption.bind(undefined, 'offset', { + +export interface OffsetDisplayOptions { + offset?: keyof typeof offsetDisplayMap +} + +const offsetDisplayMap = { auto: OffsetDisplay.Auto, never: OffsetDisplay.Never, -}) as (options: Options) => OffsetDisplay +} + +const refineOffsetDisplay = refineChoiceOption.bind< + any, [any, any], // bound + [OffsetDisplayOptions, OffsetDisplay?], // unbound + OffsetDisplay // return +>(undefined, 'offset', offsetDisplayMap) + +// Rounding Mode +// ------------------------------------------------------------------------------------------------- export enum RoundingMode { // modes that get inverted (see invertRoundingMode) @@ -328,8 +463,12 @@ export enum RoundingMode { HalfExpand, // default for date/time::round() HalfEven, } -// Caller should always supply default -const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', { + +export interface RoundingModeOptions { + roundingMode?: keyof typeof roundingModeMap +} + +const roundingModeMap = { floor: RoundingMode.Floor, halfFloor: RoundingMode.HalfFloor, ceil: RoundingMode.Ceil, @@ -339,7 +478,15 @@ const refineRoundingMode = refineChoiceOption.bind(undefined, 'roundingMode', { expand: RoundingMode.Expand, halfExpand: RoundingMode.HalfExpand, halfEven: RoundingMode.HalfEven, -}) +} + +// Caller should always supply default +const refineRoundingMode = refineChoiceOption.bind< + any, [any, any], // bound + [RoundingModeOptions, RoundingMode?], // unbound + RoundingMode // return +>(undefined, 'roundingMode', roundingModeMap) + export const roundingModeFuncs = [ Math.floor, roundHalfFloor, @@ -359,10 +506,18 @@ function invertRoundingMode(roundingMode: RoundingMode): RoundingMode { return roundingMode } +// Rounding Increment +// ------------------------------------------------------------------------------------------------- + +export interface RoundingIncOptions { + roundingIncrement?: number +} + const roundingIncName = 'roundingIncrement' -function refineRoundingInc(options: Options, smallestUnit: DayTimeUnit) { - let roundingInc = options[roundingIncName] as number +function refineRoundingInc(options: RoundingIncOptions, smallestUnit: DayTimeUnit) { + let roundingInc = options[roundingIncName] + if (roundingInc === undefined) { return 1 } @@ -385,9 +540,23 @@ function refineRoundingInc(options: Options, smallestUnit: DayTimeUnit) { return roundingInc } +// Subsec Digits +// ------------------------------------------------------------------------------------------------- + +/* +addons: + -1 means hide seconds + undefined means 'auto' (display all digits but no trailing zeros) +*/ +export type SubsecDigits = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 + +export interface SubsecDigitsOptions { + fractionalSecondDigits?: SubsecDigits +} + const subsecDigitsName = 'fractionalSecondDigits' -function refineSubsecDigits(options: Options): SubsecDigits | undefined { +function refineSubsecDigits(options: SubsecDigitsOptions): SubsecDigits | undefined { const subsecDigits = options[subsecDigitsName] if (typeof subsecDigits === 'number') { @@ -401,10 +570,17 @@ function refineSubsecDigits(options: Options): SubsecDigits | undefined { // undefind means 'auto' } +// Relative-To +// ------------------------------------------------------------------------------------------------- + +export interface RelativeToOptions { + relativeTo?: ZonedDateTime | PlainDate | string // TODO: include 'bag' in here +} + // TODO: use in definition of `createMarkerSystem` ? type RelativeToInternals = ZonedInternals | IsoDateInternals -function refineRelativeTo(options: Options): RelativeToInternals | undefined { +function refineRelativeTo(options: RelativeToOptions): RelativeToInternals | undefined { const { relativeTo } = options if (relativeTo) { @@ -431,14 +607,15 @@ function refineRelativeTo(options: Options): RelativeToInternals | undefined { /* If defaultUnit is undefined, will throw error if not specified */ -function refineUnitOption( - optionName: string, - options: Options, +function refineUnitOption( + optionName: (keyof O) & string, + options: O, maxUnit: Unit = Unit.Year, minUnit: Unit = Unit.Nanosecond, defaultUnit?: Unit, ): Unit { - let unitName = options[optionName] + let unitName = options[optionName] as (string | undefined) + if (unitName === undefined || unitName === 'auto') { if (defaultUnit === undefined) { throw new RangeError('Must specify' + optionName) // best error? @@ -460,13 +637,13 @@ function refineUnitOption( return unit } -function refineChoiceOption( - optionName: string, +function refineChoiceOption( + optionName: keyof O, enumNameMap: Record, - options: Options, + options: O, defaultChoice = 0, -) { - const enumName = options[optionName] as string +): number { + const enumName = options[optionName] as (string | undefined) if (enumName === undefined) { return defaultChoice } @@ -478,27 +655,27 @@ function refineChoiceOption( return enumNum } -export function normalizeOptions(options: Options | undefined) { +export function normalizeOptions(options: O | undefined): O { if (options === undefined) { - return {} + return {} as O } return ensureObjectlike(options) } -function normalizeUnitNameOptions( - options: Options | undefined, - optionName: string, -) { +function normalizeUnitNameOptions( + options: O | UnitName, + optionName: keyof O, +): O { if (typeof options === 'string') { - return { [optionName]: options } + return { [optionName]: options } as O } - return ensureObjectlike(options as Options) + return ensureObjectlike(options) } -function mustHaveMatch( - props: Options, - propNames: string[], -) { +function mustHaveMatch( + props: O, + propNames: (keyof O)[], +): void { if (!hasAnyPropsByName(props, propNames)) { throw new TypeError('Need one: ' + JSON.stringify(propNames)) } @@ -558,7 +735,7 @@ export function ensureArray(arg: A): A { return arg } -export function ensureObjectlike(arg: O): O { +export function ensureObjectlike(arg: O): O { if (!isObjectlike(arg)) { throw new TypeError('Must be object-like') } diff --git a/packages/temporal-polyfill/src/plainDate.ts b/packages/temporal-polyfill/src/plainDate.ts index 83c5a2a5..44c50a8b 100644 --- a/packages/temporal-polyfill/src/plainDate.ts +++ b/packages/temporal-polyfill/src/plainDate.ts @@ -27,7 +27,7 @@ import { import { formatCalendar, formatIsoDateFields } from './isoFormat' import { compareIsoDateFields, refineIsoDateInternals } from './isoMath' import { parsePlainDate } from './isoParse' -import { refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' +import { DateTimeDisplayOptions, DiffOptions, OverflowOptions, refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' import { PlainDateTime, createPlainDateTime } from './plainDateTime' import { PlainMonthDay } from './plainMonthDay' import { PlainTimeArg, toPlainTimeFields } from './plainTime' @@ -92,7 +92,7 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals: IsoDateInternals, mod: PlainDateMod, options): PlainDate { + with(internals: IsoDateInternals, mod: PlainDateMod, options?: OverflowOptions): PlainDate { return createPlainDate(mergePlainDateBag(this, mod, options)) }, @@ -103,31 +103,31 @@ export const [ }) }, - add(internals: IsoDateInternals, durationArg: DurationArg, options): PlainDate { + add(internals: IsoDateInternals, durationArg: DurationArg, options?: OverflowOptions): PlainDate { return createPlainDate( internals.calendar.dateAdd( internals, toDurationInternals(durationArg), - options, + refineOverflowOptions(options), ), ) }, - subtract(internals: IsoDateInternals, durationArg: DurationArg, options): PlainDate { + subtract(internals: IsoDateInternals, durationArg: DurationArg, options?: OverflowOptions): PlainDate { return createPlainDate( internals.calendar.dateAdd( internals, negateDurationInternals(toDurationInternals(durationArg)), - options, + refineOverflowOptions(options), ), ) }, - until(internals: IsoDateInternals, otherArg: PlainDateArg, options): Duration { + until(internals: IsoDateInternals, otherArg: PlainDateArg, options?: DiffOptions): Duration { return diffPlainDates(internals, toPlainDateInternals(otherArg), options) }, - since(internals: IsoDateInternals, otherArg: PlainDateArg, options): Duration { + since(internals: IsoDateInternals, otherArg: PlainDateArg, options?: DiffOptions): Duration { return diffPlainDates(toPlainDateInternals(otherArg), internals, options, true) }, @@ -138,7 +138,7 @@ export const [ isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals: IsoDateInternals, options: any): string { + toString(internals: IsoDateInternals, options?: DateTimeDisplayOptions): string { return formatIsoDateFields(internals) + formatCalendar(internals.calendar, refineDateDisplayOptions(options)) }, @@ -190,7 +190,7 @@ export const [ function diffPlainDates( internals0: IsoDateInternals, internals1: IsoDateInternals, - options: any, + options: DiffOptions | undefined, roundingModeInvert?: boolean, ): Duration { const calendarOps = getCommonCalendarOps(internals0, internals1) diff --git a/packages/temporal-polyfill/src/plainDateTime.ts b/packages/temporal-polyfill/src/plainDateTime.ts index 6700475a..26e607e1 100644 --- a/packages/temporal-polyfill/src/plainDateTime.ts +++ b/packages/temporal-polyfill/src/plainDateTime.ts @@ -25,7 +25,12 @@ import { compareIsoDateTimeFields, refineIsoDateTimeInternals } from './isoMath' import { parsePlainDateTime } from './isoParse' import { moveDateTime } from './move' import { + DateTimeDisplayOptions, + DiffOptions, + EpochDisambigOptions, + OverflowOptions, RoundingMode, + RoundingOptions, refineDateTimeDisplayOptions, refineDiffOptions, refineEpochDisambigOptions, @@ -39,7 +44,7 @@ import { PlainYearMonth } from './plainYearMonth' import { roundDateTime, roundDateTimeToNano } from './round' import { TimeZoneArg } from './timeZone' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' -import { DayTimeUnit, Unit } from './units' +import { DayTimeUnit, Unit, UnitName } from './units' import { NumSign } from './utils' import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' @@ -107,7 +112,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr // ----------------------------------------------------------------------------------------------- { - with(internals: IsoDateTimeInternals, mod: PlainDateTimeMod, options): PlainDateTime { + with(internals: IsoDateTimeInternals, mod: PlainDateTimeMod, options?: OverflowOptions): PlainDateTime { return createPlainDateTime(mergePlainDateTimeBag(this, mod, options)) }, @@ -132,7 +137,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr }) }, - add(internals: IsoDateTimeInternals, durationArg: DurationArg, options): PlainDateTime { + add(internals: IsoDateTimeInternals, durationArg: DurationArg, options?: OverflowOptions): PlainDateTime { return movePlainDateTime( internals, toDurationInternals(durationArg), @@ -140,7 +145,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr ) }, - subtract(internals: IsoDateTimeInternals, durationArg: DurationArg, options): PlainDateTime { + subtract(internals: IsoDateTimeInternals, durationArg: DurationArg, options?: OverflowOptions): PlainDateTime { return movePlainDateTime( internals, negateDurationInternals(toDurationInternals(durationArg)), @@ -148,15 +153,15 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr ) }, - until(internals: IsoDateTimeInternals, otherArg: PlainDateTimeArg, options): Duration { + until(internals: IsoDateTimeInternals, otherArg: PlainDateTimeArg, options?: DiffOptions): Duration { return diffPlainDateTimes(internals, toPlainDateTimeInternals(otherArg), options) }, - since(internals: IsoDateTimeInternals, otherArg: PlainDateTimeArg, options): Duration { + since(internals: IsoDateTimeInternals, otherArg: PlainDateTimeArg, options?: DiffOptions): Duration { return diffPlainDateTimes(toPlainDateTimeInternals(otherArg), internals, options, true) }, - round(internals: IsoDateTimeInternals, options): PlainDateTime { + round(internals: IsoDateTimeInternals, options: RoundingOptions | UnitName): PlainDateTime { const isoDateTimeFields = roundDateTime( internals, ...(refineRoundOptions(options) as [DayTimeUnit, number, RoundingMode]), @@ -174,7 +179,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr isObjIdsEqual(internals.calendar, otherInternals.calendar) }, - toString(internals: IsoDateTimeInternals, options: any): string { + toString(internals: IsoDateTimeInternals, options?: DateTimeDisplayOptions): string { const [ calendarDisplayI, nanoInc, @@ -195,7 +200,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr toZonedDateTime( internals: IsoDateTimeInternals, timeZoneArg: TimeZoneArg, - options, // { disambiguation } - optional + options?: EpochDisambigOptions, ): ZonedDateTime { const { calendar } = internals const timeZone = queryTimeZoneOps(timeZoneArg) @@ -249,7 +254,7 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr function movePlainDateTime( internals: IsoDateTimeInternals, durationInternals: DurationInternals, - options: any, + options: OverflowOptions | undefined, ): PlainDateTime { return createPlainDateTime( moveDateTime( @@ -264,7 +269,7 @@ function movePlainDateTime( function diffPlainDateTimes( internals0: IsoDateTimeInternals, internals1: IsoDateTimeInternals, - options: any, + options: DiffOptions | undefined, roundingModeInvert?: boolean ): Duration { return createDuration( diff --git a/packages/temporal-polyfill/src/plainTime.ts b/packages/temporal-polyfill/src/plainTime.ts index fdd647d4..ad6e70de 100644 --- a/packages/temporal-polyfill/src/plainTime.ts +++ b/packages/temporal-polyfill/src/plainTime.ts @@ -14,7 +14,10 @@ import { compareIsoTimeFields, refineIsoTimeInternals } from './isoMath' import { parsePlainTime } from './isoParse' import { moveTime } from './move' import { + DiffOptions, RoundingMode, + RoundingOptions, + TimeDisplayOptions, refineDiffOptions, refineOverflowOptions, refineRoundOptions, @@ -24,7 +27,7 @@ import { PlainDateArg, toPlainDateInternals } from './plainDate' import { PlainDateTime, createPlainDateTime } from './plainDateTime' import { roundTime, roundTimeToNano } from './round' import { zonedInternalsToIso } from './timeZoneOps' -import { TimeUnit, Unit } from './units' +import { TimeUnit, Unit, UnitName } from './units' import { NumSign } from './utils' export type PlainTimeArg = PlainTime | PlainTimeBag | string @@ -99,15 +102,15 @@ export const [ return movePlainTime(fields, negateDurationInternals(toDurationInternals(durationArg))) }, - until(fields: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { + until(fields: IsoTimeFields, otherArg: PlainTimeArg, options?: DiffOptions): Duration { return diffPlainTimes(fields, toPlainTimeFields(otherArg), options) }, - since(fields: IsoTimeFields, otherArg: PlainTimeArg, options): Duration { + since(fields: IsoTimeFields, otherArg: PlainTimeArg, options?: DiffOptions): Duration { return diffPlainTimes(toPlainTimeFields(otherArg), fields, options, true) }, - round(fields: IsoTimeFields, options): PlainTime { + round(fields: IsoTimeFields, options: RoundingOptions | UnitName): PlainTime { return createPlainTime( roundTime( fields, @@ -121,7 +124,7 @@ export const [ return !compareIsoTimeFields(fields, otherInternals) }, - toString(fields: IsoTimeFields, options: any): string { + toString(fields: IsoTimeFields, options?: TimeDisplayOptions): string { const [nanoInc, roundingMode, subsecDigits] = refineTimeDisplayOptions(options) return formatIsoTimeFields( @@ -134,7 +137,7 @@ export const [ valueOf: neverValueOf, - toZonedDateTime: createZonedDateTimeConverter((options) => { + toZonedDateTime: createZonedDateTimeConverter((options: any) => { return toPlainDateInternals(options.plainDate) }), @@ -171,7 +174,7 @@ function movePlainTime(internals: IsoTimeFields, durationInternals: DurationInte function diffPlainTimes( internals0: IsoTimeFields, internals1: IsoTimeFields, - options: any, + options: DiffOptions | undefined, roundingModeInvert?: boolean ): Duration { return createDuration( diff --git a/packages/temporal-polyfill/src/plainYearMonth.ts b/packages/temporal-polyfill/src/plainYearMonth.ts index cfcee210..e5a94596 100644 --- a/packages/temporal-polyfill/src/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/plainYearMonth.ts @@ -16,7 +16,7 @@ import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' import { compareIsoDateFields, refineIsoDateInternals } from './isoMath' import { parsePlainYearMonth } from './isoParse' import { moveDateByDays } from './move' -import { refineDiffOptions, refineOverflowOptions } from './options' +import { DiffOptions, OverflowOptions, refineDiffOptions, refineOverflowOptions } from './options' import { PlainDate } from './plainDate' import { Unit } from './units' import { NumSign } from './utils' @@ -73,11 +73,11 @@ export const [ // ----------------------------------------------------------------------------------------------- { - with(internals: IsoDateInternals, mod: PlainYearMonthMod, options): PlainYearMonth { + with(internals: IsoDateInternals, mod: PlainYearMonthMod, options?: OverflowOptions): PlainYearMonth { return createPlainYearMonth(mergePlainYearMonthBag(this, mod, options)) }, - add(internals: IsoDateInternals, durationArg: DurationArg, options): PlainYearMonth { + add(internals: IsoDateInternals, durationArg: DurationArg, options?: OverflowOptions): PlainYearMonth { return movePlainYearMonth( internals, toDurationInternals(durationArg), @@ -85,7 +85,7 @@ export const [ ) }, - subtract(internals: IsoDateInternals, durationArg: DurationArg, options): PlainYearMonth { + subtract(internals: IsoDateInternals, durationArg: DurationArg, options?: OverflowOptions): PlainYearMonth { return movePlainYearMonth( internals, negateDurationInternals(toDurationInternals(durationArg)), @@ -93,11 +93,11 @@ export const [ ) }, - until(internals: IsoDateInternals, otherArg: PlainYearMonthArg, options): Duration { + until(internals: IsoDateInternals, otherArg: PlainYearMonthArg, options?: DiffOptions): Duration { return diffPlainYearMonths(internals, toPlainYearMonthInternals(otherArg), options) }, - since(internals: IsoDateInternals, otherArg: PlainYearMonthArg, options): Duration { + since(internals: IsoDateInternals, otherArg: PlainYearMonthArg, options?: DiffOptions): Duration { return diffPlainYearMonths(toPlainYearMonthInternals(otherArg), internals, options, true) }, @@ -142,7 +142,7 @@ export const [ function diffPlainYearMonths( internals0: IsoDateInternals, internals1: IsoDateInternals, - options: any, + options: DiffOptions | undefined, roundingModeInvert?: boolean ): Duration { return createDuration( @@ -160,7 +160,7 @@ function diffPlainYearMonths( function movePlainYearMonth( internals: IsoDateInternals, durationInternals: DurationInternals, - options: any, + options: OverflowOptions | undefined, ): PlainYearMonth { const { calendar } = internals const isoDateFields = movePlainYearMonthToDay( diff --git a/packages/temporal-polyfill/src/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts index cb523711..218a3da7 100644 --- a/packages/temporal-polyfill/src/timeZone.ts +++ b/packages/temporal-polyfill/src/timeZone.ts @@ -4,7 +4,7 @@ import { queryCalendarOps } from './calendarOps' import { TemporalInstance, createSimpleTemporalClass, getObjId, idGetters } from './class' import { Instant, InstantArg, createInstant, toInstantEpochNano } from './instant' import { formatOffsetNano } from './isoFormat' -import { refineEpochDisambigOptions } from './options' +import { EpochDisambigOptions, refineEpochDisambigOptions } from './options' import { PlainDateTime, PlainDateTimeArg, createPlainDateTime, toPlainDateTimeInternals } from './plainDateTime' import { getSingleInstantFor, queryTimeZonePublic, zonedEpochNanoToIso } from './timeZoneOps' import { isoCalendarId } from './calendarConfig' @@ -64,7 +64,7 @@ const timeZoneMethods: { }) }, - getInstantFor(impl: TimeZoneImpl, plainDateTimeArg: PlainDateTimeArg, options: any): Instant { + getInstantFor(impl: TimeZoneImpl, plainDateTimeArg: PlainDateTimeArg, options?: EpochDisambigOptions): Instant { return createInstant( getSingleInstantFor( impl, diff --git a/packages/temporal-polyfill/src/units.ts b/packages/temporal-polyfill/src/units.ts index 2064ee5c..c19bbd4f 100644 --- a/packages/temporal-polyfill/src/units.ts +++ b/packages/temporal-polyfill/src/units.ts @@ -30,6 +30,7 @@ export const unitNameMap = { } export type UnitName = keyof typeof unitNameMap +// TODO: more convenient type for OR-ing with DurationFields (for plural?) export type TimeUnit = Unit.Nanosecond | diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index a3dbc522..63558a15 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -37,10 +37,14 @@ import { parseZonedDateTime } from './isoParse' import { LargeInt, compareLargeInts } from './largeInt' import { moveZonedEpochNano } from './move' import { + DiffOptions, EpochDisambig, OffsetDisambig, Overflow, + OverflowOptions, RoundingMode, + RoundingOptions, + ZonedDateTimeDisplayOptions, refineDiffOptions, refineOverflowOptions, refineRoundOptions, @@ -63,7 +67,7 @@ import { queryTimeZoneOps, zonedInternalsToIso, } from './timeZoneOps' -import { DayTimeUnit, Unit, nanoInHour } from './units' +import { DayTimeUnit, Unit, UnitName, nanoInHour } from './units' import { NumSign, mapProps } from './utils' export type ZonedDateTimeArg = ZonedDateTime | ZonedDateTimeBag | string @@ -226,34 +230,34 @@ export const [ }) }, - add(internals: ZonedInternals, durationArg: DurationArg, options): ZonedDateTime { + add(internals: ZonedInternals, durationArg: DurationArg, options?: OverflowOptions): ZonedDateTime { return moveZonedDateTime( internals, toDurationInternals(durationArg), - options, + refineOverflowOptions(options), ) }, - subtract(internals: ZonedInternals, durationArg: DurationArg, options): ZonedDateTime { + subtract(internals: ZonedInternals, durationArg: DurationArg, options?: OverflowOptions): ZonedDateTime { return moveZonedDateTime( internals, negateDurationInternals(toDurationInternals(durationArg)), - options, + refineOverflowOptions(options), ) }, - until(internals: ZonedInternals, otherArg: ZonedDateTimeArg, options): Duration { + until(internals: ZonedInternals, otherArg: ZonedDateTimeArg, options?: DiffOptions): Duration { return diffZonedDateTimes(internals, toZonedInternals(otherArg), options) }, - since(internals: ZonedInternals, otherArg: ZonedDateTimeArg, options): Duration { + since(internals: ZonedInternals, otherArg: ZonedDateTimeArg, options?: DiffOptions): Duration { return diffZonedDateTimes(toZonedInternals(otherArg), internals, options, true) }, /* Do param-list destructuring here and other methods! */ - round(internals: ZonedInternals, options): ZonedDateTime { + round(internals: ZonedInternals, options: RoundingOptions | UnitName): ZonedDateTime { let { epochNanoseconds, timeZone, calendar } = internals const offsetNanoseconds = timeZone.getOffsetNanosecondsFor(epochNanoseconds) @@ -314,7 +318,7 @@ export const [ isObjIdsEqual(internals.timeZone, otherInternals.timeZone) }, - toString(internals: ZonedInternals, options: any): string { + toString(internals: ZonedInternals, options?: ZonedDateTimeDisplayOptions): string { let { epochNanoseconds, timeZone, calendar } = internals const [ calendarDisplayI, @@ -351,8 +355,8 @@ export const [ toLocaleString( internals: ZonedInternals, - locales: string | string[], - options: any, + locales?: string | string[], + options?: Intl.DateTimeFormatOptions, ): string { const [epochMilli, format] = resolveZonedFormattable(internals, locales, options) return format.format(epochMilli) @@ -438,7 +442,7 @@ function moveZonedDateTime( function diffZonedDateTimes( internals: ZonedInternals, otherInternals: ZonedInternals, - options: any, + options: DiffOptions | undefined, roundingModeInvert?: boolean ): Duration { return createDuration( From 735a66fedbf6bd71ecb8ab130b158297729ca206 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 20:26:22 -0400 Subject: [PATCH 185/805] fix last type errors --- packages/temporal-polyfill/src/calendarOps.ts | 9 +++++---- packages/temporal-polyfill/src/class.ts | 2 +- packages/temporal-polyfill/src/convert.ts | 4 ++-- packages/temporal-polyfill/src/instant.ts | 4 ++-- packages/temporal-polyfill/src/options.ts | 17 +++++++++-------- packages/temporal-polyfill/src/utils.ts | 2 +- packages/temporal-polyfill/src/zonedDateTime.ts | 2 +- 7 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/temporal-polyfill/src/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts index bacc6ec6..ddede380 100644 --- a/packages/temporal-polyfill/src/calendarOps.ts +++ b/packages/temporal-polyfill/src/calendarOps.ts @@ -20,7 +20,7 @@ import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' import { Unit, unitNamesAsc } from './units' -import { isObjectlike, mapProps } from './utils' +import { Callable, isObjectlike, mapProps } from './utils' // types @@ -133,10 +133,11 @@ const getDurationInternals = getStrictInternals.bind< >(undefined, Duration) const calendarOpsAdapterMethods = { - ...mapProps((refiner, propName) => { + ...mapProps((refiner: Callable, propName) => { return ((calendar: CalendarProtocol, isoDateFields: IsoDateFields) => { - // TODO: fix type error by having more specific refiner inputs - return refiner(calendar[propName](createPlainDate(isoDateFields))) + // HACK: hopefully `calendar` not accessed + const pd = createPlainDate(isoDateFields as IsoDateInternals) + return refiner(calendar[propName](pd)) }) }, dateGetterRefiners) as { [K in keyof DateGetterFields]: (calendar: CalendarProtocol, isoFields: IsoDateFields) => DateGetterFields[K] diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index cb0d02d3..8008e723 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -233,7 +233,7 @@ export function createTemporalClass< } return (!argInternals && isObjectlike(arg) && bagToInternals(arg as B, options)) || - (handleUnusedOptions(options), (argInternals as I) || stringToInternals(toString(arg))) + (handleUnusedOptions(options), (argInternals as I) || stringToInternals(toString(arg as string))) } return [TemporalClass as any, createInstance, toInternals] diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index 95201d0a..dff25685 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -49,7 +49,7 @@ import { PlainMonthDay, createPlainMonthDay } from './plainMonthDay' import { PlainTime } from './plainTime' import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { Reused, excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' +import { Callable, Reused, excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' import { ZonedDateTime, ZonedDateTimeBag, ZonedInternals, createZonedDateTime } from './zonedDateTime' /* @@ -555,7 +555,7 @@ function refineFields( any = true if (builtinRefiners[fieldName as keyof typeof builtinRefiners]) { - fieldVal = builtinRefiners[fieldName as keyof typeof builtinRefiners](fieldVal) + fieldVal = (builtinRefiners[fieldName as keyof typeof builtinRefiners] as Callable)(fieldVal) } res[fieldName] = fieldVal diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index daeab0b1..e6d0cd47 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -169,11 +169,11 @@ export const [ fromEpochMilliseconds: epochMilliToInstant, - fromEpochMicroseconds(epochMicro: LargeInt): Instant { + fromEpochMicroseconds(epochMicro: bigint): Instant { return epochMicroToInstant(toEpochNano(epochMicro)) }, - fromEpochNanoseconds(epochNano: LargeInt): Instant { + fromEpochNanoseconds(epochNano: bigint): Instant { return createInstant(toEpochNano(epochNano)) }, }, diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index e0ce2a9b..aae2fb68 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -681,7 +681,7 @@ function mustHaveMatch( } } -export function toEpochNano(arg: any): LargeInt { +export function toEpochNano(arg: bigint): LargeInt { if (typeof arg !== 'bigint') { throw new TypeError('Needs bigint') } @@ -700,6 +700,7 @@ export function clampProp

( // Primitives // ------------------------------------------------------------------------------------------------- +// NOTE: even though these accept 'any', strictly type so TS interface is more strict export function ensureInstanceOf(Class: { new(): T }, obj: T): T { if (!(obj instanceof Class)) { @@ -716,13 +717,13 @@ function ensureType(typeName: string, arg: A): A { } export const ensureString = ensureType.bind(undefined, 'string') as - (arg: unknown) => string + (arg: string) => string export const ensureNumber = ensureType.bind(undefined, 'number') as - (arg: unknown) => number + (arg: number) => number export const ensureBoolean = ensureType.bind(undefined, 'boolean') as - (arg: unknown) => boolean + (arg: boolean) => boolean export function ensureInteger(arg: number): number { return ensureNumberIsInteger(ensureNumber(arg)) @@ -742,7 +743,7 @@ export function ensureObjectlike(arg: O): O { return arg } -export function toString(arg: any): string { +export function toString(arg: string): string { if (typeof arg === 'symbol') { throw new TypeError('Cannot convert a Symbol to a String') } @@ -752,14 +753,14 @@ export function toString(arg: any): string { /* truncates floats */ -export function toInteger(arg: any): number { +export function toInteger(arg: number): number { return Math.trunc(toNumber(arg)) || 0 // ensure no -0 } /* throws error on floats */ -export function toIntegerStrict(arg: any): number { +export function toIntegerStrict(arg: number): number { return ensureNumberIsInteger(toNumber(arg)) } @@ -773,7 +774,7 @@ function ensureNumberIsInteger(num: number): number { /* Caller must do ||0 to ensure no -0 */ -function toNumber(arg: any): number { +function toNumber(arg: number): number { arg = Number(arg) if (isNaN(arg)) { throw new RangeError('not a number') diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index 48423859..e9fd3d33 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -1,7 +1,7 @@ -import { IsoDateFields, IsoDateInternals } from './isoFields' import { Overflow } from './options' export type Reused = any +export type Callable = (...args: any[]) => any const objectlikeRE = /object|function/ diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index 63558a15..b739609e 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -96,7 +96,7 @@ export const [ // constructorToInternals ( - epochNano: LargeInt, + epochNano: bigint, timeZoneArg: TimeZoneArg, calendarArg: CalendarArg = isoCalendarId, ): ZonedInternals => { From 2abb6e1c0a828c9cd44968076b9fdbb5ee7f143b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 20:35:21 -0400 Subject: [PATCH 186/805] use const enums --- packages/temporal-polyfill/src/options.ts | 14 +++++++------- packages/temporal-polyfill/src/units.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index aae2fb68..cb37b7a2 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -298,7 +298,7 @@ const refineTotalUnit = refineUnitOption.bind< // Overflow // ------------------------------------------------------------------------------------------------- -export enum Overflow { +export const enum Overflow { Constrain, Reject, } @@ -321,7 +321,7 @@ const refineOverflow = refineChoiceOption.bind< // Epoch Disambig // ------------------------------------------------------------------------------------------------- -export enum EpochDisambig { +export const enum EpochDisambig { Compat, Reject, Earlier, @@ -348,7 +348,7 @@ const refineEpochDisambig = refineChoiceOption.bind< // Offset Disambig // ------------------------------------------------------------------------------------------------- -export enum OffsetDisambig { +export const enum OffsetDisambig { Use, Reject, Prefer, @@ -375,7 +375,7 @@ const refineOffsetDisambig = refineChoiceOption.bind< // Calendar Display // ------------------------------------------------------------------------------------------------- -export enum CalendarDisplay { +export const enum CalendarDisplay { Auto, Never, Critical, @@ -402,7 +402,7 @@ const refineCalendarDisplay = refineChoiceOption.bind< // TimeZone Display // ------------------------------------------------------------------------------------------------- -export enum TimeZoneDisplay { +export const enum TimeZoneDisplay { Auto, Never, Critical, @@ -427,7 +427,7 @@ const refineTimeZoneDisplay = refineChoiceOption.bind< // Offset Display // ------------------------------------------------------------------------------------------------- -export enum OffsetDisplay { +export const enum OffsetDisplay { Auto, Never, } @@ -450,7 +450,7 @@ const refineOffsetDisplay = refineChoiceOption.bind< // Rounding Mode // ------------------------------------------------------------------------------------------------- -export enum RoundingMode { +export const enum RoundingMode { // modes that get inverted (see invertRoundingMode) Floor, HalfFloor, diff --git a/packages/temporal-polyfill/src/units.ts b/packages/temporal-polyfill/src/units.ts index c19bbd4f..63444fb3 100644 --- a/packages/temporal-polyfill/src/units.ts +++ b/packages/temporal-polyfill/src/units.ts @@ -3,7 +3,7 @@ import { LargeInt, numberToLargeInt } from './largeInt' /* TODO: use short names? */ -export enum Unit { +export const enum Unit { Nanosecond, Microsecond, Millisecond, From 5a9320298ae55bd7ea528c866cb7858353873ad6 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 31 Jul 2023 20:47:38 -0400 Subject: [PATCH 187/805] hack building --- .npmrc | 2 +- packages/temporal-polyfill/tsconfig.json | 2 +- scripts/lib/pkgBundle.cjs | 18 ++++++++++-------- tsconfig.base.json | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.npmrc b/.npmrc index bffee7e0..67a92923 100644 --- a/.npmrc +++ b/.npmrc @@ -2,6 +2,6 @@ engine-strict = true # for some reason 16.18.0 cause sub-second tz offsets to fail # NOTE: keep in sync with github workflow -use-node-version = 16.13.1 +use-node-version = 16.18.0 prefer-workspace-packages = true diff --git a/packages/temporal-polyfill/tsconfig.json b/packages/temporal-polyfill/tsconfig.json index 6bb08d54..ccd8e3cd 100644 --- a/packages/temporal-polyfill/tsconfig.json +++ b/packages/temporal-polyfill/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.base", "compilerOptions": { "rootDir": "src", - "outDir": "dist", + "outDir": "dist/.tsc", "types": [], "target": "ES2018", "lib": [ diff --git a/scripts/lib/pkgBundle.cjs b/scripts/lib/pkgBundle.cjs index 409cf488..d7c916b1 100644 --- a/scripts/lib/pkgBundle.cjs +++ b/scripts/lib/pkgBundle.cjs @@ -26,13 +26,14 @@ async function buildPkgBundleConfigs(pkgDir, commandLineArgs) { const { entryPoints, entryPointTypes, globalEntryPoints, dependencyNames } = pkgAnalysis const configs = globalEntryPoints.map((globalEntryPoint) => ({ - input: path.join(pkgDir, globalEntryPoint), + input: path.join(pkgDir, globalEntryPoint.replace('/src/', '/dist/.tsc/').replace(/\.ts$/, '.js')), external: dependencyNames, output: buildGlobalOutputConfig(pkgDir), watch: watchOptions, plugins: buildPlugins(watch), })) + /* if (entryPoints.length) { configs.push({ input: entryPoints.map((f) => path.join(pkgDir, f)), @@ -45,6 +46,7 @@ async function buildPkgBundleConfigs(pkgDir, commandLineArgs) { plugins: buildPlugins(watch), }) } + */ /* if (entryPointTypes.length && !watch) { @@ -90,14 +92,14 @@ function buildGlobalOutputConfig(pkgDir) { function buildPlugins(watch) { return [ resolve({ - extensions: ['.js', '.ts'], - }), - esbuild({ - // TODO: this is a bad technique because it has the potential to inject multiple - // helper-functions in the same output. Luckily it doesn't for this target. - target: 'es2018', + extensions: ['.js', /* '.ts' */], }), - tsFileOverriding('.build.ts'), + // esbuild({ + // // TODO: this is a bad technique because it has the potential to inject multiple + // // helper-functions in the same output. Luckily it doesn't for this target. + // target: 'es2018', + // }), + // tsFileOverriding('.build.ts'), !watch && !noMin && terser(terserConfig), ] } diff --git a/tsconfig.base.json b/tsconfig.base.json index ef48e603..3e3b9141 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -7,8 +7,8 @@ "moduleResolution": "Node", "composite": true, "allowJs": true, - "isolatedModules": true, - "emitDeclarationOnly": true, + "isolatedModules": false, + "emitDeclarationOnly": false, "esModuleInterop": true, "importHelpers": true, "resolveJsonModule": true, From e7593ecb908a832909ead957d2a61812c268d6f7 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 1 Aug 2023 15:59:36 -0400 Subject: [PATCH 188/805] much better types for bags --- packages/temporal-polyfill/src/calendar.ts | 40 +++-- .../temporal-polyfill/src/calendarFields.ts | 61 ++++++-- .../temporal-polyfill/src/calendarImpl.ts | 55 ++++--- packages/temporal-polyfill/src/calendarOps.ts | 59 +++++-- packages/temporal-polyfill/src/convert.ts | 146 ++++++++++-------- .../src/old/calendarImpl/calendarImpl.ts | 4 +- packages/temporal-polyfill/src/options.ts | 9 +- packages/temporal-polyfill/src/plainDate.ts | 6 +- .../temporal-polyfill/src/plainDateTime.ts | 6 +- .../temporal-polyfill/src/plainMonthDay.ts | 8 +- packages/temporal-polyfill/src/plainTime.ts | 6 +- .../temporal-polyfill/src/plainYearMonth.ts | 6 +- packages/temporal-polyfill/src/utils.ts | 4 + .../temporal-polyfill/src/zonedDateTime.ts | 2 +- 14 files changed, 266 insertions(+), 146 deletions(-) diff --git a/packages/temporal-polyfill/src/calendar.ts b/packages/temporal-polyfill/src/calendar.ts index fb677237..5ded8889 100644 --- a/packages/temporal-polyfill/src/calendar.ts +++ b/packages/temporal-polyfill/src/calendar.ts @@ -1,4 +1,4 @@ -import { DateGetterFields, dateGetterNames } from './calendarFields' +import { DateBagStrict, DateGetterFields, MonthDayBagStrict, YearMonthBagStrict, dateGetterNames } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { queryCalendarPublic } from './calendarOps' import { TemporalInstance, createSimpleTemporalClass, getInternals, getObjId, getTemporalName, idGetters } from './class' @@ -10,6 +10,8 @@ import { import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { IsoDateFields } from './isoFields' import { + LargestUnitOptions, + OverflowOptions, ensureObjectlike, ensureString, refineCalendarDiffOptions, @@ -38,13 +40,13 @@ interface CalendarProtocolMethods { daysInYear(dateArg: PlainYearMonth | PlainDateArg): number monthsInYear(dateArg: PlainYearMonth | PlainDateArg): number inLeapYear(dateArg: PlainYearMonth | PlainDateArg): boolean - dateFromFields(fields: any, options: any): PlainDate - yearMonthFromFields(fields: any, options: any): PlainYearMonth - monthDayFromFields(fields: any, options: any): PlainMonthDay - dateAdd(dateArg: PlainDateArg, duration: DurationArg, options: any): PlainDate - dateUntil(dateArg0: PlainDateArg, dateArg1: PlainDateArg, options: any): Duration + dateFromFields(fields: DateBagStrict, options: OverflowOptions): PlainDate + yearMonthFromFields(fields: YearMonthBagStrict, options: OverflowOptions): PlainYearMonth + monthDayFromFields(fields: MonthDayBagStrict, options: OverflowOptions): PlainMonthDay + dateAdd(dateArg: PlainDateArg, duration: DurationArg, options: OverflowOptions): PlainDate + dateUntil(dateArg0: PlainDateArg, dateArg1: PlainDateArg, options: LargestUnitOptions): Duration fields(fieldNames: Iterable): Iterable - mergeFields(fields0: any, fields1: any): any + mergeFields(fields0: Record, fields1: Record): Record toString?(): string; toJSON?(): string; } @@ -84,14 +86,14 @@ export const calendarProtocolMethods = { return impl[propName](isoFields) } }, dateGetterNames) as { - [K in keyof DateGetterFields]: (impl: CalendarImpl, dateArg: any) => DateGetterFields[K] + [K in keyof DateGetterFields]: (impl: CalendarImpl, dateArg: DateArg) => DateGetterFields[K] }, dateAdd( impl: CalendarImpl, plainDateArg: PlainDateArg, durationArg: DurationArg, - options?: any, + options?: OverflowOptions, ): PlainDate { return createPlainDate( impl.dateAdd( @@ -106,7 +108,7 @@ export const calendarProtocolMethods = { impl: CalendarImpl, plainDateArg0: PlainDateArg, plainDateArg1: PlainDateArg, - options?: any, + options?: LargestUnitOptions, ): Duration { return createDuration( impl.dateUntil( @@ -119,24 +121,24 @@ export const calendarProtocolMethods = { dateFromFields( impl: CalendarImpl, - fields: any, - options?: any, + fields: DateBagStrict, + options?: OverflowOptions, ): PlainDate { return createPlainDate(refinePlainDateBag(fields, options, impl)) }, yearMonthFromFields( impl: CalendarImpl, - fields: any, - options?: any, + fields: YearMonthBagStrict, + options?: OverflowOptions, ): PlainYearMonth { return createPlainYearMonth(refinePlainYearMonthBag(fields, options, impl)) }, monthDayFromFields( impl: CalendarImpl, - fields: any, - options?: any, + fields: MonthDayBagStrict, + options?: OverflowOptions, ): PlainMonthDay { return createPlainMonthDay(refinePlainMonthDayBag(fields, options, impl)) }, @@ -146,7 +148,11 @@ export const calendarProtocolMethods = { // TODO: kill ensureArray everywhere? use [...] technique? }, - mergeFields(impl: CalendarImpl, fields0: any, fields1: any): any { + mergeFields( + impl: CalendarImpl, + fields0: Record, + fields1: Record + ): Record { return impl.mergeFields( excludeUndefinedProps(ensureObjectlike(fields0)), excludeUndefinedProps(ensureObjectlike(fields1)), diff --git a/packages/temporal-polyfill/src/calendarFields.ts b/packages/temporal-polyfill/src/calendarFields.ts index 0b96d8a1..df164bd6 100644 --- a/packages/temporal-polyfill/src/calendarFields.ts +++ b/packages/temporal-polyfill/src/calendarFields.ts @@ -8,12 +8,10 @@ import { import { ensureBoolean, ensureInteger, toInteger, toString } from './options' import { FilterPropValues, mapPropNames, mapPropNamesToConstant, remapProps } from './utils' -export interface EraYearFields { - era: string - eraYear: number -} +// Year/Month/Day (no era/eraYear) +// ------------------------------------------------------------------------------------------------- -export interface AllYearFields extends EraYearFields { +export interface YearFields { year: number } @@ -22,9 +20,46 @@ export interface MonthFields { month: number } -export type YearMonthFields = { year: number } & MonthFields -export type DateFields = YearMonthFields & { day: number } -type MonthDayFields = MonthFields & { day: number } +export interface DayFields { + day: number +} + +export type YearMonthFields = YearFields & MonthFields +export type DateFields = YearMonthFields & DayFields +export type MonthDayFields = MonthFields & DayFields + +// Fields with era/eraYear +// ------------------------------------------------------------------------------------------------- + +export interface EraYearFields { + era: string + eraYear: number +} + +export type YearFieldsIntl = EraYearFields & YearFields +export type YearMonthFieldsIntl = EraYearFields & YearMonthFields +export type DateFieldsIntl = EraYearFields & DateFields +export type MonthDayFieldsIntl = EraYearFields & MonthDayFields + +// Simple Bag (all props optional) +// ------------------------------------------------------------------------------------------------- + +export type YearMonthBag = Partial +export type DateBag = Partial +export type MonthDayBag = Partial + +// Strict Bag (with complex expressions) +// ------------------------------------------------------------------------------------------------- + +export type EraYearOrYear = EraYearFields | YearFields +export type MonthCodeOrMonthAndYear = { monthCode: string } | ({ month: number } & EraYearOrYear) +export type MonthCodeOrMonth = { monthCode: string } | { month: number } + +export type YearMonthBagStrict = EraYearOrYear & MonthCodeOrMonth +export type DateBagStrict = EraYearOrYear & MonthCodeOrMonth & DayFields +export type MonthDayBagStrict = MonthCodeOrMonthAndYear & DayFields + +// ------------------------------------------------------------------------------------------------- export interface TimeFields { hour: number @@ -35,6 +70,9 @@ export interface TimeFields { second: number } +export type TimeBag = Partial +export type DateTimeBag = DateBag & TimeBag // TODO: use for PlainDateTime? + type DateTimeFields = DateFields & TimeFields export interface DateBasics { @@ -154,8 +192,9 @@ export const dateStatRefiners = { export const eraYearFieldNames = Object.keys(eraYearFieldRefiners) as (keyof EraYearFields)[] -export const allYearFieldNames = [...eraYearFieldNames, 'year'] as - (keyof AllYearFields)[] +// eraYearAndYearFieldNames +export const intlYearFieldNames = [...eraYearFieldNames, 'year'] as + (keyof YearFieldsIntl)[] export const dateFieldNames = Object.keys(dateFieldRefiners) as (keyof DateFields)[] @@ -199,7 +238,7 @@ export const yearMonthStatNames = Object.keys(yearMonthStatRefiners) as export const dateStatNames = Object.keys(dateStatRefiners) as (keyof DateStats)[] -export type DateGetterFields = EraYearFields & DateFields & DateStats +export type DateGetterFields = DateFieldsIntl & DateStats export const dateGetterRefiners = { ...eraYearFieldRefiners, diff --git a/packages/temporal-polyfill/src/calendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl.ts index a0151010..77e00439 100644 --- a/packages/temporal-polyfill/src/calendarImpl.ts +++ b/packages/temporal-polyfill/src/calendarImpl.ts @@ -9,12 +9,19 @@ import { leapYearMetas, } from './calendarConfig' import { - AllYearFields, - allYearFieldNames, + EraYearOrYear, + MonthFields, + YearFieldsIntl, + intlYearFieldNames, eraYearFieldNames, monthDayFieldNames, monthFieldNames, yearStatNames, + DayFields, + DateBag, + YearMonthBag, + MonthDayBag, + DateFields, } from './calendarFields' import { computeIntlMonthsInYearSpan, @@ -42,7 +49,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { Overflow } from './options' import { Unit, milliInDay } from './units' -import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2, remapProps } from './utils' +import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './utils' import { CalendarOps } from './calendarOps' import { DurationInternals } from './durationFields' @@ -82,23 +89,23 @@ export class CalendarImpl implements CalendarOps { ) } - dateFromFields(fields: any, overflow: Overflow): IsoDateInternals { + dateFromFields(fields: DateBag, overflow: Overflow): IsoDateInternals { const year = this.refineYear(fields) const month = this.refineMonth(fields, year, overflow) - const day = this.refineDay(fields, month, year, overflow) + const day = this.refineDay(fields as DateFields, month, year, overflow) return this.queryIsoFields(year, month, day) } - yearMonthFromFields(fields: any, overflow: Overflow): IsoDateInternals { + yearMonthFromFields(fields: YearMonthBag, overflow: Overflow): IsoDateInternals { const year = this.refineYear(fields) const month = this.refineMonth(fields, year, overflow) return this.queryIsoFields(year, month, 1) } - monthDayFromFields(fields: any, overflow: Overflow): IsoDateInternals { - let { month, monthCode, day } = fields + monthDayFromFields(fields: MonthDayBag, overflow: Overflow): IsoDateInternals { + let { month, monthCode, day } = fields as (Partial & DayFields) let year if (monthCode !== undefined) { @@ -107,7 +114,7 @@ export class CalendarImpl implements CalendarOps { ;([year, month] = this.queryYearMonthForMonthDay(monthCodeNumber, isLeapMonth, day)) } else { // year is required - year = this.refineYear(fields) + year = this.refineYear(fields as EraYearOrYear) month = this.refineMonth(fields, year, overflow) } @@ -122,13 +129,16 @@ export class CalendarImpl implements CalendarOps { return fieldNames } - mergeFields(baseFields: any, additionalFields: any): any { + mergeFields( + baseFields: Record, + additionalFields: Record + ): Record { const merged = { ...baseFields } removeIfAnyProps(merged, additionalFields, monthFieldNames) if (getAllowErasInFields(this)) { - removeIfAnyProps(merged, additionalFields, allYearFieldNames) + removeIfAnyProps(merged, additionalFields, intlYearFieldNames) } if (getErasBeginMidYear(this)) { @@ -198,7 +208,7 @@ export class CalendarImpl implements CalendarOps { // Field Refining // -------------- - refineYear(fields: any): number { + refineYear(fields: Partial): number { let { era, eraYear, year } = fields const allowEras = getAllowErasInFields(this) @@ -218,9 +228,9 @@ export class CalendarImpl implements CalendarOps { } refineMonth( - fields: any, + fields: Partial, year: number, // optional if known that calendar doesn't support leap months - overflow: Overflow = Overflow.Reject, + overflow: Overflow = Overflow.Reject, // TODO: do this elsewhere? ): number { let { month, monthCode } = fields @@ -245,9 +255,14 @@ export class CalendarImpl implements CalendarOps { ) } - refineDay(fields: any, month: number, year: number, overflow: Overflow) { + refineDay( + fields: DayFields, // day guaranteed to exist because of required*Fields + month: number, + year: number, + overflow: Overflow + ): number { return clamp( - fields.day, // day guaranteed to exist because of required*Fields + fields.day, 1, this.queryDaysInMonth(year, month), overflow, @@ -578,14 +593,14 @@ class IntlCalendarImpl extends CalendarImpl { // IntlCalendarImpl - Prototype Trickery // ------------------------------------------------------------------------------------------------- -type EasyIntlMethodName = keyof AllYearFields | 'day' +type EasyIntlMethodName = (keyof YearFieldsIntl) | 'day' /* era/eraYear/year/day Fields that are easily-extractable from IntlFields (non-month fields) */ ( - [...allYearFieldNames, 'day'] as EasyIntlMethodName[] + [...intlYearFieldNames, 'day'] as EasyIntlMethodName[] ).forEach((dateFieldName) => { IntlCalendarImpl.prototype[dateFieldName] = function( this: IntlCalendarImpl, @@ -851,8 +866,8 @@ function getCalendarIdBase(calendarId: string): string { // ------------------------------------------------------------------------------------------------- function removeIfAnyProps( - targetObj: any, - testObj: any, + targetObj: Record, + testObj: Record, testPropNames: string[], deletablePropNames: string[] = testPropNames, ): void { diff --git a/packages/temporal-polyfill/src/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts index ddede380..1d0e0a4b 100644 --- a/packages/temporal-polyfill/src/calendarOps.ts +++ b/packages/temporal-polyfill/src/calendarOps.ts @@ -1,5 +1,5 @@ import { Calendar, CalendarArg, CalendarProtocol, calendarProtocolMethods, createCalendar } from './calendar' -import { DateGetterFields, dateGetterRefiners } from './calendarFields' +import { DateBag, DateBagStrict, DateGetterFields, MonthDayBag, MonthDayBagStrict, YearMonthBag, YearMonthBagStrict, dateGetterRefiners } from './calendarFields' import { CalendarImpl, queryCalendarImpl } from './calendarImpl' import { createProtocolChecker, @@ -15,7 +15,7 @@ import { Duration, createDuration } from './duration' import { DurationInternals } from './durationFields' import { CalendarInternals, IsoDateFields, IsoDateInternals } from './isoFields' import { parseCalendarId } from './isoParse' -import { Overflow, ensureObjectlike, ensureString, toString } from './options' +import { Overflow, ensureObjectlike, ensureString, overflowMapNames, toString } from './options' import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' @@ -41,13 +41,13 @@ export interface CalendarOps { weekOfYear(isoFields: IsoDateFields): number yearOfWeek(isoFields: IsoDateFields): number daysInWeek(isoFields: IsoDateFields): number - dateFromFields(fields: any, overflow: Overflow): IsoDateInternals - yearMonthFromFields(fields: any, overflow: Overflow): IsoDateInternals - monthDayFromFields(fields: any, overflow: Overflow): IsoDateInternals + dateFromFields(fields: DateBag, overflow: Overflow): IsoDateInternals + yearMonthFromFields(fields: YearMonthBag, overflow: Overflow): IsoDateInternals + monthDayFromFields(fields: MonthDayBag, overflow: Overflow): IsoDateInternals dateAdd(isoFields: IsoDateFields, durationInternals: DurationInternals, overflow: Overflow): IsoDateInternals dateUntil(isoFields0: IsoDateFields, isoFields1: IsoDateFields, largestUnit: Unit): DurationInternals fields(fieldNames: string[]): string[] - mergeFields(fields0: any, fields1: any): any + mergeFields(fields0: Record, fields1: Record): Record } // @@ -153,7 +153,7 @@ const calendarOpsAdapterMethods = { calendar.dateAdd( createPlainDate(isoDateFields), createDuration(durationInternals), - { overflow }, + { overflow: overflowMapNames[overflow] }, ), ) }, @@ -173,16 +173,43 @@ const calendarOpsAdapterMethods = { ) }, - dateFromFields(calendar: CalendarProtocol, fields: any, overflow: Overflow): IsoDateInternals { - return getPlainDateInternals(calendar.dateFromFields(fields, { overflow })) + dateFromFields( + calendar: CalendarProtocol, + fields: DateBag, + overflow: Overflow, + ): IsoDateInternals { + return getPlainDateInternals( + calendar.dateFromFields( + fields as DateBagStrict, + { overflow: overflowMapNames[overflow] }, + ) + ) }, - yearMonthFromFields(calendar: CalendarProtocol, fields: any, overflow: Overflow): IsoDateInternals { - return getPlainYearMonthInternals(calendar.yearMonthFromFields(fields, { overflow })) + yearMonthFromFields( + calendar: CalendarProtocol, + fields: YearMonthBag, + overflow: Overflow, + ): IsoDateInternals { + return getPlainYearMonthInternals( + calendar.yearMonthFromFields( + fields as YearMonthBagStrict, + { overflow: overflowMapNames[overflow] }, + ) + ) }, - monthDayFromFields(calendar: CalendarProtocol, fields: any, overflow: Overflow): IsoDateInternals { - return getPlainMonthDayInternals(calendar.monthDayFromFields(fields, { overflow })) + monthDayFromFields( + calendar: CalendarProtocol, + fields: MonthDayBag, + overflow: Overflow, + ): IsoDateInternals { + return getPlainMonthDayInternals( + calendar.monthDayFromFields( + fields as MonthDayBagStrict, + { overflow: overflowMapNames[overflow] }, + ) + ) }, fields(calendar: CalendarProtocol, fieldNames: string[]): string[] { @@ -190,7 +217,11 @@ const calendarOpsAdapterMethods = { // TODO: kill ensureArray elsewhere? }, - mergeFields(calendar: CalendarProtocol, fields0: any, fields1: any): any { + mergeFields( + calendar: CalendarProtocol, + fields0: Record, + fields1: Record, + ): Record { return ensureObjectlike(calendar.mergeFields(fields0, fields1)) }, } diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index dff25685..26f02dfc 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -1,3 +1,4 @@ +import { CalendarArg, CalendarProtocol } from './calendar' import { getRequiredDateFields, getRequiredMonthDayFields, @@ -5,8 +6,12 @@ import { isoCalendarId, } from './calendarConfig' import { - DateFields, + DateBag, + DateBagStrict, + DateTimeBag, + DayFields, TimeFields, + YearFields, dateFieldNames, dateTimeFieldNames, dateTimeFieldRefiners, @@ -23,6 +28,7 @@ import { CalendarOps, queryCalendarOps } from './calendarOps' import { TemporalInstance, getInternals } from './class' import { DurationBag, DurationMod } from './duration' import { + DurationFields, DurationInternals, durationFieldNames, durationFieldRefiners, @@ -43,14 +49,15 @@ import { refineZonedFieldOptions, toString, // TODO: shouldn't we use this all over the place? } from './options' -import { PlainDate, createPlainDate } from './plainDate' -import { PlainDateTime, PlainDateTimeBag } from './plainDateTime' -import { PlainMonthDay, createPlainMonthDay } from './plainMonthDay' -import { PlainTime } from './plainTime' -import { PlainYearMonth, createPlainYearMonth } from './plainYearMonth' +import { PlainDate, PlainDateBag, PlainDateMod, createPlainDate } from './plainDate' +import { PlainDateTime, PlainDateTimeBag, PlainDateTimeMod } from './plainDateTime' +import { PlainMonthDay, PlainMonthDayBag, PlainMonthDayMod, createPlainMonthDay } from './plainMonthDay' +import { PlainTime, PlainTimeBag, PlainTimeMod } from './plainTime' +import { PlainYearMonth, PlainYearMonthBag, PlainYearMonthMod, createPlainYearMonth } from './plainYearMonth' +import { TimeZoneArg } from './timeZone' import { getMatchingInstantFor, getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { Callable, Reused, excludeArrayDuplicates, isObjectlike, pluckProps } from './utils' -import { ZonedDateTime, ZonedDateTimeBag, ZonedInternals, createZonedDateTime } from './zonedDateTime' +import { Callable, Reused, excludeArrayDuplicates, pluckProps } from './utils' +import { ZonedDateTime, ZonedDateTimeBag, ZonedDateTimeMod, ZonedInternals, createZonedDateTime } from './zonedDateTime' /* Rules: @@ -58,8 +65,12 @@ Rules: - converting returns public object */ -// TODO: make more DRY with other methods -export function refineMaybeZonedDateTimeBag(bag: any): ZonedInternals | IsoDateInternals { +/* +TODO: make more DRY with other methods +*/ +export function refineMaybeZonedDateTimeBag( + bag: ZonedDateTimeBag, +): ZonedInternals | IsoDateInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, @@ -67,7 +78,7 @@ export function refineMaybeZonedDateTimeBag(bag: any): ZonedInternals | IsoDateI dateTimeFieldNames, // validFieldNames getRequiredDateFields(calendar), // requireFields ['timeZone', 'offset'], // forcedValidFieldNames - ) + ) as ZonedDateTimeBag if (fields.timeZone) { const timeZone = queryTimeZoneOps(fields.timeZone) @@ -100,7 +111,10 @@ export function refineMaybeZonedDateTimeBag(bag: any): ZonedInternals | IsoDateI // ZonedDateTime // ------------------------------------------------------------------------------------------------- -export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: ZonedFieldOptions | undefined): ZonedInternals { +export function refineZonedDateTimeBag( + bag: ZonedDateTimeBag, + options: ZonedFieldOptions | undefined, +): ZonedInternals { const calendar = getBagCalendarOps(bag) const fields = refineCalendarFields( calendar, @@ -108,10 +122,11 @@ export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: ZonedFiel dateTimeFieldNames, // validFieldNames [...getRequiredDateFields(calendar), 'timeZone'], // requireFields ['timeZone', 'offset'], // forcedValidFieldNames - ) + ) as ZonedDateTimeBag + const [overflow, epochDisambig, offsetDisambig] = refineZonedFieldOptions(options) - const timeZone = queryTimeZoneOps(fields.timeZone) + const timeZone = queryTimeZoneOps(fields.timeZone!) // guaranteed via refineCalendarFields const isoDateFields = calendar.dateFromFields(fields, overflow) const isoTimeFields = refineTimeFields(fields, overflow) @@ -134,17 +149,18 @@ export function refineZonedDateTimeBag(bag: ZonedDateTimeBag, options: ZonedFiel export function mergeZonedDateTimeBag( zonedDateTime: ZonedDateTime, - bag: any, + mod: ZonedDateTimeMod, options: ZonedFieldOptions, ): ZonedInternals { const { calendar, timeZone } = getInternals(zonedDateTime) const fields = mergeCalendarFields( calendar, zonedDateTime, - bag, + mod, dateTimeFieldNames, // validFieldNames ['offset'], // forcedValidFieldNames - ) + ) as ZonedDateTimeBag + const [overflow, epochDisambig, offsetDisambig] = refineZonedFieldOptions(options) const isoDateFields = calendar.dateFromFields(fields, overflow) @@ -153,7 +169,7 @@ export function mergeZonedDateTimeBag( const epochNanoseconds = getMatchingInstantFor( timeZone, { ...isoDateFields, ...isoTimeFields }, - parseOffsetNano(fields.offset), + parseOffsetNano(fields.offset!), // guaranteed via mergeCalendarFields false, // z? offsetDisambig, epochDisambig, @@ -213,14 +229,14 @@ export function refinePlainDateTimeBag( export function mergePlainDateTimeBag( plainDateTime: PlainDateTime, - bag: any, + mod: PlainDateTimeMod, options: OverflowOptions | undefined, ): IsoDateTimeInternals { const { calendar } = getInternals(plainDateTime) const fields = mergeCalendarFields( calendar, plainDateTime, - bag, + mod, dateTimeFieldNames, ) @@ -235,9 +251,9 @@ export function mergePlainDateTimeBag( // ------------------------------------------------------------------------------------------------- export function refinePlainDateBag( - bag: DateFields, + bag: PlainDateBag, options: OverflowOptions | undefined, - calendar: CalendarOps | undefined = getBagCalendarOps(bag) + calendar: CalendarOps = getBagCalendarOps(bag) ): IsoDateInternals { const fields = refineCalendarFields( calendar, @@ -251,14 +267,14 @@ export function refinePlainDateBag( export function mergePlainDateBag( plainDate: PlainDate, - bag: any, + mod: PlainDateMod, options: OverflowOptions | undefined, ): IsoDateInternals { const { calendar } = getInternals(plainDate) const fields = mergeCalendarFields( calendar, plainDate, - bag, + mod, dateFieldNames, ) @@ -266,15 +282,15 @@ export function mergePlainDateBag( } function convertToIso( - input: PlainYearMonth | PlainMonthDay, + input: TemporalInstance<{ calendar: CalendarOps }> | Reused, inputFieldNames: string[], - extra: any, + extra: {}, extraFieldNames: string[], ): IsoDateInternals { - const { calendar } = getInternals(input) + const { calendar } = getInternals(input as TemporalInstance<{ calendar: CalendarOps }>) inputFieldNames = calendar.fields(inputFieldNames) - input = pluckProps(inputFieldNames, input as Record) as Reused + input = pluckProps(inputFieldNames, input as Record) extraFieldNames = calendar.fields(extraFieldNames) extra = refineFields(extra, extraFieldNames, getRequiredDateFields(calendar)) @@ -290,9 +306,9 @@ function convertToIso( // ------------------------------------------------------------------------------------------------- export function refinePlainYearMonthBag( - bag: any, + bag: PlainYearMonthBag, options: OverflowOptions | undefined, - calendar: CalendarOps | undefined = getBagCalendarOps(bag) + calendar: CalendarOps = getBagCalendarOps(bag) ): IsoDateInternals { const fields = refineCalendarFields( calendar, @@ -306,7 +322,7 @@ export function refinePlainYearMonthBag( export function mergePlainYearMonthBag( plainYearMonth: PlainYearMonth, - bag: any, + bag: PlainYearMonthMod, options: OverflowOptions | undefined, ): IsoDateInternals { const { calendar } = getInternals(plainYearMonth) @@ -320,9 +336,12 @@ export function mergePlainYearMonthBag( return calendar.yearMonthFromFields(fields, refineOverflowOptions(options)) } +/* +Responsible for ensuring bag is an object. Best place? +*/ export function convertPlainYearMonthToDate( plainYearMonth: PlainYearMonth, - bag: any, + bag: DayFields, ): PlainYearMonth { return createPlainDate( convertToIso(plainYearMonth, yearMonthBasicNames, ensureObjectlike(bag), ['day']), @@ -330,7 +349,7 @@ export function convertPlainYearMonthToDate( } export function convertToPlainYearMonth( - input: PlainDate | PlainDateTime | ZonedDateTime + input: PlainDate | PlainDateTime | ZonedDateTime // TODO: more generic type ) { const { calendar } = getInternals(input) const fields = refineCalendarFields( @@ -349,17 +368,14 @@ export function convertToPlainYearMonth( // ------------------------------------------------------------------------------------------------- export function refinePlainMonthDayBag( - bag: any, + bag: PlainMonthDayBag, options: OverflowOptions | undefined, - calendar: CalendarOps | undefined = extractBagCalendarOps(bag), + calendar?: CalendarOps, ): IsoDateInternals { const calendarAbsent = !calendar + calendar ||= getBagCalendarOps(bag) - if (calendarAbsent) { - calendar = queryCalendarImpl(isoCalendarId) - } - - const fieldNames = calendar!.fields(dateFieldNames) + const fieldNames = calendar.fields(dateFieldNames) as (keyof PlainMonthDayBag)[] const fields = refineFields(bag, fieldNames, []) // Callers who omit the calendar are not writing calendar-independent @@ -379,7 +395,7 @@ export function refinePlainMonthDayBag( export function mergePlainMonthDayBag( plainMonthDay: PlainMonthDay, - bag: any, + bag: PlainMonthDayMod, options: OverflowOptions | undefined, ): IsoDateInternals { const { calendar } = getInternals(plainMonthDay) @@ -394,7 +410,7 @@ export function mergePlainMonthDayBag( } export function convertToPlainMonthDay( - input: PlainDate | PlainDateTime | ZonedDateTime, + input: PlainDate | PlainDateTime | ZonedDateTime, // TODO: make more general? ): PlainMonthDay { const { calendar } = getInternals(input) const fields = refineCalendarFields( @@ -409,12 +425,15 @@ export function convertToPlainMonthDay( ) } +/* +Responsible for ensuring bag is an object. Best place? +*/ export function convertPlainMonthDayToDate( plainMonthDay: PlainMonthDay, - bag: any, + bag: YearFields, ): PlainDate { return createPlainDate( - convertToIso(plainMonthDay, monthDayBasicNames, bag, ['year']), + convertToIso(plainMonthDay, monthDayBasicNames, ensureObjectlike(bag), ['year']), ) } @@ -422,7 +441,7 @@ export function convertPlainMonthDayToDate( // ------------------------------------------------------------------------------------------------- export function refinePlainTimeBag( - bag: any, + bag: PlainTimeBag, options: OverflowOptions | undefined, ): IsoTimeFields { const fields = refineFields(bag, timeFieldNames, []) @@ -432,7 +451,7 @@ export function refinePlainTimeBag( export function mergePlainTimeBag( plainTime: PlainTime, - bag: any, + bag: PlainTimeMod, options: OverflowOptions | undefined, ): IsoTimeFields { const fields = pluckProps(timeFieldNames, plainTime as unknown as TimeFields) // TODO: wish PlainTime had real TS methods @@ -450,8 +469,8 @@ function refineTimeFields(fields: any, overflow: any): IsoTimeFields { // ------------------------------------------------------------------------------------------------- export function refineDurationBag(bag: DurationBag): DurationInternals { - const durationFields = refineFields(bag, durationFieldNames, []) - return updateDurationFieldsSign(durationFields) + const durationFields = refineFields(bag, durationFieldNames, []) as DurationBag + return updateDurationFieldsSign(durationFields as DurationFields) } export function mergeDurationBag( @@ -467,22 +486,22 @@ export function mergeDurationBag( function refineCalendarFields( calendar: CalendarOps, - bag: any, + bag: Record, validFieldNames: string[], requiredFieldNames: string[] = [], // a subset of validFieldNames forcedValidFieldNames: string[] = [], -): any { +): Record { const fieldNames = [...calendar.fields(validFieldNames), ...forcedValidFieldNames] return refineFields(bag, fieldNames, requiredFieldNames) } function mergeCalendarFields( calendar: CalendarOps, - obj: any, - bag: any, + obj: Record, + bag: Record, validFieldNames: string[], forcedValidFieldNames: string[] = [], -): any { +): Record { rejectInvalidBag(bag) const fieldNames = [...calendar.fields(validFieldNames), ...forcedValidFieldNames] @@ -496,26 +515,29 @@ function mergeCalendarFields( /* defaults to ISO */ -function getBagCalendarOps(bag: any): CalendarOps { +function getBagCalendarOps( + bag: TemporalInstance | { calendar?: CalendarArg }, +): CalendarOps { return extractBagCalendarOps(bag) || queryCalendarImpl(isoCalendarId) } function extractBagCalendarOps( - bag: TemporalInstance | { calendar: string }, + bag: TemporalInstance | { calendar?: CalendarArg }, ): CalendarOps | undefined { - let calendar: CalendarOps | string | undefined = (getInternals(bag) || {}).calendar + let calendar: CalendarOps | CalendarProtocol | string | undefined = + (getInternals(bag) || {}).calendar if (calendar) { return calendar // CalendarOps } - calendar = (bag as { calendar: string }).calendar + calendar = (bag as { calendar: CalendarProtocol | string }).calendar if (calendar) { return queryCalendarOps(calendar) } } -function rejectInvalidBag(bag: any): void { +function rejectInvalidBag(bag: { calendar?: unknown, timeZone?: unknown }): void { if (getInternals(bag)) { throw new TypeError('Cant pass any Temporal object') } @@ -540,15 +562,15 @@ const builtinRefiners = { const builtinDefaults = timeFieldDefaults function refineFields( - bag: any, + bag: Record, validFieldNames: string[], requiredFieldNames?: string[], // a subset of fieldNames // if not given, then assumed to be 'partial' (defaults won't be applied) -): any { - const res: any = {} +): Record { + const res: Record = {} let any = false - for (const fieldName in validFieldNames) { + for (const fieldName of validFieldNames) { let fieldVal = bag[fieldName] if (fieldVal !== undefined) { diff --git a/packages/temporal-polyfill/src/old/calendarImpl/calendarImpl.ts b/packages/temporal-polyfill/src/old/calendarImpl/calendarImpl.ts index a06d62ab..e62962a6 100644 --- a/packages/temporal-polyfill/src/old/calendarImpl/calendarImpl.ts +++ b/packages/temporal-polyfill/src/old/calendarImpl/calendarImpl.ts @@ -13,8 +13,8 @@ export interface CalendarImplFields { // like DateFields, but without monthCode export interface CalendarImplFieldsDumb { // like CalendarImplFields, but with month string era: string | undefined eraYear: number | undefined - year: number, - month: string, + year: number + month: string day: number } diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index cb37b7a2..0f2ddd6d 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -19,7 +19,7 @@ import { roundHalfFloor, roundHalfTrunc, } from './utils' -import { ZonedDateTime, ZonedInternals } from './zonedDateTime' +import { ZonedDateTime, ZonedDateTimeBag, ZonedInternals } from './zonedDateTime' // Compound Options // ------------------------------------------------------------------------------------------------- @@ -266,7 +266,8 @@ interface SmallestUnitOptions { smallestUnit?: UnitName | keyof DurationFields } -interface LargestUnitOptions { +// TODO: rename to CalendarDiffOptions? +export interface LargestUnitOptions { largestUnit?: UnitName | keyof DurationFields } @@ -312,6 +313,8 @@ const overflowMap = { reject: Overflow.Reject, } +export const overflowMapNames = Object.keys(overflowMap) as (keyof typeof overflowMap)[] + const refineOverflow = refineChoiceOption.bind< any, [any, any], // bound [OverflowOptions, Overflow?], // unbound @@ -594,7 +597,7 @@ function refineRelativeTo(options: RelativeToOptions): RelativeToInternals | und return pluckIsoDateInternals(getInternals(relativeTo)) } - return refineMaybeZonedDateTimeBag(relativeTo) + return refineMaybeZonedDateTimeBag(relativeTo as unknown as ZonedDateTimeBag) } return parseMaybeZonedDateTime(toString(relativeTo)) diff --git a/packages/temporal-polyfill/src/plainDate.ts b/packages/temporal-polyfill/src/plainDate.ts index 44c50a8b..2a12ddae 100644 --- a/packages/temporal-polyfill/src/plainDate.ts +++ b/packages/temporal-polyfill/src/plainDate.ts @@ -1,6 +1,6 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' -import { DateFields, dateGetters } from './calendarFields' +import { DateBag, dateGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, @@ -37,8 +37,8 @@ import { Unit } from './units' import { NumSign } from './utils' export type PlainDateArg = PlainDate | PlainDateBag | string -export type PlainDateBag = DateFields & { calendar?: CalendarArg } -export type PlainDateMod = Partial +export type PlainDateBag = DateBag & { calendar?: CalendarArg } +export type PlainDateMod = DateBag export type PlainDate = TemporalInstance export const [ diff --git a/packages/temporal-polyfill/src/plainDateTime.ts b/packages/temporal-polyfill/src/plainDateTime.ts index 26e607e1..65044cd6 100644 --- a/packages/temporal-polyfill/src/plainDateTime.ts +++ b/packages/temporal-polyfill/src/plainDateTime.ts @@ -1,6 +1,6 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' -import { DateFields, TimeFields, dateTimeGetters } from './calendarFields' +import { DateBag, TimeBag, dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { @@ -49,8 +49,8 @@ import { NumSign } from './utils' import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' export type PlainDateTimeArg = PlainDateTime | PlainDateTimeBag | string -export type PlainDateTimeBag = DateFields & Partial & { calendar?: CalendarArg } -export type PlainDateTimeMod = Partial & Partial +export type PlainDateTimeBag = DateBag & TimeBag & { calendar?: CalendarArg } +export type PlainDateTimeMod = DateBag & TimeBag export type PlainDateTime = TemporalInstance export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = createTemporalClass( diff --git a/packages/temporal-polyfill/src/plainMonthDay.ts b/packages/temporal-polyfill/src/plainMonthDay.ts index 5e2a50a7..4368d6b2 100644 --- a/packages/temporal-polyfill/src/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/plainMonthDay.ts @@ -1,6 +1,6 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' -import { YearMonthFields, monthDayGetters } from './calendarFields' +import { MonthDayBag, YearFields, monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { @@ -16,8 +16,8 @@ import { refineOverflowOptions } from './options' import { PlainDate } from './plainDate' export type PlainMonthDayArg = PlainMonthDay | PlainMonthDayBag | string -export type PlainMonthDayBag = YearMonthFields & { calendar?: CalendarArg } -export type PlainMonthDayMod = Partial +export type PlainMonthDayBag = MonthDayBag & { calendar?: CalendarArg } +export type PlainMonthDayMod = MonthDayBag export type PlainMonthDay = TemporalInstance export const [ @@ -84,7 +84,7 @@ export const [ valueOf: neverValueOf, - toPlainDate(internals: IsoDateInternals, bag: { year: number }): PlainDate { + toPlainDate(internals: IsoDateInternals, bag: YearFields): PlainDate { return convertPlainMonthDayToDate(this, bag) }, diff --git a/packages/temporal-polyfill/src/plainTime.ts b/packages/temporal-polyfill/src/plainTime.ts index ad6e70de..2d9d200b 100644 --- a/packages/temporal-polyfill/src/plainTime.ts +++ b/packages/temporal-polyfill/src/plainTime.ts @@ -1,4 +1,4 @@ -import { TimeFields, timeGetters } from './calendarFields' +import { TimeBag, timeGetters } from './calendarFields' import { TemporalInstance, createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' import { createZonedDateTimeConverter, @@ -31,8 +31,8 @@ import { TimeUnit, Unit, UnitName } from './units' import { NumSign } from './utils' export type PlainTimeArg = PlainTime | PlainTimeBag | string -export type PlainTimeBag = Partial -export type PlainTimeMod = Partial +export type PlainTimeBag = TimeBag +export type PlainTimeMod = TimeBag export type PlainTime = TemporalInstance export const [ diff --git a/packages/temporal-polyfill/src/plainYearMonth.ts b/packages/temporal-polyfill/src/plainYearMonth.ts index e5a94596..3080da7c 100644 --- a/packages/temporal-polyfill/src/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/plainYearMonth.ts @@ -1,6 +1,6 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' -import { YearMonthFields, yearMonthGetters } from './calendarFields' +import { YearMonthBag, yearMonthGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar } from './calendarOps' import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' import { @@ -22,8 +22,8 @@ import { Unit } from './units' import { NumSign } from './utils' export type PlainYearMonthArg = PlainYearMonth | PlainYearMonthBag | string -export type PlainYearMonthBag = YearMonthFields & { calendar?: CalendarArg } -export type PlainYearMonthMod = Partial +export type PlainYearMonthBag = YearMonthBag & { calendar?: CalendarArg } +export type PlainYearMonthMod = YearMonthBag export type PlainYearMonth = TemporalInstance export const [ diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index e9fd3d33..3a8dbaad 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -1,6 +1,10 @@ import { Overflow } from './options' +/* +Is this making this more complex at cost of no lower min size? +*/ export type Reused = any + export type Callable = (...args: any[]) => any const objectlikeRE = /object|function/ diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index b739609e..803748f4 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -71,7 +71,7 @@ import { DayTimeUnit, Unit, UnitName, nanoInHour } from './units' import { NumSign, mapProps } from './utils' export type ZonedDateTimeArg = ZonedDateTime | ZonedDateTimeBag | string -export type ZonedDateTimeBag = PlainDateTimeBag & { timeZone: TimeZoneArg } +export type ZonedDateTimeBag = PlainDateTimeBag & { timeZone: TimeZoneArg, offset?: string } export type ZonedDateTimeMod = PlainDateTimeMod export type TimeZonePublic = TimeZoneProtocol | string From 5dfcda422d0ba45079da5c9e23f85715a2f1d787 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 1 Aug 2023 16:14:31 -0400 Subject: [PATCH 189/805] get rid of a lot of any --- .../temporal-polyfill/src/calendarFields.ts | 8 +++---- .../temporal-polyfill/src/calendarImpl.ts | 8 +++---- packages/temporal-polyfill/src/calendarOps.ts | 12 +++++------ .../temporal-polyfill/src/durationFields.ts | 3 ++- packages/temporal-polyfill/src/isoFields.ts | 20 +++++++++--------- packages/temporal-polyfill/src/options.ts | 21 ++++++++++--------- packages/temporal-polyfill/src/utils.ts | 8 +++++++ .../temporal-polyfill/src/zonedDateTime.ts | 5 +++-- 8 files changed, 47 insertions(+), 38 deletions(-) diff --git a/packages/temporal-polyfill/src/calendarFields.ts b/packages/temporal-polyfill/src/calendarFields.ts index df164bd6..f6bac932 100644 --- a/packages/temporal-polyfill/src/calendarFields.ts +++ b/packages/temporal-polyfill/src/calendarFields.ts @@ -6,7 +6,7 @@ import { isoTimeFieldNames, } from './isoFields' import { ensureBoolean, ensureInteger, toInteger, toString } from './options' -import { FilterPropValues, mapPropNames, mapPropNamesToConstant, remapProps } from './utils' +import { BoundArg, FilterPropValues, mapPropNames, mapPropNamesToConstant, remapProps } from './utils' // Year/Month/Day (no era/eraYear) // ------------------------------------------------------------------------------------------------- @@ -109,7 +109,7 @@ export interface DateStats extends YearMonthStats { daysInWeek: number } -type DateMethods = FilterPropValues any> +type DateMethods = FilterPropValues unknown> type DateGetters = { [K in keyof DateMethods]: (internals: IsoDateInternals) => ReturnType @@ -276,7 +276,7 @@ function createCalendarGetters( ): CalendarGetters { const getters = mapPropNames(createCalendarGetter, propNames) - ;(getters as any).calendarId = (internals: { calendar: CalendarOps }) => { + ;(getters as unknown as CalendarIdGetters).calendarId = (internals: { calendar: CalendarOps }) => { return internals.calendar.id } @@ -302,7 +302,7 @@ export const dateTimeGetters = { // ------------------------------------------------------------------------------------------------- export const timeFieldsToIso = remapProps.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [TimeFields], // unbound IsoTimeFields // return >(undefined, timeFieldNames, isoTimeFieldNames) diff --git a/packages/temporal-polyfill/src/calendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl.ts index 77e00439..94ce58f1 100644 --- a/packages/temporal-polyfill/src/calendarImpl.ts +++ b/packages/temporal-polyfill/src/calendarImpl.ts @@ -49,7 +49,7 @@ import { import { moveByIntlMonths, moveByIsoMonths, moveDate } from './move' import { Overflow } from './options' import { Unit, milliInDay } from './units' -import { clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './utils' +import { Callable, clamp, createLazyGenerator, mapPropNamesToIndex, padNumber2 } from './utils' import { CalendarOps } from './calendarOps' import { DurationInternals } from './durationFields' @@ -296,8 +296,6 @@ interface YearMethods { monthsInYear(isoFields: IsoDateFields): number } -type VeryGeneric = any - const yearMethods = {} as YearMethods ( @@ -308,7 +306,7 @@ const yearMethods = {} as YearMethods isoDateFields: IsoDateFields, ) { return this[computeMethodName](this.year(isoDateFields)) - } as VeryGeneric + } as Callable }) // Base Calendar Implementation :: Week Methods @@ -607,7 +605,7 @@ Fields that are easily-extractable from IntlFields (non-month fields) isoDateFields: IsoDateFields, ) { return this.isoDateFieldsToIntl(isoDateFields)[dateFieldName as EasyIntlMethodName] - } as VeryGeneric + } as Callable }) // CalendarImpl Querying diff --git a/packages/temporal-polyfill/src/calendarOps.ts b/packages/temporal-polyfill/src/calendarOps.ts index 1d0e0a4b..af418a55 100644 --- a/packages/temporal-polyfill/src/calendarOps.ts +++ b/packages/temporal-polyfill/src/calendarOps.ts @@ -20,7 +20,7 @@ import { PlainDate, createPlainDate } from './plainDate' import { PlainMonthDay } from './plainMonthDay' import { PlainYearMonth } from './plainYearMonth' import { Unit, unitNamesAsc } from './units' -import { Callable, isObjectlike, mapProps } from './utils' +import { BoundArg, Callable, isObjectlike, mapProps } from './utils' // types @@ -100,7 +100,7 @@ function calendarOpsToPublic(calendarOps: CalendarOps): CalendarProtocol { } export const getCommonCalendarOps = getCommonInnerObj.bind< - any, [any], // bound + undefined, [BoundArg], // bound [CalendarInternals, CalendarInternals], // unbound CalendarOps // return >(undefined, 'calendar') @@ -109,25 +109,25 @@ export const getCommonCalendarOps = getCommonInnerObj.bind< // ------------------------------------------------------------------------------------------------- const getPlainDateInternals = getStrictInternals.bind< - any, [any], // bound + undefined, [BoundArg], // bound [PlainDate], // unbound IsoDateInternals // return >(undefined, PlainDate) const getPlainYearMonthInternals = getStrictInternals.bind< - any, [any], // bound + undefined, [BoundArg], // bound [PlainYearMonth], // unbound IsoDateInternals // return >(undefined, PlainYearMonth) const getPlainMonthDayInternals = getStrictInternals.bind< - any, [any], // bound + undefined, [BoundArg], // bound [PlainMonthDay], // unbound IsoDateInternals // return >(undefined, PlainMonthDay) const getDurationInternals = getStrictInternals.bind< - any, [any], // bound + undefined, [BoundArg], // bound [Duration], // unbound DurationInternals // return >(undefined, Duration) diff --git a/packages/temporal-polyfill/src/durationFields.ts b/packages/temporal-polyfill/src/durationFields.ts index d8ee8d5e..0d155a85 100644 --- a/packages/temporal-polyfill/src/durationFields.ts +++ b/packages/temporal-polyfill/src/durationFields.ts @@ -17,6 +17,7 @@ import { mapPropNamesToIndex, mapProps, remapProps, + BoundArg, } from './utils' interface DurationDateFields { @@ -97,7 +98,7 @@ export function refineDurationFields( } export const durationTimeFieldsToIso = remapProps.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [DurationTimeFields], // unbound IsoTimeFields // return >(undefined, durationTimeFieldNames, isoTimeFieldNames) diff --git a/packages/temporal-polyfill/src/isoFields.ts b/packages/temporal-polyfill/src/isoFields.ts index b2225cd9..456b2657 100644 --- a/packages/temporal-polyfill/src/isoFields.ts +++ b/packages/temporal-polyfill/src/isoFields.ts @@ -2,7 +2,7 @@ import { CalendarProtocol } from './calendar' import { CalendarOps, queryCalendarOps } from './calendarOps' import { getInternals } from './class' import { toInteger } from './options' -import { mapPropNamesToConstant, pluckProps, pluckPropsTuple } from './utils' +import { BoundArg, mapPropNamesToConstant, pluckProps, pluckPropsTuple } from './utils' export interface IsoDateFields { isoDay: number @@ -21,7 +21,7 @@ export interface IsoTimeFields { // TODO: move // TODO: same as CalendarArg? -type CalendarPublic = CalendarProtocol | string +export type CalendarPublic = CalendarProtocol | string export interface CalendarInternals { calendar: CalendarOps @@ -85,19 +85,19 @@ export const isoTimeFieldDefaults = mapPropNamesToConstant(isoTimeFieldNames, 0) // ------------------------------------------------------------------------------------------------- export const pluckIsoDateInternals = pluckProps.bind< - any, [any], // bound + undefined, [BoundArg], // bound [IsoDateInternals], // unbound IsoDateInternals // return >(undefined, isoDateInternalNames) // bound export const pluckIsoDateTimeInternals = pluckProps.bind< - any, [any], // bound + undefined, [BoundArg], // bound [IsoDateTimeInternals], // unbound IsoDateTimeInternals // return >(undefined, isoDateTimeInternalNames) export const pluckIsoTimeFields = pluckProps.bind< - any, [any], // bound + undefined, [BoundArg], // bound [IsoTimeFields], // unbound IsoTimeFields // return >(undefined, isoTimeFieldNames) @@ -115,7 +115,7 @@ export type IsoTuple = [ // TODO: move? export const pluckIsoTuple = pluckPropsTuple.bind< - any, [any], + undefined, [BoundArg], [Partial & { isoYear: number }], // unbound IsoTuple // return >(undefined, isoDateTimeFieldNamesAsc.reverse()) @@ -125,7 +125,7 @@ function generatePublicIsoFields

( internals: P & { calendar: CalendarOps }, ): P & { calendar: CalendarPublic } { const publicFields = pluckFunc(internals) as P & { calendar: CalendarPublic } - publicFields.calendar = getPublicIdOrObj(internals.calendar) + publicFields.calendar = getPublicIdOrObj(internals.calendar) as CalendarPublic return publicFields } @@ -133,13 +133,13 @@ export type IsoDatePublic = IsoDateFields & { calendar: CalendarPublic } export type IsoDateTimePublic = IsoDateTimeFields & { calendar: CalendarPublic } export const generatePublicIsoDateFields = generatePublicIsoFields.bind< - any, [any], // bound + undefined, [BoundArg], // bound [IsoDateInternals], // unbound IsoDatePublic // return >(undefined, pluckIsoDateInternals) export const generatePublicIsoDateTimeFields = generatePublicIsoFields.bind< - any, [any], // bound + undefined, [BoundArg], // bound [IsoDateTimeInternals], // unbound IsoDateTimePublic // return >(undefined, pluckIsoDateTimeInternals) @@ -149,7 +149,7 @@ Similar to getPublicCalendar and getPublicTimeZone */ export function getPublicIdOrObj( ops: { id: string }, -): { id: string } | any { +): unknown { return getInternals(ops) || // adapter (return internal object) ops.id // impl (return id) } diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index 0f2ddd6d..09ab2467 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -9,6 +9,7 @@ import { PlainDateTime } from './plainDateTime' import { TimeZoneArg } from './timeZone' import { DayTimeUnit, TimeUnit, Unit, UnitName, unitNameMap, unitNanoMap } from './units' import { + BoundArg, FilterPropValues, clamp, hasAnyPropsByName, @@ -278,20 +279,20 @@ interface TotalUnitOptions { // const refineSmallestUnit = refineUnitOption.bind< - any, [any], // bound + undefined, [BoundArg], // bound [SmallestUnitOptions, Unit?, Unit?, Unit?], // unbound Unit // return >(undefined, smallestUnitStr) const refineLargestUnit = refineUnitOption.bind< - any, [any], // bound + undefined, [BoundArg], // bound [LargestUnitOptions, Unit?, Unit?, Unit?], // unbound Unit >(undefined, largestUnitStr) // TODO: get totalUnitStr closer to this! etc const refineTotalUnit = refineUnitOption.bind< - any, [any], // bound + undefined, [BoundArg], // bound [TotalUnitOptions, Unit?, Unit?, Unit?], // unbound Unit >(undefined, totalUnitStr) @@ -316,7 +317,7 @@ const overflowMap = { export const overflowMapNames = Object.keys(overflowMap) as (keyof typeof overflowMap)[] const refineOverflow = refineChoiceOption.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [OverflowOptions, Overflow?], // unbound Overflow // return >(undefined, 'overflow', overflowMap) @@ -343,7 +344,7 @@ const epochDisambigMap = { } const refineEpochDisambig = refineChoiceOption.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [EpochDisambigOptions, EpochDisambig?], // unbound EpochDisambig // return >(undefined, 'disambiguation', epochDisambigMap) @@ -370,7 +371,7 @@ const offsetDisambigMap = { } const refineOffsetDisambig = refineChoiceOption.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [OffsetDisambigOptions, OffsetDisambig?], // unbound OffsetDisambig // return >(undefined, 'offset', offsetDisambigMap) @@ -397,7 +398,7 @@ const calendarDisplayMap = { } const refineCalendarDisplay = refineChoiceOption.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [CalendarDisplayOptions, CalendarDisplay?], // unbound CalendarDisplay // return >(undefined, 'calendarName', calendarDisplayMap) @@ -422,7 +423,7 @@ const timeZoneDisplayMap = { } const refineTimeZoneDisplay = refineChoiceOption.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [TimeZoneDisplayOptions, TimeZoneDisplay?], // unbound TimeZoneDisplay // return >(undefined, 'timeZoneName', timeZoneDisplayMap) @@ -445,7 +446,7 @@ const offsetDisplayMap = { } const refineOffsetDisplay = refineChoiceOption.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [OffsetDisplayOptions, OffsetDisplay?], // unbound OffsetDisplay // return >(undefined, 'offset', offsetDisplayMap) @@ -485,7 +486,7 @@ const roundingModeMap = { // Caller should always supply default const refineRoundingMode = refineChoiceOption.bind< - any, [any, any], // bound + undefined, [BoundArg, BoundArg], // bound [RoundingModeOptions, RoundingMode?], // unbound RoundingMode // return >(undefined, 'roundingMode', roundingModeMap) diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index 3a8dbaad..743038ac 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -5,6 +5,14 @@ Is this making this more complex at cost of no lower min size? */ export type Reused = any +/* +Will linter make [any] for bind okay? If so, this is unnecessary +*/ +export type BoundArg = any + +/* +For programmatically-generated functions that have overly-complex inferred types +*/ export type Callable = (...args: any[]) => any const objectlikeRE = /object|function/ diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index 803748f4..e4d1151b 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -15,6 +15,7 @@ import { DurationFields, negateDurationInternals, updateDurationFieldsSign } fro import { Instant, createInstant } from './instant' import { resolveZonedFormattable } from './intlFormat' import { + CalendarPublic, IsoDateTimePublic, getPublicIdOrObj, isoTimeFieldDefaults, @@ -392,12 +393,12 @@ export const [ return { ...pluckIsoDateTimeInternals(zonedInternalsToIso(internals)), // alphabetical - calendar: getPublicIdOrObj(internals.calendar), + calendar: getPublicIdOrObj(internals.calendar) as CalendarPublic, offset: formatOffsetNano( // TODO: more DRY zonedInternalsToIso(internals).offsetNanoseconds, ), - timeZone: getPublicIdOrObj(internals.timeZone), + timeZone: getPublicIdOrObj(internals.timeZone) as TimeZonePublic, } }, From 2a8cbf2023c2cae27837511c36591544fb82b8f2 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 1 Aug 2023 17:18:29 -0400 Subject: [PATCH 190/805] tame class any --- packages/temporal-polyfill/src/class.ts | 54 +++++++++++-------- packages/temporal-polyfill/src/instant.ts | 4 +- packages/temporal-polyfill/src/intlFormat.ts | 3 +- .../temporal-polyfill/src/plainDateTime.ts | 20 ++++--- packages/temporal-polyfill/src/plainTime.ts | 3 +- packages/temporal-polyfill/src/timeZone.ts | 6 +-- packages/temporal-polyfill/src/timeZoneOps.ts | 9 ++-- packages/temporal-polyfill/src/utils.ts | 2 + 8 files changed, 61 insertions(+), 40 deletions(-) diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index 8008e723..93ea714f 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -1,6 +1,8 @@ -import { DateTimeFormat } from './intlFormat' +import { DateTimeFormat, Formattable } from './intlFormat' import { ensureInstanceOf, ensureString, toString } from './options' import { + Callable, + Classlike, Reused, createGetterDescriptors, createPropDescriptors, createTemporalNameDescriptors, defineProps, @@ -60,9 +62,9 @@ export function createWrapperClass< >( getters: G, methods: M, - constructorToInternals: (...args: A) => I = (identityFunc as any), - extraPrototypeDescriptors: P = {} as any, - staticMembers: S = {} as any, + constructorToInternals: (...args: A) => I = (identityFunc as Callable), + extraPrototypeDescriptors: P | {} = {}, + staticMembers: S | {} = {}, handleInstance: (inst: WrapperInstance) => void = noop, ): ( WrapperClass @@ -94,7 +96,7 @@ export function createWrapperClass< defineProps(InternalObj, staticMembers) - return InternalObj as any + return InternalObj as Classlike } export function getStrictInternals( // rename: getInternalsStrict? @@ -113,7 +115,6 @@ type TemporalClass< B, A extends any[], I, - O, G extends { [propName: string]: (internals: I) => unknown }, M extends { [methodName: string]: (internals: I, ...args: any[]) => unknown }, S extends {}, @@ -147,18 +148,17 @@ export function createSimpleTemporalClass< B, A extends any[], I, - O, G extends { [propName: string]: (this: TemporalInstance, internals: I) => unknown }, M extends { [methodName: string]: (this: TemporalInstance, internals: I, ...args: any[]) => unknown }, S extends {} >( temporalName: string, - constructorToInternals: (...args: A) => I = (identityFunc as any), + constructorToInternals: ((...args: A) => I) = (identityFunc as Callable), getters: G, methods: M, - staticMembers: S = {} as any, // need this to be optional? + staticMembers: S | {} = {}, // need this to be optional? ): [ - Class: TemporalClass, + Class: TemporalClass, createInstance: (internals: I) => TemporalInstance, ] { ;(methods as unknown as ToJsonMethods).toJSON = function() { @@ -185,7 +185,10 @@ export function createSimpleTemporalClass< temporaNameMap.set(instance, temporalName) } - return [TemporalClass as any, createInstance] + return [ + TemporalClass as Classlike, + createInstance + ] } export function createTemporalClass< @@ -198,21 +201,20 @@ export function createTemporalClass< S extends {} >( temporalName: string, - constructorToInternals: (...args: A) => I = (identityFunc as any), + constructorToInternals: ((...args: A) => I) = (identityFunc as Callable), internalsConversionMap: { [typeName: string]: (otherInternal: any) => I }, bagToInternals: (bag: B, options?: O) => I | void, // void opts-out of bag processing stringToInternals: (str: string) => I, handleUnusedOptions: (options?: O) => void, getters: G, methods: M, - staticMembers: S = {} as any, + staticMembers: S | {} = {}, ): [ - Class: TemporalClass, + Class: TemporalClass, createInstance: (internals: I) => TemporalInstance, toInternals: (arg: TemporalInstance | B | string, options?: O) => I ] { - // TODO: cast to better type - ;(staticMembers as any).from = function(arg: TemporalInstance | B | string, options: O) { + ;(staticMembers as { from: Callable }).from = function(arg: TemporalInstance | B | string, options: O) { return createInstance(toInternals(arg, options)) } @@ -236,14 +238,18 @@ export function createTemporalClass< (handleUnusedOptions(options), (argInternals as I) || stringToInternals(toString(arg as string))) } - return [TemporalClass as any, createInstance, toInternals] + return [ + TemporalClass as Classlike, + createInstance, + toInternals, + ] } // Utils for Specific Classes // ------------------------------------------------------------------------------------------------- export function toLocaleStringMethod( - this: any, // !!! + this: Formattable, internals: unknown, locales: string | string[], options: Intl.DateTimeFormatOptions, @@ -263,17 +269,19 @@ export function neverValueOf() { // Complex Objects with IDs // ------------------------------------------------------------------------------------------------- -export function createProtocolChecker

( - protocolMethods: P +type ProtocolMembers = { [K in keyof Methods]: unknown } & { id: string } + +export function createProtocolChecker( + protocolMethods: M ): ( - (obj: { [K in keyof P]: any } & { id: string }) => void + (obj: ProtocolMembers) => void ) { - const propNames = Object.keys(protocolMethods) as (keyof (P & { id: string }))[] + const propNames = Object.keys(protocolMethods) as (keyof ProtocolMembers)[] propNames.push('id') propNames.sort() // TODO: order matters? return (obj) => { - if (!hasAllPropsByName

(obj, propNames)) { + if (!hasAllPropsByName>(obj, propNames)) { throw new TypeError('Invalid protocol') } } diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index e6d0cd47..f2dce607 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -29,7 +29,7 @@ import { import { computeNanoInc, roundByIncLarge } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' import { noop } from './utils' -import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' +import { ZonedDateTime, ZonedInternals, createZonedDateTime } from './zonedDateTime' import { TimeUnit, Unit } from './units' import { TimeZoneArg } from './timeZone' @@ -53,7 +53,7 @@ export const [ // internalsConversionMap { - ZonedDateTime: (argInternals) => argInternals.epochNanoseconds, + ZonedDateTime: (argInternals: ZonedInternals) => argInternals.epochNanoseconds, }, // bagToInternals diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 53ae7d10..e4be9d5b 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -8,6 +8,7 @@ import { LargeInt } from './largeInt' import { PlainDate } from './plainDate' import { PlainDateTime } from './plainDateTime' import { PlainMonthDay } from './plainMonthDay' +import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { @@ -173,7 +174,7 @@ export function resolveZonedFormattable( } type OrigFormattable = number | Date -type Formattable = Instant | PlainDate | PlainDateTime | ZonedDateTime | PlainYearMonth | PlainMonthDay | OrigFormattable +export type Formattable = Instant | PlainDate | PlainDateTime | ZonedDateTime | PlainYearMonth | PlainMonthDay | PlainTime | OrigFormattable function resolveFormattable( arg: Formattable, diff --git a/packages/temporal-polyfill/src/plainDateTime.ts b/packages/temporal-polyfill/src/plainDateTime.ts index 65044cd6..51edffda 100644 --- a/packages/temporal-polyfill/src/plainDateTime.ts +++ b/packages/temporal-polyfill/src/plainDateTime.ts @@ -13,6 +13,7 @@ import { diffDateTimes } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { DurationInternals, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { + IsoDateInternals, IsoDateTimeInternals, generatePublicIsoDateTimeFields, isoTimeFieldDefaults, @@ -46,7 +47,7 @@ import { TimeZoneArg } from './timeZone' import { getSingleInstantFor, queryTimeZoneOps, zonedInternalsToIso } from './timeZoneOps' import { DayTimeUnit, Unit, UnitName } from './units' import { NumSign } from './utils' -import { ZonedDateTime, createZonedDateTime } from './zonedDateTime' +import { ZonedDateTime, ZonedInternals, createZonedDateTime } from './zonedDateTime' export type PlainDateTimeArg = PlainDateTime | PlainDateTimeBag | string export type PlainDateTimeBag = DateBag & TimeBag & { calendar?: CalendarArg } @@ -83,13 +84,17 @@ export const [PlainDateTime, createPlainDateTime, toPlainDateTimeInternals] = cr isoMicrosecond, isoNanosecond, calendar, - }) + }) as unknown as bigint[] as unknown as IsoDateTimeInternals }, // internalsConversionMap + // TODO: add types to other conversion maps + // Important that return types exactly match, because affects inferenced Internals { - PlainDate: (argInternals) => ({ ...argInternals, ...isoTimeFieldDefaults }), - ZonedDateTime: (argInternals) => { + PlainDate: (argInternals: IsoDateInternals) => { + return { ...argInternals, ...isoTimeFieldDefaults } + }, + ZonedDateTime: (argInternals: ZonedInternals) => { return pluckIsoDateTimeInternals(zonedInternalsToIso(argInternals)) }, }, @@ -256,14 +261,15 @@ function movePlainDateTime( durationInternals: DurationInternals, options: OverflowOptions | undefined, ): PlainDateTime { - return createPlainDateTime( - moveDateTime( + return createPlainDateTime({ + calendar: internals.calendar, // TODO: make this nicer + ...moveDateTime( internals.calendar, internals, durationInternals, refineOverflowOptions(options), ), - ) + }) } function diffPlainDateTimes( diff --git a/packages/temporal-polyfill/src/plainTime.ts b/packages/temporal-polyfill/src/plainTime.ts index 2d9d200b..173550ab 100644 --- a/packages/temporal-polyfill/src/plainTime.ts +++ b/packages/temporal-polyfill/src/plainTime.ts @@ -29,6 +29,7 @@ import { roundTime, roundTimeToNano } from './round' import { zonedInternalsToIso } from './timeZoneOps' import { TimeUnit, Unit, UnitName } from './units' import { NumSign } from './utils' +import { ZonedInternals } from './zonedDateTime' export type PlainTimeArg = PlainTime | PlainTimeBag | string export type PlainTimeBag = TimeBag @@ -67,7 +68,7 @@ export const [ // internalsConversionMap { PlainDateTime: pluckIsoTimeFields, - ZonedDateTime(argInternals) { + ZonedDateTime(argInternals: ZonedInternals) { return pluckIsoTimeFields(zonedInternalsToIso(argInternals)) }, }, diff --git a/packages/temporal-polyfill/src/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts index 218a3da7..61dc13e4 100644 --- a/packages/temporal-polyfill/src/timeZone.ts +++ b/packages/temporal-polyfill/src/timeZone.ts @@ -18,12 +18,12 @@ interface TimeZoneProtocolMethods { getNextTransition?(startingPoint: InstantArg): Instant | null getPreviousTransition?(startingPoint: InstantArg): Instant | null getPossibleInstantsFor(dateTime: PlainDateTimeArg): Instant[] - toString?(): string; - toJSON?(): string; + toString?(): string + toJSON?(): string } export interface TimeZoneProtocol extends TimeZoneProtocolMethods { - id: string; + id: string } // the *required* protocol methods diff --git a/packages/temporal-polyfill/src/timeZoneOps.ts b/packages/temporal-polyfill/src/timeZoneOps.ts index bf8131cf..5d63681e 100644 --- a/packages/temporal-polyfill/src/timeZoneOps.ts +++ b/packages/temporal-polyfill/src/timeZoneOps.ts @@ -9,7 +9,7 @@ import { idGettersStrict, } from './class' import { Instant, createInstant } from './instant' -import { IsoDateFields, IsoDateTimeFields, isoTimeFieldDefaults } from './isoFields' +import { IsoDateFields, IsoDateTimeFields, IsoDateTimeInternals, isoTimeFieldDefaults } from './isoFields' import { epochNanoToIso, isoToEpochNano, @@ -260,8 +260,11 @@ const timeZoneOpsAdapterMethods = { }, getPossibleInstantsFor(timeZone: TimeZoneProtocol, isoDateTimeFields: IsoDateTimeFields): LargeInt[] { - return ensureArray(timeZone.getPossibleInstantsFor(createPlainDateTime(isoDateTimeFields))) - .map(getInstantEpochNano) + return ensureArray( + timeZone.getPossibleInstantsFor( + createPlainDateTime(isoDateTimeFields as IsoDateTimeInternals) // HACK: hope Calendar isn't needed + ) + ).map(getInstantEpochNano) }, } diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index 743038ac..e99662a5 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -15,6 +15,8 @@ For programmatically-generated functions that have overly-complex inferred types */ export type Callable = (...args: any[]) => any +export type Classlike = any + const objectlikeRE = /object|function/ // TODO: Record From 8f5f5d2d98434b1e95c77f8db1d5f8749045f8a9 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 1 Aug 2023 17:35:49 -0400 Subject: [PATCH 191/805] better types for createZonedDateTimeConverter --- packages/temporal-polyfill/src/convert.ts | 25 +++++++++++---------- packages/temporal-polyfill/src/instant.ts | 3 --- packages/temporal-polyfill/src/plainDate.ts | 2 +- packages/temporal-polyfill/src/plainTime.ts | 2 +- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index 26f02dfc..91cca9e2 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -6,9 +6,6 @@ import { isoCalendarId, } from './calendarConfig' import { - DateBag, - DateBagStrict, - DateTimeBag, DayFields, TimeFields, YearFields, @@ -183,19 +180,23 @@ export function mergeZonedDateTimeBag( } } -export function createZonedDateTimeConverter( - getExtraIsoFields: (options: any) => any, +export function createZonedDateTimeConverter< + Internals extends Partial, + NarrowOptions +>( + getMoreInternals: (options: NarrowOptions) => Partial, ): ( - (internals: any, options: any) => ZonedDateTime + (internals: Internals, options: NarrowOptions & { timeZone: TimeZoneArg }) => ZonedDateTime ) { return (internals, options) => { - const { calendar } = internals - const timeZone = queryTimeZoneOps(options.timeZone) - - const epochNanoseconds = getSingleInstantFor(timeZone, { + const finalInternals = { ...internals, - ...getExtraIsoFields(normalizeOptions(options)), - }) + ...getMoreInternals(normalizeOptions(options)) + } as IsoDateTimeInternals + + const { calendar } = finalInternals + const timeZone = queryTimeZoneOps(options.timeZone) + const epochNanoseconds = getSingleInstantFor(timeZone, finalInternals) return createZonedDateTime({ calendar, diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index f2dce607..b018b01b 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -74,9 +74,6 @@ export const [ // ----------------------------------------------------------------------------------------------- { - /* - TODO: doesn't accept timeZoneArg anymore??? - */ toZonedDateTimeISO(epochNano: LargeInt, timeZoneArg: TimeZoneArg): ZonedDateTime { return createZonedDateTime({ epochNanoseconds: epochNano, diff --git a/packages/temporal-polyfill/src/plainDate.ts b/packages/temporal-polyfill/src/plainDate.ts index 2a12ddae..b37e6ca3 100644 --- a/packages/temporal-polyfill/src/plainDate.ts +++ b/packages/temporal-polyfill/src/plainDate.ts @@ -147,7 +147,7 @@ export const [ valueOf: neverValueOf, - toZonedDateTime: createZonedDateTimeConverter((options: any) => { + toZonedDateTime: createZonedDateTimeConverter((options: { plainTime: PlainTimeArg }) => { return optionalToPlainTimeFields(options.plainTime) }), diff --git a/packages/temporal-polyfill/src/plainTime.ts b/packages/temporal-polyfill/src/plainTime.ts index 173550ab..884f6a18 100644 --- a/packages/temporal-polyfill/src/plainTime.ts +++ b/packages/temporal-polyfill/src/plainTime.ts @@ -138,7 +138,7 @@ export const [ valueOf: neverValueOf, - toZonedDateTime: createZonedDateTimeConverter((options: any) => { + toZonedDateTime: createZonedDateTimeConverter((options: { plainDate: PlainDateArg }) => { return toPlainDateInternals(options.plainDate) }), From 349e1a69f59575270ddfebb27d2fefc160dada43 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 1 Aug 2023 17:44:32 -0400 Subject: [PATCH 192/805] remove any in convert --- .../temporal-polyfill/src/calendarFields.ts | 1 - packages/temporal-polyfill/src/convert.ts | 36 ++++++++++--------- packages/temporal-polyfill/src/diff.ts | 2 +- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/temporal-polyfill/src/calendarFields.ts b/packages/temporal-polyfill/src/calendarFields.ts index f6bac932..6ac96a0c 100644 --- a/packages/temporal-polyfill/src/calendarFields.ts +++ b/packages/temporal-polyfill/src/calendarFields.ts @@ -72,7 +72,6 @@ export interface TimeFields { export type TimeBag = Partial export type DateTimeBag = DateBag & TimeBag // TODO: use for PlainDateTime? - type DateTimeFields = DateFields & TimeFields export interface DateBasics { diff --git a/packages/temporal-polyfill/src/convert.ts b/packages/temporal-polyfill/src/convert.ts index 91cca9e2..b8de9af8 100644 --- a/packages/temporal-polyfill/src/convert.ts +++ b/packages/temporal-polyfill/src/convert.ts @@ -6,7 +6,9 @@ import { isoCalendarId, } from './calendarConfig' import { + DateTimeBag, DayFields, + TimeBag, TimeFields, YearFields, dateFieldNames, @@ -80,7 +82,7 @@ export function refineMaybeZonedDateTimeBag( if (fields.timeZone) { const timeZone = queryTimeZoneOps(fields.timeZone) const isoDateFields = calendar.dateFromFields(fields, Overflow.Constrain) - const isoTimeFields = refineTimeFields(fields, Overflow.Constrain) + const isoTimeFields = refineTimeBag(fields, Overflow.Constrain) const epochNanoseconds = getMatchingInstantFor( timeZone, @@ -99,7 +101,7 @@ export function refineMaybeZonedDateTimeBag( } } else { const isoDateInternals = calendar.dateFromFields(fields, Overflow.Constrain) - const isoTimeFields = refineTimeFields(fields, Overflow.Constrain) + const isoTimeFields = refineTimeBag(fields, Overflow.Constrain) return { ...isoDateInternals, ...isoTimeFields } } @@ -125,7 +127,7 @@ export function refineZonedDateTimeBag( const timeZone = queryTimeZoneOps(fields.timeZone!) // guaranteed via refineCalendarFields const isoDateFields = calendar.dateFromFields(fields, overflow) - const isoTimeFields = refineTimeFields(fields, overflow) + const isoTimeFields = refineTimeBag(fields, overflow) const epochNanoseconds = getMatchingInstantFor( timeZone, @@ -161,7 +163,7 @@ export function mergeZonedDateTimeBag( const [overflow, epochDisambig, offsetDisambig] = refineZonedFieldOptions(options) const isoDateFields = calendar.dateFromFields(fields, overflow) - const isoTimeFields = refineTimeFields(fields, overflow) + const isoTimeFields = refineTimeBag(fields, overflow) const epochNanoseconds = getMatchingInstantFor( timeZone, @@ -219,11 +221,11 @@ export function refinePlainDateTimeBag( bag, dateTimeFieldNames, getRequiredDateFields(calendar), - ) + ) as DateTimeBag const overflow = refineOverflowOptions(options) const isoDateInternals = calendar.dateFromFields(fields, overflow) - const isoTimeFields = refineTimeFields(fields, overflow) + const isoTimeFields = refineTimeBag(fields, overflow) return { ...isoDateInternals, ...isoTimeFields } } @@ -239,11 +241,11 @@ export function mergePlainDateTimeBag( plainDateTime, mod, dateTimeFieldNames, - ) + ) as DateTimeBag const overflow = refineOverflowOptions(options) const isoDateInternals = calendar.dateFromFields(fields, overflow) - const isoTimeFields = refineTimeFields(fields, overflow) + const isoTimeFields = refineTimeBag(fields, overflow) return { ...isoDateInternals, ...isoTimeFields } } @@ -445,9 +447,9 @@ export function refinePlainTimeBag( bag: PlainTimeBag, options: OverflowOptions | undefined, ): IsoTimeFields { - const fields = refineFields(bag, timeFieldNames, []) + const fields = refineFields(bag, timeFieldNames, []) as TimeBag - return refineTimeFields(fields, refineOverflowOptions(options)) + return refineTimeBag(fields, refineOverflowOptions(options)) } export function mergePlainTimeBag( @@ -459,11 +461,11 @@ export function mergePlainTimeBag( const partialFields = refineFields(bag, timeFieldNames) const mergeFields = { ...fields, ...partialFields } - return refineTimeFields(mergeFields, refineOverflowOptions(options)) + return refineTimeBag(mergeFields, refineOverflowOptions(options)) } -function refineTimeFields(fields: any, overflow: any): IsoTimeFields { - return constrainIsoTimeFields(timeFieldsToIso(fields), overflow) +function refineTimeBag(fields: TimeBag, overflow: Overflow): IsoTimeFields { + return constrainIsoTimeFields(timeFieldsToIso({ ...timeFieldDefaults, ...fields }), overflow) } // Duration @@ -540,7 +542,7 @@ function extractBagCalendarOps( function rejectInvalidBag(bag: { calendar?: unknown, timeZone?: unknown }): void { if (getInternals(bag)) { - throw new TypeError('Cant pass any Temporal object') + throw new TypeError('Cant pass a Temporal object') } if (bag.calendar !== undefined) { throw new TypeError('Ah') @@ -569,13 +571,13 @@ function refineFields( // if not given, then assumed to be 'partial' (defaults won't be applied) ): Record { const res: Record = {} - let any = false + let anyMatching = false for (const fieldName of validFieldNames) { let fieldVal = bag[fieldName] if (fieldVal !== undefined) { - any = true + anyMatching = true if (builtinRefiners[fieldName as keyof typeof builtinRefiners]) { fieldVal = (builtinRefiners[fieldName as keyof typeof builtinRefiners] as Callable)(fieldVal) @@ -591,7 +593,7 @@ function refineFields( } } - if (!any) { + if (!anyMatching) { throw new TypeError('No valid fields') } diff --git a/packages/temporal-polyfill/src/diff.ts b/packages/temporal-polyfill/src/diff.ts index 58e327fc..b09d4fe4 100644 --- a/packages/temporal-polyfill/src/diff.ts +++ b/packages/temporal-polyfill/src/diff.ts @@ -19,7 +19,7 @@ import { import { LargeInt, compareLargeInts } from './largeInt' import { moveDateByDays, moveDateTime, moveZonedEpochNano } from './move' import { Overflow, RoundingMode } from './options' -import { MarkerToEpochNano, MoveMarker, computeNanoInc, roundByInc, roundByIncLarge, roundRelativeDuration } from './round' +import { computeNanoInc, roundByInc, roundByIncLarge, roundRelativeDuration } from './round' import { TimeZoneOps, getSingleInstantFor, zonedEpochNanoToIso } from './timeZoneOps' import { DayTimeUnit, From 9ebddca77379c4c86f73385b1195f6bed13e946d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 1 Aug 2023 17:53:30 -0400 Subject: [PATCH 193/805] remove more any --- packages/temporal-polyfill/src/intlFormat.ts | 23 +++++++++++-------- packages/temporal-polyfill/src/options.ts | 1 - packages/temporal-polyfill/src/timeZone.ts | 2 +- packages/temporal-polyfill/src/timeZoneOps.ts | 6 ++--- packages/temporal-polyfill/src/utils.ts | 4 +++- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index e4be9d5b..6e76b4fe 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -12,7 +12,9 @@ import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { + Classlike, createLazyGenerator, + defineProps, excludePropsByName, hasAnyPropsByName, identityFunc, @@ -41,6 +43,7 @@ export function hashIntlFormatParts( // AHHH... problem with resolvedOptions... need to whitelist original // PERFORMANCE: avoid using our DateTimeFormat for toLocaleString, because creates two objects +// TODOOOOO: this needs to be rewritten. who cares about `any` for now export const IntlDateTimeFormat = Intl.DateTimeFormat @@ -63,17 +66,19 @@ export class DateTimeFormat extends IntlDateTimeFormat { } ['formatRange', 'formatRangeToParts'].forEach((methodName) => { - const origMethod = (IntlDateTimeFormat as any).prototype[methodName] + const origMethod = (IntlDateTimeFormat as Classlike).prototype[methodName] if (origMethod) { - // TODO: not sufficient for defining method. Use defineProperty! - (DateTimeFormat as any).prototype[methodName] = function( - arg0: Formattable, - arg1: Formattable, - ) { - const [formattable0, formattable1, format] = resolveRangeFormattables(this, arg0, arg1) - return origMethod.call(format, formattable0, formattable1) - } + defineProps(DateTimeFormat.prototype, { + [methodName]: function( + this: Intl.DateTimeFormat, + arg0: Formattable, + arg1: Formattable, + ) { + const [formattable0, formattable1, format] = resolveRangeFormattables(this, arg0, arg1) + return origMethod.call(format, formattable0, formattable1) + } + }) } }) diff --git a/packages/temporal-polyfill/src/options.ts b/packages/temporal-polyfill/src/options.ts index 09ab2467..16db961d 100644 --- a/packages/temporal-polyfill/src/options.ts +++ b/packages/temporal-polyfill/src/options.ts @@ -704,7 +704,6 @@ export function clampProp

( // Primitives // ------------------------------------------------------------------------------------------------- -// NOTE: even though these accept 'any', strictly type so TS interface is more strict export function ensureInstanceOf(Class: { new(): T }, obj: T): T { if (!(obj instanceof Class)) { diff --git a/packages/temporal-polyfill/src/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts index 61dc13e4..52f63282 100644 --- a/packages/temporal-polyfill/src/timeZone.ts +++ b/packages/temporal-polyfill/src/timeZone.ts @@ -14,7 +14,7 @@ interface TimeZoneProtocolMethods { getOffsetNanosecondsFor(instant: InstantArg): number getOffsetStringFor?(instant: InstantArg): string getPlainDateTimeFor?(instant: InstantArg, calendarArg?: CalendarArg): PlainDateTime - getInstantFor?(dateTime: PlainDateTimeArg, options?: any): Instant + getInstantFor?(dateTime: PlainDateTimeArg, options?: EpochDisambigOptions): Instant getNextTransition?(startingPoint: InstantArg): Instant | null getPreviousTransition?(startingPoint: InstantArg): Instant | null getPossibleInstantsFor(dateTime: PlainDateTimeArg): Instant[] diff --git a/packages/temporal-polyfill/src/timeZoneOps.ts b/packages/temporal-polyfill/src/timeZoneOps.ts index 5d63681e..f6bdd204 100644 --- a/packages/temporal-polyfill/src/timeZoneOps.ts +++ b/packages/temporal-polyfill/src/timeZoneOps.ts @@ -23,7 +23,7 @@ import { roundToMinute } from './round' import { TimeZone, TimeZoneArg, TimeZoneProtocol, createTimeZone, timeZoneProtocolMethods } from './timeZone' import { TimeZoneImpl, queryTimeZoneImpl } from './timeZoneImpl' import { nanoInUtcDay } from './units' -import { createLazyGenerator, isObjectlike } from './utils' +import { BoundArg, createLazyGenerator, isObjectlike } from './utils' import { ZonedInternals } from './zonedDateTime' export interface TimeZoneOps { @@ -87,7 +87,7 @@ function timeZoneOpsToPublic(timeZoneOps: TimeZoneOps): TimeZoneProtocol { } export const getCommonTimeZoneOps = getCommonInnerObj.bind< - any, [any], // bound + undefined, [BoundArg], // bound [TimeZoneInternals, TimeZoneInternals], // unbound TimeZoneOps // return >(undefined, 'timeZone') @@ -249,7 +249,7 @@ export function zonedEpochNanoToIso(timeZoneOps: TimeZoneOps, epochNano: LargeIn // ------- const getInstantEpochNano = getStrictInternals.bind< - any, [any], // bound + undefined, [BoundArg], // bound [Instant], // unbound LargeInt // return >(undefined, Instant) diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index e99662a5..65c5dd46 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -136,7 +136,9 @@ function filterProps( } export const excludePropsByName = filterProps.bind< - any, [any], [any, Set], any + undefined, [BoundArg], // bound + [any, Set], // unbound + any // return >(undefined, ( propVal: unknown, propName: string, From c764006fd5812c8c940ec2adaa1bf14f9446544f Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 3 Aug 2023 17:42:49 -0400 Subject: [PATCH 194/805] more readable DateTimeFormat --- .../temporal-polyfill/src/calendarImpl.ts | 4 +- packages/temporal-polyfill/src/class.ts | 4 - packages/temporal-polyfill/src/intlFormat.ts | 85 +++++++++---------- packages/temporal-polyfill/src/now.ts | 4 +- packages/temporal-polyfill/src/timeZone.ts | 2 +- .../temporal-polyfill/src/timeZoneImpl.ts | 4 +- 6 files changed, 49 insertions(+), 54 deletions(-) diff --git a/packages/temporal-polyfill/src/calendarImpl.ts b/packages/temporal-polyfill/src/calendarImpl.ts index 94ce58f1..9465cf06 100644 --- a/packages/temporal-polyfill/src/calendarImpl.ts +++ b/packages/temporal-polyfill/src/calendarImpl.ts @@ -29,7 +29,7 @@ import { diffDatesExact, diffEpochMilliByDay, } from './diff' -import { IntlDateTimeFormat, hashIntlFormatParts, standardLocaleId } from './intlFormat' +import { OrigDateTimeFormat, hashIntlFormatParts, standardLocaleId } from './intlFormat' import { IsoDateFields, IsoDateInternals, isoTimeFieldDefaults } from './isoFields' import { computeIsoDayOfWeek, @@ -723,7 +723,7 @@ export function parseIntlYear( } function buildIntlFormat(calendarId: string): Intl.DateTimeFormat { - return new IntlDateTimeFormat(standardLocaleId, { + return new OrigDateTimeFormat(standardLocaleId, { calendar: calendarId, timeZone: 'UTC', era: 'short', // 'narrow' is too terse for japanese months diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index 93ea714f..54690204 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -254,10 +254,6 @@ export function toLocaleStringMethod( locales: string | string[], options: Intl.DateTimeFormatOptions, ) { - /* - Will create two internal Intl.DateTimeFormats :( - Create just one instead - */ const format = new DateTimeFormat(locales, options) return format.format(this) } diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 6e76b4fe..75a3ee4d 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -13,6 +13,7 @@ import { PlainYearMonth } from './plainYearMonth' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' import { Classlike, + Reused, createLazyGenerator, defineProps, excludePropsByName, @@ -41,13 +42,9 @@ export function hashIntlFormatParts( // Stuff // ------------------------------------------------------------------------------------------------- -// AHHH... problem with resolvedOptions... need to whitelist original -// PERFORMANCE: avoid using our DateTimeFormat for toLocaleString, because creates two objects -// TODOOOOO: this needs to be rewritten. who cares about `any` for now +export const OrigDateTimeFormat = Intl.DateTimeFormat -export const IntlDateTimeFormat = Intl.DateTimeFormat - -export class DateTimeFormat extends IntlDateTimeFormat { +export class DateTimeFormat extends OrigDateTimeFormat { format(arg?: Formattable): string { const [formattable, format] = resolveSingleFormattable(this as Intl.DateTimeFormat, arg) return format @@ -66,7 +63,7 @@ export class DateTimeFormat extends IntlDateTimeFormat { } ['formatRange', 'formatRangeToParts'].forEach((methodName) => { - const origMethod = (IntlDateTimeFormat as Classlike).prototype[methodName] + const origMethod = (OrigDateTimeFormat as Classlike).prototype[methodName] if (origMethod) { defineProps(DateTimeFormat.prototype, { @@ -85,7 +82,7 @@ export class DateTimeFormat extends IntlDateTimeFormat { // DateTimeFormat Helpers // ------------------------------------------------------------------------------------------------- -const getGetSpecificFormat = createLazyGenerator((dtf: Intl.DateTimeFormat) => { +const getSpecificFormatStore = createLazyGenerator((origFormat: Intl.DateTimeFormat) => { return createLazyGenerator(createSpecificFormat) }, WeakMap) @@ -93,28 +90,28 @@ function createSpecificFormat( transformOptions: OptionsTransformer, resolvedOptions: Intl.ResolvedDateTimeFormatOptions, ): Intl.DateTimeFormat { - return new IntlDateTimeFormat(resolvedOptions.locale, transformOptions(resolvedOptions)) + return new OrigDateTimeFormat(resolvedOptions.locale, transformOptions(resolvedOptions)) } function resolveSingleFormattable( - format: Intl.DateTimeFormat, + origFormat: Intl.DateTimeFormat, arg: Formattable | undefined, ): [ OrigFormattable | undefined, Intl.DateTimeFormat | undefined ] { if (arg === undefined) { - return [arg, format] + return [arg, origFormat] } - const getSpecificFormat = getGetSpecificFormat(format) - const resolvedOptions = format.resolvedOptions() + const specificFormatStore = getSpecificFormatStore(origFormat) + const resolvedOptions = origFormat.resolvedOptions() - return resolveFormattable(arg, getSpecificFormat, resolvedOptions) + return resolveFormattable(arg, specificFormatStore, resolvedOptions) } function resolveRangeFormattables( - format: Intl.DateTimeFormat, + origFormat: Intl.DateTimeFormat, arg0: Formattable, arg1: Formattable, ): [ @@ -122,21 +119,21 @@ function resolveRangeFormattables( OrigFormattable, Intl.DateTimeFormat, ] { - const getSpecificFormat = getGetSpecificFormat(format) - const resolvedOptions = format.resolvedOptions() + const specificFormatStore = getSpecificFormatStore(origFormat) + const resolvedOptions = origFormat.resolvedOptions() - const [formattable0, format0] = resolveFormattable(arg0, getSpecificFormat, resolvedOptions) - const [formattable1, format1] = resolveFormattable(arg1, getSpecificFormat, resolvedOptions) + const [formattable0, format0] = resolveFormattable(arg0, specificFormatStore, resolvedOptions) + const [formattable1, format1] = resolveFormattable(arg1, specificFormatStore, resolvedOptions) if (format0 && format1) { if (format0 !== format1) { throw new TypeError('Accepts two Temporal values of same type') } - format = format0 + origFormat = format0 } // always returns a format - return [formattable0, formattable1, format] + return [formattable0, formattable1, origFormat] } // Resolving Formattable Objects (and Format) @@ -165,7 +162,7 @@ export function resolveZonedFormattable( options.timeZoneName = 'short' } - const format = new IntlDateTimeFormat(locales, options) + const format = new OrigDateTimeFormat(locales, options) checkCalendarsCompatible( internals.calendar.id, @@ -181,9 +178,14 @@ export function resolveZonedFormattable( type OrigFormattable = number | Date export type Formattable = Instant | PlainDate | PlainDateTime | ZonedDateTime | PlainYearMonth | PlainMonthDay | PlainTime | OrigFormattable +type SpecificFormatStore = ( + optionsTransformer: OptionsTransformer, // a proxy for the Temporal type + resolvedOptions: Intl.ResolvedDateTimeFormatOptions, +) => Intl.DateTimeFormat + function resolveFormattable( arg: Formattable, - getSpecificFormat: (optionsTransformer: OptionsTransformer, resolvedOptions: Intl.ResolvedDateTimeFormatOptions) => Intl.DateTimeFormat, + specificFormatStore: SpecificFormatStore, resolvedOptions: Intl.ResolvedDateTimeFormatOptions, ): [ OrigFormattable, @@ -198,7 +200,7 @@ function resolveFormattable( return [ epochNanoToMilli(epochNano), - getSpecificFormat(transformOptions, resolvedOptions), + specificFormatStore(transformOptions, resolvedOptions), ] } @@ -259,21 +261,22 @@ const optionTransformers: Record = { }, } -// TODO: use Intl.DateTimeFormatOptions? -type OptionsTransformer = (options: any) => any +type OptionsTransformer = (options: Intl.ResolvedDateTimeFormatOptions) => Intl.DateTimeFormatOptions function createTransformer( - optionNames: string[], - basicNames: string[], - exclusionNames: string[], + validNames: string[], + implicitNames: string[], + excludedNames: string[], ): OptionsTransformer { - const defaults = mapPropNamesToConstant(basicNames, 'numeric') - const exclusionNamesSet = new Set(exclusionNames) + const defaults = mapPropNamesToConstant(implicitNames, 'numeric') + const excludedNameSet = new Set(excludedNames) - return (options: any) => { - options = excludePropsByName(options, exclusionNamesSet) + return ( + options: Intl.ResolvedDateTimeFormatOptions | Reused + ) => { + options = excludePropsByName(options, excludedNameSet) - if (!hasAnyPropsByName(options, optionNames)) { + if (!hasAnyPropsByName(options, validNames)) { Object.assign(options, defaults) } @@ -335,24 +338,20 @@ function dateInternalsToEpochNano( // Calendar Check // ------------------------------------------------------------------------------------------------- -// TODO: simply check for absense of 'Date' in name? const strictCalendarCheck: Record = { PlainYearMonth: true, PlainMonthDay: true, } function checkCalendarsCompatible( - calendarId: string, + internalCalendarId: string, resolveCalendarId: string, strict?: boolean, ): void { - if (!( - calendarId === resolveCalendarId || - (!strict && ( - calendarId === isoCalendarId || - resolveCalendarId === isoCalendarId - )) - )) { + if ( + (!strict || internalCalendarId !== isoCalendarId) && + (internalCalendarId !== resolveCalendarId) + ) { throw new RangeError('Mismatching calendars') } } diff --git a/packages/temporal-polyfill/src/now.ts b/packages/temporal-polyfill/src/now.ts index 4a3cf0d7..09d595bb 100644 --- a/packages/temporal-polyfill/src/now.ts +++ b/packages/temporal-polyfill/src/now.ts @@ -3,7 +3,7 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' import { Instant, createInstant } from './instant' -import { IntlDateTimeFormat } from './intlFormat' +import { OrigDateTimeFormat } from './intlFormat' import { IsoDateTimeInternals, pluckIsoDateInternals, pluckIsoDateTimeInternals, pluckIsoTimeFields } from './isoFields' import { LargeInt, numberToLargeInt } from './largeInt' import { PlainDate, createPlainDate } from './plainDate' @@ -106,5 +106,5 @@ function getCurrentTimeZoneId(): string { } function queryCurrentTimeZoneId(): string { - return new IntlDateTimeFormat().resolvedOptions().timeZone + return new OrigDateTimeFormat().resolvedOptions().timeZone } diff --git a/packages/temporal-polyfill/src/timeZone.ts b/packages/temporal-polyfill/src/timeZone.ts index 52f63282..7071d41c 100644 --- a/packages/temporal-polyfill/src/timeZone.ts +++ b/packages/temporal-polyfill/src/timeZone.ts @@ -101,7 +101,7 @@ export const [TimeZone, createTimeZone] = createSimpleTemporalClass( // Getters // ----------------------------------------------------------------------------------------------- - idGetters as { id: (impl: TimeZoneImpl) => string }, // type needed? + idGetters, // Methods // ----------------------------------------------------------------------------------------------- diff --git a/packages/temporal-polyfill/src/timeZoneImpl.ts b/packages/temporal-polyfill/src/timeZoneImpl.ts index c02ecc37..4b490b68 100644 --- a/packages/temporal-polyfill/src/timeZoneImpl.ts +++ b/packages/temporal-polyfill/src/timeZoneImpl.ts @@ -1,6 +1,6 @@ import { isoCalendarId } from './calendarConfig' import { parseIntlYear } from './calendarImpl' -import { IntlDateTimeFormat, hashIntlFormatParts, standardLocaleId } from './intlFormat' +import { OrigDateTimeFormat, hashIntlFormatParts, standardLocaleId } from './intlFormat' import { IsoDateTimeFields } from './isoFields' import { epochNanoToSec, @@ -265,7 +265,7 @@ function createComputeOffsetSec(timeZoneId: string): ( function buildIntlFormat(timeZoneId: string): Intl.DateTimeFormat { // format will ALWAYS do gregorian. need to parse year - return new IntlDateTimeFormat(standardLocaleId, { + return new OrigDateTimeFormat(standardLocaleId, { timeZone: timeZoneId, era: 'short', year: 'numeric', From 7d7dca8610cfb4d01324396c2dfc85957af0298e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 3 Aug 2023 17:55:07 -0400 Subject: [PATCH 195/805] make datetimeformat more better --- packages/temporal-polyfill/src/intlFormat.ts | 28 +++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 75a3ee4d..291bd11d 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -46,7 +46,7 @@ export const OrigDateTimeFormat = Intl.DateTimeFormat export class DateTimeFormat extends OrigDateTimeFormat { format(arg?: Formattable): string { - const [formattable, format] = resolveSingleFormattable(this as Intl.DateTimeFormat, arg) + const [formattable, format] = resolveSingleFormattable(this, arg) return format ? format.format(formattable) : super.format(formattable) @@ -55,13 +55,18 @@ export class DateTimeFormat extends OrigDateTimeFormat { } formatToParts(arg?: Formattable): Intl.DateTimeFormatPart[] { - const [formattable, format] = resolveSingleFormattable(this as Intl.DateTimeFormat, arg) + const [formattable, format] = resolveSingleFormattable(this, arg) return format ? format.formatToParts(formattable) : super.formatToParts(formattable) } } +export interface DateTimeFormat { + formatRange(arg0: Formattable, arg1: Formattable): string + formatRangeToParts(arg0: Formattable, arg1: Formattable): Intl.DateTimeFormatPart[] +} + ['formatRange', 'formatRangeToParts'].forEach((methodName) => { const origMethod = (OrigDateTimeFormat as Classlike).prototype[methodName] @@ -82,6 +87,9 @@ export class DateTimeFormat extends OrigDateTimeFormat { // DateTimeFormat Helpers // ------------------------------------------------------------------------------------------------- +/* +Returns a unique store for each original DateTimeFormat +*/ const getSpecificFormatStore = createLazyGenerator((origFormat: Intl.DateTimeFormat) => { return createLazyGenerator(createSpecificFormat) }, WeakMap) @@ -126,13 +134,14 @@ function resolveRangeFormattables( const [formattable1, format1] = resolveFormattable(arg1, specificFormatStore, resolvedOptions) if (format0 && format1) { + // the returned DateTimeFormats are idempotent per Temporal type, + // so testing inequality is a way to test mismatching Temporal types. if (format0 !== format1) { throw new TypeError('Accepts two Temporal values of same type') } - origFormat = format0 + origFormat = format0 // reused } - // always returns a format return [formattable0, formattable1, origFormat] } @@ -197,15 +206,14 @@ function resolveFormattable( if (transformOptions) { const internalsToEpochNano = epochNanoConverters[temporalName] || dateInternalsToEpochNano const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) + const epochMilli = epochNanoToMilli(epochNano) + const format = specificFormatStore(transformOptions, resolvedOptions) - return [ - epochNanoToMilli(epochNano), - specificFormatStore(transformOptions, resolvedOptions), - ] + return [epochMilli, format] } - return [arg as number] as - unknown as [number, undefined] + return [arg as number] as unknown as + [number, undefined] } // Format Option Massagers From 76efc9d913b477b221ff9461b9c6c80b641a3e87 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Thu, 3 Aug 2023 18:44:56 -0400 Subject: [PATCH 196/805] more datetimeformat improvements --- packages/temporal-polyfill/src/class.ts | 4 +-- packages/temporal-polyfill/src/intlFormat.ts | 36 +++++++++++++------ .../temporal-polyfill/src/zonedDateTime.ts | 4 +-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index 54690204..2ac36098 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -1,4 +1,4 @@ -import { DateTimeFormat, Formattable } from './intlFormat' +import { DateTimeFormat, Formattable, LocalesArg } from './intlFormat' import { ensureInstanceOf, ensureString, toString } from './options' import { Callable, @@ -251,7 +251,7 @@ export function createTemporalClass< export function toLocaleStringMethod( this: Formattable, internals: unknown, - locales: string | string[], + locales: LocalesArg, options: Intl.DateTimeFormatOptions, ) { const format = new DateTimeFormat(locales, options) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 291bd11d..d8e70f74 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -23,6 +23,8 @@ import { } from './utils' import { ZonedDateTime, ZonedInternals } from './zonedDateTime' +export type LocalesArg = string | string[] + export const standardLocaleId = 'en-GB' // gives 24-hour clock export function hashIntlFormatParts( @@ -148,9 +150,12 @@ function resolveRangeFormattables( // Resolving Formattable Objects (and Format) // ------------------------------------------------------------------------------------------------- +/* +ZonedDateTime call this directly. Doesn't leverage our DateTimeFormat +*/ export function resolveZonedFormattable( internals: ZonedInternals, - locales?: string | string[], + locales?: LocalesArg, options?: Intl.DateTimeFormatOptions, // NOT resolved yet (does not include locale) ): [ number, @@ -167,25 +172,34 @@ export function resolveZonedFormattable( options.timeZoneName === undefined && !hasAnyPropsByName(options as Record, dateTimeOptionNames) ) { - // The rest of the defaults will be filled in by formatting the Instant options.timeZoneName = 'short' } - const format = new OrigDateTimeFormat(locales, options) + const origFormat = new OrigDateTimeFormat(locales, options) + const resolvedOptions = origFormat.resolvedOptions() + const transformedOptions = instantOptionsTransformer(resolvedOptions) + const specificFormat = new OrigDateTimeFormat(resolvedOptions.locale, transformedOptions) + const epochMilli = epochNanoToMilli(internals.epochNanoseconds) checkCalendarsCompatible( internals.calendar.id, - format.resolvedOptions().calendar, + resolvedOptions.calendar, ) - return [ - epochNanoToMilli(internals.epochNanoseconds), - format, - ] + return [epochMilli, specificFormat] } type OrigFormattable = number | Date -export type Formattable = Instant | PlainDate | PlainDateTime | ZonedDateTime | PlainYearMonth | PlainMonthDay | PlainTime | OrigFormattable + +export type Formattable = + | Instant + | PlainDate + | PlainDateTime + | ZonedDateTime + | PlainYearMonth + | PlainMonthDay + | PlainTime + | OrigFormattable type SpecificFormatStore = ( optionsTransformer: OptionsTransformer, // a proxy for the Temporal type @@ -257,13 +271,15 @@ const monthDayExclusions = [ ...timeOptionNames, ] +const instantOptionsTransformer = createTransformer(dateTimeOptionNames, dateTimeBasicNames, []) + const optionTransformers: Record = { PlainTime: createTransformer(timeOptionNames, timeBasicNames, timeExclusions), PlainDateTime: createTransformer(dateTimeOptionNames, dateTimeBasicNames, dateTimeExclusions), PlainDate: createTransformer(dateOptionNames, dateBasicNames, dateExclusions), PlainYearMonth: createTransformer(yearMonthBasicNames, yearMonthBasicNames, yearMonthExclusions), PlainMonthDay: createTransformer(monthDayBasicNames, monthDayBasicNames, monthDayExclusions), - Instant: createTransformer(dateTimeOptionNames, dateTimeBasicNames, []), + Instant: instantOptionsTransformer, ZonedDateTime: () => { throw new TypeError('Cant do on ZonedDateTime') }, diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index e4d1151b..94404ee6 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -13,7 +13,7 @@ import { diffZonedEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { DurationFields, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { Instant, createInstant } from './instant' -import { resolveZonedFormattable } from './intlFormat' +import { LocalesArg, resolveZonedFormattable } from './intlFormat' import { CalendarPublic, IsoDateTimePublic, @@ -356,7 +356,7 @@ export const [ toLocaleString( internals: ZonedInternals, - locales?: string | string[], + locales?: LocalesArg, options?: Intl.DateTimeFormatOptions, ): string { const [epochMilli, format] = resolveZonedFormattable(internals, locales, options) From 204911aaa7a4091c96a76066a372665be77a1cb3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 14:23:29 -0400 Subject: [PATCH 197/805] tmp intl format stuff --- .../temporal-polyfill/src/calendarFields.ts | 9 - packages/temporal-polyfill/src/class.ts | 10 - packages/temporal-polyfill/src/instant.ts | 3 +- packages/temporal-polyfill/src/intlFormat.ts | 319 +++++++++--------- packages/temporal-polyfill/src/plainDate.ts | 3 +- .../temporal-polyfill/src/plainDateTime.ts | 3 +- .../temporal-polyfill/src/plainMonthDay.ts | 3 +- packages/temporal-polyfill/src/plainTime.ts | 3 +- .../temporal-polyfill/src/plainYearMonth.ts | 3 +- .../temporal-polyfill/src/zonedDateTime.ts | 11 +- 10 files changed, 170 insertions(+), 197 deletions(-) diff --git a/packages/temporal-polyfill/src/calendarFields.ts b/packages/temporal-polyfill/src/calendarFields.ts index 6ac96a0c..20060f4d 100644 --- a/packages/temporal-polyfill/src/calendarFields.ts +++ b/packages/temporal-polyfill/src/calendarFields.ts @@ -74,12 +74,6 @@ export type TimeBag = Partial export type DateTimeBag = DateBag & TimeBag // TODO: use for PlainDateTime? type DateTimeFields = DateFields & TimeFields -export interface DateBasics { - year: number - month: number - day: number -} - export interface YearMonthBasics { year: number month: number @@ -216,9 +210,6 @@ export const dateTimeFieldNames = Object.keys(dateTimeFieldRefiners).sort() as export const timeFieldNames = Object.keys(timeFieldRefiners) as (keyof TimeFields)[] -export const dateBasicNames = ['day', 'month', 'year'] as - (keyof DateBasics)[] - // monthCode/year export const yearMonthBasicNames = yearMonthFieldNames.slice(1) as (keyof YearMonthBasics)[] diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index 2ac36098..8c725b61 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -248,16 +248,6 @@ export function createTemporalClass< // Utils for Specific Classes // ------------------------------------------------------------------------------------------------- -export function toLocaleStringMethod( - this: Formattable, - internals: unknown, - locales: LocalesArg, - options: Intl.DateTimeFormatOptions, -) { - const format = new DateTimeFormat(locales, options) - return format.format(this) -} - export function neverValueOf() { throw new TypeError('Cannot convert object using valueOf') } diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index b018b01b..6cbb9293 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -1,10 +1,11 @@ import { isoCalendarId } from './calendarConfig' import { queryCalendarOps } from './calendarOps' -import { TemporalInstance, createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, neverValueOf } from './class' import { diffEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { formatIsoDateTimeFields, formatOffsetNano } from './isoFormat' +import { toLocaleStringMethod } from './intlFormat' import { epochGetters, epochMicroToNano, diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index d8e70f74..554ec3d8 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -1,5 +1,4 @@ import { isoCalendarId } from './calendarConfig' -import { dateBasicNames } from './calendarFields' import { getInternals, getTemporalName } from './class' import { Instant } from './instant' import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' @@ -11,42 +10,58 @@ import { PlainMonthDay } from './plainMonthDay' import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' -import { - Classlike, - Reused, - createLazyGenerator, - defineProps, - excludePropsByName, - hasAnyPropsByName, - identityFunc, - mapPropNamesToConstant, -} from './utils' +import { Classlike, createLazyGenerator, defineProps, excludePropsByName, hasAnyPropsByName, identityFunc } from './utils' import { ZonedDateTime, ZonedInternals } from './zonedDateTime' export type LocalesArg = string | string[] -export const standardLocaleId = 'en-GB' // gives 24-hour clock +type OrigFormattable = number | Date -export function hashIntlFormatParts( - intlFormat: Intl.DateTimeFormat, - epochMilliseconds: number, -): Record { - const parts = intlFormat.formatToParts(epochMilliseconds) - const hash = {} as Record +export type Formattable = + | Instant + | PlainDate + | PlainDateTime + | ZonedDateTime + | PlainYearMonth + | PlainMonthDay + | PlainTime + | OrigFormattable - for (const part of parts) { - hash[part.type] = part.value - } +// Temporal-aware Intl.DateTimeFormat +// ------------------------------------------------------------------------------------------------- - return hash -} +type DateTimeFormatInternals = [ + SubformatFactory, + Intl.ResolvedDateTimeFormatOptions, +] -// Stuff -// ------------------------------------------------------------------------------------------------- +type SubformatFactory = (temporalName: string) => Intl.DateTimeFormat | undefined + +const formatInternalsMap = new WeakMap() export const OrigDateTimeFormat = Intl.DateTimeFormat export class DateTimeFormat extends OrigDateTimeFormat { + constructor(locales: LocalesArg, options: Intl.DateTimeFormatOptions = {}) { + super(locales, options) + + // copy options + const resolvedOptions = this.resolvedOptions() + const { locale } = resolvedOptions + options = whitelistOptions(resolvedOptions, options) + + const subformatFactory = createLazyGenerator((temporalName: string) => { + if (optionsTransformers[temporalName]) { + return new OrigDateTimeFormat(locale, optionsTransformers[temporalName](options)) + } + }) + + formatInternalsMap.set(this, [ + subformatFactory, + resolvedOptions, + ]) + } + format(arg?: Formattable): string { const [formattable, format] = resolveSingleFormattable(this, arg) return format @@ -86,42 +101,65 @@ export interface DateTimeFormat { } }) -// DateTimeFormat Helpers +// toLocaleString // ------------------------------------------------------------------------------------------------- -/* -Returns a unique store for each original DateTimeFormat -*/ -const getSpecificFormatStore = createLazyGenerator((origFormat: Intl.DateTimeFormat) => { - return createLazyGenerator(createSpecificFormat) -}, WeakMap) +export function toLocaleStringMethod( + this: Formattable, + internals: unknown, + locales: LocalesArg, + options: Intl.DateTimeFormatOptions, +) { + const format = new DateTimeFormat(locales, options) + return format.format(this) +} -function createSpecificFormat( - transformOptions: OptionsTransformer, - resolvedOptions: Intl.ResolvedDateTimeFormatOptions, -): Intl.DateTimeFormat { - return new OrigDateTimeFormat(resolvedOptions.locale, transformOptions(resolvedOptions)) +export function zonedDateTimeToLocaleString( + internals: ZonedInternals, + locales?: LocalesArg, + options?: Intl.DateTimeFormatOptions, // reused +): string { + const origFormat = new OrigDateTimeFormat(locales, options) + + // copy options + const resolvedOptions = origFormat.resolvedOptions() + const { locale } = resolvedOptions + options = whitelistOptions(resolvedOptions, options!) + + if (options!.timeZone !== undefined) { + throw new RangeError('Cannot specify timeZone') + } + options!.timeZone = internals.timeZone.id + + checkCalendarsCompatible( + internals.calendar.id, + resolvedOptions.calendar, + ) + + options = zonedOptionsTransformer(options!) + const format = new OrigDateTimeFormat(locale, options) + return format.format(epochNanoToMilli(internals.epochNanoseconds)) } +// Format-method Utils +// ------------------------------------------------------------------------------------------------- + function resolveSingleFormattable( - origFormat: Intl.DateTimeFormat, + format: DateTimeFormat, arg: Formattable | undefined, ): [ OrigFormattable | undefined, Intl.DateTimeFormat | undefined ] { - if (arg === undefined) { - return [arg, origFormat] + if (arg !== undefined) { + return resolveFormattable(arg, ...formatInternalsMap.get(format)!) } - const specificFormatStore = getSpecificFormatStore(origFormat) - const resolvedOptions = origFormat.resolvedOptions() - - return resolveFormattable(arg, specificFormatStore, resolvedOptions) + return [arg, format] } function resolveRangeFormattables( - origFormat: Intl.DateTimeFormat, + format: DateTimeFormat | Intl.DateTimeFormat, // reused arg0: Formattable, arg1: Formattable, ): [ @@ -129,11 +167,9 @@ function resolveRangeFormattables( OrigFormattable, Intl.DateTimeFormat, ] { - const specificFormatStore = getSpecificFormatStore(origFormat) - const resolvedOptions = origFormat.resolvedOptions() - - const [formattable0, format0] = resolveFormattable(arg0, specificFormatStore, resolvedOptions) - const [formattable1, format1] = resolveFormattable(arg1, specificFormatStore, resolvedOptions) + const formatInternals = formatInternalsMap.get(format)! + const [formattable0, format0] = resolveFormattable(arg0, ...formatInternals) + const [formattable1, format1] = resolveFormattable(arg1, ...formatInternals) if (format0 && format1) { // the returned DateTimeFormats are idempotent per Temporal type, @@ -141,167 +177,105 @@ function resolveRangeFormattables( if (format0 !== format1) { throw new TypeError('Accepts two Temporal values of same type') } - origFormat = format0 // reused - } - - return [formattable0, formattable1, origFormat] -} - -// Resolving Formattable Objects (and Format) -// ------------------------------------------------------------------------------------------------- - -/* -ZonedDateTime call this directly. Doesn't leverage our DateTimeFormat -*/ -export function resolveZonedFormattable( - internals: ZonedInternals, - locales?: LocalesArg, - options?: Intl.DateTimeFormatOptions, // NOT resolved yet (does not include locale) -): [ - number, - Intl.DateTimeFormat, -] { - options = { ...options } - - if (options.timeZone !== undefined) { - throw new TypeError('ZonedDateTime toLocaleString does not accept a timeZone option') - } - options.timeZone = internals.timeZone.id - - if ( - options.timeZoneName === undefined && - !hasAnyPropsByName(options as Record, dateTimeOptionNames) - ) { - options.timeZoneName = 'short' + format = format0 } - const origFormat = new OrigDateTimeFormat(locales, options) - const resolvedOptions = origFormat.resolvedOptions() - const transformedOptions = instantOptionsTransformer(resolvedOptions) - const specificFormat = new OrigDateTimeFormat(resolvedOptions.locale, transformedOptions) - const epochMilli = epochNanoToMilli(internals.epochNanoseconds) - - checkCalendarsCompatible( - internals.calendar.id, - resolvedOptions.calendar, - ) - - return [epochMilli, specificFormat] + return [formattable0, formattable1, format] } -type OrigFormattable = number | Date - -export type Formattable = - | Instant - | PlainDate - | PlainDateTime - | ZonedDateTime - | PlainYearMonth - | PlainMonthDay - | PlainTime - | OrigFormattable - -type SpecificFormatStore = ( - optionsTransformer: OptionsTransformer, // a proxy for the Temporal type - resolvedOptions: Intl.ResolvedDateTimeFormatOptions, -) => Intl.DateTimeFormat - function resolveFormattable( arg: Formattable, - specificFormatStore: SpecificFormatStore, + subformatFactory: SubformatFactory, resolvedOptions: Intl.ResolvedDateTimeFormatOptions, ): [ OrigFormattable, Intl.DateTimeFormat | undefined ] { const temporalName = getTemporalName(arg) - const transformOptions = temporalName && optionTransformers[temporalName] + const format = temporalName && subformatFactory(temporalName) - if (transformOptions) { + if (format) { const internalsToEpochNano = epochNanoConverters[temporalName] || dateInternalsToEpochNano const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) const epochMilli = epochNanoToMilli(epochNano) - const format = specificFormatStore(transformOptions, resolvedOptions) return [epochMilli, format] } - return [arg as number] as unknown as + return [arg as OrigFormattable] as unknown as [number, undefined] } // Format Option Massagers // ------------------------------------------------------------------------------------------------- -const timeBasicNames = ['hour', 'minute', 'second'] -const dateTimeBasicNames = [...dateBasicNames, ...timeBasicNames] -const yearMonthBasicNames = ['year', 'month'] -const monthDayBasicNames = ['month', 'day'] - -const dateOptionNames = [ - ...dateBasicNames, - 'weekday', - 'dateStyle', -] -const timeOptionNames = [ - ...timeBasicNames, - 'dayPeriod', // am/pm - 'timeStyle', -] -const dateTimeOptionNames = [ - ...dateOptionNames, - ...timeOptionNames, -] +/* +For transformer: give specific instance if doing toLocaleString? +*/ -const dateTimeExclusions = ['timeZoneName'] -const dateExclusions = [...dateTimeExclusions, ...timeOptionNames] -const timeExclusions = [...dateTimeExclusions, ...dateOptionNames] -const yearMonthExclusions = [ +type OptionsTransformer = (options: Intl.DateTimeFormatOptions) => Intl.DateTimeFormatOptions +type OptionNames = (keyof Intl.DateTimeFormatOptions)[] + +const numericStr = 'numeric' +const monthDayFallbacks: Intl.DateTimeFormatOptions = { month: numericStr, day: numericStr } +const yearMonthFallbacks: Intl.DateTimeFormatOptions = { year: numericStr, month: numericStr } +const dateFallbacks: Intl.DateTimeFormatOptions = { ...yearMonthFallbacks, day: numericStr } +const timeFallbacks: Intl.DateTimeFormatOptions = { hour: numericStr, minute: numericStr, second: numericStr } +const dateTimeFallbacks: Intl.DateTimeFormatOptions = { ...dateFallbacks, ...timeFallbacks } +const zonedFallbacks: Intl.DateTimeFormatOptions = { ...dateTimeFallbacks, timeZoneName: 'short' } + +const dateTimeExclusions: OptionNames = ['timeZoneName'] + +const monthDayValidNames = Object.keys(monthDayFallbacks) as OptionNames +const yearMonthValidNames = Object.keys(yearMonthFallbacks) as OptionNames +const dateValidNames: OptionNames = [...(Object.keys(dateFallbacks) as OptionNames), 'weekday', 'dateStyle'] +const timeValidNames: OptionNames = [...(Object.keys(timeFallbacks) as OptionNames), 'dayPeriod', 'timeStyle'] +const dateTimeValidNames: OptionNames = [...dateValidNames, ...timeValidNames] +const zonedValidNames: OptionNames = [...dateTimeValidNames, ...dateTimeExclusions] + +const dateExclusions: OptionNames = [...dateTimeExclusions, ...timeValidNames] +const timeExclusions: OptionNames = [...dateTimeExclusions, ...dateValidNames] +const yearMonthExclusions: OptionNames = [ ...dateTimeExclusions, 'day', 'weekday', 'dateStyle', - ...timeOptionNames, + ...timeValidNames, ] -const monthDayExclusions = [ +const monthDayExclusions: OptionNames = [ ...dateTimeExclusions, 'year', 'weekday', 'dateStyle', - ...timeOptionNames, + ...timeValidNames, ] -const instantOptionsTransformer = createTransformer(dateTimeOptionNames, dateTimeBasicNames, []) - -const optionTransformers: Record = { - PlainTime: createTransformer(timeOptionNames, timeBasicNames, timeExclusions), - PlainDateTime: createTransformer(dateTimeOptionNames, dateTimeBasicNames, dateTimeExclusions), - PlainDate: createTransformer(dateOptionNames, dateBasicNames, dateExclusions), - PlainYearMonth: createTransformer(yearMonthBasicNames, yearMonthBasicNames, yearMonthExclusions), - PlainMonthDay: createTransformer(monthDayBasicNames, monthDayBasicNames, monthDayExclusions), - Instant: instantOptionsTransformer, - ZonedDateTime: () => { - throw new TypeError('Cant do on ZonedDateTime') - }, +const optionsTransformers: Record = { + PlainMonthDay: createTransformer(monthDayValidNames, monthDayFallbacks, monthDayExclusions), + PlainYearMonth: createTransformer(yearMonthValidNames, yearMonthFallbacks, yearMonthExclusions), + PlainDate: createTransformer(dateValidNames, dateFallbacks, dateExclusions), + PlainDateTime: createTransformer(dateTimeValidNames, dateTimeFallbacks, dateTimeExclusions), + PlainTime: createTransformer(timeValidNames, timeFallbacks, timeExclusions), + Instant: createTransformer(dateTimeValidNames, dateTimeFallbacks, []), + // Intl.DateTimeFormat can't be given a ZonedDateTime. for zonedDateTimeToLocaleString + ZonedDateTime: () => { throw new TypeError('Cant do on ZonedDateTime') }, } -type OptionsTransformer = (options: Intl.ResolvedDateTimeFormatOptions) => Intl.DateTimeFormatOptions +// for zonedDateTimeToLocaleString +const zonedOptionsTransformer = createTransformer(zonedValidNames, zonedFallbacks, []) function createTransformer( - validNames: string[], - implicitNames: string[], - excludedNames: string[], + validNames: OptionNames, + fallbacks: Intl.DateTimeFormatOptions, + excludedNames: OptionNames, ): OptionsTransformer { - const defaults = mapPropNamesToConstant(implicitNames, 'numeric') const excludedNameSet = new Set(excludedNames) - return ( - options: Intl.ResolvedDateTimeFormatOptions | Reused - ) => { + return (options: Intl.DateTimeFormatOptions) => { options = excludePropsByName(options, excludedNameSet) if (!hasAnyPropsByName(options, validNames)) { - Object.assign(options, defaults) + Object.assign(options, fallbacks) } return options @@ -379,3 +353,22 @@ function checkCalendarsCompatible( throw new RangeError('Mismatching calendars') } } + +// Utils +// ------------------------------------------------------------------------------------------------- + +export const standardLocaleId = 'en-GB' // gives 24-hour clock + +export function hashIntlFormatParts( + intlFormat: Intl.DateTimeFormat, + epochMilliseconds: number, +): Record { + const parts = intlFormat.formatToParts(epochMilliseconds) + const hash = {} as Record + + for (const part of parts) { + hash[part.type] = part.value + } + + return hash +} diff --git a/packages/temporal-polyfill/src/plainDate.ts b/packages/temporal-polyfill/src/plainDate.ts index b37e6ca3..050455eb 100644 --- a/packages/temporal-polyfill/src/plainDate.ts +++ b/packages/temporal-polyfill/src/plainDate.ts @@ -6,7 +6,7 @@ import { getPublicCalendar, queryCalendarOps, } from './calendarOps' -import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -25,6 +25,7 @@ import { pluckIsoDateInternals, } from './isoFields' import { formatCalendar, formatIsoDateFields } from './isoFormat' +import { toLocaleStringMethod } from './intlFormat' import { compareIsoDateFields, refineIsoDateInternals } from './isoMath' import { parsePlainDate } from './isoParse' import { DateTimeDisplayOptions, DiffOptions, OverflowOptions, refineDateDisplayOptions, refineDiffOptions, refineOverflowOptions } from './options' diff --git a/packages/temporal-polyfill/src/plainDateTime.ts b/packages/temporal-polyfill/src/plainDateTime.ts index 51edffda..914a023c 100644 --- a/packages/temporal-polyfill/src/plainDateTime.ts +++ b/packages/temporal-polyfill/src/plainDateTime.ts @@ -2,7 +2,7 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { DateBag, TimeBag, dateTimeGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar, queryCalendarOps } from './calendarOps' -import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { convertToPlainMonthDay, convertToPlainYearMonth, @@ -22,6 +22,7 @@ import { pluckIsoTimeFields, } from './isoFields' import { formatCalendar, formatIsoDateTimeFields } from './isoFormat' +import { toLocaleStringMethod } from './intlFormat' import { compareIsoDateTimeFields, refineIsoDateTimeInternals } from './isoMath' import { parsePlainDateTime } from './isoParse' import { moveDateTime } from './move' diff --git a/packages/temporal-polyfill/src/plainMonthDay.ts b/packages/temporal-polyfill/src/plainMonthDay.ts index 4368d6b2..b89faaad 100644 --- a/packages/temporal-polyfill/src/plainMonthDay.ts +++ b/packages/temporal-polyfill/src/plainMonthDay.ts @@ -2,7 +2,7 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { MonthDayBag, YearFields, monthDayGetters } from './calendarFields' import { getPublicCalendar } from './calendarOps' -import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { convertPlainMonthDayToDate, mergePlainMonthDayBag, @@ -10,6 +10,7 @@ import { } from './convert' import { IsoDateInternals, generatePublicIsoDateFields } from './isoFields' import { formatIsoMonthDayFields, formatPossibleDate } from './isoFormat' +import { toLocaleStringMethod } from './intlFormat' import { compareIsoDateFields, isoEpochFirstLeapYear, refineIsoDateInternals } from './isoMath' import { parsePlainMonthDay } from './isoParse' import { refineOverflowOptions } from './options' diff --git a/packages/temporal-polyfill/src/plainTime.ts b/packages/temporal-polyfill/src/plainTime.ts index 884f6a18..fc566990 100644 --- a/packages/temporal-polyfill/src/plainTime.ts +++ b/packages/temporal-polyfill/src/plainTime.ts @@ -1,5 +1,5 @@ import { TimeBag, timeGetters } from './calendarFields' -import { TemporalInstance, createTemporalClass, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, neverValueOf } from './class' import { createZonedDateTimeConverter, mergePlainTimeBag, @@ -10,6 +10,7 @@ import { Duration, DurationArg, createDuration, toDurationInternals } from './du import { DurationInternals, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { IsoTimeFields, pluckIsoTimeFields } from './isoFields' import { formatIsoTimeFields } from './isoFormat' +import { toLocaleStringMethod } from './intlFormat' import { compareIsoTimeFields, refineIsoTimeInternals } from './isoMath' import { parsePlainTime } from './isoParse' import { moveTime } from './move' diff --git a/packages/temporal-polyfill/src/plainYearMonth.ts b/packages/temporal-polyfill/src/plainYearMonth.ts index 3080da7c..c3fbf0fa 100644 --- a/packages/temporal-polyfill/src/plainYearMonth.ts +++ b/packages/temporal-polyfill/src/plainYearMonth.ts @@ -2,7 +2,7 @@ import { CalendarArg } from './calendar' import { isoCalendarId } from './calendarConfig' import { YearMonthBag, yearMonthGetters } from './calendarFields' import { getCommonCalendarOps, getPublicCalendar } from './calendarOps' -import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf, toLocaleStringMethod } from './class' +import { TemporalInstance, createTemporalClass, isObjIdsEqual, neverValueOf } from './class' import { convertPlainYearMonthToDate, mergePlainYearMonthBag, @@ -13,6 +13,7 @@ import { Duration, DurationArg, createDuration, toDurationInternals } from './du import { DurationInternals, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { IsoDateFields, IsoDateInternals, generatePublicIsoDateFields } from './isoFields' import { formatIsoYearMonthFields, formatPossibleDate } from './isoFormat' +import { toLocaleStringMethod } from './intlFormat' import { compareIsoDateFields, refineIsoDateInternals } from './isoMath' import { parsePlainYearMonth } from './isoParse' import { moveDateByDays } from './move' diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index 94404ee6..d6ef0d64 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -13,7 +13,7 @@ import { diffZonedEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { DurationFields, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { Instant, createInstant } from './instant' -import { LocalesArg, resolveZonedFormattable } from './intlFormat' +import { LocalesArg, zonedDateTimeToLocaleString } from './intlFormat' import { CalendarPublic, IsoDateTimePublic, @@ -354,14 +354,7 @@ export const [ formatCalendar(calendar, calendarDisplayI) }, - toLocaleString( - internals: ZonedInternals, - locales?: LocalesArg, - options?: Intl.DateTimeFormatOptions, - ): string { - const [epochMilli, format] = resolveZonedFormattable(internals, locales, options) - return format.format(epochMilli) - }, + toLocaleString: zonedDateTimeToLocaleString, valueOf: neverValueOf, From 2573170b7b31f4cf7754ce0ac3be106df500f663 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 14:27:26 -0400 Subject: [PATCH 198/805] more --- packages/temporal-polyfill/src/intlFormat.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 554ec3d8..b20927bf 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -9,7 +9,8 @@ import { PlainDateTime } from './plainDateTime' import { PlainMonthDay } from './plainMonthDay' import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' -import { getSingleInstantFor, queryTimeZoneOps } from './timeZoneOps' +import { queryTimeZoneImpl } from './timeZoneImpl' +import { getSingleInstantFor } from './timeZoneOps' import { Classlike, createLazyGenerator, defineProps, excludePropsByName, hasAnyPropsByName, identityFunc } from './utils' import { ZonedDateTime, ZonedInternals } from './zonedDateTime' @@ -302,7 +303,7 @@ function timeFieldsToEpochNano( resolvedOptions: Intl.ResolvedDateTimeFormatOptions, ): LargeInt { return getSingleInstantFor( - queryTimeZoneOps(resolvedOptions.timeZone), + queryTimeZoneImpl(resolvedOptions.timeZone), { isoYear: isoEpochOriginYear, isoMonth: 1, @@ -324,7 +325,7 @@ function dateInternalsToEpochNano( ) return getSingleInstantFor( - queryTimeZoneOps(resolvedOptions.timeZone), + queryTimeZoneImpl(resolvedOptions.timeZone), { ...isoTimeFieldDefaults, isoHour: 12, // for whole-day dates, will not dst-shift into prev/next day From 4a4b523f2d795580a685fee327fca89e289a8557 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 15:22:36 -0400 Subject: [PATCH 199/805] more normal way to do toLocaleString --- packages/temporal-polyfill/src/intlFormat.ts | 156 ++++++++++-------- packages/temporal-polyfill/src/utils.ts | 1 - .../temporal-polyfill/src/zonedDateTime.ts | 4 +- 3 files changed, 87 insertions(+), 74 deletions(-) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index b20927bf..9303832f 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -1,4 +1,5 @@ import { isoCalendarId } from './calendarConfig' +import { CalendarOps } from './calendarOps' import { getInternals, getTemporalName } from './class' import { Instant } from './instant' import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' @@ -11,14 +12,13 @@ import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { queryTimeZoneImpl } from './timeZoneImpl' import { getSingleInstantFor } from './timeZoneOps' -import { Classlike, createLazyGenerator, defineProps, excludePropsByName, hasAnyPropsByName, identityFunc } from './utils' +import { Classlike, createLazyGenerator, defineProps, excludePropsByName, hasAnyPropsByName, identityFunc, pluckProps } from './utils' import { ZonedDateTime, ZonedInternals } from './zonedDateTime' export type LocalesArg = string | string[] type OrigFormattable = number | Date - -export type Formattable = +type TemporalFormattable = | Instant | PlainDate | PlainDateTime @@ -26,7 +26,35 @@ export type Formattable = | PlainYearMonth | PlainMonthDay | PlainTime - | OrigFormattable + +export type Formattable = TemporalFormattable | OrigFormattable + +// toLocaleString +// ------------------------------------------------------------------------------------------------- + +export function toLocaleStringMethod( + this: TemporalFormattable, + internals: unknown, + locales: LocalesArg, + options: Intl.DateTimeFormatOptions, +) { + const temporalName = getTemporalName(this)! + const origFormat = new OrigDateTimeFormat(locales, options) + + // copy options + const resolvedOptions = origFormat.resolvedOptions() + const { locale } = resolvedOptions + options = pluckProps( + Object.keys(options) as OptionNames, + resolvedOptions as Intl.DateTimeFormatOptions + ) + + options = optionsTransformers[temporalName](options, internals) + const format = new OrigDateTimeFormat(locale, options) + const epochMilli = toEpochMilli(temporalName, internals, resolvedOptions) + + return format.format(epochMilli) +} // Temporal-aware Intl.DateTimeFormat // ------------------------------------------------------------------------------------------------- @@ -49,7 +77,10 @@ export class DateTimeFormat extends OrigDateTimeFormat { // copy options const resolvedOptions = this.resolvedOptions() const { locale } = resolvedOptions - options = whitelistOptions(resolvedOptions, options) + options = pluckProps( + Object.keys(options) as OptionNames, + resolvedOptions as Intl.DateTimeFormatOptions + ) const subformatFactory = createLazyGenerator((temporalName: string) => { if (optionsTransformers[temporalName]) { @@ -65,6 +96,7 @@ export class DateTimeFormat extends OrigDateTimeFormat { format(arg?: Formattable): string { const [formattable, format] = resolveSingleFormattable(this, arg) + return format ? format.format(formattable) : super.format(formattable) @@ -74,6 +106,7 @@ export class DateTimeFormat extends OrigDateTimeFormat { formatToParts(arg?: Formattable): Intl.DateTimeFormatPart[] { const [formattable, format] = resolveSingleFormattable(this, arg) + return format ? format.formatToParts(formattable) : super.formatToParts(formattable) @@ -102,47 +135,7 @@ export interface DateTimeFormat { } }) -// toLocaleString -// ------------------------------------------------------------------------------------------------- - -export function toLocaleStringMethod( - this: Formattable, - internals: unknown, - locales: LocalesArg, - options: Intl.DateTimeFormatOptions, -) { - const format = new DateTimeFormat(locales, options) - return format.format(this) -} - -export function zonedDateTimeToLocaleString( - internals: ZonedInternals, - locales?: LocalesArg, - options?: Intl.DateTimeFormatOptions, // reused -): string { - const origFormat = new OrigDateTimeFormat(locales, options) - - // copy options - const resolvedOptions = origFormat.resolvedOptions() - const { locale } = resolvedOptions - options = whitelistOptions(resolvedOptions, options!) - - if (options!.timeZone !== undefined) { - throw new RangeError('Cannot specify timeZone') - } - options!.timeZone = internals.timeZone.id - - checkCalendarsCompatible( - internals.calendar.id, - resolvedOptions.calendar, - ) - - options = zonedOptionsTransformer(options!) - const format = new OrigDateTimeFormat(locale, options) - return format.format(epochNanoToMilli(internals.epochNanoseconds)) -} - -// Format-method Utils +// Intl.DateTimeFormat Arg-normalization Utils // ------------------------------------------------------------------------------------------------- function resolveSingleFormattable( @@ -156,7 +149,9 @@ function resolveSingleFormattable( return resolveFormattable(arg, ...formatInternalsMap.get(format)!) } - return [arg, format] + // arg was not specified (current datetime) + return [arg] as unknown as + [OrigFormattable | undefined, undefined] } function resolveRangeFormattables( @@ -196,25 +191,18 @@ function resolveFormattable( const format = temporalName && subformatFactory(temporalName) if (format) { - const internalsToEpochNano = epochNanoConverters[temporalName] || dateInternalsToEpochNano - const epochNano = internalsToEpochNano(getInternals(arg), resolvedOptions, temporalName) - const epochMilli = epochNanoToMilli(epochNano) - + const epochMilli = toEpochMilli(temporalName, getInternals(arg)!, resolvedOptions) return [epochMilli, format] } - return [arg as OrigFormattable] as unknown as - [number, undefined] + // arg is an OrigFormattable + return [arg] as unknown as + [OrigFormattable, undefined] } // Format Option Massagers // ------------------------------------------------------------------------------------------------- -/* -For transformer: give specific instance if doing toLocaleString? -*/ - -type OptionsTransformer = (options: Intl.DateTimeFormatOptions) => Intl.DateTimeFormatOptions type OptionNames = (keyof Intl.DateTimeFormatOptions)[] const numericStr = 'numeric' @@ -251,6 +239,13 @@ const monthDayExclusions: OptionNames = [ ...timeValidNames, ] +type OptionsTransformer = ( + options: Intl.DateTimeFormatOptions, + subjectInternals?: any, // `this` object for toLocaleString +) => Intl.DateTimeFormatOptions + +const zonedOptionsTransformer = createTransformer(zonedValidNames, zonedFallbacks, []) + const optionsTransformers: Record = { PlainMonthDay: createTransformer(monthDayValidNames, monthDayFallbacks, monthDayExclusions), PlainYearMonth: createTransformer(yearMonthValidNames, yearMonthFallbacks, yearMonthExclusions), @@ -258,12 +253,18 @@ const optionsTransformers: Record = { PlainDateTime: createTransformer(dateTimeValidNames, dateTimeFallbacks, dateTimeExclusions), PlainTime: createTransformer(timeValidNames, timeFallbacks, timeExclusions), Instant: createTransformer(dateTimeValidNames, dateTimeFallbacks, []), - // Intl.DateTimeFormat can't be given a ZonedDateTime. for zonedDateTimeToLocaleString - ZonedDateTime: () => { throw new TypeError('Cant do on ZonedDateTime') }, -} -// for zonedDateTimeToLocaleString -const zonedOptionsTransformer = createTransformer(zonedValidNames, zonedFallbacks, []) + ZonedDateTime(options: Intl.DateTimeFormatOptions, subjectInternals: ZonedInternals) { + if (!subjectInternals) { + throw new TypeError('Cant do on ZonedDateTime') + } + if (options.timeZone !== undefined) { + throw new RangeError('Cannot specify timeZone') + } + options.timeZone = subjectInternals.timeZone.id + return zonedOptionsTransformer(options) + } +} function createTransformer( validNames: OptionNames, @@ -286,14 +287,34 @@ function createTransformer( // Epoch Conversions // ------------------------------------------------------------------------------------------------- +type MaybeHasCalendar = { calendar?: CalendarOps } + +function toEpochMilli( + temporalName: string, + internals: unknown | MaybeHasCalendar, + resolvedOptions: Intl.ResolvedDateTimeFormatOptions, +) { + if ((internals as MaybeHasCalendar).calendar) { + checkCalendarsCompatible( + (internals as MaybeHasCalendar).calendar!.id, + resolvedOptions.calendar, + strictCalendarCheck[temporalName], + ) + } + + const internalsToEpochNano = epochNanoConverters[temporalName] || dateInternalsToEpochNano + const epochNano = internalsToEpochNano(internals, resolvedOptions) + return epochNanoToMilli(epochNano) +} + type EpochNanoConverter = ( internals: any, resolvedOptions: Intl.ResolvedDateTimeFormatOptions, - temporalName: string, ) => LargeInt const epochNanoConverters: Record = { Instant: identityFunc, + ZonedDateTime: (internals: ZonedInternals) => internals.epochNanoseconds, PlainTime: timeFieldsToEpochNano, // otherwise, use dateInternalsToEpochNano } @@ -316,14 +337,7 @@ function timeFieldsToEpochNano( function dateInternalsToEpochNano( internals: IsoDateTimeInternals | IsoDateInternals, resolvedOptions: Intl.ResolvedDateTimeFormatOptions, - temporalName: string, ): LargeInt { - checkCalendarsCompatible( - internals.calendar.id, - resolvedOptions.calendar, - strictCalendarCheck[temporalName], - ) - return getSingleInstantFor( queryTimeZoneImpl(resolvedOptions.timeZone), { diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index 65c5dd46..e19bb9f0 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -19,7 +19,6 @@ export type Classlike = any const objectlikeRE = /object|function/ -// TODO: Record export function isObjectlike(arg: unknown): arg is {} { return arg !== null && objectlikeRE.test(typeof arg) } diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index d6ef0d64..c7927fda 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -13,7 +13,7 @@ import { diffZonedEpochNano } from './diff' import { Duration, DurationArg, createDuration, toDurationInternals } from './duration' import { DurationFields, negateDurationInternals, updateDurationFieldsSign } from './durationFields' import { Instant, createInstant } from './instant' -import { LocalesArg, zonedDateTimeToLocaleString } from './intlFormat' +import { toLocaleStringMethod } from './intlFormat' import { CalendarPublic, IsoDateTimePublic, @@ -354,7 +354,7 @@ export const [ formatCalendar(calendar, calendarDisplayI) }, - toLocaleString: zonedDateTimeToLocaleString, + toLocaleString: toLocaleStringMethod, valueOf: neverValueOf, From 0de1ab3e1bae0af1d8d1fbaa60266651d4a67fb2 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 15:35:32 -0400 Subject: [PATCH 200/805] cleanup --- packages/temporal-polyfill/src/intlFormat.ts | 87 ++++++++++++++------ 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 9303832f..30a8f087 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -2,7 +2,12 @@ import { isoCalendarId } from './calendarConfig' import { CalendarOps } from './calendarOps' import { getInternals, getTemporalName } from './class' import { Instant } from './instant' -import { IsoDateInternals, IsoDateTimeInternals, IsoTimeFields, isoTimeFieldDefaults } from './isoFields' +import { + IsoDateInternals, + IsoDateTimeInternals, + IsoTimeFields, + isoTimeFieldDefaults, +} from './isoFields' import { epochNanoToMilli, isoEpochOriginYear } from './isoMath' import { LargeInt } from './largeInt' import { PlainDate } from './plainDate' @@ -12,7 +17,15 @@ import { PlainTime } from './plainTime' import { PlainYearMonth } from './plainYearMonth' import { queryTimeZoneImpl } from './timeZoneImpl' import { getSingleInstantFor } from './timeZoneOps' -import { Classlike, createLazyGenerator, defineProps, excludePropsByName, hasAnyPropsByName, identityFunc, pluckProps } from './utils' +import { + Classlike, + createLazyGenerator, + defineProps, + excludePropsByName, + hasAnyPropsByName, + identityFunc, + pluckProps, +} from './utils' import { ZonedDateTime, ZonedInternals } from './zonedDateTime' export type LocalesArg = string | string[] @@ -50,10 +63,10 @@ export function toLocaleStringMethod( ) options = optionsTransformers[temporalName](options, internals) - const format = new OrigDateTimeFormat(locale, options) + const subformat = new OrigDateTimeFormat(locale, options) const epochMilli = toEpochMilli(temporalName, internals, resolvedOptions) - return format.format(epochMilli) + return subformat.format(epochMilli) } // Temporal-aware Intl.DateTimeFormat @@ -143,7 +156,7 @@ function resolveSingleFormattable( arg: Formattable | undefined, ): [ OrigFormattable | undefined, - Intl.DateTimeFormat | undefined + Intl.DateTimeFormat | undefined // undefined if should use orig method ] { if (arg !== undefined) { return resolveFormattable(arg, ...formatInternalsMap.get(format)!) @@ -161,19 +174,19 @@ function resolveRangeFormattables( ): [ OrigFormattable, OrigFormattable, - Intl.DateTimeFormat, + Intl.DateTimeFormat, // always defined ] { const formatInternals = formatInternalsMap.get(format)! const [formattable0, format0] = resolveFormattable(arg0, ...formatInternals) const [formattable1, format1] = resolveFormattable(arg1, ...formatInternals) - if (format0 && format1) { + if (format0 || format1) { // the returned DateTimeFormats are idempotent per Temporal type, // so testing inequality is a way to test mismatching Temporal types. if (format0 !== format1) { throw new TypeError('Accepts two Temporal values of same type') } - format = format0 + format = format0! // guaranteed to be truthy and equal } return [formattable0, formattable1, format] @@ -185,7 +198,7 @@ function resolveFormattable( resolvedOptions: Intl.ResolvedDateTimeFormatOptions, ): [ OrigFormattable, - Intl.DateTimeFormat | undefined + Intl.DateTimeFormat | undefined // undefined if should use orig method ] { const temporalName = getTemporalName(arg) const format = temporalName && subformatFactory(temporalName) @@ -200,45 +213,69 @@ function resolveFormattable( [OrigFormattable, undefined] } -// Format Option Massagers +// Option Transformers // ------------------------------------------------------------------------------------------------- type OptionNames = (keyof Intl.DateTimeFormatOptions)[] const numericStr = 'numeric' +const timeZoneNameStrs: OptionNames = ['timeZoneName'] + +// Fallbacks +// --------- + const monthDayFallbacks: Intl.DateTimeFormatOptions = { month: numericStr, day: numericStr } const yearMonthFallbacks: Intl.DateTimeFormatOptions = { year: numericStr, month: numericStr } const dateFallbacks: Intl.DateTimeFormatOptions = { ...yearMonthFallbacks, day: numericStr } -const timeFallbacks: Intl.DateTimeFormatOptions = { hour: numericStr, minute: numericStr, second: numericStr } +const timeFallbacks: Intl.DateTimeFormatOptions = { + hour: numericStr, + minute: numericStr, + second: numericStr, +} const dateTimeFallbacks: Intl.DateTimeFormatOptions = { ...dateFallbacks, ...timeFallbacks } const zonedFallbacks: Intl.DateTimeFormatOptions = { ...dateTimeFallbacks, timeZoneName: 'short' } -const dateTimeExclusions: OptionNames = ['timeZoneName'] +// Valid Names +// ----------- const monthDayValidNames = Object.keys(monthDayFallbacks) as OptionNames const yearMonthValidNames = Object.keys(yearMonthFallbacks) as OptionNames -const dateValidNames: OptionNames = [...(Object.keys(dateFallbacks) as OptionNames), 'weekday', 'dateStyle'] -const timeValidNames: OptionNames = [...(Object.keys(timeFallbacks) as OptionNames), 'dayPeriod', 'timeStyle'] +const dateValidNames: OptionNames = [ + ...(Object.keys(dateFallbacks) as OptionNames), + 'weekday', + 'dateStyle', +] +const timeValidNames: OptionNames = [ + ...(Object.keys(timeFallbacks) as OptionNames), + 'dayPeriod', + 'timeStyle', +] const dateTimeValidNames: OptionNames = [...dateValidNames, ...timeValidNames] -const zonedValidNames: OptionNames = [...dateTimeValidNames, ...dateTimeExclusions] +const zonedValidNames: OptionNames = [...dateTimeValidNames, ...timeZoneNameStrs] -const dateExclusions: OptionNames = [...dateTimeExclusions, ...timeValidNames] -const timeExclusions: OptionNames = [...dateTimeExclusions, ...dateValidNames] +// Exclusions +// ---------- + +const dateExclusions: OptionNames = [...timeZoneNameStrs, ...timeValidNames] +const timeExclusions: OptionNames = [...timeZoneNameStrs, ...dateValidNames] const yearMonthExclusions: OptionNames = [ - ...dateTimeExclusions, + ...timeZoneNameStrs, 'day', 'weekday', 'dateStyle', ...timeValidNames, ] const monthDayExclusions: OptionNames = [ - ...dateTimeExclusions, + ...timeZoneNameStrs, 'year', 'weekday', 'dateStyle', ...timeValidNames, ] +// Options Transformer Config +// -------------------------- + type OptionsTransformer = ( options: Intl.DateTimeFormatOptions, subjectInternals?: any, // `this` object for toLocaleString @@ -250,11 +287,11 @@ const optionsTransformers: Record = { PlainMonthDay: createTransformer(monthDayValidNames, monthDayFallbacks, monthDayExclusions), PlainYearMonth: createTransformer(yearMonthValidNames, yearMonthFallbacks, yearMonthExclusions), PlainDate: createTransformer(dateValidNames, dateFallbacks, dateExclusions), - PlainDateTime: createTransformer(dateTimeValidNames, dateTimeFallbacks, dateTimeExclusions), + PlainDateTime: createTransformer(dateTimeValidNames, dateTimeFallbacks, timeZoneNameStrs), PlainTime: createTransformer(timeValidNames, timeFallbacks, timeExclusions), Instant: createTransformer(dateTimeValidNames, dateTimeFallbacks, []), - ZonedDateTime(options: Intl.DateTimeFormatOptions, subjectInternals: ZonedInternals) { + ZonedDateTime(options: Intl.DateTimeFormatOptions, subjectInternals?: ZonedInternals) { if (!subjectInternals) { throw new TypeError('Cant do on ZonedDateTime') } @@ -287,16 +324,16 @@ function createTransformer( // Epoch Conversions // ------------------------------------------------------------------------------------------------- -type MaybeHasCalendar = { calendar?: CalendarOps } +type MaybeWithCalendar = { calendar?: CalendarOps } function toEpochMilli( temporalName: string, - internals: unknown | MaybeHasCalendar, + internals: unknown | MaybeWithCalendar, resolvedOptions: Intl.ResolvedDateTimeFormatOptions, ) { - if ((internals as MaybeHasCalendar).calendar) { + if ((internals as MaybeWithCalendar).calendar) { checkCalendarsCompatible( - (internals as MaybeHasCalendar).calendar!.id, + (internals as MaybeWithCalendar).calendar!.id, resolvedOptions.calendar, strictCalendarCheck[temporalName], ) From 0e0ef0e499997b63b41d419add31b7816da1fb28 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 15:53:05 -0400 Subject: [PATCH 201/805] more performant toLocaleString --- packages/temporal-polyfill/src/intlFormat.ts | 24 ++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 30a8f087..6a7f3d99 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -49,22 +49,16 @@ export function toLocaleStringMethod( this: TemporalFormattable, internals: unknown, locales: LocalesArg, - options: Intl.DateTimeFormatOptions, + options: Intl.DateTimeFormatOptions = {}, ) { const temporalName = getTemporalName(this)! - const origFormat = new OrigDateTimeFormat(locales, options) - - // copy options - const resolvedOptions = origFormat.resolvedOptions() - const { locale } = resolvedOptions - options = pluckProps( - Object.keys(options) as OptionNames, - resolvedOptions as Intl.DateTimeFormatOptions - ) + + // Copy options so accessing doesn't cause side-effects + options = { ...options } options = optionsTransformers[temporalName](options, internals) - const subformat = new OrigDateTimeFormat(locale, options) - const epochMilli = toEpochMilli(temporalName, internals, resolvedOptions) + const subformat = new OrigDateTimeFormat(locales, options) + const epochMilli = toEpochMilli(temporalName, internals, subformat.resolvedOptions()) return subformat.format(epochMilli) } @@ -87,7 +81,9 @@ export class DateTimeFormat extends OrigDateTimeFormat { constructor(locales: LocalesArg, options: Intl.DateTimeFormatOptions = {}) { super(locales, options) - // copy options + // Copy options so accessing doesn't cause side-effects + // Must store recursively flattened options because given `options` could mutate in future + // Algorithm: whitelist against resolved options const resolvedOptions = this.resolvedOptions() const { locale } = resolvedOptions options = pluckProps( @@ -278,7 +274,7 @@ const monthDayExclusions: OptionNames = [ type OptionsTransformer = ( options: Intl.DateTimeFormatOptions, - subjectInternals?: any, // `this` object for toLocaleString + subjectInternals?: any, // `this` object during toLocaleString ) => Intl.DateTimeFormatOptions const zonedOptionsTransformer = createTransformer(zonedValidNames, zonedFallbacks, []) From 39b51ad0dd72a2ed80b374882d546b2ea5cf3e7e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 17:33:50 -0400 Subject: [PATCH 202/805] better checking stuff --- packages/temporal-polyfill/src/intlFormat.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/temporal-polyfill/src/intlFormat.ts b/packages/temporal-polyfill/src/intlFormat.ts index 6a7f3d99..9deda80a 100644 --- a/packages/temporal-polyfill/src/intlFormat.ts +++ b/packages/temporal-polyfill/src/intlFormat.ts @@ -289,10 +289,10 @@ const optionsTransformers: Record = { ZonedDateTime(options: Intl.DateTimeFormatOptions, subjectInternals?: ZonedInternals) { if (!subjectInternals) { - throw new TypeError('Cant do on ZonedDateTime') + throw new TypeError('DateTimeFormat does not accept ZonedDateTime') } if (options.timeZone !== undefined) { - throw new RangeError('Cannot specify timeZone') + throw new RangeError('Cannot specify timeZone') // for ZonedDateTime::toLocaleString } options.timeZone = subjectInternals.timeZone.id return zonedOptionsTransformer(options) @@ -329,9 +329,9 @@ function toEpochMilli( ) { if ((internals as MaybeWithCalendar).calendar) { checkCalendarsCompatible( + temporalName, (internals as MaybeWithCalendar).calendar!.id, resolvedOptions.calendar, - strictCalendarCheck[temporalName], ) } @@ -390,12 +390,12 @@ const strictCalendarCheck: Record = { } function checkCalendarsCompatible( + temporalName: string, internalCalendarId: string, resolveCalendarId: string, - strict?: boolean, ): void { if ( - (!strict || internalCalendarId !== isoCalendarId) && + (!strictCalendarCheck[temporalName] || internalCalendarId !== isoCalendarId) && (internalCalendarId !== resolveCalendarId) ) { throw new RangeError('Mismatching calendars') From 4eeaa552c3ab514574388d40a36b6e868a612f31 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 17:34:07 -0400 Subject: [PATCH 203/805] update definitions --- packages/temporal-spec/global.d.ts | 130 ++++++++++++++----------- packages/temporal-spec/index.d.ts | 151 ++++++++++++++++------------- 2 files changed, 156 insertions(+), 125 deletions(-) diff --git a/packages/temporal-spec/global.d.ts b/packages/temporal-spec/global.d.ts index 9f4044ee..90874110 100644 --- a/packages/temporal-spec/global.d.ts +++ b/packages/temporal-spec/global.d.ts @@ -1,12 +1,19 @@ -/* eslint-disable */ -// derived from https://github.com/js-temporal/temporal-polyfill/blob/main/index.d.ts export {} // treat as a module declare global { namespace Temporal { type ComparisonResult = -1 | 0 | 1; - type RoundingMode = 'halfExpand' | 'ceil' | 'trunc' | 'floor'; + type RoundingMode = + | 'ceil' + | 'floor' + | 'expand' + | 'trunc' + | 'halfCeil' + | 'halfFloor' + | 'halfExpand' + | 'halfTrunc' + | 'halfEven'; /** * Options for assigning fields using `with()` or entire objects with @@ -57,7 +64,7 @@ declare global { * destination time zone (e.g. near "Spring Forward" DST transitions), or * exists more than once (e.g. near "Fall Back" DST transitions). * - * In case of ambiguous or non-existent times, this option controls what + * In case of ambiguous or nonexistent times, this option controls what * exact time to return: * - `'compatible'`: Equivalent to `'earlier'` for backward transitions like * the start of DST in the Spring, and `'later'` for forward transitions @@ -181,14 +188,14 @@ declare global { }; type ShowCalendarOption = { - calendarName?: 'auto' | 'always' | 'never'; + calendarName?: 'auto' | 'always' | 'never' | 'critical'; }; type CalendarTypeToStringOptions = Partial; type ZonedDateTimeToStringOptions = Partial< CalendarTypeToStringOptions & { - timeZoneName?: 'auto' | 'never'; + timeZoneName?: 'auto' | 'never' | 'critical'; offset?: 'auto' | 'never'; } >; @@ -610,8 +617,7 @@ declare global { type MonthOrMonthCode = { month: number } | { monthCode: string }; interface CalendarProtocol { - id?: string; - calendar?: never; + id: string; year(date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string): number; month( date: @@ -637,6 +643,7 @@ declare global { dayOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; dayOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; weekOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; + yearOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInMonth( date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string @@ -672,13 +679,23 @@ declare global { two: Temporal.PlainDate | PlainDateLike | string, options?: DifferenceOptions<'year' | 'month' | 'week' | 'day'> ): Temporal.Duration; - fields?(fields: Iterable): Iterable; - mergeFields?(fields: Record, additionalFields: Record): Record; - toString(): string; + fields(fields: Iterable): Iterable; + mergeFields(fields: Record, additionalFields: Record): Record; + toString?(): string; toJSON?(): string; } - type CalendarLike = CalendarProtocol | string | { calendar: CalendarProtocol | string }; + /** + * Any of these types can be passed to Temporal methods instead of a Temporal.Calendar. + * */ + type CalendarLike = + | string + | CalendarProtocol + | ZonedDateTime + | PlainDateTime + | PlainDate + | PlainYearMonth + | PlainMonthDay; /** * A `Temporal.Calendar` is a representation of a calendar system. It includes @@ -688,7 +705,7 @@ declare global { * * See https://tc39.es/proposal-temporal/docs/calendar.html for more details. */ - class Calendar implements Omit, 'calendar'> { + class Calendar implements CalendarProtocol { static from(item: CalendarLike): Temporal.Calendar | CalendarProtocol; constructor(calendarIdentifier: string); readonly id: string; @@ -717,6 +734,7 @@ declare global { dayOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; dayOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; weekOfYear(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; + yearOfWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInWeek(date: Temporal.PlainDate | Temporal.PlainDateTime | PlainDateLike | string): number; daysInMonth( date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string @@ -773,7 +791,7 @@ declare global { isoYear: number; isoMonth: number; isoDay: number; - calendar: CalendarProtocol; + calendar: string | CalendarProtocol; }; /** @@ -798,10 +816,12 @@ declare global { readonly month: number; readonly monthCode: string; readonly day: number; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; + readonly yearOfWeek: number; readonly daysInWeek: number; readonly daysInYear: number; readonly daysInMonth: number; @@ -866,7 +886,7 @@ declare global { isoMillisecond: number; isoMicrosecond: number; isoNanosecond: number; - calendar: CalendarProtocol; + calendar: string | CalendarProtocol; }; /** @@ -912,10 +932,12 @@ declare global { readonly millisecond: number; readonly microsecond: number; readonly nanosecond: number; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; + readonly yearOfWeek: number; readonly daysInWeek: number; readonly daysInYear: number; readonly daysInMonth: number; @@ -984,7 +1006,8 @@ declare global { constructor(isoMonth: number, isoDay: number, calendar?: CalendarLike, referenceISOYear?: number); readonly monthCode: string; readonly day: number; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; equals(other: Temporal.PlainMonthDay | PlainMonthDayLike | string): boolean; with(monthDayLike: PlainMonthDayLike, options?: AssignmentOptions): Temporal.PlainMonthDay; toPlainDate(year: { year: number }): Temporal.PlainDate; @@ -996,24 +1019,14 @@ declare global { readonly [Symbol.toStringTag]: 'Temporal.PlainMonthDay'; } - // Temporal.PlainTime's `calendar` field is a Temporal.Calendar, not a - // Temporal.CalendarProtocol, because that type's calendar is not customizable - // by users. Temporal.ZonedDateTime and Temporal.PlainDateTime are also - // "time-like" but their `calendar` is a Temporal.CalendarProtocol. Therefore, - // those types are added below to ensure that their instances are accepted by - // methods that take a PlainTimeLike object. - type PlainTimeLike = - | { - hour?: number; - minute?: number; - second?: number; - millisecond?: number; - microsecond?: number; - nanosecond?: number; - calendar?: Temporal.Calendar | 'iso8601'; - } - | Temporal.ZonedDateTime - | Temporal.PlainDateTime; + type PlainTimeLike = { + hour?: number; + minute?: number; + second?: number; + millisecond?: number; + microsecond?: number; + nanosecond?: number; + }; type PlainTimeISOFields = { isoHour: number; @@ -1022,7 +1035,6 @@ declare global { isoMillisecond: number; isoMicrosecond: number; isoNanosecond: number; - calendar: Temporal.Calendar; }; /** @@ -1060,7 +1072,6 @@ declare global { readonly millisecond: number; readonly microsecond: number; readonly nanosecond: number; - readonly calendar: Temporal.Calendar; equals(other: Temporal.PlainTime | PlainTimeLike | string): boolean; with(timeLike: Temporal.PlainTime | PlainTimeLike, options?: AssignmentOptions): Temporal.PlainTime; add(durationLike: Temporal.Duration | DurationLike | string, options?: ArithmeticOptions): Temporal.PlainTime; @@ -1093,8 +1104,7 @@ declare global { * A plain object implementing the protocol for a custom time zone. */ interface TimeZoneProtocol { - id?: string; - timeZone?: never; + id: string; getOffsetNanosecondsFor(instant: Temporal.Instant | string): number; getOffsetStringFor?(instant: Temporal.Instant | string): string; getPlainDateTimeFor?(instant: Temporal.Instant | string, calendar?: CalendarLike): Temporal.PlainDateTime; @@ -1105,11 +1115,14 @@ declare global { getNextTransition?(startingPoint: Temporal.Instant | string): Temporal.Instant | null; getPreviousTransition?(startingPoint: Temporal.Instant | string): Temporal.Instant | null; getPossibleInstantsFor(dateTime: Temporal.PlainDateTime | PlainDateTimeLike | string): Temporal.Instant[]; - toString(): string; + toString?(): string; toJSON?(): string; } - type TimeZoneLike = TimeZoneProtocol | string | { timeZone: TimeZoneProtocol | string }; + /** + * Any of these types can be passed to Temporal methods instead of a Temporal.TimeZone. + * */ + type TimeZoneLike = string | TimeZoneProtocol | ZonedDateTime; /** * A `Temporal.TimeZone` is a representation of a time zone: either an @@ -1118,13 +1131,14 @@ declare global { * and UTC at a particular time, and daylight saving time (DST) changes; or * simply a particular UTC offset with no DST. * - * Since `Temporal.Instant` and `Temporal.PlainDateTime` do not contain any time - * zone information, a `Temporal.TimeZone` object is required to convert - * between the two. + * `Temporal.ZonedDateTime` is the only Temporal type to contain a time zone. + * Other types, like `Temporal.Instant` and `Temporal.PlainDateTime`, do not + * contain any time zone information, and a `Temporal.TimeZone` object is + * required to convert between them. * * See https://tc39.es/proposal-temporal/docs/timezone.html for more details. */ - class TimeZone implements Omit, 'timeZone'> { + class TimeZone implements TimeZoneProtocol { static from(timeZone: TimeZoneLike): Temporal.TimeZone | TimeZoneProtocol; constructor(timeZoneIdentifier: string); readonly id: string; @@ -1174,7 +1188,8 @@ declare global { readonly year: number; readonly month: number; readonly monthCode: string; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly daysInMonth: number; readonly daysInYear: number; readonly monthsInYear: number; @@ -1232,8 +1247,8 @@ declare global { isoMicrosecond: number; isoNanosecond: number; offset: string; - timeZone: TimeZoneProtocol; - calendar: CalendarProtocol; + timeZone: string | TimeZoneProtocol; + calendar: string | CalendarProtocol; }; class ZonedDateTime { @@ -1258,11 +1273,14 @@ declare global { readonly millisecond: number; readonly microsecond: number; readonly nanosecond: number; - readonly timeZone: TimeZoneProtocol; - readonly calendar: CalendarProtocol; + readonly timeZoneId: string; + getTimeZone(): TimeZoneProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; + readonly yearOfWeek: number; readonly hoursInDay: number; readonly daysInWeek: number; readonly daysInMonth: number; @@ -1453,13 +1471,13 @@ declare global { plainTimeISO: (tzLike?: TimeZoneLike) => Temporal.PlainTime; /** - * Get the environment's current time zone. + * Get the identifier of the environment's current time zone. * - * This method gets the current system time zone. This will usually be a - * named + * This method gets the identifier of the current system time zone. This + * will usually be a named * {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones|IANA time zone}. */ - timeZone: () => Temporal.TimeZone; + timeZoneId: () => string; readonly [Symbol.toStringTag]: 'Temporal.Now'; }; @@ -1476,7 +1494,7 @@ declare global { | Temporal.PlainYearMonth | Temporal.PlainMonthDay; - interface DateTimeFormatRangePart extends DateTimeFormatPart { + interface DateTimeFormatRangePart { source: 'shared' | 'startRange' | 'endRange'; } diff --git a/packages/temporal-spec/index.d.ts b/packages/temporal-spec/index.d.ts index adca675c..784677c9 100644 --- a/packages/temporal-spec/index.d.ts +++ b/packages/temporal-spec/index.d.ts @@ -1,9 +1,15 @@ -/* eslint-disable */ -// derived from https://github.com/js-temporal/temporal-polyfill/blob/main/index.d.ts - export namespace Temporal { export type ComparisonResult = -1 | 0 | 1; - export type RoundingMode = 'halfExpand' | 'ceil' | 'trunc' | 'floor'; + export type RoundingMode = + | 'ceil' + | 'floor' + | 'expand' + | 'trunc' + | 'halfCeil' + | 'halfFloor' + | 'halfExpand' + | 'halfTrunc' + | 'halfEven'; /** * Options for assigning fields using `with()` or entire objects with @@ -54,7 +60,7 @@ export namespace Temporal { * destination time zone (e.g. near "Spring Forward" DST transitions), or * exists more than once (e.g. near "Fall Back" DST transitions). * - * In case of ambiguous or non-existent times, this option controls what + * In case of ambiguous or nonexistent times, this option controls what * exact time to return: * - `'compatible'`: Equivalent to `'earlier'` for backward transitions like * the start of DST in the Spring, and `'later'` for forward transitions @@ -178,14 +184,14 @@ export namespace Temporal { }; export type ShowCalendarOption = { - calendarName?: 'auto' | 'always' | 'never'; + calendarName?: 'auto' | 'always' | 'never' | 'critical'; }; export type CalendarTypeToStringOptions = Partial; export type ZonedDateTimeToStringOptions = Partial< CalendarTypeToStringOptions & { - timeZoneName?: 'auto' | 'never'; + timeZoneName?: 'auto' | 'never' | 'critical'; offset?: 'auto' | 'never'; } >; @@ -607,8 +613,7 @@ export namespace Temporal { type MonthOrMonthCode = { month: number } | { monthCode: string }; export interface CalendarProtocol { - id?: string; - calendar?: never; + id: string; year(date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string): number; month( date: @@ -670,13 +675,23 @@ export namespace Temporal { two: Temporal.PlainDate | PlainDateLike | string, options?: DifferenceOptions<'year' | 'month' | 'week' | 'day'> ): Temporal.Duration; - fields?(fields: Iterable): Iterable; - mergeFields?(fields: Record, additionalFields: Record): Record; - toString(): string; + fields(fields: Iterable): Iterable; + mergeFields(fields: Record, additionalFields: Record): Record; + toString?(): string; toJSON?(): string; } - export type CalendarLike = CalendarProtocol | string | { calendar: CalendarProtocol | string }; + /** + * Any of these types can be passed to Temporal methods instead of a Temporal.Calendar. + * */ + export type CalendarLike = + | string + | CalendarProtocol + | ZonedDateTime + | PlainDateTime + | PlainDate + | PlainYearMonth + | PlainMonthDay; /** * A `Temporal.Calendar` is a representation of a calendar system. It includes @@ -686,7 +701,7 @@ export namespace Temporal { * * See https://tc39.es/proposal-temporal/docs/calendar.html for more details. */ - export class Calendar implements Omit, 'calendar'> { + export class Calendar implements CalendarProtocol { static from(item: CalendarLike): Temporal.Calendar | CalendarProtocol; constructor(calendarIdentifier: string); readonly id: string; @@ -772,7 +787,7 @@ export namespace Temporal { isoYear: number; isoMonth: number; isoDay: number; - calendar: CalendarProtocol; + calendar: string | CalendarProtocol; }; /** @@ -797,7 +812,8 @@ export namespace Temporal { readonly month: number; readonly monthCode: string; readonly day: number; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; @@ -866,7 +882,7 @@ export namespace Temporal { isoMillisecond: number; isoMicrosecond: number; isoNanosecond: number; - calendar: CalendarProtocol; + calendar: string | CalendarProtocol; }; /** @@ -912,7 +928,8 @@ export namespace Temporal { readonly millisecond: number; readonly microsecond: number; readonly nanosecond: number; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; @@ -985,7 +1002,8 @@ export namespace Temporal { constructor(isoMonth: number, isoDay: number, calendar?: CalendarLike, referenceISOYear?: number); readonly monthCode: string; readonly day: number; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; equals(other: Temporal.PlainMonthDay | PlainMonthDayLike | string): boolean; with(monthDayLike: PlainMonthDayLike, options?: AssignmentOptions): Temporal.PlainMonthDay; toPlainDate(year: { year: number }): Temporal.PlainDate; @@ -997,24 +1015,14 @@ export namespace Temporal { readonly [Symbol.toStringTag]: 'Temporal.PlainMonthDay'; } - // Temporal.PlainTime's `calendar` field is a Temporal.Calendar, not a - // Temporal.CalendarProtocol, because that type's calendar is not customizable - // by users. Temporal.ZonedDateTime and Temporal.PlainDateTime are also - // "time-like" but their `calendar` is a Temporal.CalendarProtocol. Therefore, - // those types are added below to ensure that their instances are accepted by - // methods that take a PlainTimeLike object. - export type PlainTimeLike = - | { - hour?: number; - minute?: number; - second?: number; - millisecond?: number; - microsecond?: number; - nanosecond?: number; - calendar?: Temporal.Calendar | 'iso8601'; - } - | Temporal.ZonedDateTime - | Temporal.PlainDateTime; + export type PlainTimeLike = { + hour?: number; + minute?: number; + second?: number; + millisecond?: number; + microsecond?: number; + nanosecond?: number; + }; type PlainTimeISOFields = { isoHour: number; @@ -1023,7 +1031,6 @@ export namespace Temporal { isoMillisecond: number; isoMicrosecond: number; isoNanosecond: number; - calendar: Temporal.Calendar; }; /** @@ -1061,7 +1068,6 @@ export namespace Temporal { readonly millisecond: number; readonly microsecond: number; readonly nanosecond: number; - readonly calendar: Temporal.Calendar; equals(other: Temporal.PlainTime | PlainTimeLike | string): boolean; with(timeLike: Temporal.PlainTime | PlainTimeLike, options?: AssignmentOptions): Temporal.PlainTime; add(durationLike: Temporal.Duration | DurationLike | string, options?: ArithmeticOptions): Temporal.PlainTime; @@ -1094,8 +1100,7 @@ export namespace Temporal { * A plain object implementing the protocol for a custom time zone. */ export interface TimeZoneProtocol { - id?: string; - timeZone?: never; + id: string; getOffsetNanosecondsFor(instant: Temporal.Instant | string): number; getOffsetStringFor?(instant: Temporal.Instant | string): string; getPlainDateTimeFor?(instant: Temporal.Instant | string, calendar?: CalendarLike): Temporal.PlainDateTime; @@ -1106,11 +1111,14 @@ export namespace Temporal { getNextTransition?(startingPoint: Temporal.Instant | string): Temporal.Instant | null; getPreviousTransition?(startingPoint: Temporal.Instant | string): Temporal.Instant | null; getPossibleInstantsFor(dateTime: Temporal.PlainDateTime | PlainDateTimeLike | string): Temporal.Instant[]; - toString(): string; + toString?(): string; toJSON?(): string; } - export type TimeZoneLike = TimeZoneProtocol | string | { timeZone: TimeZoneProtocol | string }; + /** + * Any of these types can be passed to Temporal methods instead of a Temporal.TimeZone. + * */ + export type TimeZoneLike = string | TimeZoneProtocol | ZonedDateTime; /** * A `Temporal.TimeZone` is a representation of a time zone: either an @@ -1119,13 +1127,14 @@ export namespace Temporal { * and UTC at a particular time, and daylight saving time (DST) changes; or * simply a particular UTC offset with no DST. * - * Since `Temporal.Instant` and `Temporal.PlainDateTime` do not contain any time - * zone information, a `Temporal.TimeZone` object is required to convert - * between the two. + * `Temporal.ZonedDateTime` is the only Temporal type to contain a time zone. + * Other types, like `Temporal.Instant` and `Temporal.PlainDateTime`, do not + * contain any time zone information, and a `Temporal.TimeZone` object is + * required to convert between them. * * See https://tc39.es/proposal-temporal/docs/timezone.html for more details. */ - export class TimeZone implements Omit, 'timeZone'> { + export class TimeZone implements TimeZoneProtocol { static from(timeZone: TimeZoneLike): Temporal.TimeZone | TimeZoneProtocol; constructor(timeZoneIdentifier: string); readonly id: string; @@ -1175,7 +1184,8 @@ export namespace Temporal { readonly year: number; readonly month: number; readonly monthCode: string; - readonly calendar: CalendarProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly daysInMonth: number; readonly daysInYear: number; readonly monthsInYear: number; @@ -1233,8 +1243,8 @@ export namespace Temporal { isoMicrosecond: number; isoNanosecond: number; offset: string; - timeZone: TimeZoneProtocol; - calendar: CalendarProtocol; + timeZone: string | TimeZoneProtocol; + calendar: string | CalendarProtocol; }; export class ZonedDateTime { @@ -1259,8 +1269,10 @@ export namespace Temporal { readonly millisecond: number; readonly microsecond: number; readonly nanosecond: number; - readonly timeZone: TimeZoneProtocol; - readonly calendar: CalendarProtocol; + readonly timeZoneId: string; + getTimeZone(): TimeZoneProtocol; + readonly calendarId: string; + getCalendar(): CalendarProtocol; readonly dayOfWeek: number; readonly dayOfYear: number; readonly weekOfYear: number; @@ -1455,20 +1467,20 @@ export namespace Temporal { plainTimeISO: (tzLike?: TimeZoneLike) => Temporal.PlainTime; /** - * Get the environment's current time zone. + * Get the identifier of the environment's current time zone. * - * This method gets the current system time zone. This will usually be a - * named + * This method gets the identifier of the current system time zone. This + * will usually be a named * {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones|IANA time zone}. */ - timeZone: () => Temporal.TimeZone; + timeZoneId: () => string; readonly [Symbol.toStringTag]: 'Temporal.Now'; }; } -export namespace Intl { - export type Formattable = +declare namespace Intl { + type Formattable = | Date | Temporal.Instant | Temporal.ZonedDateTime @@ -1478,7 +1490,7 @@ export namespace Intl { | Temporal.PlainYearMonth | Temporal.PlainMonthDay; - export interface DateTimeFormatRangePart extends globalThis.Intl.DateTimeFormatPart { + interface DateTimeFormatRangePart extends globalThis.Intl.DateTimeFormatPart { source: 'shared' | 'startRange' | 'endRange'; } @@ -1522,6 +1534,15 @@ export namespace Intl { formatRangeToParts(startDate: Date | number, endDate: Date | number): DateTimeFormatRangePart[]; } + export interface DateTimeFormatOptions extends Omit { + calendar?: string | Temporal.CalendarProtocol; + timeZone?: string | Temporal.TimeZoneProtocol; + // TODO: remove the props below after TS lib declarations are updated + dayPeriod?: 'narrow' | 'short' | 'long'; + dateStyle?: 'full' | 'long' | 'medium' | 'short'; + timeStyle?: 'full' | 'long' | 'medium' | 'short'; + } + export const DateTimeFormat: { /** * Creates `Intl.DateTimeFormat` objects that enable language-sensitive @@ -1537,16 +1558,8 @@ export namespace Intl { */ supportedLocalesOf(locales: string | string[], options?: DateTimeFormatOptions): string[]; }; - - export interface DateTimeFormatOptions extends Omit { - calendar?: string | Temporal.CalendarProtocol; - timeZone?: string | Temporal.TimeZoneProtocol; - - // TODO: remove the props below after TS lib declarations are updated - dayPeriod?: 'narrow' | 'short' | 'long'; - dateStyle?: 'full' | 'long' | 'medium' | 'short'; - timeStyle?: 'full' | 'long' | 'medium' | 'short'; - } } +export { Intl as Intl }; + export function toTemporalInstant(this: Date): Temporal.Instant; From 785232d2ef8d3d214b758b918a5f7168d23cfe8d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 18:14:45 -0400 Subject: [PATCH 204/805] improve types --- packages/temporal-polyfill/src/class.ts | 2 +- packages/temporal-polyfill/src/instant.ts | 24 +++++++++++++++++------ packages/temporal-polyfill/src/utils.ts | 15 ++++++++------ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index 8c725b61..d1a5e1b2 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -212,7 +212,7 @@ export function createTemporalClass< ): [ Class: TemporalClass, createInstance: (internals: I) => TemporalInstance, - toInternals: (arg: TemporalInstance | B | string, options?: O) => I + toInternals: (arg: TemporalInstance | B | string) => I ] { ;(staticMembers as { from: Callable }).from = function(arg: TemporalInstance | B | string, options: O) { return createInstance(toInternals(arg, options)) diff --git a/packages/temporal-polyfill/src/instant.ts b/packages/temporal-polyfill/src/instant.ts index 6cbb9293..4151cb59 100644 --- a/packages/temporal-polyfill/src/instant.ts +++ b/packages/temporal-polyfill/src/instant.ts @@ -21,6 +21,7 @@ import { DiffOptions, InstantDisplayOptions, RoundingMode, + RoundingOptions, ensureObjectlike, refineDiffOptions, refineInstantDisplayOptions, @@ -29,10 +30,11 @@ import { } from './options' import { computeNanoInc, roundByIncLarge } from './round' import { queryTimeZoneOps, utcTimeZoneId } from './timeZoneOps' -import { noop } from './utils' +import { NumSign, noop } from './utils' import { ZonedDateTime, ZonedInternals, createZonedDateTime } from './zonedDateTime' -import { TimeUnit, Unit } from './units' +import { TimeUnit, Unit, UnitName } from './units' import { TimeZoneArg } from './timeZone' +import { CalendarArg } from './calendar' export type InstantArg = Instant | string @@ -83,7 +85,10 @@ export const [ }) }, - toZonedDateTime(epochNano: LargeInt, options): ZonedDateTime { + toZonedDateTime( + epochNano: LargeInt, + options: { timeZone: TimeZoneArg, calendar: CalendarArg }, + ): ZonedDateTime { const refinedObj = ensureObjectlike(options) return createZonedDateTime({ @@ -111,15 +116,15 @@ export const [ ) }, - until(epochNano: LargeInt, otherArg: InstantArg, options): Duration { + until(epochNano: LargeInt, otherArg: InstantArg, options?: DiffOptions): Duration { return diffInstants(epochNano, toInstantEpochNano(otherArg), options) }, - since(epochNano: LargeInt, otherArg: InstantArg, options): Duration { + since(epochNano: LargeInt, otherArg: InstantArg, options?: DiffOptions): Duration { return diffInstants(toInstantEpochNano(otherArg), epochNano, options, true) }, - round(epochNano: LargeInt, options): Instant { + round(epochNano: LargeInt, options: RoundingOptions | UnitName): Instant { const [smallestUnit, roundingInc, roundingModeI] = refineRoundOptions(options, Unit.Hour) return createInstant( @@ -174,6 +179,13 @@ export const [ fromEpochNanoseconds(epochNano: bigint): Instant { return createInstant(toEpochNano(epochNano)) }, + + compare(a: InstantArg, b: InstantArg): NumSign { + return compareLargeInts( + toInstantEpochNano(a), + toInstantEpochNano(b), + ) + } }, ) diff --git a/packages/temporal-polyfill/src/utils.ts b/packages/temporal-polyfill/src/utils.ts index e19bb9f0..5f8d35c1 100644 --- a/packages/temporal-polyfill/src/utils.ts +++ b/packages/temporal-polyfill/src/utils.ts @@ -208,15 +208,18 @@ export function createLazyGenerator( // descriptor stuff // ---------------- -export function defineProps( +export function defineProps( target: Target, - propVals: Record, -): Target & PropVals { - return Object.defineProperties(target, createPropDescriptors(propVals)) as (Target & PropVals) + propVals: NewProps, +): Target & NewProps { + return Object.defineProperties( + target, + createPropDescriptors(propVals), + ) as (Target & NewProps) } export function createPropDescriptors( - propVals: Record, + propVals: { [propName: string]: unknown }, ): PropertyDescriptorMap { return mapProps((value) => ({ value, @@ -226,7 +229,7 @@ export function createPropDescriptors( } export function createGetterDescriptors( - getters: Record unknown>, + getters: { [propName: string]: () => unknown }, ): PropertyDescriptorMap { return mapProps((getter) => ({ get: getter, From d9e4e9e493bd3c74e56219900809e8961069e355 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 7 Aug 2023 21:53:43 -0400 Subject: [PATCH 205/805] lil tweaks --- packages/temporal-polyfill/src/class.ts | 1 - packages/temporal-polyfill/src/isoFields.ts | 5 ++--- packages/temporal-polyfill/src/isoMath.ts | 1 - packages/temporal-polyfill/src/zonedDateTime.ts | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/temporal-polyfill/src/class.ts b/packages/temporal-polyfill/src/class.ts index d1a5e1b2..0b941cdb 100644 --- a/packages/temporal-polyfill/src/class.ts +++ b/packages/temporal-polyfill/src/class.ts @@ -1,4 +1,3 @@ -import { DateTimeFormat, Formattable, LocalesArg } from './intlFormat' import { ensureInstanceOf, ensureString, toString } from './options' import { Callable, diff --git a/packages/temporal-polyfill/src/isoFields.ts b/packages/temporal-polyfill/src/isoFields.ts index 456b2657..ae4265c5 100644 --- a/packages/temporal-polyfill/src/isoFields.ts +++ b/packages/temporal-polyfill/src/isoFields.ts @@ -19,8 +19,7 @@ export interface IsoTimeFields { isoHour: number, } -// TODO: move -// TODO: same as CalendarArg? +// TODO: make DRY with CalendarArg (it's a subset) export type CalendarPublic = CalendarProtocol | string export interface CalendarInternals { @@ -115,7 +114,7 @@ export type IsoTuple = [ // TODO: move? export const pluckIsoTuple = pluckPropsTuple.bind< - undefined, [BoundArg], + undefined, [BoundArg], // bound [Partial & { isoYear: number }], // unbound IsoTuple // return >(undefined, isoDateTimeFieldNamesAsc.reverse()) diff --git a/packages/temporal-polyfill/src/isoMath.ts b/packages/temporal-polyfill/src/isoMath.ts index b2f12380..de9dc83a 100644 --- a/packages/temporal-polyfill/src/isoMath.ts +++ b/packages/temporal-polyfill/src/isoMath.ts @@ -8,7 +8,6 @@ import { IsoTimeFields, IsoTuple, isoDateInternalRefiners, - isoDateTimeFieldNamesAsc, isoDateTimeInternalRefiners, isoTimeFieldNamesAsc, isoTimeFieldRefiners, diff --git a/packages/temporal-polyfill/src/zonedDateTime.ts b/packages/temporal-polyfill/src/zonedDateTime.ts index c7927fda..46886012 100644 --- a/packages/temporal-polyfill/src/zonedDateTime.ts +++ b/packages/temporal-polyfill/src/zonedDateTime.ts @@ -75,6 +75,7 @@ export type ZonedDateTimeArg = ZonedDateTime | ZonedDateTimeBag | string export type ZonedDateTimeBag = PlainDateTimeBag & { timeZone: TimeZoneArg, offset?: string } export type ZonedDateTimeMod = PlainDateTimeMod +// TODO: make DRY with TimeZoneArg (it's a subset) export type TimeZonePublic = TimeZoneProtocol | string export type ZonedPublic = IsoDateTimePublic & { timeZone: TimeZonePublic, offset: string } From 54e365fa13f2045248c9cf4a0c1d59aa1a39f552 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:13:01 -0400 Subject: [PATCH 206/805] move test262 to root --- .gitmodules | 2 +- packages/temporal-polyfill/test262 => test262 | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/temporal-polyfill/test262 => test262 (100%) diff --git a/.gitmodules b/.gitmodules index 331f0a63..49a256fb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,5 +5,5 @@ path = scripts/data/fullcalendar url = https://github.com/fullcalendar/fullcalendar.git [submodule "packages/temporal-polyfill/test262"] - path = packages/temporal-polyfill/test262 + path = test262 url = https://github.com/tc39/test262 diff --git a/packages/temporal-polyfill/test262 b/test262 similarity index 100% rename from packages/temporal-polyfill/test262 rename to test262 From e88e9515bc2f7ba94bb4fb5ce18943730ffddbbd Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:22:06 -0400 Subject: [PATCH 207/805] locale-data package --- .gitmodules | 4 ++-- package.json | 4 +--- {scripts => packages/locale-data}/data/fullcalendar | 0 {scripts => packages/locale-data}/data/moment | 0 {locales => packages/locale-data/locales}/af.json | 0 {locales => packages/locale-data/locales}/ar-DZ.json | 0 {locales => packages/locale-data/locales}/ar-KW.json | 0 {locales => packages/locale-data/locales}/ar-LY.json | 0 {locales => packages/locale-data/locales}/ar-MA.json | 0 {locales => packages/locale-data/locales}/ar-SA.json | 0 {locales => packages/locale-data/locales}/ar-TN.json | 0 {locales => packages/locale-data/locales}/ar.json | 0 {locales => packages/locale-data/locales}/az.json | 0 {locales => packages/locale-data/locales}/be.json | 0 {locales => packages/locale-data/locales}/bg.json | 0 {locales => packages/locale-data/locales}/bm.json | 0 {locales => packages/locale-data/locales}/bn-BD.json | 0 {locales => packages/locale-data/locales}/bn.json | 0 {locales => packages/locale-data/locales}/bo.json | 0 {locales => packages/locale-data/locales}/br.json | 0 {locales => packages/locale-data/locales}/bs.json | 0 {locales => packages/locale-data/locales}/ca.json | 0 {locales => packages/locale-data/locales}/cs.json | 0 {locales => packages/locale-data/locales}/cv.json | 0 {locales => packages/locale-data/locales}/cy.json | 0 {locales => packages/locale-data/locales}/da.json | 0 {locales => packages/locale-data/locales}/de-AT.json | 0 {locales => packages/locale-data/locales}/de-CH.json | 0 {locales => packages/locale-data/locales}/de.json | 0 {locales => packages/locale-data/locales}/dv.json | 0 {locales => packages/locale-data/locales}/el.json | 0 {locales => packages/locale-data/locales}/en-AU.json | 0 {locales => packages/locale-data/locales}/en-CA.json | 0 {locales => packages/locale-data/locales}/en-GB.json | 0 {locales => packages/locale-data/locales}/en-IE.json | 0 {locales => packages/locale-data/locales}/en-IL.json | 0 {locales => packages/locale-data/locales}/en-IN.json | 0 {locales => packages/locale-data/locales}/en-NZ.json | 0 {locales => packages/locale-data/locales}/en-SG.json | 0 {locales => packages/locale-data/locales}/en.json | 0 {locales => packages/locale-data/locales}/eo.json | 0 {locales => packages/locale-data/locales}/es-DO.json | 0 {locales => packages/locale-data/locales}/es-MX.json | 0 {locales => packages/locale-data/locales}/es-US.json | 0 {locales => packages/locale-data/locales}/es.json | 0 {locales => packages/locale-data/locales}/et.json | 0 {locales => packages/locale-data/locales}/eu.json | 0 {locales => packages/locale-data/locales}/fa.json | 0 {locales => packages/locale-data/locales}/fi.json | 0 {locales => packages/locale-data/locales}/fil.json | 0 {locales => packages/locale-data/locales}/fo.json | 0 {locales => packages/locale-data/locales}/fr-CA.json | 0 {locales => packages/locale-data/locales}/fr-CH.json | 0 {locales => packages/locale-data/locales}/fr.json | 0 {locales => packages/locale-data/locales}/fy.json | 0 {locales => packages/locale-data/locales}/ga.json | 0 {locales => packages/locale-data/locales}/gd.json | 0 {locales => packages/locale-data/locales}/gl.json | 0 .../locale-data/locales}/gom-DEVA.json | 0 .../locale-data/locales}/gom-LATN.json | 0 {locales => packages/locale-data/locales}/gu.json | 0 {locales => packages/locale-data/locales}/he.json | 0 {locales => packages/locale-data/locales}/hi.json | 0 {locales => packages/locale-data/locales}/hr.json | 0 {locales => packages/locale-data/locales}/hu.json | 0 {locales => packages/locale-data/locales}/hy-AM.json | 0 {locales => packages/locale-data/locales}/id.json | 0 {locales => packages/locale-data/locales}/is.json | 0 {locales => packages/locale-data/locales}/it-CH.json | 0 {locales => packages/locale-data/locales}/it.json | 0 {locales => packages/locale-data/locales}/ja.json | 0 {locales => packages/locale-data/locales}/jv.json | 0 {locales => packages/locale-data/locales}/ka.json | 0 {locales => packages/locale-data/locales}/kk.json | 0 {locales => packages/locale-data/locales}/km.json | 0 {locales => packages/locale-data/locales}/kn.json | 0 {locales => packages/locale-data/locales}/ko.json | 0 {locales => packages/locale-data/locales}/ku.json | 0 {locales => packages/locale-data/locales}/ky.json | 0 {locales => packages/locale-data/locales}/lb.json | 0 {locales => packages/locale-data/locales}/lo.json | 0 {locales => packages/locale-data/locales}/lt.json | 0 {locales => packages/locale-data/locales}/lv.json | 0 {locales => packages/locale-data/locales}/me.json | 0 {locales => packages/locale-data/locales}/mi.json | 0 {locales => packages/locale-data/locales}/mk.json | 0 {locales => packages/locale-data/locales}/ml.json | 0 {locales => packages/locale-data/locales}/mn.json | 0 {locales => packages/locale-data/locales}/mr.json | 0 {locales => packages/locale-data/locales}/ms-MY.json | 0 {locales => packages/locale-data/locales}/ms.json | 0 {locales => packages/locale-data/locales}/mt.json | 0 {locales => packages/locale-data/locales}/my.json | 0 {locales => packages/locale-data/locales}/nb.json | 0 {locales => packages/locale-data/locales}/ne.json | 0 {locales => packages/locale-data/locales}/nl-BE.json | 0 {locales => packages/locale-data/locales}/nl.json | 0 {locales => packages/locale-data/locales}/nn.json | 0 .../locale-data/locales}/oc-LNC.json | 0 {locales => packages/locale-data/locales}/pa-IN.json | 0 {locales => packages/locale-data/locales}/pl.json | 0 {locales => packages/locale-data/locales}/pt-BR.json | 0 {locales => packages/locale-data/locales}/pt.json | 0 {locales => packages/locale-data/locales}/ro.json | 0 {locales => packages/locale-data/locales}/ru.json | 0 {locales => packages/locale-data/locales}/sd.json | 0 {locales => packages/locale-data/locales}/se.json | 0 {locales => packages/locale-data/locales}/si.json | 0 {locales => packages/locale-data/locales}/sk.json | 0 {locales => packages/locale-data/locales}/sl.json | 0 {locales => packages/locale-data/locales}/sq.json | 0 .../locale-data/locales}/sr-CYRL.json | 0 {locales => packages/locale-data/locales}/sr.json | 0 {locales => packages/locale-data/locales}/ss.json | 0 {locales => packages/locale-data/locales}/sv.json | 0 {locales => packages/locale-data/locales}/sw.json | 0 {locales => packages/locale-data/locales}/ta.json | 0 {locales => packages/locale-data/locales}/te.json | 0 {locales => packages/locale-data/locales}/tet.json | 0 {locales => packages/locale-data/locales}/tg.json | 0 {locales => packages/locale-data/locales}/th.json | 0 {locales => packages/locale-data/locales}/tk.json | 0 {locales => packages/locale-data/locales}/tl-PH.json | 0 {locales => packages/locale-data/locales}/tlh.json | 0 {locales => packages/locale-data/locales}/tr.json | 0 {locales => packages/locale-data/locales}/tzl.json | 0 .../locale-data/locales}/tzm-LATN.json | 0 {locales => packages/locale-data/locales}/tzm.json | 0 {locales => packages/locale-data/locales}/ug-CN.json | 0 {locales => packages/locale-data/locales}/uk.json | 0 {locales => packages/locale-data/locales}/ur.json | 0 .../locale-data/locales}/uz-LATN.json | 0 {locales => packages/locale-data/locales}/uz.json | 0 {locales => packages/locale-data/locales}/vi.json | 0 .../locale-data/locales}/x-PSEUDO.json | 0 {locales => packages/locale-data/locales}/yo.json | 0 {locales => packages/locale-data/locales}/zh-CN.json | 0 {locales => packages/locale-data/locales}/zh-HK.json | 0 {locales => packages/locale-data/locales}/zh-MO.json | 0 {locales => packages/locale-data/locales}/zh-TW.json | 0 packages/locale-data/package.json | 9 +++++++++ .../locale-data/scripts}/localesScrape.cjs | 12 ++++-------- 142 files changed, 16 insertions(+), 13 deletions(-) rename {scripts => packages/locale-data}/data/fullcalendar (100%) rename {scripts => packages/locale-data}/data/moment (100%) rename {locales => packages/locale-data/locales}/af.json (100%) rename {locales => packages/locale-data/locales}/ar-DZ.json (100%) rename {locales => packages/locale-data/locales}/ar-KW.json (100%) rename {locales => packages/locale-data/locales}/ar-LY.json (100%) rename {locales => packages/locale-data/locales}/ar-MA.json (100%) rename {locales => packages/locale-data/locales}/ar-SA.json (100%) rename {locales => packages/locale-data/locales}/ar-TN.json (100%) rename {locales => packages/locale-data/locales}/ar.json (100%) rename {locales => packages/locale-data/locales}/az.json (100%) rename {locales => packages/locale-data/locales}/be.json (100%) rename {locales => packages/locale-data/locales}/bg.json (100%) rename {locales => packages/locale-data/locales}/bm.json (100%) rename {locales => packages/locale-data/locales}/bn-BD.json (100%) rename {locales => packages/locale-data/locales}/bn.json (100%) rename {locales => packages/locale-data/locales}/bo.json (100%) rename {locales => packages/locale-data/locales}/br.json (100%) rename {locales => packages/locale-data/locales}/bs.json (100%) rename {locales => packages/locale-data/locales}/ca.json (100%) rename {locales => packages/locale-data/locales}/cs.json (100%) rename {locales => packages/locale-data/locales}/cv.json (100%) rename {locales => packages/locale-data/locales}/cy.json (100%) rename {locales => packages/locale-data/locales}/da.json (100%) rename {locales => packages/locale-data/locales}/de-AT.json (100%) rename {locales => packages/locale-data/locales}/de-CH.json (100%) rename {locales => packages/locale-data/locales}/de.json (100%) rename {locales => packages/locale-data/locales}/dv.json (100%) rename {locales => packages/locale-data/locales}/el.json (100%) rename {locales => packages/locale-data/locales}/en-AU.json (100%) rename {locales => packages/locale-data/locales}/en-CA.json (100%) rename {locales => packages/locale-data/locales}/en-GB.json (100%) rename {locales => packages/locale-data/locales}/en-IE.json (100%) rename {locales => packages/locale-data/locales}/en-IL.json (100%) rename {locales => packages/locale-data/locales}/en-IN.json (100%) rename {locales => packages/locale-data/locales}/en-NZ.json (100%) rename {locales => packages/locale-data/locales}/en-SG.json (100%) rename {locales => packages/locale-data/locales}/en.json (100%) rename {locales => packages/locale-data/locales}/eo.json (100%) rename {locales => packages/locale-data/locales}/es-DO.json (100%) rename {locales => packages/locale-data/locales}/es-MX.json (100%) rename {locales => packages/locale-data/locales}/es-US.json (100%) rename {locales => packages/locale-data/locales}/es.json (100%) rename {locales => packages/locale-data/locales}/et.json (100%) rename {locales => packages/locale-data/locales}/eu.json (100%) rename {locales => packages/locale-data/locales}/fa.json (100%) rename {locales => packages/locale-data/locales}/fi.json (100%) rename {locales => packages/locale-data/locales}/fil.json (100%) rename {locales => packages/locale-data/locales}/fo.json (100%) rename {locales => packages/locale-data/locales}/fr-CA.json (100%) rename {locales => packages/locale-data/locales}/fr-CH.json (100%) rename {locales => packages/locale-data/locales}/fr.json (100%) rename {locales => packages/locale-data/locales}/fy.json (100%) rename {locales => packages/locale-data/locales}/ga.json (100%) rename {locales => packages/locale-data/locales}/gd.json (100%) rename {locales => packages/locale-data/locales}/gl.json (100%) rename {locales => packages/locale-data/locales}/gom-DEVA.json (100%) rename {locales => packages/locale-data/locales}/gom-LATN.json (100%) rename {locales => packages/locale-data/locales}/gu.json (100%) rename {locales => packages/locale-data/locales}/he.json (100%) rename {locales => packages/locale-data/locales}/hi.json (100%) rename {locales => packages/locale-data/locales}/hr.json (100%) rename {locales => packages/locale-data/locales}/hu.json (100%) rename {locales => packages/locale-data/locales}/hy-AM.json (100%) rename {locales => packages/locale-data/locales}/id.json (100%) rename {locales => packages/locale-data/locales}/is.json (100%) rename {locales => packages/locale-data/locales}/it-CH.json (100%) rename {locales => packages/locale-data/locales}/it.json (100%) rename {locales => packages/locale-data/locales}/ja.json (100%) rename {locales => packages/locale-data/locales}/jv.json (100%) rename {locales => packages/locale-data/locales}/ka.json (100%) rename {locales => packages/locale-data/locales}/kk.json (100%) rename {locales => packages/locale-data/locales}/km.json (100%) rename {locales => packages/locale-data/locales}/kn.json (100%) rename {locales => packages/locale-data/locales}/ko.json (100%) rename {locales => packages/locale-data/locales}/ku.json (100%) rename {locales => packages/locale-data/locales}/ky.json (100%) rename {locales => packages/locale-data/locales}/lb.json (100%) rename {locales => packages/locale-data/locales}/lo.json (100%) rename {locales => packages/locale-data/locales}/lt.json (100%) rename {locales => packages/locale-data/locales}/lv.json (100%) rename {locales => packages/locale-data/locales}/me.json (100%) rename {locales => packages/locale-data/locales}/mi.json (100%) rename {locales => packages/locale-data/locales}/mk.json (100%) rename {locales => packages/locale-data/locales}/ml.json (100%) rename {locales => packages/locale-data/locales}/mn.json (100%) rename {locales => packages/locale-data/locales}/mr.json (100%) rename {locales => packages/locale-data/locales}/ms-MY.json (100%) rename {locales => packages/locale-data/locales}/ms.json (100%) rename {locales => packages/locale-data/locales}/mt.json (100%) rename {locales => packages/locale-data/locales}/my.json (100%) rename {locales => packages/locale-data/locales}/nb.json (100%) rename {locales => packages/locale-data/locales}/ne.json (100%) rename {locales => packages/locale-data/locales}/nl-BE.json (100%) rename {locales => packages/locale-data/locales}/nl.json (100%) rename {locales => packages/locale-data/locales}/nn.json (100%) rename {locales => packages/locale-data/locales}/oc-LNC.json (100%) rename {locales => packages/locale-data/locales}/pa-IN.json (100%) rename {locales => packages/locale-data/locales}/pl.json (100%) rename {locales => packages/locale-data/locales}/pt-BR.json (100%) rename {locales => packages/locale-data/locales}/pt.json (100%) rename {locales => packages/locale-data/locales}/ro.json (100%) rename {locales => packages/locale-data/locales}/ru.json (100%) rename {locales => packages/locale-data/locales}/sd.json (100%) rename {locales => packages/locale-data/locales}/se.json (100%) rename {locales => packages/locale-data/locales}/si.json (100%) rename {locales => packages/locale-data/locales}/sk.json (100%) rename {locales => packages/locale-data/locales}/sl.json (100%) rename {locales => packages/locale-data/locales}/sq.json (100%) rename {locales => packages/locale-data/locales}/sr-CYRL.json (100%) rename {locales => packages/locale-data/locales}/sr.json (100%) rename {locales => packages/locale-data/locales}/ss.json (100%) rename {locales => packages/locale-data/locales}/sv.json (100%) rename {locales => packages/locale-data/locales}/sw.json (100%) rename {locales => packages/locale-data/locales}/ta.json (100%) rename {locales => packages/locale-data/locales}/te.json (100%) rename {locales => packages/locale-data/locales}/tet.json (100%) rename {locales => packages/locale-data/locales}/tg.json (100%) rename {locales => packages/locale-data/locales}/th.json (100%) rename {locales => packages/locale-data/locales}/tk.json (100%) rename {locales => packages/locale-data/locales}/tl-PH.json (100%) rename {locales => packages/locale-data/locales}/tlh.json (100%) rename {locales => packages/locale-data/locales}/tr.json (100%) rename {locales => packages/locale-data/locales}/tzl.json (100%) rename {locales => packages/locale-data/locales}/tzm-LATN.json (100%) rename {locales => packages/locale-data/locales}/tzm.json (100%) rename {locales => packages/locale-data/locales}/ug-CN.json (100%) rename {locales => packages/locale-data/locales}/uk.json (100%) rename {locales => packages/locale-data/locales}/ur.json (100%) rename {locales => packages/locale-data/locales}/uz-LATN.json (100%) rename {locales => packages/locale-data/locales}/uz.json (100%) rename {locales => packages/locale-data/locales}/vi.json (100%) rename {locales => packages/locale-data/locales}/x-PSEUDO.json (100%) rename {locales => packages/locale-data/locales}/yo.json (100%) rename {locales => packages/locale-data/locales}/zh-CN.json (100%) rename {locales => packages/locale-data/locales}/zh-HK.json (100%) rename {locales => packages/locale-data/locales}/zh-MO.json (100%) rename {locales => packages/locale-data/locales}/zh-TW.json (100%) create mode 100644 packages/locale-data/package.json rename {scripts => packages/locale-data/scripts}/localesScrape.cjs (94%) diff --git a/.gitmodules b/.gitmodules index 49a256fb..8bc13760 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,8 @@ [submodule "scripts/data/moment"] - path = scripts/data/moment + path = packages/locale-data/data/moment url = https://github.com/moment/moment.git [submodule "scripts/data/fullcalendar"] - path = scripts/data/fullcalendar + path = packages/locale-data/data/fullcalendar url = https://github.com/fullcalendar/fullcalendar.git [submodule "packages/temporal-polyfill/test262"] path = test262 diff --git a/package.json b/package.json index 8405737b..6236c7a8 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "@typescript-eslint/eslint-plugin": "^4.22.1", "@typescript-eslint/parser": "^4.22.1", "colors": "^1.4.0", - "deepmerge": "^4.2.2", "esbuild": "^0.18.17", "eslint": "^7.25.0", "eslint-config-standard": "^16.0.3", @@ -55,8 +54,7 @@ "rollup-plugin-dts": "^3.0.2", "rollup-plugin-esbuild": "^4.9.1", "rollup-plugin-terser": "^7.0.2", - "typescript": "^5.1.6", - "yargs": "^17.0.1" + "typescript": "^5.1.6" }, "pnpm": { "patchedDependencies": { diff --git a/scripts/data/fullcalendar b/packages/locale-data/data/fullcalendar similarity index 100% rename from scripts/data/fullcalendar rename to packages/locale-data/data/fullcalendar diff --git a/scripts/data/moment b/packages/locale-data/data/moment similarity index 100% rename from scripts/data/moment rename to packages/locale-data/data/moment diff --git a/locales/af.json b/packages/locale-data/locales/af.json similarity index 100% rename from locales/af.json rename to packages/locale-data/locales/af.json diff --git a/locales/ar-DZ.json b/packages/locale-data/locales/ar-DZ.json similarity index 100% rename from locales/ar-DZ.json rename to packages/locale-data/locales/ar-DZ.json diff --git a/locales/ar-KW.json b/packages/locale-data/locales/ar-KW.json similarity index 100% rename from locales/ar-KW.json rename to packages/locale-data/locales/ar-KW.json diff --git a/locales/ar-LY.json b/packages/locale-data/locales/ar-LY.json similarity index 100% rename from locales/ar-LY.json rename to packages/locale-data/locales/ar-LY.json diff --git a/locales/ar-MA.json b/packages/locale-data/locales/ar-MA.json similarity index 100% rename from locales/ar-MA.json rename to packages/locale-data/locales/ar-MA.json diff --git a/locales/ar-SA.json b/packages/locale-data/locales/ar-SA.json similarity index 100% rename from locales/ar-SA.json rename to packages/locale-data/locales/ar-SA.json diff --git a/locales/ar-TN.json b/packages/locale-data/locales/ar-TN.json similarity index 100% rename from locales/ar-TN.json rename to packages/locale-data/locales/ar-TN.json diff --git a/locales/ar.json b/packages/locale-data/locales/ar.json similarity index 100% rename from locales/ar.json rename to packages/locale-data/locales/ar.json diff --git a/locales/az.json b/packages/locale-data/locales/az.json similarity index 100% rename from locales/az.json rename to packages/locale-data/locales/az.json diff --git a/locales/be.json b/packages/locale-data/locales/be.json similarity index 100% rename from locales/be.json rename to packages/locale-data/locales/be.json diff --git a/locales/bg.json b/packages/locale-data/locales/bg.json similarity index 100% rename from locales/bg.json rename to packages/locale-data/locales/bg.json diff --git a/locales/bm.json b/packages/locale-data/locales/bm.json similarity index 100% rename from locales/bm.json rename to packages/locale-data/locales/bm.json diff --git a/locales/bn-BD.json b/packages/locale-data/locales/bn-BD.json similarity index 100% rename from locales/bn-BD.json rename to packages/locale-data/locales/bn-BD.json diff --git a/locales/bn.json b/packages/locale-data/locales/bn.json similarity index 100% rename from locales/bn.json rename to packages/locale-data/locales/bn.json diff --git a/locales/bo.json b/packages/locale-data/locales/bo.json similarity index 100% rename from locales/bo.json rename to packages/locale-data/locales/bo.json diff --git a/locales/br.json b/packages/locale-data/locales/br.json similarity index 100% rename from locales/br.json rename to packages/locale-data/locales/br.json diff --git a/locales/bs.json b/packages/locale-data/locales/bs.json similarity index 100% rename from locales/bs.json rename to packages/locale-data/locales/bs.json diff --git a/locales/ca.json b/packages/locale-data/locales/ca.json similarity index 100% rename from locales/ca.json rename to packages/locale-data/locales/ca.json diff --git a/locales/cs.json b/packages/locale-data/locales/cs.json similarity index 100% rename from locales/cs.json rename to packages/locale-data/locales/cs.json diff --git a/locales/cv.json b/packages/locale-data/locales/cv.json similarity index 100% rename from locales/cv.json rename to packages/locale-data/locales/cv.json diff --git a/locales/cy.json b/packages/locale-data/locales/cy.json similarity index 100% rename from locales/cy.json rename to packages/locale-data/locales/cy.json diff --git a/locales/da.json b/packages/locale-data/locales/da.json similarity index 100% rename from locales/da.json rename to packages/locale-data/locales/da.json diff --git a/locales/de-AT.json b/packages/locale-data/locales/de-AT.json similarity index 100% rename from locales/de-AT.json rename to packages/locale-data/locales/de-AT.json diff --git a/locales/de-CH.json b/packages/locale-data/locales/de-CH.json similarity index 100% rename from locales/de-CH.json rename to packages/locale-data/locales/de-CH.json diff --git a/locales/de.json b/packages/locale-data/locales/de.json similarity index 100% rename from locales/de.json rename to packages/locale-data/locales/de.json diff --git a/locales/dv.json b/packages/locale-data/locales/dv.json similarity index 100% rename from locales/dv.json rename to packages/locale-data/locales/dv.json diff --git a/locales/el.json b/packages/locale-data/locales/el.json similarity index 100% rename from locales/el.json rename to packages/locale-data/locales/el.json diff --git a/locales/en-AU.json b/packages/locale-data/locales/en-AU.json similarity index 100% rename from locales/en-AU.json rename to packages/locale-data/locales/en-AU.json diff --git a/locales/en-CA.json b/packages/locale-data/locales/en-CA.json similarity index 100% rename from locales/en-CA.json rename to packages/locale-data/locales/en-CA.json diff --git a/locales/en-GB.json b/packages/locale-data/locales/en-GB.json similarity index 100% rename from locales/en-GB.json rename to packages/locale-data/locales/en-GB.json diff --git a/locales/en-IE.json b/packages/locale-data/locales/en-IE.json similarity index 100% rename from locales/en-IE.json rename to packages/locale-data/locales/en-IE.json diff --git a/locales/en-IL.json b/packages/locale-data/locales/en-IL.json similarity index 100% rename from locales/en-IL.json rename to packages/locale-data/locales/en-IL.json diff --git a/locales/en-IN.json b/packages/locale-data/locales/en-IN.json similarity index 100% rename from locales/en-IN.json rename to packages/locale-data/locales/en-IN.json diff --git a/locales/en-NZ.json b/packages/locale-data/locales/en-NZ.json similarity index 100% rename from locales/en-NZ.json rename to packages/locale-data/locales/en-NZ.json diff --git a/locales/en-SG.json b/packages/locale-data/locales/en-SG.json similarity index 100% rename from locales/en-SG.json rename to packages/locale-data/locales/en-SG.json diff --git a/locales/en.json b/packages/locale-data/locales/en.json similarity index 100% rename from locales/en.json rename to packages/locale-data/locales/en.json diff --git a/locales/eo.json b/packages/locale-data/locales/eo.json similarity index 100% rename from locales/eo.json rename to packages/locale-data/locales/eo.json diff --git a/locales/es-DO.json b/packages/locale-data/locales/es-DO.json similarity index 100% rename from locales/es-DO.json rename to packages/locale-data/locales/es-DO.json diff --git a/locales/es-MX.json b/packages/locale-data/locales/es-MX.json similarity index 100% rename from locales/es-MX.json rename to packages/locale-data/locales/es-MX.json diff --git a/locales/es-US.json b/packages/locale-data/locales/es-US.json similarity index 100% rename from locales/es-US.json rename to packages/locale-data/locales/es-US.json diff --git a/locales/es.json b/packages/locale-data/locales/es.json similarity index 100% rename from locales/es.json rename to packages/locale-data/locales/es.json diff --git a/locales/et.json b/packages/locale-data/locales/et.json similarity index 100% rename from locales/et.json rename to packages/locale-data/locales/et.json diff --git a/locales/eu.json b/packages/locale-data/locales/eu.json similarity index 100% rename from locales/eu.json rename to packages/locale-data/locales/eu.json diff --git a/locales/fa.json b/packages/locale-data/locales/fa.json similarity index 100% rename from locales/fa.json rename to packages/locale-data/locales/fa.json diff --git a/locales/fi.json b/packages/locale-data/locales/fi.json similarity index 100% rename from locales/fi.json rename to packages/locale-data/locales/fi.json diff --git a/locales/fil.json b/packages/locale-data/locales/fil.json similarity index 100% rename from locales/fil.json rename to packages/locale-data/locales/fil.json diff --git a/locales/fo.json b/packages/locale-data/locales/fo.json similarity index 100% rename from locales/fo.json rename to packages/locale-data/locales/fo.json diff --git a/locales/fr-CA.json b/packages/locale-data/locales/fr-CA.json similarity index 100% rename from locales/fr-CA.json rename to packages/locale-data/locales/fr-CA.json diff --git a/locales/fr-CH.json b/packages/locale-data/locales/fr-CH.json similarity index 100% rename from locales/fr-CH.json rename to packages/locale-data/locales/fr-CH.json diff --git a/locales/fr.json b/packages/locale-data/locales/fr.json similarity index 100% rename from locales/fr.json rename to packages/locale-data/locales/fr.json diff --git a/locales/fy.json b/packages/locale-data/locales/fy.json similarity index 100% rename from locales/fy.json rename to packages/locale-data/locales/fy.json diff --git a/locales/ga.json b/packages/locale-data/locales/ga.json similarity index 100% rename from locales/ga.json rename to packages/locale-data/locales/ga.json diff --git a/locales/gd.json b/packages/locale-data/locales/gd.json similarity index 100% rename from locales/gd.json rename to packages/locale-data/locales/gd.json diff --git a/locales/gl.json b/packages/locale-data/locales/gl.json similarity index 100% rename from locales/gl.json rename to packages/locale-data/locales/gl.json diff --git a/locales/gom-DEVA.json b/packages/locale-data/locales/gom-DEVA.json similarity index 100% rename from locales/gom-DEVA.json rename to packages/locale-data/locales/gom-DEVA.json diff --git a/locales/gom-LATN.json b/packages/locale-data/locales/gom-LATN.json similarity index 100% rename from locales/gom-LATN.json rename to packages/locale-data/locales/gom-LATN.json diff --git a/locales/gu.json b/packages/locale-data/locales/gu.json similarity index 100% rename from locales/gu.json rename to packages/locale-data/locales/gu.json diff --git a/locales/he.json b/packages/locale-data/locales/he.json similarity index 100% rename from locales/he.json rename to packages/locale-data/locales/he.json diff --git a/locales/hi.json b/packages/locale-data/locales/hi.json similarity index 100% rename from locales/hi.json rename to packages/locale-data/locales/hi.json diff --git a/locales/hr.json b/packages/locale-data/locales/hr.json similarity index 100% rename from locales/hr.json rename to packages/locale-data/locales/hr.json diff --git a/locales/hu.json b/packages/locale-data/locales/hu.json similarity index 100% rename from locales/hu.json rename to packages/locale-data/locales/hu.json diff --git a/locales/hy-AM.json b/packages/locale-data/locales/hy-AM.json similarity index 100% rename from locales/hy-AM.json rename to packages/locale-data/locales/hy-AM.json diff --git a/locales/id.json b/packages/locale-data/locales/id.json similarity index 100% rename from locales/id.json rename to packages/locale-data/locales/id.json diff --git a/locales/is.json b/packages/locale-data/locales/is.json similarity index 100% rename from locales/is.json rename to packages/locale-data/locales/is.json diff --git a/locales/it-CH.json b/packages/locale-data/locales/it-CH.json similarity index 100% rename from locales/it-CH.json rename to packages/locale-data/locales/it-CH.json diff --git a/locales/it.json b/packages/locale-data/locales/it.json similarity index 100% rename from locales/it.json rename to packages/locale-data/locales/it.json diff --git a/locales/ja.json b/packages/locale-data/locales/ja.json similarity index 100% rename from locales/ja.json rename to packages/locale-data/locales/ja.json diff --git a/locales/jv.json b/packages/locale-data/locales/jv.json similarity index 100% rename from locales/jv.json rename to packages/locale-data/locales/jv.json diff --git a/locales/ka.json b/packages/locale-data/locales/ka.json similarity index 100% rename from locales/ka.json rename to packages/locale-data/locales/ka.json diff --git a/locales/kk.json b/packages/locale-data/locales/kk.json similarity index 100% rename from locales/kk.json rename to packages/locale-data/locales/kk.json diff --git a/locales/km.json b/packages/locale-data/locales/km.json similarity index 100% rename from locales/km.json rename to packages/locale-data/locales/km.json diff --git a/locales/kn.json b/packages/locale-data/locales/kn.json similarity index 100% rename from locales/kn.json rename to packages/locale-data/locales/kn.json diff --git a/locales/ko.json b/packages/locale-data/locales/ko.json similarity index 100% rename from locales/ko.json rename to packages/locale-data/locales/ko.json diff --git a/locales/ku.json b/packages/locale-data/locales/ku.json similarity index 100% rename from locales/ku.json rename to packages/locale-data/locales/ku.json diff --git a/locales/ky.json b/packages/locale-data/locales/ky.json similarity index 100% rename from locales/ky.json rename to packages/locale-data/locales/ky.json diff --git a/locales/lb.json b/packages/locale-data/locales/lb.json similarity index 100% rename from locales/lb.json rename to packages/locale-data/locales/lb.json diff --git a/locales/lo.json b/packages/locale-data/locales/lo.json similarity index 100% rename from locales/lo.json rename to packages/locale-data/locales/lo.json diff --git a/locales/lt.json b/packages/locale-data/locales/lt.json similarity index 100% rename from locales/lt.json rename to packages/locale-data/locales/lt.json diff --git a/locales/lv.json b/packages/locale-data/locales/lv.json similarity index 100% rename from locales/lv.json rename to packages/locale-data/locales/lv.json diff --git a/locales/me.json b/packages/locale-data/locales/me.json similarity index 100% rename from locales/me.json rename to packages/locale-data/locales/me.json diff --git a/locales/mi.json b/packages/locale-data/locales/mi.json similarity index 100% rename from locales/mi.json rename to packages/locale-data/locales/mi.json diff --git a/locales/mk.json b/packages/locale-data/locales/mk.json similarity index 100% rename from locales/mk.json rename to packages/locale-data/locales/mk.json diff --git a/locales/ml.json b/packages/locale-data/locales/ml.json similarity index 100% rename from locales/ml.json rename to packages/locale-data/locales/ml.json diff --git a/locales/mn.json b/packages/locale-data/locales/mn.json similarity index 100% rename from locales/mn.json rename to packages/locale-data/locales/mn.json diff --git a/locales/mr.json b/packages/locale-data/locales/mr.json similarity index 100% rename from locales/mr.json rename to packages/locale-data/locales/mr.json diff --git a/locales/ms-MY.json b/packages/locale-data/locales/ms-MY.json similarity index 100% rename from locales/ms-MY.json rename to packages/locale-data/locales/ms-MY.json diff --git a/locales/ms.json b/packages/locale-data/locales/ms.json similarity index 100% rename from locales/ms.json rename to packages/locale-data/locales/ms.json diff --git a/locales/mt.json b/packages/locale-data/locales/mt.json similarity index 100% rename from locales/mt.json rename to packages/locale-data/locales/mt.json diff --git a/locales/my.json b/packages/locale-data/locales/my.json similarity index 100% rename from locales/my.json rename to packages/locale-data/locales/my.json diff --git a/locales/nb.json b/packages/locale-data/locales/nb.json similarity index 100% rename from locales/nb.json rename to packages/locale-data/locales/nb.json diff --git a/locales/ne.json b/packages/locale-data/locales/ne.json similarity index 100% rename from locales/ne.json rename to packages/locale-data/locales/ne.json diff --git a/locales/nl-BE.json b/packages/locale-data/locales/nl-BE.json similarity index 100% rename from locales/nl-BE.json rename to packages/locale-data/locales/nl-BE.json diff --git a/locales/nl.json b/packages/locale-data/locales/nl.json similarity index 100% rename from locales/nl.json rename to packages/locale-data/locales/nl.json diff --git a/locales/nn.json b/packages/locale-data/locales/nn.json similarity index 100% rename from locales/nn.json rename to packages/locale-data/locales/nn.json diff --git a/locales/oc-LNC.json b/packages/locale-data/locales/oc-LNC.json similarity index 100% rename from locales/oc-LNC.json rename to packages/locale-data/locales/oc-LNC.json diff --git a/locales/pa-IN.json b/packages/locale-data/locales/pa-IN.json similarity index 100% rename from locales/pa-IN.json rename to packages/locale-data/locales/pa-IN.json diff --git a/locales/pl.json b/packages/locale-data/locales/pl.json similarity index 100% rename from locales/pl.json rename to packages/locale-data/locales/pl.json diff --git a/locales/pt-BR.json b/packages/locale-data/locales/pt-BR.json similarity index 100% rename from locales/pt-BR.json rename to packages/locale-data/locales/pt-BR.json diff --git a/locales/pt.json b/packages/locale-data/locales/pt.json similarity index 100% rename from locales/pt.json rename to packages/locale-data/locales/pt.json diff --git a/locales/ro.json b/packages/locale-data/locales/ro.json similarity index 100% rename from locales/ro.json rename to packages/locale-data/locales/ro.json diff --git a/locales/ru.json b/packages/locale-data/locales/ru.json similarity index 100% rename from locales/ru.json rename to packages/locale-data/locales/ru.json diff --git a/locales/sd.json b/packages/locale-data/locales/sd.json similarity index 100% rename from locales/sd.json rename to packages/locale-data/locales/sd.json diff --git a/locales/se.json b/packages/locale-data/locales/se.json similarity index 100% rename from locales/se.json rename to packages/locale-data/locales/se.json diff --git a/locales/si.json b/packages/locale-data/locales/si.json similarity index 100% rename from locales/si.json rename to packages/locale-data/locales/si.json diff --git a/locales/sk.json b/packages/locale-data/locales/sk.json similarity index 100% rename from locales/sk.json rename to packages/locale-data/locales/sk.json diff --git a/locales/sl.json b/packages/locale-data/locales/sl.json similarity index 100% rename from locales/sl.json rename to packages/locale-data/locales/sl.json diff --git a/locales/sq.json b/packages/locale-data/locales/sq.json similarity index 100% rename from locales/sq.json rename to packages/locale-data/locales/sq.json diff --git a/locales/sr-CYRL.json b/packages/locale-data/locales/sr-CYRL.json similarity index 100% rename from locales/sr-CYRL.json rename to packages/locale-data/locales/sr-CYRL.json diff --git a/locales/sr.json b/packages/locale-data/locales/sr.json similarity index 100% rename from locales/sr.json rename to packages/locale-data/locales/sr.json diff --git a/locales/ss.json b/packages/locale-data/locales/ss.json similarity index 100% rename from locales/ss.json rename to packages/locale-data/locales/ss.json diff --git a/locales/sv.json b/packages/locale-data/locales/sv.json similarity index 100% rename from locales/sv.json rename to packages/locale-data/locales/sv.json diff --git a/locales/sw.json b/packages/locale-data/locales/sw.json similarity index 100% rename from locales/sw.json rename to packages/locale-data/locales/sw.json diff --git a/locales/ta.json b/packages/locale-data/locales/ta.json similarity index 100% rename from locales/ta.json rename to packages/locale-data/locales/ta.json diff --git a/locales/te.json b/packages/locale-data/locales/te.json similarity index 100% rename from locales/te.json rename to packages/locale-data/locales/te.json diff --git a/locales/tet.json b/packages/locale-data/locales/tet.json similarity index 100% rename from locales/tet.json rename to packages/locale-data/locales/tet.json diff --git a/locales/tg.json b/packages/locale-data/locales/tg.json similarity index 100% rename from locales/tg.json rename to packages/locale-data/locales/tg.json diff --git a/locales/th.json b/packages/locale-data/locales/th.json similarity index 100% rename from locales/th.json rename to packages/locale-data/locales/th.json diff --git a/locales/tk.json b/packages/locale-data/locales/tk.json similarity index 100% rename from locales/tk.json rename to packages/locale-data/locales/tk.json diff --git a/locales/tl-PH.json b/packages/locale-data/locales/tl-PH.json similarity index 100% rename from locales/tl-PH.json rename to packages/locale-data/locales/tl-PH.json diff --git a/locales/tlh.json b/packages/locale-data/locales/tlh.json similarity index 100% rename from locales/tlh.json rename to packages/locale-data/locales/tlh.json diff --git a/locales/tr.json b/packages/locale-data/locales/tr.json similarity index 100% rename from locales/tr.json rename to packages/locale-data/locales/tr.json diff --git a/locales/tzl.json b/packages/locale-data/locales/tzl.json similarity index 100% rename from locales/tzl.json rename to packages/locale-data/locales/tzl.json diff --git a/locales/tzm-LATN.json b/packages/locale-data/locales/tzm-LATN.json similarity index 100% rename from locales/tzm-LATN.json rename to packages/locale-data/locales/tzm-LATN.json diff --git a/locales/tzm.json b/packages/locale-data/locales/tzm.json similarity index 100% rename from locales/tzm.json rename to packages/locale-data/locales/tzm.json diff --git a/locales/ug-CN.json b/packages/locale-data/locales/ug-CN.json similarity index 100% rename from locales/ug-CN.json rename to packages/locale-data/locales/ug-CN.json diff --git a/locales/uk.json b/packages/locale-data/locales/uk.json similarity index 100% rename from locales/uk.json rename to packages/locale-data/locales/uk.json diff --git a/locales/ur.json b/packages/locale-data/locales/ur.json similarity index 100% rename from locales/ur.json rename to packages/locale-data/locales/ur.json diff --git a/locales/uz-LATN.json b/packages/locale-data/locales/uz-LATN.json similarity index 100% rename from locales/uz-LATN.json rename to packages/locale-data/locales/uz-LATN.json diff --git a/locales/uz.json b/packages/locale-data/locales/uz.json similarity index 100% rename from locales/uz.json rename to packages/locale-data/locales/uz.json diff --git a/locales/vi.json b/packages/locale-data/locales/vi.json similarity index 100% rename from locales/vi.json rename to packages/locale-data/locales/vi.json diff --git a/locales/x-PSEUDO.json b/packages/locale-data/locales/x-PSEUDO.json similarity index 100% rename from locales/x-PSEUDO.json rename to packages/locale-data/locales/x-PSEUDO.json diff --git a/locales/yo.json b/packages/locale-data/locales/yo.json similarity index 100% rename from locales/yo.json rename to packages/locale-data/locales/yo.json diff --git a/locales/zh-CN.json b/packages/locale-data/locales/zh-CN.json similarity index 100% rename from locales/zh-CN.json rename to packages/locale-data/locales/zh-CN.json diff --git a/locales/zh-HK.json b/packages/locale-data/locales/zh-HK.json similarity index 100% rename from locales/zh-HK.json rename to packages/locale-data/locales/zh-HK.json diff --git a/locales/zh-MO.json b/packages/locale-data/locales/zh-MO.json similarity index 100% rename from locales/zh-MO.json rename to packages/locale-data/locales/zh-MO.json diff --git a/locales/zh-TW.json b/packages/locale-data/locales/zh-TW.json similarity index 100% rename from locales/zh-TW.json rename to packages/locale-data/locales/zh-TW.json diff --git a/packages/locale-data/package.json b/packages/locale-data/package.json new file mode 100644 index 00000000..7229d4a5 --- /dev/null +++ b/packages/locale-data/package.json @@ -0,0 +1,9 @@ +{ + "name": "locale-data", + "version": "0.0.0", + "dependencies": { + "colors": "^1.4.0", + "deepmerge": "^4.2.2", + "yargs": "^17.0.1" + } +} diff --git a/scripts/localesScrape.cjs b/packages/locale-data/scripts/localesScrape.cjs similarity index 94% rename from scripts/localesScrape.cjs rename to packages/locale-data/scripts/localesScrape.cjs index b8b23f8d..49985ba4 100644 --- a/scripts/localesScrape.cjs +++ b/packages/locale-data/scripts/localesScrape.cjs @@ -8,12 +8,8 @@ const { hideBin } = require('yargs/helpers') require('colors') const args = yargs(hideBin(process.argv)).boolean('v').argv -const momentLocaleRoot = resolve(args.$0, '..', 'data/moment/locale') -const fullcalendarLocaleRoot = resolve( - args.$0, - '..', - 'data/fullcalendar/packages/core/src/locales', -) +const momentLocaleRoot = resolve(args.$0, '../data/moment/locale') +const fullcalendarLocaleRoot = resolve(args.$0, '../data/fullcalendar/packages/core/src/locales') async function writeLocale(localeStr) { // Used for specific parsing nuances, intlStr represents the locale with the suffix capitalized @@ -89,7 +85,7 @@ async function writeLocale(localeStr) { const workspaceLocalePath = resolve( args.$0, - '../../locales', + '../locales', `${intlStr}.json`, ) @@ -118,7 +114,7 @@ async function writeLocale(localeStr) { // Write to file await writeFile( - resolve(args.$0, '../../locales', `${intlStr}.json`), + resolve(args.$0, '../locales', `${intlStr}.json`), JSON.stringify(localeData, null, 2), { encoding: 'utf8', flag: 'w' }, ) From 8b8643af9a0c2dda511c142421694b14368bad8a Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:24:59 -0400 Subject: [PATCH 208/805] locale-data wire up w/ packages --- packages/datetimeformat-tokens/package.json | 1 + packages/locale-textinfo/package.json | 1 + packages/locale-weekinfo/package.json | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/datetimeformat-tokens/package.json b/packages/datetimeformat-tokens/package.json index 6fbab7ff..e8db1662 100644 --- a/packages/datetimeformat-tokens/package.json +++ b/packages/datetimeformat-tokens/package.json @@ -37,6 +37,7 @@ "devDependencies": { "@types/jest": "^26.0.23", "jest": "^27.0.4", + "locale-data": "workspace:*", "temporal-polyfill": "workspace:*" } } diff --git a/packages/locale-textinfo/package.json b/packages/locale-textinfo/package.json index f271410a..16ec5f0a 100644 --- a/packages/locale-textinfo/package.json +++ b/packages/locale-textinfo/package.json @@ -33,6 +33,7 @@ }, "devDependencies": { "@types/jest": "^26.0.23", + "locale-data": "workspace:*", "jest": "^27.0.4" } } diff --git a/packages/locale-weekinfo/package.json b/packages/locale-weekinfo/package.json index 0c8d77e1..527b14ec 100644 --- a/packages/locale-weekinfo/package.json +++ b/packages/locale-weekinfo/package.json @@ -34,6 +34,7 @@ }, "devDependencies": { "@types/jest": "^26.0.23", + "locale-data": "workspace:*", "jest": "^27.0.4" } } From 0f6996afebbe5dac56feff9138aed7dd7b71727b Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:25:30 -0400 Subject: [PATCH 209/805] update pnpm lock --- pnpm-lock.yaml | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 017385aa..5fcd5836 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,9 +37,6 @@ importers: colors: specifier: ^1.4.0 version: 1.4.0 - deepmerge: - specifier: ^4.2.2 - version: 4.3.0 esbuild: specifier: ^0.18.17 version: 0.18.17 @@ -82,9 +79,6 @@ importers: typescript: specifier: ^5.1.6 version: 5.1.6 - yargs: - specifier: ^17.0.1 - version: 17.7.1 packages/datetimeformat-tokens: dependencies: @@ -98,6 +92,9 @@ importers: jest: specifier: ^27.0.4 version: 27.5.1 + locale-data: + specifier: workspace:* + version: link:../locale-data temporal-polyfill: specifier: workspace:* version: link:../temporal-polyfill @@ -118,6 +115,18 @@ importers: specifier: workspace:* version: link:../temporal-polyfill + packages/locale-data: + dependencies: + colors: + specifier: ^1.4.0 + version: 1.4.0 + deepmerge: + specifier: ^4.2.2 + version: 4.3.0 + yargs: + specifier: ^17.0.1 + version: 17.7.1 + packages/locale-textinfo: devDependencies: '@types/jest': @@ -126,6 +135,9 @@ importers: jest: specifier: ^27.0.4 version: 27.5.1 + locale-data: + specifier: workspace:* + version: link:../locale-data packages/locale-weekinfo: devDependencies: @@ -135,6 +147,9 @@ importers: jest: specifier: ^27.0.4 version: 27.5.1 + locale-data: + specifier: workspace:* + version: link:../locale-data packages/temporal-polyfill: dependencies: @@ -2284,7 +2299,6 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -2298,7 +2312,6 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} @@ -2629,7 +2642,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true /co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} @@ -2651,7 +2663,6 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -2659,12 +2670,10 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true /colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} - dev: true /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} @@ -2790,7 +2799,6 @@ packages: /deepmerge@4.3.0: resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==} engines: {node: '>=0.10.0'} - dev: true /define-properties@1.2.0: resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} @@ -2859,7 +2867,6 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true /enquirer@2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} @@ -2974,7 +2981,6 @@ packages: /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} - dev: true /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -3417,7 +3423,6 @@ packages: /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: true /get-func-name@2.0.0: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} @@ -3715,7 +3720,6 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} @@ -4920,7 +4924,6 @@ packages: /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - dev: true /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} @@ -5179,7 +5182,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true /string.prototype.trimend@1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} @@ -5202,7 +5204,6 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: true /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -5595,7 +5596,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -5634,7 +5634,6 @@ packages: /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - dev: true /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -5652,7 +5651,6 @@ packages: /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - dev: true /yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} @@ -5678,4 +5676,3 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true From 141f00e3dea841f15bb7093a10ad5c67b0772c24 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:30:53 -0400 Subject: [PATCH 210/805] move eslint --- scripts/config/eslint.cjs => eslint.base.cjs | 0 {scripts => packages/locale-data/scripts}/lib/localesList.cjs | 0 packages/temporal-polyfill/.eslintrc.cjs.disabled | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename scripts/config/eslint.cjs => eslint.base.cjs (100%) rename {scripts => packages/locale-data/scripts}/lib/localesList.cjs (100%) diff --git a/scripts/config/eslint.cjs b/eslint.base.cjs similarity index 100% rename from scripts/config/eslint.cjs rename to eslint.base.cjs diff --git a/scripts/lib/localesList.cjs b/packages/locale-data/scripts/lib/localesList.cjs similarity index 100% rename from scripts/lib/localesList.cjs rename to packages/locale-data/scripts/lib/localesList.cjs diff --git a/packages/temporal-polyfill/.eslintrc.cjs.disabled b/packages/temporal-polyfill/.eslintrc.cjs.disabled index 2a75cc97..9d9447f7 100644 --- a/packages/temporal-polyfill/.eslintrc.cjs.disabled +++ b/packages/temporal-polyfill/.eslintrc.cjs.disabled @@ -1,2 +1,2 @@ -module.exports = require('../../scripts/config/eslint.cjs') +module.exports = require('../../eslint.base.cjs') From 876b19c53256819ae15c29f49d0d5190b177db43 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:34:51 -0400 Subject: [PATCH 211/805] move minimatch --- package.json | 1 - packages/temporal-polyfill/package.json | 1 + .../temporal-polyfill/scripts}/config/pkgBundle.cjs | 0 .../temporal-polyfill/scripts}/config/terser.json | 0 .../temporal-polyfill/scripts}/lib/pkgAnalyze.cjs | 0 .../temporal-polyfill/scripts}/lib/pkgBundle.cjs | 0 .../temporal-polyfill/scripts}/lib/pkgTypes.cjs | 0 .../temporal-polyfill/scripts}/pkgClean.cjs | 0 {scripts => packages/temporal-polyfill/scripts}/pkgSize.cjs | 0 pnpm-lock.yaml | 6 +++--- 10 files changed, 4 insertions(+), 4 deletions(-) rename {scripts => packages/temporal-polyfill/scripts}/config/pkgBundle.cjs (100%) rename {scripts => packages/temporal-polyfill/scripts}/config/terser.json (100%) rename {scripts => packages/temporal-polyfill/scripts}/lib/pkgAnalyze.cjs (100%) rename {scripts => packages/temporal-polyfill/scripts}/lib/pkgBundle.cjs (100%) rename {scripts => packages/temporal-polyfill/scripts}/lib/pkgTypes.cjs (100%) rename {scripts => packages/temporal-polyfill/scripts}/pkgClean.cjs (100%) rename {scripts => packages/temporal-polyfill/scripts}/pkgSize.cjs (100%) diff --git a/package.json b/package.json index 6236c7a8..58b691c2 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", "jest": "^27.0.4", - "minimatch": "^5.0.1", "rollup": "^2.55.1", "rollup-plugin-dts": "^3.0.2", "rollup-plugin-esbuild": "^4.9.1", diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 56a77a1d..6ebd4351 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -79,6 +79,7 @@ "jest": "^27.0.6", "jest-date-mock": "^1.0.8", "js-yaml": "^4.1.0", + "minimatch": "^5.0.1", "progress": "^2.0.3", "rollup": "^2.55.1", "tiny-glob": "^0.2.9", diff --git a/scripts/config/pkgBundle.cjs b/packages/temporal-polyfill/scripts/config/pkgBundle.cjs similarity index 100% rename from scripts/config/pkgBundle.cjs rename to packages/temporal-polyfill/scripts/config/pkgBundle.cjs diff --git a/scripts/config/terser.json b/packages/temporal-polyfill/scripts/config/terser.json similarity index 100% rename from scripts/config/terser.json rename to packages/temporal-polyfill/scripts/config/terser.json diff --git a/scripts/lib/pkgAnalyze.cjs b/packages/temporal-polyfill/scripts/lib/pkgAnalyze.cjs similarity index 100% rename from scripts/lib/pkgAnalyze.cjs rename to packages/temporal-polyfill/scripts/lib/pkgAnalyze.cjs diff --git a/scripts/lib/pkgBundle.cjs b/packages/temporal-polyfill/scripts/lib/pkgBundle.cjs similarity index 100% rename from scripts/lib/pkgBundle.cjs rename to packages/temporal-polyfill/scripts/lib/pkgBundle.cjs diff --git a/scripts/lib/pkgTypes.cjs b/packages/temporal-polyfill/scripts/lib/pkgTypes.cjs similarity index 100% rename from scripts/lib/pkgTypes.cjs rename to packages/temporal-polyfill/scripts/lib/pkgTypes.cjs diff --git a/scripts/pkgClean.cjs b/packages/temporal-polyfill/scripts/pkgClean.cjs similarity index 100% rename from scripts/pkgClean.cjs rename to packages/temporal-polyfill/scripts/pkgClean.cjs diff --git a/scripts/pkgSize.cjs b/packages/temporal-polyfill/scripts/pkgSize.cjs similarity index 100% rename from scripts/pkgSize.cjs rename to packages/temporal-polyfill/scripts/pkgSize.cjs diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5fcd5836..dc6d8ba4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -61,9 +61,6 @@ importers: jest: specifier: ^27.0.4 version: 27.5.1 - minimatch: - specifier: ^5.0.1 - version: 5.1.6 rollup: specifier: ^2.55.1 version: 2.79.1 @@ -190,6 +187,9 @@ importers: js-yaml: specifier: ^4.1.0 version: 4.1.0 + minimatch: + specifier: ^5.0.1 + version: 5.1.6 progress: specifier: ^2.0.3 version: 2.0.3 From 7f9c1306a17075397d8285745d276965148d0d5c Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:38:56 -0400 Subject: [PATCH 212/805] move script --- packages/temporal-polyfill/{ => scripts}/runtest262.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/temporal-polyfill/{ => scripts}/runtest262.js (100%) diff --git a/packages/temporal-polyfill/runtest262.js b/packages/temporal-polyfill/scripts/runtest262.js similarity index 100% rename from packages/temporal-polyfill/runtest262.js rename to packages/temporal-polyfill/scripts/runtest262.js From 0592f1b0232d4900fbbb8a8d615591e2c0a49d42 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 10:56:02 -0400 Subject: [PATCH 213/805] remove jest and babel --- .vscode/extensions.json | 3 +- .vscode/launch.json | 35 - babel.config.cjs | 9 - jest.config.base.cjs | 8 - jest.config.cjs | 12 - package.json | 5 - .../datetimeformat-tokens/babel.config.cjs | 4 - .../datetimeformat-tokens/jest.config.cjs | 8 - packages/datetimeformat-tokens/package.json | 2 - .../durationformat-polyfill/babel.config.cjs | 4 - .../durationformat-polyfill/jest.config.cjs | 8 - packages/durationformat-polyfill/package.json | 2 - packages/locale-textinfo/babel.config.cjs | 4 - packages/locale-textinfo/jest.config.cjs | 8 - packages/locale-textinfo/package.json | 4 +- packages/locale-weekinfo/babel.config.cjs | 4 - packages/locale-weekinfo/jest.config.cjs | 8 - packages/locale-weekinfo/package.json | 4 +- packages/temporal-polyfill/babel.config.cjs | 4 - packages/temporal-polyfill/jest-setup.js | 21 - packages/temporal-polyfill/jest.config.cjs | 16 - packages/temporal-polyfill/package.json | 6 - packages/temporal-polyfill/tests/README.md | 3 - packages/temporal-polyfill/tests/calendar.js | 401 -- packages/temporal-polyfill/tests/dateMath.js | 90 - packages/temporal-polyfill/tests/duration.js | 2024 ------ packages/temporal-polyfill/tests/exports.js | 78 - packages/temporal-polyfill/tests/instant.js | 1404 ----- packages/temporal-polyfill/tests/intl.js | 1912 ------ packages/temporal-polyfill/tests/largeInt.js | 88 - packages/temporal-polyfill/tests/now.js | 104 - packages/temporal-polyfill/tests/plainDate.js | 1138 ---- .../temporal-polyfill/tests/plainDateTime.js | 1774 ------ .../temporal-polyfill/tests/plainMonthDay.js | 348 -- packages/temporal-polyfill/tests/plainTime.js | 1386 ----- .../temporal-polyfill/tests/plainYearMonth.js | 820 --- packages/temporal-polyfill/tests/regex.js | 731 --- packages/temporal-polyfill/tests/timeZone.js | 565 -- .../temporal-polyfill/tests/tsconfig.json | 9 - .../temporal-polyfill/tests/userCalendar.js | 524 -- .../temporal-polyfill/tests/userTimeZone.js | 208 - .../temporal-polyfill/tests/zonedDateTime.js | 2961 --------- pnpm-lock.yaml | 5405 ++++------------- 43 files changed, 1078 insertions(+), 21074 deletions(-) delete mode 100644 babel.config.cjs delete mode 100644 jest.config.base.cjs delete mode 100644 jest.config.cjs delete mode 100644 packages/datetimeformat-tokens/babel.config.cjs delete mode 100644 packages/datetimeformat-tokens/jest.config.cjs delete mode 100644 packages/durationformat-polyfill/babel.config.cjs delete mode 100644 packages/durationformat-polyfill/jest.config.cjs delete mode 100644 packages/locale-textinfo/babel.config.cjs delete mode 100644 packages/locale-textinfo/jest.config.cjs delete mode 100644 packages/locale-weekinfo/babel.config.cjs delete mode 100644 packages/locale-weekinfo/jest.config.cjs delete mode 100644 packages/temporal-polyfill/babel.config.cjs delete mode 100644 packages/temporal-polyfill/jest-setup.js delete mode 100644 packages/temporal-polyfill/jest.config.cjs delete mode 100644 packages/temporal-polyfill/tests/README.md delete mode 100644 packages/temporal-polyfill/tests/calendar.js delete mode 100644 packages/temporal-polyfill/tests/dateMath.js delete mode 100644 packages/temporal-polyfill/tests/duration.js delete mode 100644 packages/temporal-polyfill/tests/exports.js delete mode 100644 packages/temporal-polyfill/tests/instant.js delete mode 100644 packages/temporal-polyfill/tests/intl.js delete mode 100644 packages/temporal-polyfill/tests/largeInt.js delete mode 100644 packages/temporal-polyfill/tests/now.js delete mode 100644 packages/temporal-polyfill/tests/plainDate.js delete mode 100644 packages/temporal-polyfill/tests/plainDateTime.js delete mode 100644 packages/temporal-polyfill/tests/plainMonthDay.js delete mode 100644 packages/temporal-polyfill/tests/plainTime.js delete mode 100644 packages/temporal-polyfill/tests/plainYearMonth.js delete mode 100644 packages/temporal-polyfill/tests/regex.js delete mode 100644 packages/temporal-polyfill/tests/timeZone.js delete mode 100644 packages/temporal-polyfill/tests/tsconfig.json delete mode 100644 packages/temporal-polyfill/tests/userCalendar.js delete mode 100644 packages/temporal-polyfill/tests/userTimeZone.js delete mode 100644 packages/temporal-polyfill/tests/zonedDateTime.js diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 7f3f4ffc..b308e589 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,5 @@ { "recommendations": [ - "dbaeumer.vscode-eslint", - "firsttris.vscode-jest-runner" + "dbaeumer.vscode-eslint" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 5e0065c7..27286c67 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,40 +1,5 @@ { "configurations": [ - { - "name": "Jest: Debug All", - "type": "node", - "request": "launch", - "runtimeArgs": [ - "--inspect-brk", - "${workspaceRoot}/node_modules/jest/bin/jest.js", - "--runInBand", - // NOTE: keep following args in sync with settings.json - "--no-cache", - "--watchAll=false" - ], - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "sourceMaps": true - }, - { - "name": "Jest: Debug File", - "type": "node", - "request": "launch", - // NOTE: keep args in sync with settings.json - "runtimeArgs": [ - "--inspect-brk", - "${workspaceRoot}/node_modules/jest/bin/jest.js", - "--runInBand", - // NOTE: keep following args in sync with settings.json - "--no-cache", - "--watchAll=false", - // specific file - "${file}" - ], - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "sourceMaps": true - }, { "name": "Test262: Run All", "type": "node", diff --git a/babel.config.cjs b/babel.config.cjs deleted file mode 100644 index c6279a40..00000000 --- a/babel.config.cjs +++ /dev/null @@ -1,9 +0,0 @@ -// For Jest. Individual packages extend this config -// TODO: when running test in "built-mode", don't do any babel transforming - -module.exports = { - presets: [ - ['@babel/preset-env', { targets: { node: 'current' } }], - '@babel/preset-typescript', - ], -} diff --git a/jest.config.base.cjs b/jest.config.base.cjs deleted file mode 100644 index 11d8343d..00000000 --- a/jest.config.base.cjs +++ /dev/null @@ -1,8 +0,0 @@ -// Only contains simple config that does not reference third-party packages - -process.env.TZ = 'America/New_York' - -module.exports = { - // timers: 'modern', - // verbose: true, -} diff --git a/jest.config.cjs b/jest.config.cjs deleted file mode 100644 index 46fca186..00000000 --- a/jest.config.cjs +++ /dev/null @@ -1,12 +0,0 @@ -const base = require('./jest.config.base.cjs') - -module.exports = { - ...base, - projects: [ - '/packages/temporal-polyfill', - // '/packages/locale-weekinfo', - // '/packages/locale-textinfo', - // '/packages/datetimeformat-tokens', - // '/packages/durationformat-polyfill', - ], -} diff --git a/package.json b/package.json index 58b691c2..3faf41fc 100644 --- a/package.json +++ b/package.json @@ -33,11 +33,7 @@ "locales-compile": "echo 'TODO: recursively execute locales-compile'" }, "devDependencies": { - "@babel/core": "^7.14.6", - "@babel/preset-env": "^7.14.5", - "@babel/preset-typescript": "^7.15.0", "@rollup/plugin-node-resolve": "^13.3.0", - "@types/jest": "^26.0.23", "@typescript-eslint/eslint-plugin": "^4.22.1", "@typescript-eslint/parser": "^4.22.1", "colors": "^1.4.0", @@ -48,7 +44,6 @@ "eslint-plugin-import": "^2.24.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", - "jest": "^27.0.4", "rollup": "^2.55.1", "rollup-plugin-dts": "^3.0.2", "rollup-plugin-esbuild": "^4.9.1", diff --git a/packages/datetimeformat-tokens/babel.config.cjs b/packages/datetimeformat-tokens/babel.config.cjs deleted file mode 100644 index 085ec4d0..00000000 --- a/packages/datetimeformat-tokens/babel.config.cjs +++ /dev/null @@ -1,4 +0,0 @@ - -module.exports = { - extends: '../../babel.config.cjs', -} diff --git a/packages/datetimeformat-tokens/jest.config.cjs b/packages/datetimeformat-tokens/jest.config.cjs deleted file mode 100644 index 6f34bce6..00000000 --- a/packages/datetimeformat-tokens/jest.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -const base = require('../../jest.config.base.cjs') - -module.exports = { - ...base, - roots: [ - '/src', - ], -} diff --git a/packages/datetimeformat-tokens/package.json b/packages/datetimeformat-tokens/package.json index e8db1662..4e7ea0b0 100644 --- a/packages/datetimeformat-tokens/package.json +++ b/packages/datetimeformat-tokens/package.json @@ -35,8 +35,6 @@ "temporal-spec": "workspace:*" }, "devDependencies": { - "@types/jest": "^26.0.23", - "jest": "^27.0.4", "locale-data": "workspace:*", "temporal-polyfill": "workspace:*" } diff --git a/packages/durationformat-polyfill/babel.config.cjs b/packages/durationformat-polyfill/babel.config.cjs deleted file mode 100644 index 085ec4d0..00000000 --- a/packages/durationformat-polyfill/babel.config.cjs +++ /dev/null @@ -1,4 +0,0 @@ - -module.exports = { - extends: '../../babel.config.cjs', -} diff --git a/packages/durationformat-polyfill/jest.config.cjs b/packages/durationformat-polyfill/jest.config.cjs deleted file mode 100644 index 6f34bce6..00000000 --- a/packages/durationformat-polyfill/jest.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -const base = require('../../jest.config.base.cjs') - -module.exports = { - ...base, - roots: [ - '/src', - ], -} diff --git a/packages/durationformat-polyfill/package.json b/packages/durationformat-polyfill/package.json index 19175135..d0ed64b9 100644 --- a/packages/durationformat-polyfill/package.json +++ b/packages/durationformat-polyfill/package.json @@ -31,8 +31,6 @@ "temporal-spec": "workspace:*" }, "devDependencies": { - "@types/jest": "^26.0.23", - "jest": "^27.0.4", "temporal-polyfill": "workspace:*" } } diff --git a/packages/locale-textinfo/babel.config.cjs b/packages/locale-textinfo/babel.config.cjs deleted file mode 100644 index 085ec4d0..00000000 --- a/packages/locale-textinfo/babel.config.cjs +++ /dev/null @@ -1,4 +0,0 @@ - -module.exports = { - extends: '../../babel.config.cjs', -} diff --git a/packages/locale-textinfo/jest.config.cjs b/packages/locale-textinfo/jest.config.cjs deleted file mode 100644 index 6f34bce6..00000000 --- a/packages/locale-textinfo/jest.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -const base = require('../../jest.config.base.cjs') - -module.exports = { - ...base, - roots: [ - '/src', - ], -} diff --git a/packages/locale-textinfo/package.json b/packages/locale-textinfo/package.json index 16ec5f0a..5fa265ea 100644 --- a/packages/locale-textinfo/package.json +++ b/packages/locale-textinfo/package.json @@ -32,8 +32,6 @@ "locales-compile": "pnpm run compile-directions" }, "devDependencies": { - "@types/jest": "^26.0.23", - "locale-data": "workspace:*", - "jest": "^27.0.4" + "locale-data": "workspace:*" } } diff --git a/packages/locale-weekinfo/babel.config.cjs b/packages/locale-weekinfo/babel.config.cjs deleted file mode 100644 index 085ec4d0..00000000 --- a/packages/locale-weekinfo/babel.config.cjs +++ /dev/null @@ -1,4 +0,0 @@ - -module.exports = { - extends: '../../babel.config.cjs', -} diff --git a/packages/locale-weekinfo/jest.config.cjs b/packages/locale-weekinfo/jest.config.cjs deleted file mode 100644 index 6f34bce6..00000000 --- a/packages/locale-weekinfo/jest.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -const base = require('../../jest.config.base.cjs') - -module.exports = { - ...base, - roots: [ - '/src', - ], -} diff --git a/packages/locale-weekinfo/package.json b/packages/locale-weekinfo/package.json index 527b14ec..51a4c7a0 100644 --- a/packages/locale-weekinfo/package.json +++ b/packages/locale-weekinfo/package.json @@ -33,8 +33,6 @@ "locales-compile": "pnpm compile-firstDays && pnpm compile-minimalDays" }, "devDependencies": { - "@types/jest": "^26.0.23", - "locale-data": "workspace:*", - "jest": "^27.0.4" + "locale-data": "workspace:*" } } diff --git a/packages/temporal-polyfill/babel.config.cjs b/packages/temporal-polyfill/babel.config.cjs deleted file mode 100644 index 085ec4d0..00000000 --- a/packages/temporal-polyfill/babel.config.cjs +++ /dev/null @@ -1,4 +0,0 @@ - -module.exports = { - extends: '../../babel.config.cjs', -} diff --git a/packages/temporal-polyfill/jest-setup.js b/packages/temporal-polyfill/jest-setup.js deleted file mode 100644 index 876f6ea6..00000000 --- a/packages/temporal-polyfill/jest-setup.js +++ /dev/null @@ -1,21 +0,0 @@ - -/* -Shims to make tests from @js-temporal/temporal-polyfill conform to Jest -*/ - -/* -Ignore the returned value of test. The tests often do arrow functions like this: - it('test name', () => doSomething()) -*/ -const origTest = global.test -global.test = global.it = function(name, fn, timeout) { - origTest(name, function() { - fn() // don't forward return value - }, timeout) -} - -/* -Simple aliases -*/ -global.before = global.beforeEach -global.after = global.afterEach diff --git a/packages/temporal-polyfill/jest.config.cjs b/packages/temporal-polyfill/jest.config.cjs deleted file mode 100644 index 8baae5b1..00000000 --- a/packages/temporal-polyfill/jest.config.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const base = require('../../jest.config.base.cjs') - -module.exports = { - ...base, - setupFilesAfterEnv: [ - '/jest-setup.js', - ], - moduleNameMapper: { - // TODO: supply the built file when in CI mode - // TODO: way to test built files? - 'temporal-polyfill/impl': '/src/impl.build.ts', - }, - testMatch: [ - '/tests/**/*.js', - ], -} diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 6ebd4351..983428aa 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -29,7 +29,6 @@ "types:watch": "tsc --build --preserveWatchOutput --watch", "bundle": "rollup -c ../../scripts/config/pkgBundle.cjs", "bundle:watch": "rollup -c ../../scripts/config/pkgBundle.cjs --watch", - "test": "jest .", "test262": "node ./runtest262.js", "lint": "eslint .", "size": "node ../../scripts/pkgSize.cjs", @@ -68,16 +67,11 @@ "temporal-spec": "~0.1.0" }, "devDependencies": { - "@types/chai": "^4.2.22", - "@types/jest": "^26.0.24", "@types/node": "^16.9.1", "@js-temporal/temporal-test262-runner": "^0.9.0", "ansi-colors": "^4.1.3", - "chai": "^4.3.4", "concurrently": "^7.6.0", "eslint": "^7.25.0", - "jest": "^27.0.6", - "jest-date-mock": "^1.0.8", "js-yaml": "^4.1.0", "minimatch": "^5.0.1", "progress": "^2.0.3", diff --git a/packages/temporal-polyfill/tests/README.md b/packages/temporal-polyfill/tests/README.md deleted file mode 100644 index 6712442e..00000000 --- a/packages/temporal-polyfill/tests/README.md +++ /dev/null @@ -1,3 +0,0 @@ - -These tests are borrowed from the [@js-temporal/temporal-polyfill repo](https://github.com/js-temporal/temporal-polyfill/tree/main/test) -at [this commit](https://github.com/js-temporal/temporal-polyfill/commit/f2e2658d80af3ded8bb9445a45e8a92e6be85401). diff --git a/packages/temporal-polyfill/tests/calendar.js b/packages/temporal-polyfill/tests/calendar.js deleted file mode 100644 index c9acd47c..00000000 --- a/packages/temporal-polyfill/tests/calendar.js +++ /dev/null @@ -1,401 +0,0 @@ - -// Copyright (C) 2020 Igalia, S.L. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { Calendar } = Temporal; - -describe('Calendar', () => { - describe('Structure', () => { - it('Calendar is a Function', () => { - equal(typeof Calendar, 'function'); - }); - it('Calendar has a prototype', () => { - assert(Calendar.prototype); - equal(typeof Calendar.prototype, 'object'); - }); - describe('Calendar.prototype', () => { - it('Calendar.prototype has id', () => { - assert('id' in Calendar.prototype); - }); - it('Calendar.prototype.dateFromFields is a Function', () => { - equal(typeof Calendar.prototype.dateFromFields, 'function'); - }); - it('Calendar.prototype.yearMonthFromFields is a Function', () => { - equal(typeof Calendar.prototype.yearMonthFromFields, 'function'); - }); - it('Calendar.prototype.monthDayFromFields is a Function', () => { - equal(typeof Calendar.prototype.monthDayFromFields, 'function'); - }); - it('Calendar.prototype.dateAdd is a Function', () => { - equal(typeof Calendar.prototype.dateAdd, 'function'); - }); - it('Calendar.prototype.dateUntil is a Function', () => { - equal(typeof Calendar.prototype.dateUntil, 'function'); - }); - it('Calendar.prototype.year is a Function', () => { - equal(typeof Calendar.prototype.year, 'function'); - }); - it('Calendar.prototype.month is a Function', () => { - equal(typeof Calendar.prototype.month, 'function'); - }); - it('Calendar.prototype.monthCode is a Function', () => { - equal(typeof Calendar.prototype.monthCode, 'function'); - }); - it('Calendar.prototype.day is a Function', () => { - equal(typeof Calendar.prototype.day, 'function'); - }); - it('Calendar.prototype.era is a Function', () => { - equal(typeof Calendar.prototype.era, 'function'); - }); - it('Calendar.prototype.dayOfWeek is a Function', () => { - equal(typeof Calendar.prototype.dayOfWeek, 'function'); - }); - it('Calendar.prototype.dayOfYear is a Function', () => { - equal(typeof Calendar.prototype.dayOfYear, 'function'); - }); - it('Calendar.prototype.weekOfYear is a Function', () => { - equal(typeof Calendar.prototype.weekOfYear, 'function'); - }); - it('Calendar.prototype.daysInWeek is a Function', () => { - equal(typeof Calendar.prototype.daysInWeek, 'function'); - }); - it('Calendar.prototype.daysInMonth is a Function', () => { - equal(typeof Calendar.prototype.daysInMonth, 'function'); - }); - it('Calendar.prototype.daysInYear is a Function', () => { - equal(typeof Calendar.prototype.daysInYear, 'function'); - }); - it('Calendar.prototype.monthsInYear is a Function', () => { - equal(typeof Calendar.prototype.monthsInYear, 'function'); - }); - it('Calendar.prototype.inLeapYear is a Function', () => { - equal(typeof Calendar.prototype.inLeapYear, 'function'); - }); - it('Calendar.prototype.toString is a Function', () => { - equal(typeof Calendar.prototype.toString, 'function'); - }); - }); - it('Calendar.from is a Function', () => { - equal(typeof Calendar.from, 'function'); - }); - }); - const iso = Calendar.from('iso8601'); - describe('Calendar.from()', () => { - describe('from identifier', () => { - test('iso8601'); - test('gregory'); - test('japanese'); - function test(id) { - const calendar = Calendar.from(id); - it(`Calendar.from(${id}) is a calendar`, () => assert(calendar instanceof Calendar)); - it(`Calendar.from(${id}) has the correct ID`, () => equal(calendar.id, id)); - } - it('other types with a calendar are accepted', () => { - [ - Temporal.PlainDate.from('1976-11-18[u-ca=gregory]'), - Temporal.PlainDateTime.from('1976-11-18[u-ca=gregory]'), - Temporal.PlainMonthDay.from('1972-11-18[u-ca=gregory]'), - Temporal.PlainYearMonth.from('1976-11-01[u-ca=gregory]') - ].forEach((obj) => { - const calFrom = Calendar.from(obj); - assert(calFrom instanceof Calendar); - equal(calFrom.id, 'gregory'); - }); - }); - it('property bag with calendar object is accepted', () => { - const cal = new Calendar('iso8601'); - const calFrom = Calendar.from({ calendar: cal }); - assert(calFrom instanceof Calendar); - equal(calFrom.id, 'iso8601'); - }); - it('property bag with string is accepted', () => { - const calFrom = Calendar.from({ calendar: 'iso8601' }); - assert(calFrom instanceof Calendar); - equal(calFrom.id, 'iso8601'); - }); - it('property bag with custom calendar is accepted', () => { - const custom = { id: 'custom-calendar' }; - const calFrom = Calendar.from({ calendar: custom }); - equal(calFrom, custom); - }); - it('throws with bad identifier', () => { - throws(() => Calendar.from('local'), RangeError); - throws(() => Calendar.from('iso-8601'), RangeError); - throws(() => Calendar.from('[u-ca=iso8601]'), RangeError); - }); - it('throws with bad value in property bag', () => { - throws(() => Calendar.from({ calendar: 'local' }), RangeError); - throws(() => Calendar.from({ calendar: { calendar: 'iso8601' } }), RangeError); - }); - }); - describe('Calendar.from(ISO string)', () => { - test('1994-11-05T08:15:30-05:00', 'iso8601'); - test('1994-11-05T08:15:30-05:00[u-ca=gregory]', 'gregory'); - test('1994-11-05T13:15:30Z[u-ca=japanese]', 'japanese'); - function test(isoString, id) { - const calendar = Calendar.from(isoString); - it(`Calendar.from(${isoString}) is a calendar`, () => assert(calendar instanceof Calendar)); - it(`Calendar.from(${isoString}) has ID ${id}`, () => equal(calendar.id, id)); - } - }); - }); - describe('Calendar.dateFromFields()', () => { - it('throws on non-object fields', () => { - ['string', Math.PI, false, 42n, Symbol('sym'), null].forEach((bad) => { - throws(() => iso.dateFromFields(bad, {}), TypeError); - }); - }); - }); - describe('Calendar.monthDayFromFields()', () => { - it('throws on non-object fields', () => { - ['string', Math.PI, false, 42n, Symbol('sym'), null].forEach((bad) => { - throws(() => iso.monthDayFromFields(bad, {}), TypeError); - }); - }); - }); - describe('Calendar.yearMonthFromFields()', () => { - it('throws on non-object fields', () => { - ['string', Math.PI, false, 42n, Symbol('sym'), null].forEach((bad) => { - throws(() => iso.yearMonthFromFields(bad, {}), TypeError); - }); - }); - }); - describe('Calendar.year()', () => { - const res = 1994; - it('accepts Date', () => equal(iso.year(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.year(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts YearMonth', () => equal(iso.year(Temporal.PlainYearMonth.from('1994-11')), res)); - it('casts argument', () => { - equal(iso.year({ year: 1994, month: 11, day: 5 }), res); - equal(iso.year('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.year({ month: 5 }), TypeError); - }); - }); - describe('Calendar.month()', () => { - const res = 11; - it('accepts Date', () => equal(iso.month(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.month(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts YearMonth', () => equal(iso.month(Temporal.PlainYearMonth.from('1994-11')), res)); - it('does not accept MonthDay', () => throws(() => iso.month(Temporal.PlainMonthDay.from('11-05')), TypeError)); - it('casts argument', () => { - equal(iso.month({ year: 1994, month: 11, day: 5 }), res); - equal(iso.month('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.month({ year: 2000 }), TypeError); - }); - }); - describe('Calendar.monthCode()', () => { - const res = 'M11'; - it('accepts Date', () => equal(iso.monthCode(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.monthCode(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts YearMonth', () => equal(iso.monthCode(Temporal.PlainYearMonth.from('1994-11')), res)); - it('accepts MonthDay', () => equal(iso.monthCode(Temporal.PlainMonthDay.from('11-05')), res)); - it('casts argument', () => { - equal(iso.monthCode({ year: 1994, month: 11, day: 5 }), res); - equal(iso.monthCode('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.monthCode({ year: 2000 }), TypeError); - }); - }); - describe('Calendar.day()', () => { - const res = 5; - it('accepts Date', () => equal(iso.day(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.day(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts MonthDay', () => equal(iso.day(Temporal.PlainMonthDay.from('11-05')), res)); - it('casts argument', () => { - equal(iso.day({ year: 1994, month: 11, day: 5 }), res); - equal(iso.day('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.day({ year: 2000 }), TypeError); - }); - }); - describe('Calendar.dayOfWeek()', () => { - const res = 5; - it('accepts Date', () => equal(iso.dayOfWeek(Temporal.PlainDate.from('2020-10-23')), res)); - it('accepts DateTime', () => equal(iso.dayOfWeek(Temporal.PlainDateTime.from('2020-10-23T08:15:30')), res)); - it('casts argument', () => { - equal(iso.dayOfWeek({ year: 2020, month: 10, day: 23 }), res); - equal(iso.dayOfWeek('2020-10-23'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.dayOfWeek({ year: 2000 }), TypeError); - }); - }); - describe('Calendar.dayOfYear()', () => { - const res = 32; - it('accepts Date', () => equal(iso.dayOfYear(Temporal.PlainDate.from('1994-02-01')), res)); - it('accepts DateTime', () => equal(iso.dayOfYear(Temporal.PlainDateTime.from('1994-02-01T08:15:30')), res)); - it('casts argument', () => { - equal(iso.dayOfYear({ year: 1994, month: 2, day: 1 }), res); - equal(iso.dayOfYear('1994-02-01'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.dayOfYear({ year: 2000 }), TypeError); - }); - }); - describe('Calendar.weekOfYear()', () => { - const res = 44; - it('accepts Date', () => equal(iso.weekOfYear(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.weekOfYear(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('casts argument', () => { - equal(iso.weekOfYear({ year: 1994, month: 11, day: 5 }), res); - equal(iso.weekOfYear('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.weekOfYear({ year: 2000 }), TypeError); - }); - }); - describe('edge cases for Calendar.weekOfYear()', () => { - it('week 1 from next year', () => equal(iso.weekOfYear(Temporal.PlainDate.from('2019-12-31')), 1)); - it('week 53 from previous year', () => equal(iso.weekOfYear(Temporal.PlainDate.from('2021-01-01')), 53)); - }); - describe('Calendar.daysInWeek()', () => { - const res = 7; - it('accepts Date', () => equal(iso.daysInWeek(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.daysInWeek(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('casts argument', () => { - equal(iso.daysInWeek({ year: 1994, month: 11, day: 5 }), res); - equal(iso.daysInWeek('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.daysInWeek({ year: 2000 }), TypeError); - }); - }); - describe('Calendar.daysInMonth()', () => { - const res = 30; - it('accepts Date', () => equal(iso.daysInMonth(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.daysInMonth(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts YearMonth', () => equal(iso.daysInMonth(Temporal.PlainYearMonth.from('1994-11')), res)); - it('casts argument', () => { - equal(iso.daysInMonth({ year: 1994, month: 11, day: 5 }), res); - equal(iso.daysInMonth('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.daysInMonth({ year: 2000 }), TypeError); - }); - }); - describe('Calendar.daysInYear()', () => { - const res = 365; - it('accepts Date', () => equal(iso.daysInYear(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.daysInYear(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts YearMonth', () => equal(iso.daysInYear(Temporal.PlainYearMonth.from('1994-11')), res)); - it('casts argument', () => { - equal(iso.daysInYear({ year: 1994, month: 11, day: 5 }), res); - equal(iso.daysInYear('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.daysInYear({ month: 11 }), TypeError); - }); - }); - describe('Calendar.monthsInYear()', () => { - const res = 12; - it('accepts Date', () => equal(iso.monthsInYear(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.monthsInYear(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts YearMonth', () => equal(iso.monthsInYear(Temporal.PlainYearMonth.from('1994-11')), res)); - it('casts argument', () => { - equal(iso.monthsInYear({ year: 1994, month: 11, day: 5 }), res); - equal(iso.monthsInYear('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.monthsInYear({ month: 11 }), TypeError); - }); - }); - describe('Calendar.inLeapYear()', () => { - const res = false; - it('accepts Date', () => equal(iso.inLeapYear(Temporal.PlainDate.from('1994-11-05')), res)); - it('accepts DateTime', () => equal(iso.inLeapYear(Temporal.PlainDateTime.from('1994-11-05T08:15:30')), res)); - it('accepts YearMonth', () => equal(iso.inLeapYear(Temporal.PlainYearMonth.from('1994-11')), res)); - it('casts argument', () => { - equal(iso.inLeapYear({ year: 1994, month: 11, day: 5 }), res); - equal(iso.inLeapYear('1994-11-05'), res); - }); - it('object must contain at least the required properties', () => { - throws(() => iso.inLeapYear({ month: 11 }), TypeError); - }); - }); - describe('Calendar.dateAdd()', () => { - const date = Temporal.PlainDate.from('1994-11-05'); - const duration = Temporal.Duration.from({ months: 1, weeks: 1 }); - it('casts date argument', () => { - equal( - `${iso.dateAdd(Temporal.PlainDateTime.from('1994-11-05T08:15:30'), duration, {}, Temporal.PlainDate)}`, - '1994-12-12' - ); - equal(`${iso.dateAdd({ year: 1994, month: 11, day: 5 }, duration, {}, Temporal.PlainDate)}`, '1994-12-12'); - equal(`${iso.dateAdd('1994-11-05', duration, {}, Temporal.PlainDate)}`, '1994-12-12'); - }); - it('date object must contain at least the required properties', () => { - throws(() => iso.dateAdd({ month: 11 }, duration, {}, Temporal.PlainDate), TypeError); - }); - it('casts duration argument', () => { - equal(`${iso.dateAdd(date, { months: 1, weeks: 1 }, {}, Temporal.PlainDate)}`, '1994-12-12'); - equal(`${iso.dateAdd(date, 'P1M1W', {}, Temporal.PlainDate)}`, '1994-12-12'); - }); - it('duration object must contain at least one correctly-spelled property', () => { - throws(() => iso.dateAdd(date, { month: 1 }, {}, Temporal.PlainDate), TypeError); - }); - }); - describe('Calendar.dateAdd() (negative duration)', () => { - const duration = Temporal.Duration.from({ months: 1, weeks: 1 }).negated(); - it('casts date argument', () => { - equal(`${iso.dateAdd(Temporal.PlainDateTime.from('1994-11-05T08:15:30'), duration, {})}`, '1994-09-28'); - equal(`${iso.dateAdd({ year: 1994, month: 11, day: 5 }, duration, {})}`, '1994-09-28'); - equal(`${iso.dateAdd('1994-11-05', duration, {})}`, '1994-09-28'); - }); - }); - describe('Calendar.dateUntil()', () => { - const date1 = Temporal.PlainDate.from('1999-09-03'); - const date2 = Temporal.PlainDate.from('2000-01-01'); - it('casts first argument', () => { - equal(`${iso.dateUntil(Temporal.PlainDateTime.from('1999-09-03T08:15:30'), date2, {})}`, 'P120D'); - equal(`${iso.dateUntil({ year: 1999, month: 9, day: 3 }, date2, {})}`, 'P120D'); - equal(`${iso.dateUntil('1999-09-03', date2, {})}`, 'P120D'); - }); - it('casts second argument', () => { - equal(`${iso.dateUntil(date1, Temporal.PlainDateTime.from('2000-01-01T08:15:30'), {})}`, 'P120D'); - equal(`${iso.dateUntil(date1, { year: 2000, month: 1, day: 1 }, {})}`, 'P120D'); - equal(`${iso.dateUntil(date1, '2000-01-01', {})}`, 'P120D'); - }); - it('objects must contain at least the required properties', () => { - throws(() => iso.dateUntil({ month: 11 }, date2, {}), TypeError); - throws(() => iso.dateUntil(date1, { month: 11 }, {}), TypeError); - }); - }); -}); -describe('Built-in calendars (not standardized yet)', () => { - describe('gregory', () => { - it('era CE', () => { - const date = Temporal.PlainDate.from('1999-12-31[u-ca=gregory]'); - equal(date.era, 'ce'); - equal(date.eraYear, 1999); - equal(date.year, 1999); - }); - it('era BCE', () => { - const date = Temporal.PlainDate.from('-000001-12-31[u-ca=gregory]'); - equal(date.era, 'bce'); - equal(date.eraYear, 2); - equal(date.year, -1); - }); - it('can create from fields with era CE', () => { - const date = Temporal.PlainDate.from({ era: 'ce', eraYear: 1999, month: 12, day: 31, calendar: 'gregory' }); - equal(`${date}`, '1999-12-31[u-ca=gregory]'); - }); - it('era CE is the default', () => { - const date = Temporal.PlainDate.from({ year: 1999, month: 12, day: 31, calendar: 'gregory' }); - equal(`${date}`, '1999-12-31[u-ca=gregory]'); - }); - it('can create from fields with era BCE', () => { - const date = Temporal.PlainDate.from({ era: 'bce', eraYear: 2, month: 12, day: 31, calendar: 'gregory' }); - equal(`${date}`, '-000001-12-31[u-ca=gregory]'); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/dateMath.js b/packages/temporal-polyfill/tests/dateMath.js deleted file mode 100644 index 739010ae..00000000 --- a/packages/temporal-polyfill/tests/dateMath.js +++ /dev/null @@ -1,90 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; - -describe('Date.since(simple, simple)', () => { - build('Before Leap Day', '2020-01-03', '2020-02-15'); - build('Before Leap Day', '2020-01-28', '2020-02-15'); - build('Before Leap Day', '2020-01-31', '2020-02-15'); - build('Cross Leap Day', '2020-01-31', '2020-06-30'); - build('After Leap Day', '2020-03-31', '2020-06-30'); - build('After Leap Day', '2020-03-25', '2020-07-31'); -}); -describe('Date.since(normal, normal)', () => { - build('Month<2 & Month<2', '2018-01-20', '2019-01-05'); - build('Month>2 & Month>2', '2018-03-20', '2019-03-05'); - build('Month>2 & Month>2', '2018-04-20', '2019-04-05'); - build('Month<2 & Month>2', '2018-01-20', '2019-04-05'); - build('Month>2 & Month<2', '2018-03-20', '2019-01-05'); - build('Month>2 & Month<2', '2018-04-20', '2019-01-05'); -}); -describe('Date.since(leap, leap)', () => { - build('Month<2 & Month<2', '2016-01-20', '2020-01-05'); - build('Month>2 & Month>2', '2016-03-20', '2020-04-05'); - build('Month>2 & Month>2', '2016-03-20', '2020-03-05'); - build('Month<2 & Month>2', '2016-01-20', '2020-02-05'); - build('Month>2 & Month<2', '2016-03-20', '2020-01-05'); - build('Month>2 & Month<2', '2016-04-20', '2020-01-05'); -}); -describe('Date.since(leap, normal)', () => { - build('Month<2 & Month<2', '2016-01-20', '2017-01-05'); - build('Month>2 & Month>2', '2016-03-20', '2017-04-05'); - build('Month>2 & Month>2', '2016-04-20', '2017-03-05'); - build('Month<2 & Month>2', '2016-01-20', '2017-04-05'); - build('Month>2 & Month<2', '2016-03-20', '2017-01-05'); - build('Month>2 & Month<2', '2016-04-20', '2017-01-05'); -}); -describe('Date.since(normal, leap)', () => { - build('Month<2 & Month<2', '2019-01-20', '2020-01-05'); - build('Month>2 & Month>2', '2019-03-20', '2020-04-05'); - build('Month>2 & Month>2', '2019-04-20', '2020-03-05'); - build('Month<2 & Month>2', '2019-01-20', '2020-04-05'); - build('Month>2 & Month<2', '2019-03-20', '2020-01-05'); - build('Month>2 & Month<2', '2019-04-20', '2020-01-05'); -}); - -function build(name, sone, stwo) { - const calendars = ['iso8601', 'gregory']; - describe(name, () => { - const largestUnits = ['years', 'months', 'weeks', 'days']; - for (const calendar of calendars) { - const [one, two] = [ - Temporal.PlainDate.from(sone).withCalendar(calendar), - Temporal.PlainDate.from(stwo).withCalendar(calendar) - ].sort(Temporal.PlainDate.compare); - buildSub(one, two, largestUnits); - buildSub(one.with({ day: 25 }), two.with({ day: 5 }), largestUnits); - buildSub(one.with({ day: 30 }), two.with({ day: 29 }), largestUnits); - buildSub(one.with({ day: 30 }), two.with({ day: 5 }), largestUnits); - } - }); -} -function buildSub(one, two, largestUnits) { - largestUnits.forEach((largestUnit) => { - describe(`< ${one} : ${two} (${largestUnit})>`, () => { - const dif = two.since(one, { largestUnit }); - const overflow = 'reject'; - if (largestUnit === 'months' || largestUnit === 'years') { - // For months and years, `until` and `since` won't agree because the - // starting point is always `this` and month-aware arithmetic behavior - // varies based on the starting point. - it(`(${two}).subtract(${dif}) => ${one}`, () => assert(two.subtract(dif).equals(one))); - it(`(${two}).add(-${dif}) => ${one}`, () => assert(two.add(dif.negated()).equals(one))); - const difUntil = one.until(two, { largestUnit }); - it(`(${one}).subtract(-${difUntil}) => ${two}`, () => assert(one.subtract(difUntil.negated()).equals(two))); - it(`(${one}).add(${difUntil}) => ${two}`, () => assert(one.add(difUntil).equals(two))); - } else { - it('until() and since() agree', () => equal(`${dif}`, `${one.until(two, { largestUnit })}`)); - it(`(${one}).add(${dif}) => ${two}`, () => assert(one.add(dif, { overflow }).equals(two))); - it(`(${two}).subtract(${dif}) => ${one}`, () => assert(two.subtract(dif, { overflow }).equals(one))); - it(`(${one}).subtract(-${dif}) => ${two}`, () => assert(one.subtract(dif.negated(), { overflow }).equals(two))); - it(`(${two}).add(-${dif}) => ${one}`, () => assert(two.add(dif.negated(), { overflow }).equals(one))); - } - }); - }); -} diff --git a/packages/temporal-polyfill/tests/duration.js b/packages/temporal-polyfill/tests/duration.js deleted file mode 100644 index 05bc7ed7..00000000 --- a/packages/temporal-polyfill/tests/duration.js +++ /dev/null @@ -1,2024 +0,0 @@ - -import { assert } from 'chai'; -const { throws, strictEqual: equal, notStrictEqual: notEqual } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { Duration } = Temporal; - -describe('Duration', () => { - describe('Structure', () => { - it('Duration is a Function', () => { - equal(typeof Duration, 'function'); - }); - it('Duration has a prototype', () => { - assert(Duration.prototype); - equal(typeof Duration.prototype, 'object'); - }); - describe('Duration.prototype', () => { - it('Duration.prototype has sign', () => { - assert('sign' in Duration.prototype); - }); - it('Duration.prototype has blank', () => { - assert('blank' in Duration.prototype); - }); - it('Duration.prototype.with is a Function', () => { - equal(typeof Duration.prototype.with, 'function'); - }); - it('Duration.prototype.add is a Function', () => { - equal(typeof Duration.prototype.add, 'function'); - }); - it('Duration.prototype.subtract is a Function', () => { - equal(typeof Duration.prototype.subtract, 'function'); - }); - it('Duration.prototype.negated is a Function', () => { - equal(typeof Duration.prototype.negated, 'function'); - }); - it('Duration.prototype.abs is a Function', () => { - equal(typeof Duration.prototype.abs, 'function'); - }); - it('Duration.prototype.round is a Function', () => { - equal(typeof Duration.prototype.round, 'function'); - }); - }); - it('Duration.compare is a Function', () => { - equal(typeof Duration.compare, 'function'); - }); - }); - describe('Construction', () => { - it('positive duration, sets fields', () => { - const d = new Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 0); - equal(d.sign, 1); - equal(d.years, 5); - equal(d.months, 5); - equal(d.weeks, 5); - equal(d.days, 5); - equal(d.hours, 5); - equal(d.minutes, 5); - equal(d.seconds, 5); - equal(d.milliseconds, 5); - equal(d.microseconds, 5); - equal(d.nanoseconds, 0); - }); - it('negative duration, sets fields', () => { - const d = new Duration(-5, -5, -5, -5, -5, -5, -5, -5, -5, 0); - equal(d.sign, -1); - equal(d.years, -5); - equal(d.months, -5); - equal(d.weeks, -5); - equal(d.days, -5); - equal(d.hours, -5); - equal(d.minutes, -5); - equal(d.seconds, -5); - equal(d.milliseconds, -5); - equal(d.microseconds, -5); - equal(d.nanoseconds, 0); - }); - it('zero-length, sets fields', () => { - const d = new Duration(); - equal(d.sign, 0); - equal(d.years, 0); - equal(d.months, 0); - equal(d.weeks, 0); - equal(d.days, 0); - equal(d.hours, 0); - equal(d.minutes, 0); - equal(d.seconds, 0); - equal(d.milliseconds, 0); - equal(d.microseconds, 0); - equal(d.nanoseconds, 0); - }); - it('constructor treats -0 as 0', () => { - const d = new Duration(-0, -0, -0, -0, -0, -0, -0, -0, -0, -0); - equal(d.sign, 0); - equal(d.years, 0); - equal(d.months, 0); - equal(d.weeks, 0); - equal(d.days, 0); - equal(d.hours, 0); - equal(d.minutes, 0); - equal(d.seconds, 0); - equal(d.milliseconds, 0); - equal(d.microseconds, 0); - equal(d.nanoseconds, 0); - }); - it('mixed positive and negative values throw', () => { - throws(() => new Duration(-1, 1, 1, 1, 1, 1, 1, 1, 1, 1), RangeError); - throws(() => new Duration(1, -1, 1, 1, 1, 1, 1, 1, 1, 1), RangeError); - throws(() => new Duration(1, 1, -1, 1, 1, 1, 1, 1, 1, 1), RangeError); - throws(() => new Duration(1, 1, 1, -1, 1, 1, 1, 1, 1, 1), RangeError); - throws(() => new Duration(1, 1, 1, 1, -1, 1, 1, 1, 1, 1), RangeError); - throws(() => new Duration(1, 1, 1, 1, 1, -1, 1, 1, 1, 1), RangeError); - throws(() => new Duration(1, 1, 1, 1, 1, 1, -1, 1, 1, 1), RangeError); - throws(() => new Duration(1, 1, 1, 1, 1, 1, 1, -1, 1, 1), RangeError); - throws(() => new Duration(1, 1, 1, 1, 1, 1, 1, 1, -1, 1), RangeError); - throws(() => new Duration(1, 1, 1, 1, 1, 1, 1, 1, 1, -1), RangeError); - }); - it('fractional values throw', () => { - throws(() => new Duration(1.1), RangeError); - throws(() => new Duration(0, 1.1), RangeError); - throws(() => new Duration(0, 0, 1.1), RangeError); - throws(() => new Duration(0, 0, 0, 1.1), RangeError); - throws(() => new Duration(0, 0, 0, 0, 1.1), RangeError); - throws(() => new Duration(0, 0, 0, 0, 0, 1.1), RangeError); - throws(() => new Duration(0, 0, 0, 0, 0, 0, 1.1), RangeError); - throws(() => new Duration(0, 0, 0, 0, 0, 0, 0, 1.1), RangeError); - throws(() => new Duration(0, 0, 0, 0, 0, 0, 0, 0, 1.1), RangeError); - throws(() => new Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 1.1), RangeError); - }); - }); - describe('from()', () => { - it('Duration.from(P5Y) is not the same object', () => { - const orig = new Duration(5); - const from = Duration.from(orig); - notEqual(from, orig); - }); - it('Duration.from({ milliseconds: 5 }) == PT0.005S', () => - equal(`${Duration.from({ milliseconds: 5 })}`, 'PT0.005S')); - it('Duration.from("P1D") == P1D', () => equal(`${Duration.from('P1D')}`, 'P1D')); - it('lowercase variant', () => equal(`${Duration.from('p1y1m1dt1h1m1s')}`, 'P1Y1M1DT1H1M1S')); - it('upto nine decimal places work', () => { - equal(`${Duration.from('P1Y1M1W1DT1H1M1.1S')}`, 'P1Y1M1W1DT1H1M1.1S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.12S')}`, 'P1Y1M1W1DT1H1M1.12S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.123S')}`, 'P1Y1M1W1DT1H1M1.123S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.1234S')}`, 'P1Y1M1W1DT1H1M1.1234S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.12345S')}`, 'P1Y1M1W1DT1H1M1.12345S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.123456S')}`, 'P1Y1M1W1DT1H1M1.123456S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.1234567S')}`, 'P1Y1M1W1DT1H1M1.1234567S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.12345678S')}`, 'P1Y1M1W1DT1H1M1.12345678S'); - equal(`${Duration.from('P1Y1M1W1DT1H1M1.123456789S')}`, 'P1Y1M1W1DT1H1M1.123456789S'); - }); - it('above nine decimal places throw', () => { - throws(() => Duration.from('P1Y1M1W1DT1H1M1.123456789123S'), RangeError); - }); - it('variant decimal separator', () => { - equal(`${Duration.from('P1Y1M1W1DT1H1M1,12S')}`, 'P1Y1M1W1DT1H1M1.12S'); - }); - it('decimal places only allowed in time units', () => { - [ - 'P0.5Y', - 'P1Y0,5M', - 'P1Y1M0.5W', - 'P1Y1M1W0,5D', - { years: 0.5 }, - { months: 0.5 }, - { weeks: 0.5 }, - { days: 0.5 } - ].forEach((str) => throws(() => Duration.from(str), RangeError)); - }); - it('decimal places only allowed in last non-zero unit', () => { - [ - 'P1Y1M1W1DT0.5H5S', - 'P1Y1M1W1DT1.5H0,5M', - 'P1Y1M1W1DT1H0.5M0.5S', - { hours: 0.5, minutes: 20 }, - { hours: 0.5, seconds: 15 }, - { minutes: 10.7, nanoseconds: 400 } - ].forEach((str) => throws(() => Duration.from(str), RangeError)); - }); - it('decimal places are properly handled on valid units', () => { - equal(`${Duration.from('P1DT0.5M')}`, 'P1DT30S'); - equal(`${Duration.from('P1DT0,5H')}`, 'P1DT30M'); - }); - it('"P" by itself is not a valid string', () => { - ['P', 'PT', '-P', '-PT', '+P', '+PT'].forEach((s) => throws(() => Duration.from(s), RangeError)); - }); - it('no junk at end of string', () => throws(() => Duration.from('P1Y1M1W1DT1H1M1.01Sjunk'), RangeError)); - it('with a + sign', () => { - const d = Duration.from('+P1D'); - equal(d.days, 1); - }); - it('with a - sign', () => { - const d = Duration.from('-P1D'); - equal(d.days, -1); - }); - it('variant minus sign', () => { - const d = Duration.from('\u2212P1D'); - equal(d.days, -1); - }); - it('all units have the same sign', () => { - const d = Duration.from('-P1Y1M1W1DT1H1M1.123456789S'); - equal(d.years, -1); - equal(d.months, -1); - equal(d.weeks, -1); - equal(d.days, -1); - equal(d.hours, -1); - equal(d.minutes, -1); - equal(d.seconds, -1); - equal(d.milliseconds, -123); - equal(d.microseconds, -456); - equal(d.nanoseconds, -789); - }); - it('does not accept minus signs in individual units', () => { - throws(() => Duration.from('P-1Y1M'), RangeError); - throws(() => Duration.from('P1Y-1M'), RangeError); - }); - it('mixed positive and negative values throw', () => { - throws(() => Duration.from({ hours: 1, minutes: -30 }), RangeError); - }); - it('excessive values unchanged', () => { - equal(`${Duration.from({ minutes: 100 })}`, 'PT100M'); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => Duration.from({}), TypeError); - throws(() => Duration.from({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${Duration.from({ month: 1, days: 1 })}`, 'P1D'); - }); - }); - describe('toString()', () => { - it('excessive sub-second units balance themselves when serializing', () => { - equal(`${Duration.from({ milliseconds: 3500 })}`, 'PT3.5S'); - equal(`${Duration.from({ microseconds: 3500 })}`, 'PT0.0035S'); - equal(`${Duration.from({ nanoseconds: 3500 })}`, 'PT0.0000035S'); - equal(`${new Duration(0, 0, 0, 0, 0, 0, 0, 1111, 1111, 1111)}`, 'PT1.112112111S'); - equal(`${Duration.from({ seconds: 120, milliseconds: 3500 })}`, 'PT123.5S'); - }); - it('negative sub-second units are balanced correctly', () => { - equal(`${Duration.from({ milliseconds: -250 })}`, '-PT0.25S'); - equal(`${Duration.from({ milliseconds: -3500 })}`, '-PT3.5S'); - equal(`${Duration.from({ microseconds: -250 })}`, '-PT0.00025S'); - equal(`${Duration.from({ microseconds: -3500 })}`, '-PT0.0035S'); - equal(`${Duration.from({ nanoseconds: -250 })}`, '-PT0.00000025S'); - equal(`${Duration.from({ nanoseconds: -3500 })}`, '-PT0.0000035S'); - equal(`${new Duration(0, 0, 0, 0, 0, 0, 0, -1111, -1111, -1111)}`, '-PT1.112112111S'); - equal(`${Duration.from({ seconds: -120, milliseconds: -3500 })}`, '-PT123.5S'); - }); - it('emits a negative sign for a negative duration', () => { - equal(`${Duration.from({ weeks: -1, days: -1 })}`, '-P1W1D'); - }); - it("serializing balance doesn't trip out-of-range", () => { - const d = Duration.from({ seconds: Number.MAX_VALUE, milliseconds: Number.MAX_VALUE }); - const str = d.toString(); - assert(str.startsWith('PT')); - assert(str.endsWith('S')); - // actual string representation may vary, since MAX_VALUE is not precise - }); - it("serializing balance doesn't lose precision when values are precise", () => { - const d = Duration.from({ milliseconds: Number.MAX_SAFE_INTEGER, microseconds: Number.MAX_SAFE_INTEGER }); - equal(`${d}`, 'PT9016206453995.731991S'); - }); - const d1 = new Duration(0, 0, 0, 0, 15, 23); - const d2 = new Duration(0, 0, 0, 0, 15, 23, 30); - const d3 = new Duration(0, 0, 0, 0, 15, 23, 30, 543, 200); - it('smallestUnits are aliases for fractional digits', () => { - equal(d3.toString({ smallestUnit: 'seconds' }), d3.toString({ fractionalSecondDigits: 0 })); - equal(d3.toString({ smallestUnit: 'milliseconds' }), d3.toString({ fractionalSecondDigits: 3 })); - equal(d3.toString({ smallestUnit: 'microseconds' }), d3.toString({ fractionalSecondDigits: 6 })); - equal(d3.toString({ smallestUnit: 'nanoseconds' }), d3.toString({ fractionalSecondDigits: 9 })); - }); - it('throws on invalid or disallowed smallestUnit', () => { - ['eras', 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'nonsense'].forEach((smallestUnit) => - throws(() => d1.toString({ smallestUnit }), RangeError) - ); - }); - it('accepts singular units', () => { - equal(d3.toString({ smallestUnit: 'second' }), d3.toString({ smallestUnit: 'seconds' })); - equal(d3.toString({ smallestUnit: 'millisecond' }), d3.toString({ smallestUnit: 'milliseconds' })); - equal(d3.toString({ smallestUnit: 'microsecond' }), d3.toString({ smallestUnit: 'microseconds' })); - equal(d3.toString({ smallestUnit: 'nanosecond' }), d3.toString({ smallestUnit: 'nanoseconds' })); - }); - it('truncates or pads to 2 places', () => { - const options = { fractionalSecondDigits: 2 }; - equal(d1.toString(options), 'PT15H23M0.00S'); - equal(d2.toString(options), 'PT15H23M30.00S'); - equal(d3.toString(options), 'PT15H23M30.54S'); - }); - it('pads to 7 places', () => { - const options = { fractionalSecondDigits: 7 }; - equal(d1.toString(options), 'PT15H23M0.0000000S'); - equal(d2.toString(options), 'PT15H23M30.0000000S'); - equal(d3.toString(options), 'PT15H23M30.5432000S'); - }); - it('pads correctly in edge cases', () => { - const d4 = Duration.from({ years: 3 }); - equal(d4.toString(), 'P3Y'); - equal(d4.toString({ fractionalSecondDigits: 0 }), 'P3YT0S'); - equal(d4.toString({ smallestUnit: 'seconds' }), 'P3YT0S'); - equal(d4.toString({ smallestUnit: 'milliseconds' }), 'P3YT0.000S'); - equal(d4.toString({ fractionalSecondDigits: 5 }), 'P3YT0.00000S'); - - const d5 = Duration.from({ minutes: 30 }); - equal(d5.toString(), 'PT30M'); - equal(d5.toString({ fractionalSecondDigits: 0 }), 'PT30M0S'); - equal(d5.toString({ smallestUnit: 'seconds' }), 'PT30M0S'); - equal(d5.toString({ smallestUnit: 'milliseconds' }), 'PT30M0.000S'); - equal(d5.toString({ fractionalSecondDigits: 5 }), 'PT30M0.00000S'); - - const d6 = Duration.from({ milliseconds: 100 }); - equal(d6.toString(), 'PT0.1S'); - equal(d6.toString({ fractionalSecondDigits: 0 }), 'PT0S'); - equal(d6.toString({ smallestUnit: 'seconds' }), 'PT0S'); - equal(d6.toString({ smallestUnit: 'milliseconds' }), 'PT0.100S'); - equal(d6.toString({ fractionalSecondDigits: 5 }), 'PT0.10000S'); - - const zero = new Duration(); - equal(zero.toString(), 'PT0S'); - equal(zero.toString({ fractionalSecondDigits: 0 }), 'PT0S'); - equal(zero.toString({ smallestUnit: 'seconds' }), 'PT0S'); - equal(zero.toString({ smallestUnit: 'milliseconds' }), 'PT0.000S'); - equal(zero.toString({ fractionalSecondDigits: 5 }), 'PT0.00000S'); - }); - it('auto is the default', () => { - [d1, d2, d3].forEach((d) => equal(d.toString({ fractionalSecondDigits: 'auto' }), d.toString())); - }); - it('throws on out of range or invalid fractionalSecondDigits', () => { - [-1, 10, Infinity, NaN, 'not-auto'].forEach((fractionalSecondDigits) => - throws(() => d1.toString({ fractionalSecondDigits }), RangeError) - ); - }); - it('accepts and truncates fractional fractionalSecondDigits', () => { - equal(d3.toString({ fractionalSecondDigits: 5.5 }), 'PT15H23M30.54320S'); - }); - it('smallestUnit overrides fractionalSecondDigits', () => { - equal(d3.toString({ smallestUnit: 'seconds', fractionalSecondDigits: 9 }), 'PT15H23M30S'); - }); - it('throws on invalid roundingMode', () => { - throws(() => d1.toString({ roundingMode: 'cile' }), RangeError); - }); - it('rounds to nearest', () => { - equal(d3.toString({ smallestUnit: 'seconds', roundingMode: 'halfExpand' }), 'PT15H23M31S'); - equal(d3.toString({ fractionalSecondDigits: 3, roundingMode: 'halfExpand' }), 'PT15H23M30.543S'); - }); - it('rounds up', () => { - equal(d3.toString({ smallestUnit: 'seconds', roundingMode: 'ceil' }), 'PT15H23M31S'); - equal(d3.toString({ fractionalSecondDigits: 3, roundingMode: 'ceil' }), 'PT15H23M30.544S'); - }); - it('rounds down', () => { - equal(d3.negated().toString({ smallestUnit: 'seconds', roundingMode: 'floor' }), '-PT15H23M31S'); - equal(d3.negated().toString({ fractionalSecondDigits: 3, roundingMode: 'floor' }), '-PT15H23M30.544S'); - }); - it('truncates', () => { - equal(d3.toString({ smallestUnit: 'seconds', roundingMode: 'trunc' }), 'PT15H23M30S'); - equal(d3.toString({ fractionalSecondDigits: 3, roundingMode: 'trunc' }), 'PT15H23M30.543S'); - }); - it('rounding can affect units up to seconds', () => { - const d4 = Duration.from('P1Y1M1W1DT23H59M59.999999999S'); - equal(d4.toString({ fractionalSecondDigits: 8, roundingMode: 'halfExpand' }), 'P1Y1M1W1DT23H59M60.00000000S'); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => d1.toString(badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(d1.toString(options), 'PT15H23M')); - }); - }); - describe('toJSON()', () => { - it('is like toString but always with auto precision', () => { - const d = Duration.from({ hours: 1 }); - equal(d.toJSON(), d.toString({ fractionalSecondDigits: 'auto' })); - }); - }); - describe('toLocaleString()', () => { - it('produces an implementation-defined string', () => { - const duration = Duration.from({ hours: 12, minutes: 30 }); - equal(typeof duration.toLocaleString(), 'string'); - }); - }); - describe('min/max values', () => { - const units = [ - 'years', - 'months', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ]; - it('minimum is zero', () => { - equal(`${new Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)}`, 'PT0S'); - units.forEach((unit) => equal(`${Duration.from({ [unit]: 0 })}`, 'PT0S')); - ['P0Y', 'P0M', 'P0W', 'P0D', 'PT0H', 'PT0M', 'PT0S'].forEach((str) => equal(`${Duration.from(str)}`, 'PT0S')); - }); - it('unrepresentable number is not allowed', () => { - units.forEach((unit, ix) => { - // eslint-disable-next-line @typescript-eslint/no-loss-of-precision,no-loss-of-precision - throws(() => new Duration(...Array(ix).fill(0), 1e309), RangeError); - // eslint-disable-next-line @typescript-eslint/no-loss-of-precision,no-loss-of-precision - throws(() => Duration.from({ [unit]: 1e309 }), RangeError); - }); - const manyNines = '9'.repeat(309); - [ - `P${manyNines}Y`, - `P${manyNines}M`, - `P${manyNines}W`, - `P${manyNines}D`, - `PT${manyNines}H`, - `PT${manyNines}M`, - `PT${manyNines}S` - ].forEach((str) => throws(() => Duration.from(str), RangeError)); - }); - it('max safe integer is allowed', () => { - [ - 'P9007199254740991Y', - 'P9007199254740991M', - 'P9007199254740991W', - 'P9007199254740991D', - 'PT9007199254740991H', - 'PT9007199254740991M', - 'PT9007199254740991S', - 'PT9007199254740.991S', - 'PT9007199254.740991S', - 'PT9007199.254740991S' - ].forEach((str, ix) => { - equal(`${new Duration(...Array(ix).fill(0), Number.MAX_SAFE_INTEGER)}`, str); - equal(`${Duration.from(str)}`, str); - }); - }); - it('larger integers are allowed but may lose precision', () => { - function test(ix, prefix, suffix, infix = '') { - function doAsserts(duration) { - const str = duration.toString(); - equal(str.slice(0, prefix.length + 10), `${prefix}1000000000`); - assert(str.includes(infix)); - equal(str.slice(-1), suffix); - equal(str.length, prefix.length + suffix.length + infix.length + 27); - } - doAsserts(new Duration(...Array(ix).fill(0), 1e26, ...Array(9 - ix).fill(0))); - doAsserts(Duration.from({ [units[ix]]: 1e26 })); - if (!infix) doAsserts(Duration.from(`${prefix}100000000000000000000000000${suffix}`)); - } - test(0, 'P', 'Y'); - test(1, 'P', 'M'); - test(2, 'P', 'W'); - test(3, 'P', 'D'); - test(4, 'PT', 'H'); - test(5, 'PT', 'M'); - test(6, 'PT', 'S'); - test(7, 'PT', 'S', '.'); - test(8, 'PT', 'S', '.'); - test(9, 'PT', 'S', '.'); - }); - }); - describe('Duration.with()', () => { - const duration = new Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5); - it('duration.with({ years: 1 } works', () => { - equal(`${duration.with({ years: 1 })}`, 'P1Y5M5W5DT5H5M5.005005005S'); - }); - it('duration.with({ months: 1 } works', () => { - equal(`${duration.with({ months: 1 })}`, 'P5Y1M5W5DT5H5M5.005005005S'); - }); - it('duration.with({ weeks: 1 } works', () => { - equal(`${duration.with({ weeks: 1 })}`, 'P5Y5M1W5DT5H5M5.005005005S'); - }); - it('duration.with({ days: 1 } works', () => { - equal(`${duration.with({ days: 1 })}`, 'P5Y5M5W1DT5H5M5.005005005S'); - }); - it('duration.with({ hours: 1 } works', () => { - equal(`${duration.with({ hours: 1 })}`, 'P5Y5M5W5DT1H5M5.005005005S'); - }); - it('duration.with({ minutes: 1 } works', () => { - equal(`${duration.with({ minutes: 1 })}`, 'P5Y5M5W5DT5H1M5.005005005S'); - }); - it('duration.with({ seconds: 1 } works', () => { - equal(`${duration.with({ seconds: 1 })}`, 'P5Y5M5W5DT5H5M1.005005005S'); - }); - it('duration.with({ milliseconds: 1 } works', () => { - equal(`${duration.with({ milliseconds: 1 })}`, 'P5Y5M5W5DT5H5M5.001005005S'); - }); - it('duration.with({ microseconds: 1 } works', () => { - equal(`${duration.with({ microseconds: 1 })}`, 'P5Y5M5W5DT5H5M5.005001005S'); - }); - it('duration.with({ nanoseconds: 1 } works', () => { - equal(`${duration.with({ nanoseconds: 1 })}`, 'P5Y5M5W5DT5H5M5.005005001S'); - }); - it('duration.with({ months: 1, seconds: 15 } works', () => { - equal(`${duration.with({ months: 1, seconds: 15 })}`, 'P5Y1M5W5DT5H5M15.005005005S'); - }); - it('mixed positive and negative values throw', () => { - throws(() => duration.with({ hours: 1, minutes: -1 }), RangeError); - }); - it('can reverse the sign if all the fields are replaced', () => { - const d = Duration.from({ years: 5, days: 1 }); - const d2 = d.with({ years: -1, days: -1, minutes: 0 }); - equal(`${d2}`, '-P1Y1D'); - notEqual(d.sign, d2.sign); - }); - it('throws if new fields have a different sign from the old fields', () => { - const d = Duration.from({ years: 5, days: 1 }); - throws(() => d.with({ months: -5, minutes: 0 }), RangeError); - }); - it('sign cannot be manipulated independently', () => { - throws(() => duration.with({ sign: -1 }), TypeError); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => duration.with({}), TypeError); - throws(() => duration.with({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${duration.with({ month: 1, days: 1 })}`, 'P5Y5M5W1DT5H5M5.005005005S'); - }); - }); - describe('Duration.add()', () => { - const duration = Duration.from({ days: 1, minutes: 5 }); - it('adds same units', () => { - equal(`${duration.add({ days: 2, minutes: 5 })}`, 'P3DT10M'); - }); - it('adds different units', () => { - equal(`${duration.add({ hours: 12, seconds: 30 })}`, 'P1DT12H5M30S'); - }); - it('symmetric with regard to negative durations', () => { - equal(`${Duration.from('P3DT10M').add({ days: -2, minutes: -5 })}`, 'P1DT5M'); - equal(`${Duration.from('P1DT12H5M30S').add({ hours: -12, seconds: -30 })}`, 'P1DT5M'); - }); - it('balances time units even if both operands are positive', () => { - const d = Duration.from('P50DT50H50M50.500500500S'); - const result = d.add(d); - equal(result.days, 104); - equal(result.hours, 5); - equal(result.minutes, 41); - equal(result.seconds, 41); - equal(result.milliseconds, 1); - equal(result.microseconds, 1); - equal(result.nanoseconds, 0); - }); - it('balances correctly if adding different units flips the overall sign', () => { - const d1 = Duration.from({ hours: -1, seconds: -60 }); - equal(`${d1.add({ minutes: 122 })}`, 'PT1H1M'); - const d2 = Duration.from({ hours: -1, seconds: -3721 }); - equal(`${d2.add({ minutes: 61, nanoseconds: 3722000000001 })}`, 'PT1M1.000000001S'); - }); - const max = new Duration(0, 0, 0, ...Array(7).fill(Number.MAX_VALUE)); - it('always throws when addition overflows', () => { - throws(() => max.add(max), RangeError); - }); - it('mixed positive and negative values always throw', () => { - throws(() => duration.add({ hours: 1, minutes: -30 }), RangeError); - }); - it('relativeTo required for years, months, and weeks', () => { - const d = Duration.from({ hours: 1 }); - const dy = Duration.from({ years: 1 }); - const dm = Duration.from({ months: 1 }); - const dw = Duration.from({ weeks: 1 }); - throws(() => d.add(dy), RangeError); - throws(() => d.add(dm), RangeError); - throws(() => d.add(dw), RangeError); - throws(() => dy.add(d), RangeError); - throws(() => dm.add(d), RangeError); - throws(() => dw.add(d), RangeError); - const relativeTo = Temporal.PlainDateTime.from('2000-01-01'); - equal(`${d.add(dy, { relativeTo })}`, 'P1YT1H'); - equal(`${d.add(dm, { relativeTo })}`, 'P1MT1H'); - equal(`${d.add(dw, { relativeTo })}`, 'P1WT1H'); - equal(`${dy.add(d, { relativeTo })}`, 'P1YT1H'); - equal(`${dm.add(d, { relativeTo })}`, 'P1MT1H'); - equal(`${dw.add(d, { relativeTo })}`, 'P1WT1H'); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => duration.add({ hours: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(duration.add({ hours: 1 }, options).hours, 1)); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => duration.add({}), TypeError); - throws(() => duration.add({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${duration.add({ month: 1, days: 1 })}`, 'P2DT5M'); - }); - it('casts argument', () => { - equal(`${duration.add(Temporal.Duration.from('P2DT5M'))}`, 'P3DT10M'); - equal(`${duration.add('P2DT5M')}`, 'P3DT10M'); - }); - it('relativeTo affects year length', () => { - const oneYear = new Duration(1); - const days365 = new Duration(0, 0, 0, 365); - equal(`${oneYear.add(days365, { relativeTo: Temporal.PlainDateTime.from('2016-01-01') })}`, 'P2Y'); - equal(`${oneYear.add(days365, { relativeTo: Temporal.PlainDateTime.from('2015-01-01') })}`, 'P1Y11M30D'); - }); - it('relativeTo affects month length', () => { - const oneMonth = new Duration(0, 1); - const days30 = new Duration(0, 0, 0, 30); - equal(`${oneMonth.add(days30, { relativeTo: Temporal.PlainDateTime.from('2018-01-01') })}`, 'P2M2D'); - equal(`${oneMonth.add(days30, { relativeTo: Temporal.PlainDateTime.from('2018-02-01') })}`, 'P1M30D'); - equal(`${oneMonth.add(days30, { relativeTo: Temporal.PlainDateTime.from('2018-03-01') })}`, 'P2M'); - }); - it('first this is resolved against relativeTo, then the argument against relativeTo + this', () => { - const d1 = new Duration(0, 1, 0, 1); - const d2 = new Duration(0, 1, 0, 1); - const relativeTo = new Temporal.PlainDateTime(2000, 1, 1); - equal(`${d1.add(d2, { relativeTo })}`, 'P2M2D'); - }); - const oneDay = new Duration(0, 0, 0, 1); - const hours24 = new Duration(0, 0, 0, 0, 24); - it('relativeTo does not affect days if PlainDateTime', () => { - const relativeTo = Temporal.PlainDateTime.from('2017-01-01'); - equal(`${oneDay.add(hours24, { relativeTo })}`, 'P2D'); - }); - it('relativeTo does not affect days if ZonedDateTime, and duration encompasses no DST change', () => { - const relativeTo = Temporal.ZonedDateTime.from('2017-01-01T00:00[America/Montevideo]'); - equal(`${oneDay.add(hours24, { relativeTo })}`, 'P2D'); - }); - const skippedHourDay = Temporal.ZonedDateTime.from('2019-03-10T00:00[America/Vancouver]'); - const repeatedHourDay = Temporal.ZonedDateTime.from('2019-11-03T00:00[America/Vancouver]'); - const inRepeatedHour = Temporal.ZonedDateTime.from('2019-11-03T01:00-07:00[America/Vancouver]'); - const hours12 = new Duration(0, 0, 0, 0, 12); - const hours25 = new Duration(0, 0, 0, 0, 25); - describe('relativeTo affects days if ZonedDateTime, and duration encompasses DST change', () => { - it('start inside repeated hour, end after', () => { - equal(`${hours25.add(oneDay, { relativeTo: inRepeatedHour })}`, 'P2D'); - equal(`${oneDay.add(hours25, { relativeTo: inRepeatedHour })}`, 'P2DT1H'); - }); - it('start after repeated hour, end inside (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-05T01:00[America/Vancouver]'); - equal(`${hours25.negated().add(oneDay.negated(), { relativeTo })}`, '-P2DT1H'); - equal(`${oneDay.negated().add(hours25.negated(), { relativeTo })}`, '-P2D'); - }); - it('start inside repeated hour, end in skipped hour', () => { - equal(`${hours25.add(Duration.from({ days: 125, hours: 1 }), { relativeTo: inRepeatedHour })}`, 'P126DT1H'); - // this takes you to 03:00 on the next skipped-hour day - equal(`${oneDay.add(Duration.from({ days: 125, hours: 1 }), { relativeTo: inRepeatedHour })}`, 'P126DT1H'); - }); - it('start in normal hour, end in skipped hour', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-08T02:30[America/Vancouver]'); - equal(`${oneDay.add(hours25, { relativeTo })}`, 'P2DT1H'); - equal(`${hours25.add(oneDay, { relativeTo })}`, 'P2D'); - }); - it('start before skipped hour, end >1 day after', () => { - equal(`${hours25.add(oneDay, { relativeTo: skippedHourDay })}`, 'P2DT2H'); - equal(`${oneDay.add(hours25, { relativeTo: skippedHourDay })}`, 'P2DT1H'); - }); - it('start after skipped hour, end >1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-11T00:00[America/Vancouver]'); - equal(`${hours25.negated().add(oneDay.negated(), { relativeTo })}`, '-P2DT2H'); - equal(`${oneDay.negated().add(hours25.negated(), { relativeTo })}`, '-P2DT1H'); - }); - it('start before skipped hour, end <1 day after', () => { - equal(`${hours12.add(oneDay, { relativeTo: skippedHourDay })}`, 'P1DT13H'); - equal(`${oneDay.add(hours12, { relativeTo: skippedHourDay })}`, 'P1DT12H'); - }); - it('start after skipped hour, end <1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-10T12:00[America/Vancouver]'); - equal(`${hours12.negated().add(oneDay.negated(), { relativeTo })}`, '-P1DT13H'); - equal(`${oneDay.negated().add(hours12.negated(), { relativeTo })}`, '-P1DT12H'); - }); - it('start before repeated hour, end >1 day after', () => { - equal(`${hours25.add(oneDay, { relativeTo: repeatedHourDay })}`, 'P2D'); - equal(`${oneDay.add(hours25, { relativeTo: repeatedHourDay })}`, 'P2DT1H'); - }); - it('start after repeated hour, end >1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-04T00:00[America/Vancouver]'); - equal(`${hours25.negated().add(oneDay.negated(), { relativeTo })}`, '-P2D'); - equal(`${oneDay.negated().add(hours25.negated(), { relativeTo })}`, '-P2DT1H'); - }); - it('start before repeated hour, end <1 day after', () => { - equal(`${hours12.add(oneDay, { relativeTo: repeatedHourDay })}`, 'P1DT11H'); - equal(`${oneDay.add(hours12, { relativeTo: repeatedHourDay })}`, 'P1DT12H'); - }); - it('start after repeated hour, end <1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-03T12:00[America/Vancouver]'); - equal(`${hours12.negated().add(oneDay.negated(), { relativeTo })}`, '-P1DT11H'); - equal(`${oneDay.negated().add(hours12.negated(), { relativeTo })}`, '-P1DT12H'); - }); - it('Samoa skipped 24 hours', () => { - const relativeTo = Temporal.ZonedDateTime.from('2011-12-29T12:00-10:00[Pacific/Apia]'); - equal(`${hours25.add(oneDay, { relativeTo })}`, 'P3DT1H'); - equal(`${oneDay.add(hours25, { relativeTo })}`, 'P3DT1H'); - }); - }); - it('casts relativeTo to ZonedDateTime if possible', () => { - equal(`${oneDay.add(hours24, { relativeTo: '2019-11-02T00:00[America/Vancouver]' })}`, 'P1DT24H'); - equal( - `${oneDay.add(hours24, { relativeTo: { year: 2019, month: 11, day: 2, timeZone: 'America/Vancouver' } })}`, - 'P1DT24H' - ); - }); - it('casts relativeTo to PlainDateTime if possible', () => { - equal(`${oneDay.add(hours24, { relativeTo: '2019-11-02T00:00' })}`, 'P2D'); - equal(`${oneDay.add(hours24, { relativeTo: { year: 2019, month: 11, day: 2 } })}`, 'P2D'); - }); - it('throws on wrong offset for ZonedDateTime relativeTo string', () => { - throws(() => oneDay.add(hours24, { relativeTo: '1971-01-01T00:00+02:00[Africa/Monrovia]' }), RangeError); - }); - it('does not throw on HH:MM rounded offset for ZonedDateTime relativeTo string', () => { - equal(`${oneDay.add(hours24, { relativeTo: '1971-01-01T00:00-00:45[Africa/Monrovia]' })}`, 'P2D'); - }); - it('throws on HH:MM rounded offset for ZonedDateTime relativeTo property bag', () => { - throws( - () => - oneDay.add(hours24, { - relativeTo: { year: 1971, month: 1, day: 1, offset: '-00:45', timeZone: 'Africa/Monrovia' } - }), - RangeError - ); - }); - it('at least the required properties must be present in relativeTo', () => { - throws(() => oneDay.add(hours24, { relativeTo: { month: 11, day: 3 } }), TypeError); - throws(() => oneDay.add(hours24, { relativeTo: { year: 2019, month: 11 } }), TypeError); - throws(() => oneDay.add(hours24, { relativeTo: { year: 2019, day: 3 } }), TypeError); - }); - it('throws with invalid offset in relativeTo', () => { - throws( - () => - Temporal.Duration.from('P2D').add('P1M', { - relativeTo: { year: 2021, month: 11, day: 26, offset: '+088:00', timeZone: 'Europe/London' } - }), - RangeError - ); - }); - }); - describe('Duration.subtract()', () => { - const duration = Duration.from({ days: 3, hours: 1, minutes: 10 }); - it('subtracts same units with positive result', () => { - equal(`${duration.subtract({ days: 1, minutes: 5 })}`, 'P2DT1H5M'); - }); - it('subtracts same units with zero result', () => { - equal(`${duration.subtract(duration)}`, 'PT0S'); - equal(`${duration.subtract({ days: 3 })}`, 'PT1H10M'); - equal(`${duration.subtract({ minutes: 10 })}`, 'P3DT1H'); - }); - it('balances when subtracting same units with negative result', () => { - equal(`${duration.subtract({ minutes: 15 })}`, 'P3DT55M'); - }); - it('balances when subtracting different units', () => { - equal(`${duration.subtract({ seconds: 30 })}`, 'P3DT1H9M30S'); - }); - it('symmetric with regard to negative durations', () => { - equal(`${Duration.from('P2DT1H5M').subtract({ days: -1, minutes: -5 })}`, 'P3DT1H10M'); - equal(`${new Duration().subtract({ days: -3, hours: -1, minutes: -10 })}`, 'P3DT1H10M'); - equal(`${Duration.from('PT1H10M').subtract({ days: -3 })}`, 'P3DT1H10M'); - equal(`${Duration.from('P3DT1H').subtract({ minutes: -10 })}`, 'P3DT1H10M'); - equal(`${Duration.from('P3DT55M').subtract({ minutes: -15 })}`, 'P3DT1H10M'); - equal(`${Duration.from('P3DT1H9M30S').subtract({ seconds: -30 })}`, 'P3DT1H10M'); - }); - it('balances positive units up to the largest nonzero unit', () => { - const d = Duration.from({ - minutes: 100, - seconds: 100, - milliseconds: 2000, - microseconds: 2000, - nanoseconds: 2000 - }); - const less = Duration.from({ - minutes: 10, - seconds: 10, - milliseconds: 500, - microseconds: 500, - nanoseconds: 500 - }); - const result = d.subtract(less); - equal(result.minutes, 91); - equal(result.seconds, 31); - equal(result.milliseconds, 501); - equal(result.microseconds, 501); - equal(result.nanoseconds, 500); - }); - const tenDays = Duration.from('P10D'); - const tenMinutes = Duration.from('PT10M'); - it('has correct negative result', () => { - let result = tenDays.subtract({ days: 15 }); - equal(result.days, -5); - result = tenMinutes.subtract({ minutes: 15 }); - equal(result.minutes, -5); - }); - it('balances correctly if subtracting different units flips the overall sign', () => { - const d1 = Duration.from({ hours: 1, seconds: 60 }); - equal(`${d1.subtract({ minutes: 122 })}`, '-PT1H1M'); - const d2 = Duration.from({ hours: 1, seconds: 3721 }); - equal(`${d2.subtract({ minutes: 61, nanoseconds: 3722000000001 })}`, '-PT1M1.000000001S'); - }); - it('mixed positive and negative values always throw', () => { - throws(() => duration.subtract({ hours: 1, minutes: -30 }), RangeError); - }); - it('relativeTo required for years, months, and weeks', () => { - const d = Duration.from({ hours: 1 }); - const dy = Duration.from({ years: 1, hours: 1 }); - const dm = Duration.from({ months: 1, hours: 1 }); - const dw = Duration.from({ weeks: 1, hours: 1 }); - throws(() => d.subtract(dy), RangeError); - throws(() => d.subtract(dm), RangeError); - throws(() => d.subtract(dw), RangeError); - throws(() => dy.subtract(d), RangeError); - throws(() => dm.subtract(d), RangeError); - throws(() => dw.subtract(d), RangeError); - const relativeTo = Temporal.PlainDateTime.from('2000-01-01'); - equal(`${d.subtract(dy, { relativeTo })}`, '-P1Y'); - equal(`${d.subtract(dm, { relativeTo })}`, '-P1M'); - equal(`${d.subtract(dw, { relativeTo })}`, '-P1W'); - equal(`${dy.subtract(d, { relativeTo })}`, 'P1Y'); - equal(`${dm.subtract(d, { relativeTo })}`, 'P1M'); - equal(`${dw.subtract(d, { relativeTo })}`, 'P1W'); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => duration.subtract({ hours: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(duration.subtract({ hours: 1 }, options).hours, 0)); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => duration.subtract({}), TypeError); - throws(() => duration.subtract({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${duration.subtract({ month: 1, days: 1 })}`, 'P2DT1H10M'); - }); - it('casts argument', () => { - equal(`${duration.subtract(Temporal.Duration.from('P1DT5M'))}`, 'P2DT1H5M'); - equal(`${duration.subtract('P1DT5M')}`, 'P2DT1H5M'); - }); - it('relativeTo affects year length', () => { - const oneYear = new Duration(1); - const days365 = new Duration(0, 0, 0, 365); - equal(`${oneYear.subtract(days365, { relativeTo: Temporal.PlainDateTime.from('2017-01-01') })}`, 'PT0S'); - equal(`${oneYear.subtract(days365, { relativeTo: Temporal.PlainDateTime.from('2016-01-01') })}`, 'P1D'); - }); - it('relativeTo affects month length', () => { - const oneMonth = new Duration(0, 1); - const days30 = new Duration(0, 0, 0, 30); - equal(`${oneMonth.subtract(days30, { relativeTo: Temporal.PlainDateTime.from('2018-02-01') })}`, '-P2D'); - equal(`${oneMonth.subtract(days30, { relativeTo: Temporal.PlainDateTime.from('2018-03-01') })}`, 'P1D'); - equal(`${oneMonth.subtract(days30, { relativeTo: Temporal.PlainDateTime.from('2018-04-01') })}`, 'PT0S'); - }); - it('first this is resolved against relativeTo, then the argument against relativeTo + this', () => { - const d1 = new Duration(0, 2, 1, 4); - const d2 = new Duration(0, 1, 1, 1); - const relativeTo = new Temporal.PlainDateTime(2000, 1, 1); - equal(`${d1.subtract(d2, { relativeTo })}`, 'P1M3D'); - }); - const oneDay = new Duration(0, 0, 0, 1); - const hours24 = new Duration(0, 0, 0, 0, 24); - it('relativeTo does not affect days if PlainDateTime', () => { - const relativeTo = Temporal.PlainDateTime.from('2017-01-01'); - equal(`${oneDay.subtract(hours24, { relativeTo })}`, 'PT0S'); - }); - it('relativeTo does not affect days if ZonedDateTime, and duration encompasses no DST change', () => { - const relativeTo = Temporal.ZonedDateTime.from('2017-01-01T00:00[America/Montevideo]'); - equal(`${oneDay.subtract(hours24, { relativeTo })}`, 'PT0S'); - }); - const skippedHourDay = Temporal.ZonedDateTime.from('2019-03-10T00:00[America/Vancouver]'); - const repeatedHourDay = Temporal.ZonedDateTime.from('2019-11-03T00:00[America/Vancouver]'); - const inRepeatedHour = Temporal.ZonedDateTime.from('2019-11-03T01:00-07:00[America/Vancouver]'); - const twoDays = new Duration(0, 0, 0, 2); - const threeDays = new Duration(0, 0, 0, 3); - describe('relativeTo affects days if ZonedDateTime, and duration encompasses DST change', () => { - it('start inside repeated hour, end after', () => { - equal(`${hours24.subtract(oneDay, { relativeTo: inRepeatedHour })}`, '-PT1H'); - equal(`${oneDay.subtract(hours24, { relativeTo: inRepeatedHour })}`, 'PT1H'); - }); - it('start inside repeated hour, end in skipped hour', () => { - equal(`${Duration.from({ days: 127, hours: 1 }).subtract(oneDay, { relativeTo: inRepeatedHour })}`, 'P126DT1H'); - equal(`${Duration.from({ days: 127, hours: 1 }).subtract(hours24, { relativeTo: inRepeatedHour })}`, 'P126D'); - }); - it('start in normal hour, end in skipped hour', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-09T02:30[America/Vancouver]'); - equal(`${hours24.subtract(oneDay, { relativeTo })}`, 'PT1H'); - equal(`${oneDay.subtract(hours24, { relativeTo })}`, 'PT0S'); - }); - it('start before skipped hour, end >1 day after', () => { - equal(`${threeDays.subtract(hours24, { relativeTo: skippedHourDay })}`, 'P2D'); - equal(`${hours24.subtract(threeDays, { relativeTo: skippedHourDay })}`, '-P1DT23H'); - }); - it('start before skipped hour, end <1 day after', () => { - equal(`${twoDays.subtract(hours24, { relativeTo: skippedHourDay })}`, 'P1D'); - equal(`${hours24.subtract(twoDays, { relativeTo: skippedHourDay })}`, '-PT23H'); - }); - it('start before repeated hour, end >1 day after', () => { - equal(`${threeDays.subtract(hours24, { relativeTo: repeatedHourDay })}`, 'P2D'); - equal(`${hours24.subtract(threeDays, { relativeTo: repeatedHourDay })}`, '-P2DT1H'); - }); - it('start before repeated hour, end <1 day after', () => { - equal(`${twoDays.subtract(hours24, { relativeTo: repeatedHourDay })}`, 'P1D'); - equal(`${hours24.subtract(twoDays, { relativeTo: repeatedHourDay })}`, '-P1DT1H'); - }); - it('Samoa skipped 24 hours', () => { - const relativeTo = Temporal.ZonedDateTime.from('2011-12-29T12:00-10:00[Pacific/Apia]'); - equal(`${twoDays.subtract(Duration.from({ hours: 48 }), { relativeTo })}`, '-P1D'); - equal(`${Duration.from({ hours: 48 }).subtract(twoDays, { relativeTo })}`, 'P2D'); - }); - }); - it('casts relativeTo to ZonedDateTime if possible', () => { - equal(`${oneDay.subtract(hours24, { relativeTo: '2019-11-03T00:00[America/Vancouver]' })}`, 'PT1H'); - equal( - `${oneDay.subtract(hours24, { relativeTo: { year: 2019, month: 11, day: 3, timeZone: 'America/Vancouver' } })}`, - 'PT1H' - ); - }); - it('casts relativeTo to PlainDateTime if possible', () => { - equal(`${oneDay.subtract(hours24, { relativeTo: '2019-11-02T00:00' })}`, 'PT0S'); - equal(`${oneDay.subtract(hours24, { relativeTo: { year: 2019, month: 11, day: 2 } })}`, 'PT0S'); - }); - it('throws on wrong offset for ZonedDateTime relativeTo string', () => { - throws(() => oneDay.subtract(hours24, { relativeTo: '1971-01-01T00:00+02:00[Africa/Monrovia]' }), RangeError); - }); - it('does not throw on HH:MM rounded offset for ZonedDateTime relativeTo string', () => { - equal(`${oneDay.subtract(hours24, { relativeTo: '1971-01-01T00:00-00:45[Africa/Monrovia]' })}`, 'PT0S'); - }); - it('throws on HH:MM rounded offset for ZonedDateTime relativeTo property bag', () => { - throws( - () => - oneDay.subtract(hours24, { - relativeTo: { year: 1971, month: 1, day: 1, offset: '-00:45', timeZone: 'Africa/Monrovia' } - }), - RangeError - ); - }); - it('at least the required properties must be present in relativeTo', () => { - throws(() => oneDay.subtract(hours24, { relativeTo: { month: 11, day: 3 } }), TypeError); - throws(() => oneDay.subtract(hours24, { relativeTo: { year: 2019, month: 11 } }), TypeError); - throws(() => oneDay.subtract(hours24, { relativeTo: { year: 2019, day: 3 } }), TypeError); - }); - }); - describe("Comparison operators don't work", () => { - const d1 = Duration.from('P3DT1H'); - const d1again = Duration.from('P3DT1H'); - const d2 = Duration.from('PT2H20M30S'); - it('=== is object equality', () => equal(d1, d1)); - it('!== is object equality', () => notEqual(d1, d1again)); - it('<', () => throws(() => d1 < d2)); - it('>', () => throws(() => d1 > d2)); - it('<=', () => throws(() => d1 <= d2)); - it('>=', () => throws(() => d1 >= d2)); - }); - describe('Duration.negated()', () => { - it('makes a positive duration negative', () => { - const pos = Duration.from('P3DT1H'); - const neg = pos.negated(); - equal(`${neg}`, '-P3DT1H'); - equal(neg.sign, -1); - }); - it('makes a negative duration positive', () => { - const neg = Duration.from('-PT2H20M30S'); - const pos = neg.negated(); - equal(`${pos}`, 'PT2H20M30S'); - equal(pos.sign, 1); - }); - it('makes a copy of a zero duration', () => { - const zero = Duration.from('PT0S'); - const zero2 = zero.negated(); - equal(`${zero}`, `${zero2}`); - notEqual(zero, zero2); - equal(zero2.sign, 0); - equal(zero2.years, 0); - equal(zero2.months, 0); - equal(zero2.weeks, 0); - equal(zero2.days, 0); - equal(zero2.hours, 0); - equal(zero2.minutes, 0); - equal(zero2.seconds, 0); - equal(zero2.milliseconds, 0); - equal(zero2.microseconds, 0); - equal(zero2.nanoseconds, 0); - }); - it('throws with invalid offset in relativeTo', () => { - throws( - () => - Temporal.Duration.from('P2D').subtract('P1M', { - relativeTo: { year: 2021, month: 11, day: 26, offset: '+088:00', timeZone: 'Europe/London' } - }), - RangeError - ); - }); - }); - describe('Duration.abs()', () => { - it('makes a copy of a positive duration', () => { - const pos = Duration.from('P3DT1H'); - const pos2 = pos.abs(); - equal(`${pos}`, `${pos2}`); - notEqual(pos, pos2); - equal(pos2.sign, 1); - }); - it('makes a negative duration positive', () => { - const neg = Duration.from('-PT2H20M30S'); - const pos = neg.abs(); - equal(`${pos}`, 'PT2H20M30S'); - equal(pos.sign, 1); - }); - it('makes a copy of a zero duration', () => { - const zero = Duration.from('PT0S'); - const zero2 = zero.abs(); - equal(`${zero}`, `${zero2}`); - notEqual(zero, zero2); - equal(zero2.sign, 0); - }); - }); - describe('Duration.blank', () => { - it('works', () => { - assert(!Duration.from('P3DT1H').blank); - assert(!Duration.from('-PT2H20M30S').blank); - assert(Duration.from('PT0S').blank); - }); - it('zero regardless of how many fields are in the duration', () => { - const zero = Duration.from({ - years: 0, - months: 0, - weeks: 0, - days: 0, - hours: 0, - minutes: 0, - seconds: 0, - milliseconds: 0, - microseconds: 0, - nanoseconds: 0 - }); - assert(zero.blank); - }); - }); - describe('Duration.round()', () => { - const d = new Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5); - const d2 = new Duration(0, 0, 0, 5, 5, 5, 5, 5, 5, 5); - const relativeTo = Temporal.PlainDateTime.from('2020-01-01T00:00'); - it('parameter may only be an object or string', () => { - [null, 1, true, Symbol('foo'), 1n].forEach((badOptions) => throws(() => d.round(badOptions), TypeError)); - }); - it('throws without parameter', () => { - throws(() => d.round(), TypeError); - }); - it('throws with empty object', () => { - throws(() => d.round({}), RangeError); - }); - it("succeeds with largestUnit: 'auto'", () => { - equal(`${Duration.from({ hours: 25 }).round({ largestUnit: 'auto' })}`, 'PT25H'); - }); - it('throws on disallowed or invalid smallestUnit (object param)', () => { - ['era', 'nonsense'].forEach((smallestUnit) => { - throws(() => d.round({ smallestUnit }), RangeError); - }); - }); - it('throws on disallowed or invalid smallestUnit (string param)', () => { - ['era', 'nonsense'].forEach((smallestUnit) => { - throws(() => d.round(smallestUnit), RangeError); - }); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = [ - 'years', - 'months', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ]; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => d.round({ largestUnit, smallestUnit, relativeTo }), RangeError); - } - } - }); - it('accepts string parameter as a shortcut for {smallestUnit}', () => { - const d = Temporal.Duration.from({ - days: 1, - hours: 2, - minutes: 3, - seconds: 4, - milliseconds: 5, - microseconds: 6, - nanoseconds: 7 - }); - equal(d.round('day').toString(), 'P1D'); - equal(d.round('hour').toString(), 'P1DT2H'); - equal(d.round('minute').toString(), 'P1DT2H3M'); - equal(d.round('second').toString(), 'P1DT2H3M4S'); - equal(d.round('millisecond').toString(), 'P1DT2H3M4.005S'); - equal(d.round('microsecond').toString(), 'P1DT2H3M4.005006S'); - equal(d.round('nanosecond').toString(), 'P1DT2H3M4.005006007S'); - }); - it('assumes a different default for largestUnit if smallestUnit is larger than the default', () => { - const almostYear = Duration.from({ days: 364 }); - equal(`${almostYear.round({ smallestUnit: 'years', relativeTo })}`, 'P1Y'); - const almostMonth = Duration.from({ days: 27 }); - equal(`${almostMonth.round({ smallestUnit: 'months', relativeTo })}`, 'P1M'); - const almostWeek = Duration.from({ days: 6 }); - equal(`${almostWeek.round({ smallestUnit: 'weeks', relativeTo })}`, 'P1W'); - const almostDay = Duration.from({ seconds: 86399 }); - equal(`${almostDay.round({ smallestUnit: 'days' })}`, 'P1D'); - const almostHour = Duration.from({ seconds: 3599 }); - equal(`${almostHour.round({ smallestUnit: 'hours' })}`, 'PT1H'); - const almostMinute = Duration.from({ seconds: 59 }); - equal(`${almostMinute.round({ smallestUnit: 'minutes' })}`, 'PT1M'); - const almostSecond = Duration.from({ nanoseconds: 999999999 }); - equal(`${almostSecond.round({ smallestUnit: 'seconds' })}`, 'PT1S'); - const almostMillisecond = Duration.from({ nanoseconds: 999999 }); - equal(`${almostMillisecond.round({ smallestUnit: 'milliseconds' })}`, 'PT0.001S'); - const almostMicrosecond = Duration.from({ nanoseconds: 999 }); - equal(`${almostMicrosecond.round({ smallestUnit: 'microseconds' })}`, 'PT0.000001S'); - }); - const hours25 = new Duration(0, 0, 0, 0, 25); - it('days are 24 hours if relativeTo not given', () => { - equal(`${hours25.round({ largestUnit: 'days' })}`, 'P1DT1H'); - }); - it('days are 24 hours if relativeTo is PlainDateTime', () => { - const relativeTo = Temporal.PlainDateTime.from('2017-01-01'); - equal(`${hours25.round({ largestUnit: 'days', relativeTo })}`, 'P1DT1H'); - }); - it('days are 24 hours if relativeTo is ZonedDateTime, and duration encompasses no DST change', () => { - const relativeTo = Temporal.ZonedDateTime.from('2017-01-01T00:00[America/Montevideo]'); - equal(`${hours25.round({ largestUnit: 'days', relativeTo })}`, 'P1DT1H'); - }); - const skippedHourDay = Temporal.ZonedDateTime.from('2019-03-10T00:00[America/Vancouver]'); - const repeatedHourDay = Temporal.ZonedDateTime.from('2019-11-03T00:00[America/Vancouver]'); - const inRepeatedHour = Temporal.ZonedDateTime.from('2019-11-03T01:00-07:00[America/Vancouver]'); - const oneDay = new Duration(0, 0, 0, 1); - const hours12 = new Duration(0, 0, 0, 0, 12); - describe('relativeTo affects days if ZonedDateTime, and duration encompasses DST change', () => { - it('start inside repeated hour, end after', () => { - equal(`${hours25.round({ largestUnit: 'days', relativeTo: inRepeatedHour })}`, 'P1D'); - equal(`${oneDay.round({ largestUnit: 'hours', relativeTo: inRepeatedHour })}`, 'PT25H'); - }); - it('start after repeated hour, end inside (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-04T01:00[America/Vancouver]'); - equal(`${hours25.negated().round({ largestUnit: 'days', relativeTo })}`, '-P1D'); - equal(`${oneDay.negated().round({ largestUnit: 'hours', relativeTo })}`, '-PT25H'); - }); - it('start inside repeated hour, end in skipped hour', () => { - equal( - `${Duration.from({ days: 126, hours: 1 }).round({ largestUnit: 'days', relativeTo: inRepeatedHour })}`, - 'P126DT1H' - ); - equal( - `${Duration.from({ days: 126, hours: 1 }).round({ largestUnit: 'hours', relativeTo: inRepeatedHour })}`, - 'PT3026H' - ); - }); - it('start in normal hour, end in skipped hour', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-09T02:30[America/Vancouver]'); - equal(`${hours25.round({ largestUnit: 'days', relativeTo })}`, 'P1DT1H'); - equal(`${oneDay.round({ largestUnit: 'hours', relativeTo })}`, 'PT24H'); - }); - it('start before skipped hour, end >1 day after', () => { - equal(`${hours25.round({ largestUnit: 'days', relativeTo: skippedHourDay })}`, 'P1DT2H'); - equal(`${oneDay.round({ largestUnit: 'hours', relativeTo: skippedHourDay })}`, 'PT23H'); - }); - it('start after skipped hour, end >1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-11T00:00[America/Vancouver]'); - equal(`${hours25.negated().round({ largestUnit: 'days', relativeTo })}`, '-P1DT2H'); - equal(`${oneDay.negated().round({ largestUnit: 'hours', relativeTo })}`, '-PT23H'); - }); - it('start before skipped hour, end <1 day after', () => { - equal(`${hours12.round({ largestUnit: 'days', relativeTo: skippedHourDay })}`, 'PT12H'); - }); - it('start after skipped hour, end <1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-10T12:00[America/Vancouver]'); - equal(`${hours12.negated().round({ largestUnit: 'days', relativeTo })}`, '-PT12H'); - }); - it('start before repeated hour, end >1 day after', () => { - equal(`${hours25.round({ largestUnit: 'days', relativeTo: repeatedHourDay })}`, 'P1D'); - equal(`${oneDay.round({ largestUnit: 'hours', relativeTo: repeatedHourDay })}`, 'PT25H'); - }); - it('start after repeated hour, end >1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-04T00:00[America/Vancouver]'); - equal(`${hours25.negated().round({ largestUnit: 'days', relativeTo })}`, '-P1D'); - equal(`${oneDay.negated().round({ largestUnit: 'hours', relativeTo })}`, '-PT25H'); - }); - it('start before repeated hour, end <1 day after', () => { - equal(`${hours12.round({ largestUnit: 'days', relativeTo: repeatedHourDay })}`, 'PT12H'); - }); - it('start after repeated hour, end <1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-03T12:00[America/Vancouver]'); - equal(`${hours12.negated().round({ largestUnit: 'days', relativeTo })}`, '-PT12H'); - }); - it('Samoa skipped 24 hours', () => { - const relativeTo = Temporal.ZonedDateTime.from('2011-12-29T12:00-10:00[Pacific/Apia]'); - equal(`${hours25.round({ largestUnit: 'days', relativeTo })}`, 'P2DT1H'); - equal(`${Duration.from({ hours: 48 }).round({ largestUnit: 'days', relativeTo })}`, 'P3D'); - }); - }); - it('casts relativeTo to ZonedDateTime if possible', () => { - equal(`${hours25.round({ largestUnit: 'days', relativeTo: '2019-11-03T00:00[America/Vancouver]' })}`, 'P1D'); - equal( - `${hours25.round({ - largestUnit: 'days', - relativeTo: { year: 2019, month: 11, day: 3, timeZone: 'America/Vancouver' } - })}`, - 'P1D' - ); - }); - it('casts relativeTo to PlainDateTime if possible', () => { - equal(`${hours25.round({ largestUnit: 'days', relativeTo: '2019-11-02T00:00' })}`, 'P1DT1H'); - equal(`${hours25.round({ largestUnit: 'days', relativeTo: { year: 2019, month: 11, day: 2 } })}`, 'P1DT1H'); - }); - it('accepts datetime string equivalents or fields for relativeTo', () => { - ['2020-01-01', '2020-01-01T00:00:00.000000000', 20200101, 20200101n, { year: 2020, month: 1, day: 1 }].forEach( - (relativeTo) => { - equal(`${d.round({ smallestUnit: 'seconds', relativeTo })}`, 'P5Y5M5W5DT5H5M5S'); - } - ); - }); - it("throws on relativeTo that can't be converted to datetime string", () => { - throws(() => d.round({ smallestUnit: 'seconds', relativeTo: Symbol('foo') }), TypeError); - }); - it('throws on relativeTo that converts to an invalid datetime string', () => { - [3.14, true, null, 'hello', 1n].forEach((relativeTo) => { - throws(() => d.round({ smallestUnit: 'seconds', relativeTo }), RangeError); - }); - }); - it('throws on wrong offset for ZonedDateTime relativeTo string', () => { - throws( - () => d.round({ smallestUnit: 'seconds', relativeTo: '1971-01-01T00:00+02:00[Africa/Monrovia]' }), - RangeError - ); - }); - it('does not throw on HH:MM rounded offset for ZonedDateTime relativeTo string', () => { - equal( - `${d.round({ smallestUnit: 'seconds', relativeTo: '1971-01-01T00:00-00:45[Africa/Monrovia]' })}`, - 'P5Y5M5W5DT5H5M5S' - ); - }); - it('throws on HH:MM rounded offset for ZonedDateTime relativeTo property bag', () => { - throws( - () => - d.round({ - smallestUnit: 'seconds', - relativeTo: { year: 1971, month: 1, day: 1, offset: '-00:45', timeZone: 'Africa/Monrovia' } - }), - RangeError - ); - }); - it('relativeTo object must contain at least the required correctly-spelled properties', () => { - throws(() => hours25.round({ largestUnit: 'days', relativeTo: { month: 11, day: 3 } }), TypeError); - throws(() => hours25.round({ largestUnit: 'days', relativeTo: { year: 2019, month: 11 } }), TypeError); - throws(() => hours25.round({ largestUnit: 'days', relativeTo: { year: 2019, day: 3 } }), TypeError); - }); - it('incorrectly-spelled properties are ignored in relativeTo', () => { - const oneMonth = Duration.from({ months: 1 }); - equal( - `${oneMonth.round({ largestUnit: 'days', relativeTo: { year: 2020, month: 1, day: 1, months: 2 } })}`, - 'P31D' - ); - }); - it('throws on invalid roundingMode', () => { - throws(() => d2.round({ smallestUnit: 'nanoseconds', roundingMode: 'cile' }), RangeError); - }); - it('throws if neither one of largestUnit or smallestUnit is given', () => { - const hoursOnly = new Duration(0, 0, 0, 0, 1); - [{}, () => {}, { roundingMode: 'ceil' }].forEach((roundTo) => { - throws(() => d.round(roundTo), RangeError); - throws(() => hoursOnly.round(roundTo), RangeError); - }); - }); - it('relativeTo not required to round non-calendar units in durations w/o calendar units (string param)', () => { - equal(`${d2.round('days')}`, 'P5D'); - equal(`${d2.round('hours')}`, 'P5DT5H'); - equal(`${d2.round('minutes')}`, 'P5DT5H5M'); - equal(`${d2.round('seconds')}`, 'P5DT5H5M5S'); - equal(`${d2.round('milliseconds')}`, 'P5DT5H5M5.005S'); - equal(`${d2.round('microseconds')}`, 'P5DT5H5M5.005005S'); - equal(`${d2.round('nanoseconds')}`, 'P5DT5H5M5.005005005S'); - }); - it('relativeTo is required to round calendar units even in durations w/o calendar units (string param)', () => { - throws(() => d2.round('years'), RangeError); - throws(() => d2.round('months'), RangeError); - throws(() => d2.round('weeks'), RangeError); - }); - it('relativeTo not required to round non-calendar units in durations w/o calendar units (object param)', () => { - equal(`${d2.round({ smallestUnit: 'days' })}`, 'P5D'); - equal(`${d2.round({ smallestUnit: 'hours' })}`, 'P5DT5H'); - equal(`${d2.round({ smallestUnit: 'minutes' })}`, 'P5DT5H5M'); - equal(`${d2.round({ smallestUnit: 'seconds' })}`, 'P5DT5H5M5S'); - equal(`${d2.round({ smallestUnit: 'milliseconds' })}`, 'P5DT5H5M5.005S'); - equal(`${d2.round({ smallestUnit: 'microseconds' })}`, 'P5DT5H5M5.005005S'); - equal(`${d2.round({ smallestUnit: 'nanoseconds' })}`, 'P5DT5H5M5.005005005S'); - }); - it('relativeTo is required to round calendar units even in durations w/o calendar units (object param)', () => { - throws(() => d2.round({ smallestUnit: 'years' }), RangeError); - throws(() => d2.round({ smallestUnit: 'months' }), RangeError); - throws(() => d2.round({ smallestUnit: 'weeks' }), RangeError); - }); - it('relativeTo is required for rounding durations with calendar units', () => { - throws(() => d.round({ largestUnit: 'years' }), RangeError); - throws(() => d.round({ largestUnit: 'months' }), RangeError); - throws(() => d.round({ largestUnit: 'weeks' }), RangeError); - throws(() => d.round({ largestUnit: 'days' }), RangeError); - throws(() => d.round({ largestUnit: 'hours' }), RangeError); - throws(() => d.round({ largestUnit: 'minutes' }), RangeError); - throws(() => d.round({ largestUnit: 'seconds' }), RangeError); - throws(() => d.round({ largestUnit: 'milliseconds' }), RangeError); - throws(() => d.round({ largestUnit: 'microseconds' }), RangeError); - throws(() => d.round({ largestUnit: 'nanoseconds' }), RangeError); - }); - it('durations do not balance beyond their current largest unit by default', () => { - const fortyDays = Duration.from({ days: 40 }); - equal(`${fortyDays.round({ smallestUnit: 'seconds' })}`, 'P40D'); - }); - const roundAndBalanceResults = { - // largestUnit - years: { - // smallestUnit - years: 'P6Y', - months: 'P5Y6M', - weeks: 'P5Y5M6W', - days: 'P5Y5M5W5D', - hours: 'P5Y5M5W5DT5H', - minutes: 'P5Y5M5W5DT5H5M', - seconds: 'P5Y5M5W5DT5H5M5S', - milliseconds: 'P5Y5M5W5DT5H5M5.005S', - microseconds: 'P5Y5M5W5DT5H5M5.005005S', - nanoseconds: 'P5Y5M5W5DT5H5M5.005005005S' - }, - months: { - months: 'P66M', - weeks: 'P65M6W', - days: 'P65M5W5D', - hours: 'P65M5W5DT5H', - minutes: 'P65M5W5DT5H5M', - seconds: 'P65M5W5DT5H5M5S', - milliseconds: 'P65M5W5DT5H5M5.005S', - microseconds: 'P65M5W5DT5H5M5.005005S', - nanoseconds: 'P65M5W5DT5H5M5.005005005S' - }, - weeks: { - weeks: 'P288W', - days: 'P288W2D', - hours: 'P288W2DT5H', - minutes: 'P288W2DT5H5M', - seconds: 'P288W2DT5H5M5S', - milliseconds: 'P288W2DT5H5M5.005S', - microseconds: 'P288W2DT5H5M5.005005S', - nanoseconds: 'P288W2DT5H5M5.005005005S' - }, - days: { - days: 'P2018D', - hours: 'P2018DT5H', - minutes: 'P2018DT5H5M', - seconds: 'P2018DT5H5M5S', - milliseconds: 'P2018DT5H5M5.005S', - microseconds: 'P2018DT5H5M5.005005S', - nanoseconds: 'P2018DT5H5M5.005005005S' - }, - hours: { - hours: 'PT48437H', - minutes: 'PT48437H5M', - seconds: 'PT48437H5M5S', - milliseconds: 'PT48437H5M5.005S', - microseconds: 'PT48437H5M5.005005S', - nanoseconds: 'PT48437H5M5.005005005S' - }, - minutes: { - minutes: 'PT2906225M', - seconds: 'PT2906225M5S', - milliseconds: 'PT2906225M5.005S', - microseconds: 'PT2906225M5.005005S', - nanoseconds: 'PT2906225M5.005005005S' - }, - seconds: { - seconds: 'PT174373505S', - milliseconds: 'PT174373505.005S', - microseconds: 'PT174373505.005005S', - nanoseconds: 'PT174373505.005005005S' - }, - milliseconds: { - milliseconds: 'PT174373505.005S', - microseconds: 'PT174373505.005005S', - nanoseconds: 'PT174373505.005005005S' - } - }; - for (const [largestUnit, entry] of Object.entries(roundAndBalanceResults)) { - for (const [smallestUnit, expected] of Object.entries(entry)) { - it(`round(${largestUnit}, ${smallestUnit}) = ${expected}`, () => { - equal(`${d.round({ largestUnit, smallestUnit, relativeTo })}`, expected); - }); - } - } - const balanceLosePrecisionResults = { - // largestUnit: smallestUnits - microseconds: ['microseconds', 'nanoseconds'], - nanoseconds: ['nanoseconds'] - }; - for (const [largestUnit, entry] of Object.entries(balanceLosePrecisionResults)) { - for (const smallestUnit of entry) { - it(`round(${largestUnit}, ${smallestUnit}) may lose precision below ms`, () => { - assert(`${d.round({ largestUnit, smallestUnit, relativeTo })}`.startsWith('PT174373505.005')); - }); - } - } - const roundingModeResults = { - halfExpand: ['P6Y', '-P6Y'], - ceil: ['P6Y', '-P5Y'], - floor: ['P5Y', '-P6Y'], - trunc: ['P5Y', '-P5Y'] - }; - for (const [roundingMode, [posResult, negResult]] of Object.entries(roundingModeResults)) { - it(`rounds correctly in ${roundingMode} mode`, () => { - equal(`${d.round({ smallestUnit: 'years', relativeTo, roundingMode })}`, posResult); - equal(`${d.negated().round({ smallestUnit: 'years', relativeTo, roundingMode })}`, negResult); - }); - } - it('halfExpand is the default', () => { - equal(`${d.round({ smallestUnit: 'years', relativeTo })}`, 'P6Y'); - equal(`${d.negated().round({ smallestUnit: 'years', relativeTo })}`, '-P6Y'); - }); - it('balances up differently depending on relativeTo', () => { - const fortyDays = Duration.from({ days: 40 }); - equal(`${fortyDays.round({ largestUnit: 'years', relativeTo: '2020-01-01' })}`, 'P1M9D'); - equal(`${fortyDays.round({ largestUnit: 'years', relativeTo: '2020-02-01' })}`, 'P1M11D'); - equal(`${fortyDays.round({ largestUnit: 'years', relativeTo: '2020-03-01' })}`, 'P1M9D'); - equal(`${fortyDays.round({ largestUnit: 'years', relativeTo: '2020-04-01' })}`, 'P1M10D'); - const minusForty = Duration.from({ days: -40 }); - equal(`${minusForty.round({ largestUnit: 'years', relativeTo: '2020-02-01' })}`, '-P1M9D'); - equal(`${minusForty.round({ largestUnit: 'years', relativeTo: '2020-01-01' })}`, '-P1M9D'); - equal(`${minusForty.round({ largestUnit: 'years', relativeTo: '2020-03-01' })}`, '-P1M11D'); - equal(`${minusForty.round({ largestUnit: 'years', relativeTo: '2020-04-01' })}`, '-P1M9D'); - }); - it('balances up to the next unit after rounding', () => { - const almostWeek = Duration.from({ days: 6, hours: 20 }); - equal(`${almostWeek.round({ largestUnit: 'weeks', smallestUnit: 'days', relativeTo: '2020-01-01' })}`, 'P1W'); - }); - it('balances days up to both years and months', () => { - const twoYears = Duration.from({ months: 11, days: 396 }); - equal(`${twoYears.round({ largestUnit: 'years', relativeTo: '2017-01-01' })}`, 'P2Y'); - }); - it('does not balance up to weeks if largestUnit is larger than weeks', () => { - const monthAlmostWeek = Duration.from({ months: 1, days: 6, hours: 20 }); - equal(`${monthAlmostWeek.round({ smallestUnit: 'days', relativeTo: '2020-01-01' })}`, 'P1M7D'); - }); - it('balances down differently depending on relativeTo', () => { - const oneYear = Duration.from({ years: 1 }); - equal(`${oneYear.round({ largestUnit: 'days', relativeTo: '2019-01-01' })}`, 'P365D'); - equal(`${oneYear.round({ largestUnit: 'days', relativeTo: '2019-07-01' })}`, 'P366D'); - const minusYear = Duration.from({ years: -1 }); - equal(`${minusYear.round({ largestUnit: 'days', relativeTo: '2020-01-01' })}`, '-P365D'); - equal(`${minusYear.round({ largestUnit: 'days', relativeTo: '2020-07-01' })}`, '-P366D'); - }); - it('rounds to an increment of hours', () => { - equal(`${d.round({ smallestUnit: 'hours', roundingIncrement: 3, relativeTo })}`, 'P5Y5M5W5DT6H'); - }); - it('rounds to an increment of minutes', () => { - equal(`${d.round({ smallestUnit: 'minutes', roundingIncrement: 30, relativeTo })}`, 'P5Y5M5W5DT5H'); - }); - it('rounds to an increment of seconds', () => { - equal(`${d.round({ smallestUnit: 'seconds', roundingIncrement: 15, relativeTo })}`, 'P5Y5M5W5DT5H5M'); - }); - it('rounds to an increment of milliseconds', () => { - equal(`${d.round({ smallestUnit: 'milliseconds', roundingIncrement: 10, relativeTo })}`, 'P5Y5M5W5DT5H5M5.01S'); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${d.round({ smallestUnit: 'microseconds', roundingIncrement: 10, relativeTo })}`, - 'P5Y5M5W5DT5H5M5.00501S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${d.round({ smallestUnit: 'nanoseconds', roundingIncrement: 10, relativeTo })}`, - 'P5Y5M5W5DT5H5M5.00500501S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { smallestUnit: 'hours', roundingIncrement, relativeTo }; - assert(d.round(options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const roundTo = { smallestUnit, roundingIncrement, relativeTo }; - assert(d.round(roundTo) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const roundTo = { smallestUnit, roundingIncrement, relativeTo }; - assert(d.round(roundTo) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => d.round({ relativeTo, smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'milliseconds', roundingIncrement: 29 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'microseconds', roundingIncrement: 29 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'nanoseconds', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => d.round({ relativeTo, smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'milliseconds', roundingIncrement: 1000 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'microseconds', roundingIncrement: 1000 }), RangeError); - throws(() => d.round({ relativeTo, smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), RangeError); - }); - it('accepts singular units', () => { - equal(`${d.round({ largestUnit: 'year', relativeTo })}`, `${d.round({ largestUnit: 'years', relativeTo })}`); - equal(`${d.round({ smallestUnit: 'year', relativeTo })}`, `${d.round({ smallestUnit: 'years', relativeTo })}`); - equal(`${d.round({ largestUnit: 'month', relativeTo })}`, `${d.round({ largestUnit: 'months', relativeTo })}`); - equal(`${d.round({ smallestUnit: 'month', relativeTo })}`, `${d.round({ smallestUnit: 'months', relativeTo })}`); - equal(`${d.round({ largestUnit: 'day', relativeTo })}`, `${d.round({ largestUnit: 'days', relativeTo })}`); - equal(`${d.round({ smallestUnit: 'day', relativeTo })}`, `${d.round({ smallestUnit: 'days', relativeTo })}`); - equal(`${d.round({ largestUnit: 'hour', relativeTo })}`, `${d.round({ largestUnit: 'hours', relativeTo })}`); - equal(`${d.round({ smallestUnit: 'hour', relativeTo })}`, `${d.round({ smallestUnit: 'hours', relativeTo })}`); - equal(`${d.round({ largestUnit: 'minute', relativeTo })}`, `${d.round({ largestUnit: 'minutes', relativeTo })}`); - equal( - `${d.round({ smallestUnit: 'minute', relativeTo })}`, - `${d.round({ smallestUnit: 'minutes', relativeTo })}` - ); - equal(`${d.round({ largestUnit: 'second', relativeTo })}`, `${d.round({ largestUnit: 'seconds', relativeTo })}`); - equal( - `${d.round({ smallestUnit: 'second', relativeTo })}`, - `${d.round({ smallestUnit: 'seconds', relativeTo })}` - ); - equal( - `${d.round({ largestUnit: 'millisecond', relativeTo })}`, - `${d.round({ largestUnit: 'milliseconds', relativeTo })}` - ); - equal( - `${d.round({ smallestUnit: 'millisecond', relativeTo })}`, - `${d.round({ smallestUnit: 'milliseconds', relativeTo })}` - ); - equal( - `${d.round({ largestUnit: 'microsecond', relativeTo })}`, - `${d.round({ largestUnit: 'microseconds', relativeTo })}` - ); - equal( - `${d.round({ smallestUnit: 'microsecond', relativeTo })}`, - `${d.round({ smallestUnit: 'microseconds', relativeTo })}` - ); - equal( - `${d.round({ largestUnit: 'nanosecond', relativeTo })}`, - `${d.round({ largestUnit: 'nanoseconds', relativeTo })}` - ); - equal( - `${d.round({ smallestUnit: 'nanosecond', relativeTo })}`, - `${d.round({ smallestUnit: 'nanoseconds', relativeTo })}` - ); - }); - it('counts the correct number of days when rounding relative to a date', () => { - const days = Duration.from({ days: 45 }); - equal(`${days.round({ relativeTo: '2019-01-01', smallestUnit: 'months' })}`, 'P2M'); - equal(`${days.negated().round({ relativeTo: '2019-02-15', smallestUnit: 'months' })}`, '-P1M'); - const yearAndHalf = Duration.from({ days: 547, hours: 12 }); - equal(`${yearAndHalf.round({ relativeTo: '2018-01-01', smallestUnit: 'years' })}`, 'P2Y'); - equal(`${yearAndHalf.round({ relativeTo: '2018-07-01', smallestUnit: 'years' })}`, 'P1Y'); - equal(`${yearAndHalf.round({ relativeTo: '2019-01-01', smallestUnit: 'years' })}`, 'P1Y'); - equal(`${yearAndHalf.round({ relativeTo: '2019-07-01', smallestUnit: 'years' })}`, 'P1Y'); - equal(`${yearAndHalf.round({ relativeTo: '2020-01-01', smallestUnit: 'years' })}`, 'P1Y'); - equal(`${yearAndHalf.round({ relativeTo: '2020-07-01', smallestUnit: 'years' })}`, 'P2Y'); - }); - it('throws with invalid offset in relativeTo', () => { - throws( - () => - Temporal.Duration.from('P1M280D').round({ - smallestUnit: 'month', - relativeTo: { year: 2021, month: 11, day: 26, offset: '+088:00', timeZone: 'Europe/London' } - }), - RangeError - ); - }); - }); - describe('Duration.total()', () => { - const d = new Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5); - const d2 = new Duration(0, 0, 0, 5, 5, 5, 5, 5, 5, 5); - const relativeTo = Temporal.PlainDateTime.from('2020-01-01T00:00'); - it('parameter may only be an object or string', () => { - [null, 1, true, Symbol('foo'), 1n].forEach((badOptions) => throws(() => d.total(badOptions), TypeError)); - }); - it('accepts string parameter as shortcut for {unit}', () => { - equal(d2.total({ unit: 'days' }).toString(), d2.total('days').toString()); - equal(d2.total({ unit: 'hours' }).toString(), d2.total('hours').toString()); - equal(d2.total({ unit: 'minutes' }).toString(), d2.total('minutes').toString()); - equal(d2.total({ unit: 'seconds' }).toString(), d2.total('seconds').toString()); - equal(d2.total({ unit: 'milliseconds' }).toString(), d2.total('milliseconds').toString()); - equal(d2.total({ unit: 'microseconds' }).toString(), d2.total('microseconds').toString()); - equal(d2.total({ unit: 'nanoseconds' }).toString(), d2.total('nanoseconds').toString()); - }); - it('throws on disallowed or invalid unit (object param)', () => { - ['era', 'nonsense'].forEach((unit) => { - throws(() => d.total({ unit }), RangeError); - }); - }); - it('throws on disallowed or invalid unit (string param)', () => { - ['era', 'nonsense'].forEach((unit) => { - throws(() => d.total(unit), RangeError); - }); - }); - it('does not lose precision for seconds and smaller units', () => { - const s = Temporal.Duration.from({ milliseconds: 2, microseconds: 31 }).total({ unit: 'seconds' }); - equal(s, 0.002031); - }); - it('accepts datetime string equivalents or fields for relativeTo', () => { - ['2020-01-01', '2020-01-01T00:00:00.000000000', 20200101, 20200101n, { year: 2020, month: 1, day: 1 }].forEach( - (relativeTo) => { - const daysPastJuly1 = 5 * 7 + 5 - 30; // 5 weeks + 5 days - 30 days in June - const partialDayNanos = - d.hours * 3.6e12 + - d.minutes * 6e10 + - d.seconds * 1e9 + - d.milliseconds * 1e6 + - d.microseconds * 1e3 + - d.nanoseconds; - const partialDay = partialDayNanos / (3.6e12 * 24); - const partialMonth = (daysPastJuly1 + partialDay) / 31; - const totalMonths = 5 * 12 + 5 + 1 + partialMonth; // +1 for 5 weeks - const total = d.total({ unit: 'months', relativeTo }); - equal(total.toPrecision(15), totalMonths.toPrecision(15)); // 66.32930780242619 - } - ); - }); - it("throws on relativeTo that can't be converted to datetime string", () => { - throws(() => d.total({ unit: 'months', relativeTo: Symbol('foo') }), TypeError); - }); - it('throws on relativeTo that converts to an invalid datetime string', () => { - [3.14, true, null, 'hello', 1n].forEach((relativeTo) => { - throws(() => d.total({ unit: 'months', relativeTo }), RangeError); - }); - }); - it('throws on wrong offset for ZonedDateTime relativeTo string', () => { - throws(() => d.total({ unit: 'months', relativeTo: '1971-01-01T00:00+02:00[Africa/Monrovia]' }), RangeError); - }); - it('does not throw on HH:MM rounded offset for ZonedDateTime relativeTo string', () => { - const oneMonth = Duration.from({ months: 1 }); - equal(oneMonth.total({ unit: 'months', relativeTo: '1971-01-01T00:00-00:45[Africa/Monrovia]' }), 1); - }); - it('throws on HH:MM rounded offset for ZonedDateTime relativeTo property bag', () => { - throws( - () => - d.total({ - unit: 'months', - relativeTo: { year: 1971, month: 1, day: 1, offset: '-00:45', timeZone: 'Africa/Monrovia' } - }), - RangeError - ); - }); - it('relativeTo object must contain at least the required correctly-spelled properties', () => { - throws(() => d.total({ unit: 'months', relativeTo: {} }), TypeError); - throws(() => d.total({ unit: 'months', relativeTo: { years: 2020, month: 1, day: 1 } }), TypeError); - }); - it('incorrectly-spelled properties are ignored in relativeTo', () => { - const oneMonth = Duration.from({ months: 1 }); - equal(oneMonth.total({ unit: 'months', relativeTo: { year: 2020, month: 1, day: 1, months: 2 } }), 1); - }); - it('throws RangeError if unit property is missing', () => { - [{}, () => {}, { roundingMode: 'ceil' }].forEach((roundTo) => throws(() => d.total(roundTo), RangeError)); - }); - it('relativeTo required to round calendar units even in durations w/o calendar units (object param)', () => { - throws(() => d2.total({ unit: 'years' }), RangeError); - throws(() => d2.total({ unit: 'months' }), RangeError); - throws(() => d2.total({ unit: 'weeks' }), RangeError); - }); - it('relativeTo required to round calendar units even in durations w/o calendar units (string param)', () => { - throws(() => d2.total('years'), RangeError); - throws(() => d2.total('months'), RangeError); - throws(() => d2.total('weeks'), RangeError); - }); - it('relativeTo is required to round durations with calendar units (object param)', () => { - throws(() => d.total({ unit: 'years' }), RangeError); - throws(() => d.total({ unit: 'months' }), RangeError); - throws(() => d.total({ unit: 'weeks' }), RangeError); - throws(() => d.total({ unit: 'days' }), RangeError); - throws(() => d.total({ unit: 'hours' }), RangeError); - throws(() => d.total({ unit: 'minutes' }), RangeError); - throws(() => d.total({ unit: 'seconds' }), RangeError); - throws(() => d.total({ unit: 'milliseconds' }), RangeError); - throws(() => d.total({ unit: 'microseconds' }), RangeError); - throws(() => d.total({ unit: 'nanoseconds' }), RangeError); - }); - it('relativeTo is required to round durations with calendar units (string param)', () => { - throws(() => d.total('years'), RangeError); - throws(() => d.total('months'), RangeError); - throws(() => d.total('weeks'), RangeError); - throws(() => d.total('days'), RangeError); - throws(() => d.total('hours'), RangeError); - throws(() => d.total('minutes'), RangeError); - throws(() => d.total('seconds'), RangeError); - throws(() => d.total('milliseconds'), RangeError); - throws(() => d.total('microseconds'), RangeError); - throws(() => d.total('nanoseconds'), RangeError); - }); - const d2Nanoseconds = - d2.days * 24 * 3.6e12 + - d2.hours * 3.6e12 + - d2.minutes * 6e10 + - d2.seconds * 1e9 + - d2.milliseconds * 1e6 + - d2.microseconds * 1e3 + - d2.nanoseconds; - const totalD2 = { - days: d2Nanoseconds / (24 * 3.6e12), - hours: d2Nanoseconds / 3.6e12, - minutes: d2Nanoseconds / 6e10, - seconds: d2Nanoseconds / 1e9, - milliseconds: d2Nanoseconds / 1e6, - microseconds: d2Nanoseconds / 1e3, - nanoseconds: d2Nanoseconds - }; - it('relativeTo not required to round fixed-length units in durations without variable units', () => { - assert(Math.abs(d2.total({ unit: 'days' }) - totalD2.days) < Number.EPSILON); - assert(Math.abs(d2.total({ unit: 'hours' }) - totalD2.hours) < Number.EPSILON); - assert(Math.abs(d2.total({ unit: 'minutes' }) - totalD2.minutes) < Number.EPSILON); - assert(Math.abs(d2.total({ unit: 'seconds' }) - totalD2.seconds) < Number.EPSILON); - assert(Math.abs(d2.total({ unit: 'milliseconds' }) - totalD2.milliseconds) < Number.EPSILON); - assert(Math.abs(d2.total({ unit: 'microseconds' }) - totalD2.microseconds) < Number.EPSILON); - equal(d2.total({ unit: 'nanoseconds' }), totalD2.nanoseconds); - }); - it('relativeTo not required to round fixed-length units in durations without variable units (negative)', () => { - const negativeD2 = d2.negated(); - assert(Math.abs(negativeD2.total({ unit: 'days' }) - -totalD2.days) < Number.EPSILON); - assert(Math.abs(negativeD2.total({ unit: 'hours' }) - -totalD2.hours) < Number.EPSILON); - assert(Math.abs(negativeD2.total({ unit: 'minutes' }) - -totalD2.minutes) < Number.EPSILON); - assert(Math.abs(negativeD2.total({ unit: 'seconds' }) - -totalD2.seconds) < Number.EPSILON); - assert(Math.abs(negativeD2.total({ unit: 'milliseconds' }) - -totalD2.milliseconds) < Number.EPSILON); - assert(Math.abs(negativeD2.total({ unit: 'microseconds' }) - -totalD2.microseconds) < Number.EPSILON); - equal(negativeD2.total({ unit: 'nanoseconds' }), -totalD2.nanoseconds); - }); - - const endpoint = relativeTo.add(d); - const options = (unit) => ({ largestUnit: unit, smallestUnit: unit, roundingMode: 'trunc' }); - const fullYears = 5; - const fullDays = endpoint.since(relativeTo, options('days')).days; - const fullMilliseconds = endpoint.since(relativeTo, options('milliseconds')).milliseconds; - const partialDayMilliseconds = fullMilliseconds - fullDays * 24 * 3.6e6 + 0.005005; - const fractionalDay = partialDayMilliseconds / (24 * 3.6e6); - const partialYearDays = fullDays - (fullYears * 365 + 2); - const fractionalYear = partialYearDays / 365 + fractionalDay / 365; // split to avoid precision loss - const fractionalMonths = ((endpoint.day - 1) * (24 * 3.6e6) + partialDayMilliseconds) / (31 * 24 * 3.6e6); - - const totalResults = { - years: fullYears + fractionalYear, - months: 66 + fractionalMonths, - weeks: (fullDays + fractionalDay) / 7, - days: fullDays + fractionalDay, - hours: fullDays * 24 + partialDayMilliseconds / 3.6e6, - minutes: fullDays * 24 * 60 + partialDayMilliseconds / 60000, - seconds: fullDays * 24 * 60 * 60 + partialDayMilliseconds / 1000, - milliseconds: fullMilliseconds + 0.005005, - microseconds: fullMilliseconds * 1000 + 5.005, - nanoseconds: fullMilliseconds * 1e6 + 5005 - }; - for (const [unit, expected] of Object.entries(totalResults)) { - it(`total(${unit}) = ${expected}`, () => { - // Computed values above are approximate due to accumulated floating point - // rounding errors, so just comparing the first 15 digits is good enough. - equal(d.total({ unit, relativeTo }).toPrecision(15), expected.toPrecision(15)); - }); - } - for (const unit of ['microseconds', 'nanoseconds']) { - it(`total(${unit}) may lose precision below ms`, () => { - assert(d.total({ unit, relativeTo }).toString().startsWith('174373505005')); - }); - } - it('balances differently depending on relativeTo', () => { - const fortyDays = Duration.from({ days: 40 }); - equal( - fortyDays.total({ unit: 'months', relativeTo: '2020-02-01' }).toPrecision(16), - (1 + 11 / 31).toPrecision(16) - ); - equal( - fortyDays.total({ unit: 'months', relativeTo: '2020-01-01' }).toPrecision(16), - (1 + 9 / 29).toPrecision(16) - ); - }); - it('balances differently depending on relativeTo (negative)', () => { - const negativeFortyDays = Duration.from({ days: -40 }); - equal( - negativeFortyDays.total({ unit: 'months', relativeTo: '2020-03-01' }).toPrecision(16), - (-(1 + 11 / 31)).toPrecision(16) - ); - equal( - negativeFortyDays.total({ unit: 'months', relativeTo: '2020-04-01' }).toPrecision(16), - (-(1 + 9 / 29)).toPrecision(16) - ); - }); - const oneDay = new Duration(0, 0, 0, 1); - it('relativeTo does not affect days if PlainDateTime', () => { - const relativeTo = Temporal.PlainDateTime.from('2017-01-01'); - equal(oneDay.total({ unit: 'hours', relativeTo }), 24); - }); - it('relativeTo does not affect days if ZonedDateTime, and duration encompasses no DST change', () => { - const relativeTo = Temporal.ZonedDateTime.from('2017-01-01T00:00[America/Montevideo]'); - equal(oneDay.total({ unit: 'hours', relativeTo }), 24); - }); - const skippedHourDay = Temporal.ZonedDateTime.from('2019-03-10T00:00[America/Vancouver]'); - const repeatedHourDay = Temporal.ZonedDateTime.from('2019-11-03T00:00[America/Vancouver]'); - const inRepeatedHour = Temporal.ZonedDateTime.from('2019-11-03T01:00-07:00[America/Vancouver]'); - const hours12 = new Duration(0, 0, 0, 0, 12); - const hours25 = new Duration(0, 0, 0, 0, 25); - describe('relativeTo affects days if ZonedDateTime, and duration encompasses DST change', () => { - it('start inside repeated hour, end after', () => { - equal(hours25.total({ unit: 'days', relativeTo: inRepeatedHour }), 1); - equal(oneDay.total({ unit: 'hours', relativeTo: inRepeatedHour }), 25); - }); - it('start after repeated hour, end inside (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-04T01:00[America/Vancouver]'); - equal(hours25.negated().total({ unit: 'days', relativeTo }), -1); - equal(oneDay.negated().total({ unit: 'hours', relativeTo }), -25); - }); - it('start inside repeated hour, end in skipped hour', () => { - const totalDays = Duration.from({ days: 126, hours: 1 }).total({ unit: 'days', relativeTo: inRepeatedHour }); - assert(Math.abs(totalDays - (126 + 1 / 23)) < Number.EPSILON); - equal(Duration.from({ days: 126, hours: 1 }).total({ unit: 'hours', relativeTo: inRepeatedHour }), 3026); - }); - it('start in normal hour, end in skipped hour', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-09T02:30[America/Vancouver]'); - const totalDays = hours25.total({ unit: 'days', relativeTo }); - assert(Math.abs(totalDays - (1 + 1 / 24)) < Number.EPSILON); - equal(oneDay.total({ unit: 'hours', relativeTo }), 24); - }); - it('start before skipped hour, end >1 day after', () => { - const totalDays = hours25.total({ unit: 'days', relativeTo: skippedHourDay }); - assert(Math.abs(totalDays - (1 + 2 / 24)) < Number.EPSILON); - equal(oneDay.total({ unit: 'hours', relativeTo: skippedHourDay }), 23); - }); - it('start after skipped hour, end >1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-11T00:00[America/Vancouver]'); - const totalDays = hours25.negated().total({ unit: 'days', relativeTo }); - assert(Math.abs(totalDays - (-1 - 2 / 24)) < Number.EPSILON); - equal(oneDay.negated().total({ unit: 'hours', relativeTo }), -23); - }); - it('start before skipped hour, end <1 day after', () => { - const totalDays = hours12.total({ unit: 'days', relativeTo: skippedHourDay }); - assert(Math.abs(totalDays - 12 / 23) < Number.EPSILON); - }); - it('start after skipped hour, end <1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-03-10T12:00[America/Vancouver]'); - const totalDays = hours12.negated().total({ unit: 'days', relativeTo }); - assert(Math.abs(totalDays - -12 / 23) < Number.EPSILON); - }); - it('start before repeated hour, end >1 day after', () => { - equal(hours25.total({ unit: 'days', relativeTo: repeatedHourDay }), 1); - equal(oneDay.total({ unit: 'hours', relativeTo: repeatedHourDay }), 25); - }); - it('start after repeated hour, end >1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-04T00:00[America/Vancouver]'); - equal(hours25.negated().total({ unit: 'days', relativeTo }), -1); - equal(oneDay.negated().total({ unit: 'hours', relativeTo }), -25); - }); - it('start before repeated hour, end <1 day after', () => { - const totalDays = hours12.total({ unit: 'days', relativeTo: repeatedHourDay }); - assert(Math.abs(totalDays - 12 / 25) < Number.EPSILON); - }); - it('start after repeated hour, end <1 day before (negative)', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-03T12:00[America/Vancouver]'); - const totalDays = hours12.negated().total({ unit: 'days', relativeTo }); - assert(Math.abs(totalDays - -12 / 25) < Number.EPSILON); - }); - it('Samoa skipped 24 hours', () => { - const relativeTo = Temporal.ZonedDateTime.from('2011-12-29T12:00-10:00[Pacific/Apia]'); - const totalDays = hours25.total({ unit: 'days', relativeTo }); - assert(Math.abs(totalDays - (2 + 1 / 24)) < Number.EPSILON); - equal(Duration.from({ hours: 48 }).total({ unit: 'days', relativeTo }), 3); - equal(Duration.from({ days: 2 }).total({ unit: 'hours', relativeTo }), 24); - equal(Duration.from({ days: 3 }).total({ unit: 'hours', relativeTo }), 48); - }); - }); - it('totaling back up to days', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-02T00:00[America/Vancouver]'); - equal(Duration.from({ hours: 48 }).total({ unit: 'days' }), 2); - const totalDays = Duration.from({ hours: 48 }).total({ unit: 'days', relativeTo }); - assert(Math.abs(totalDays - (1 + 24 / 25)) < Number.EPSILON); - }); - it('casts relativeTo to ZonedDateTime if possible', () => { - equal(oneDay.total({ unit: 'hours', relativeTo: '2019-11-03T00:00[America/Vancouver]' }), 25); - equal( - oneDay.total({ unit: 'hours', relativeTo: { year: 2019, month: 11, day: 3, timeZone: 'America/Vancouver' } }), - 25 - ); - }); - it('balances up to the next unit after rounding', () => { - const almostWeek = Duration.from({ days: 6, hours: 20 }); - const totalWeeks = almostWeek.total({ unit: 'weeks', relativeTo: '2020-01-01' }); - assert(Math.abs(totalWeeks - (6 + 20 / 24) / 7) < Number.EPSILON); - }); - it('balances up to the next unit after rounding (negative)', () => { - const almostWeek = Duration.from({ days: -6, hours: -20 }); - const totalWeeks = almostWeek.total({ unit: 'weeks', relativeTo: '2020-01-01' }); - assert(Math.abs(totalWeeks - -((6 + 20 / 24) / 7)) < Number.EPSILON); - }); - it('balances days up to both years and months', () => { - const twoYears = Duration.from({ months: 11, days: 396 }); - equal(twoYears.total({ unit: 'years', relativeTo: '2017-01-01' }), 2); - }); - it('balances days up to both years and months (negative)', () => { - const twoYears = Duration.from({ months: -11, days: -396 }); - equal(twoYears.total({ unit: 'years', relativeTo: '2017-01-01' }), -2); - }); - it('accepts singular units', () => { - equal(d.total({ unit: 'year', relativeTo }), d.total({ unit: 'years', relativeTo })); - equal(d.total({ unit: 'month', relativeTo }), d.total({ unit: 'months', relativeTo })); - equal(d.total({ unit: 'day', relativeTo }), d.total({ unit: 'days', relativeTo })); - equal(d.total({ unit: 'hour', relativeTo }), d.total({ unit: 'hours', relativeTo })); - equal(d.total({ unit: 'minute', relativeTo }), d.total({ unit: 'minutes', relativeTo })); - equal(d.total({ unit: 'second', relativeTo }), d.total({ unit: 'seconds', relativeTo })); - equal(d.total({ unit: 'second', relativeTo }), d.total({ unit: 'seconds', relativeTo })); - equal(d.total({ unit: 'millisecond', relativeTo }), d.total({ unit: 'milliseconds', relativeTo })); - equal(d.total({ unit: 'microsecond', relativeTo }), d.total({ unit: 'microseconds', relativeTo })); - equal(d.total({ unit: 'nanosecond', relativeTo }), d.total({ unit: 'nanoseconds', relativeTo })); - }); - it('throws with invalid offset in relativeTo', () => { - throws( - () => - Temporal.Duration.from('P1M280D').total({ - unit: 'month', - relativeTo: { year: 2021, month: 11, day: 26, offset: '+088:00', timeZone: 'Europe/London' } - }), - RangeError - ); - }); - }); - describe('Duration.compare', () => { - describe('time units only', () => { - const d1 = new Duration(0, 0, 0, 0, 5, 5, 5, 5, 5, 5); - const d2 = new Duration(0, 0, 0, 0, 5, 4, 5, 5, 5, 5); - it('equal', () => equal(Duration.compare(d1, d1), 0)); - it('smaller/larger', () => equal(Duration.compare(d2, d1), -1)); - it('larger/smaller', () => equal(Duration.compare(d1, d2), 1)); - it('negative/negative equal', () => equal(Duration.compare(d1.negated(), d1.negated()), 0)); - it('negative/negative smaller/larger', () => equal(Duration.compare(d2.negated(), d1.negated()), 1)); - it('negative/negative larger/smaller', () => equal(Duration.compare(d1.negated(), d2.negated()), -1)); - it('negative/positive', () => equal(Duration.compare(d1.negated(), d2), -1)); - it('positive/negative', () => equal(Duration.compare(d1, d2.negated()), 1)); - }); - describe('date units', () => { - const d1 = new Duration(5, 5, 5, 5, 5, 5, 5, 5, 5, 5); - const d2 = new Duration(5, 5, 5, 5, 5, 4, 5, 5, 5, 5); - const relativeTo = Temporal.PlainDateTime.from('2017-01-01'); - it('relativeTo is required', () => throws(() => Duration.compare(d1, d2)), RangeError); - it('equal', () => equal(Duration.compare(d1, d1, { relativeTo }), 0)); - it('smaller/larger', () => equal(Duration.compare(d2, d1, { relativeTo }), -1)); - it('larger/smaller', () => equal(Duration.compare(d1, d2, { relativeTo }), 1)); - it('negative/negative equal', () => equal(Duration.compare(d1.negated(), d1.negated(), { relativeTo }), 0)); - it('negative/negative smaller/larger', () => - equal(Duration.compare(d2.negated(), d1.negated(), { relativeTo }), 1)); - it('negative/negative larger/smaller', () => - equal(Duration.compare(d1.negated(), d2.negated(), { relativeTo }), -1)); - it('negative/positive', () => equal(Duration.compare(d1.negated(), d2, { relativeTo }), -1)); - it('positive/negative', () => equal(Duration.compare(d1, d2.negated(), { relativeTo }), 1)); - }); - it('casts first argument', () => { - equal(Duration.compare({ hours: 12 }, new Duration()), 1); - equal(Duration.compare('PT12H', new Duration()), 1); - }); - it('casts second argument', () => { - equal(Duration.compare(new Duration(), { hours: 12 }), -1); - equal(Duration.compare(new Duration(), 'PT12H'), -1); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => Duration.compare({ hour: 12 }, new Duration()), TypeError); - throws(() => Duration.compare(new Duration(), { hour: 12 }), TypeError); - }); - it('ignores incorrect properties', () => { - equal(Duration.compare({ hours: 12, minute: 5 }, { hours: 12, day: 5 }), 0); - }); - it('relativeTo affects year length', () => { - const oneYear = new Duration(1); - const days365 = new Duration(0, 0, 0, 365); - equal(Duration.compare(oneYear, days365, { relativeTo: Temporal.PlainDateTime.from('2017-01-01') }), 0); - equal(Duration.compare(oneYear, days365, { relativeTo: Temporal.PlainDateTime.from('2016-01-01') }), 1); - }); - it('relativeTo affects month length', () => { - const oneMonth = new Duration(0, 1); - const days30 = new Duration(0, 0, 0, 30); - equal(Duration.compare(oneMonth, days30, { relativeTo: Temporal.PlainDateTime.from('2018-04-01') }), 0); - equal(Duration.compare(oneMonth, days30, { relativeTo: Temporal.PlainDateTime.from('2018-03-01') }), 1); - equal(Duration.compare(oneMonth, days30, { relativeTo: Temporal.PlainDateTime.from('2018-02-01') }), -1); - }); - const oneDay = new Duration(0, 0, 0, 1); - const hours24 = new Duration(0, 0, 0, 0, 24); - it('relativeTo not required for days', () => { - equal(Duration.compare(oneDay, hours24), 0); - }); - it('relativeTo does not affect days if PlainDateTime', () => { - const relativeTo = Temporal.PlainDateTime.from('2017-01-01'); - equal(Duration.compare(oneDay, hours24, { relativeTo }), 0); - }); - it('relativeTo does not affect days if ZonedDateTime, and duration encompasses no DST change', () => { - const relativeTo = Temporal.ZonedDateTime.from('2017-01-01T00:00[America/Montevideo]'); - equal(Duration.compare(oneDay, hours24, { relativeTo }), 0); - }); - it('relativeTo does affect days if ZonedDateTime, and duration encompasses DST change', () => { - const relativeTo = Temporal.ZonedDateTime.from('2019-11-03T00:00[America/Vancouver]'); - equal(Duration.compare(oneDay, hours24, { relativeTo }), 1); - }); - it('casts relativeTo to ZonedDateTime if possible', () => { - equal(Duration.compare(oneDay, hours24, { relativeTo: '2019-11-03T00:00[America/Vancouver]' }), 1); - equal( - Duration.compare(oneDay, hours24, { - relativeTo: { year: 2019, month: 11, day: 3, timeZone: 'America/Vancouver' } - }), - 1 - ); - }); - it('casts relativeTo to PlainDateTime if possible', () => { - equal(Duration.compare(oneDay, hours24, { relativeTo: '2019-11-03T00:00' }), 0); - equal(Duration.compare(oneDay, hours24, { relativeTo: { year: 2019, month: 11, day: 3 } }), 0); - }); - it('at least the required properties must be present in relativeTo', () => { - throws(() => Duration.compare(oneDay, hours24, { relativeTo: { month: 11, day: 3 } }), TypeError); - throws(() => Duration.compare(oneDay, hours24, { relativeTo: { year: 2019, month: 11 } }), TypeError); - throws(() => Duration.compare(oneDay, hours24, { relativeTo: { year: 2019, day: 3 } }), TypeError); - }); - it('does not lose precision when totaling everything down to nanoseconds', () => { - notEqual(Duration.compare({ days: 200 }, { days: 200, nanoseconds: 1 }), 0); - }); - it('throws with invalid offset in relativeTo', () => { - throws(() => { - const d1 = Temporal.Duration.from('P1M280D'); - const d2 = Temporal.Duration.from('P1M281D'); - Temporal.Duration.compare(d1, d2, { - relativeTo: { year: 2021, month: 11, day: 26, offset: '+088:00', timeZone: 'Europe/London' } - }); - }, RangeError); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/exports.js b/packages/temporal-polyfill/tests/exports.js deleted file mode 100644 index 28bb9c52..00000000 --- a/packages/temporal-polyfill/tests/exports.js +++ /dev/null @@ -1,78 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; - -describe('Exports', () => { - const named = Object.keys(Temporal) - - it('should be 11 things', () => { - equal(named.length, 11); - }); - it('should contain `Instant`', () => { - assert(named.includes('Instant')); - }); - it('should contain `TimeZone`', () => { - assert(named.includes('TimeZone')); - }); - it('should contain `PlainDate`', () => { - assert(named.includes('PlainDate')); - }); - it('should contain `PlainTime`', () => { - assert(named.includes('PlainTime')); - }); - it('should contain `PlainDateTime`', () => { - assert(named.includes('PlainDateTime')); - }); - it('should contain `ZonedDateTime`', () => { - assert(named.includes('ZonedDateTime')); - }); - it('should contain `PlainYearMonth`', () => { - assert(named.includes('PlainYearMonth')); - }); - it('should contain `PlainMonthDay`', () => { - assert(named.includes('PlainMonthDay')); - }); - it('should contain `Duration`', () => { - assert(named.includes('Duration')); - }); - it('should contain `Calendar`', () => { - assert(named.includes('Calendar')); - }); - it('should contain `Now`', () => { - assert(named.includes('Now')); - }); - - // [fullcalendar/temporal] - it('should have correct Symbol.toStringTag values', () => { - const map = { - Instant: Temporal.Now.instant(), - ZonedDateTime: Temporal.Now.zonedDateTimeISO(), - PlainDateTime: Temporal.Now.plainDateTimeISO(), - PlainDate: Temporal.Now.plainDateISO(), - PlainTime: Temporal.Now.plainTimeISO(), - PlainYearMonth: Temporal.Now.plainDateISO().toPlainYearMonth(), - PlainMonthDay: Temporal.Now.plainDateISO().toPlainMonthDay(), - Calendar: new Temporal.Calendar('iso8601'), - TimeZone: new Temporal.TimeZone('UTC'), - Now: Temporal.Now, - Duration: new Temporal.Duration(), - } - for (let key in map) { - equal( - map[key][Symbol.toStringTag], - `Temporal.${key}` - ) - } - }); - it('should have correct Symbol.toStringTag value for Temporal', () => { - equal( - Temporal[Symbol.toStringTag], - 'Temporal', - ) - }) -}); diff --git a/packages/temporal-polyfill/tests/instant.js b/packages/temporal-polyfill/tests/instant.js deleted file mode 100644 index 891f5f87..00000000 --- a/packages/temporal-polyfill/tests/instant.js +++ /dev/null @@ -1,1404 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, notStrictEqual: notEqual, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { Instant } = Temporal; - -describe('Instant', () => { - describe('Structure', () => { - it('Instant is a Function', () => { - equal(typeof Instant, 'function'); - }); - it('Instant has a prototype', () => { - assert(Instant.prototype); - equal(typeof Instant.prototype, 'object'); - }); - describe('Instant.prototype', () => { - it('Instant.prototype.equals is a Function', () => { - equal(typeof Instant.prototype.equals, 'function'); - }); - it('Instant.prototype.until is a Function', () => { - equal(typeof Instant.prototype.until, 'function'); - }); - it('Instant.prototype.since is a Function', () => { - equal(typeof Instant.prototype.since, 'function'); - }); - it('Instant.prototype.round is a Function', () => { - equal(typeof Instant.prototype.round, 'function'); - }); - it('Instant.prototype.toZonedDateTimeISO is a Function', () => { - equal(typeof Instant.prototype.toZonedDateTimeISO, 'function'); - }); - it('Instant.prototype.toZonedDateTime is a Function', () => { - equal(typeof Instant.prototype.toZonedDateTime, 'function'); - }); - }); - it('Instant.fromEpochSeconds is a Function', () => { - equal(typeof Instant.fromEpochSeconds, 'function'); - }); - it('Instant.fromEpochMicroseconds is a Function', () => { - equal(typeof Instant.fromEpochMicroseconds, 'function'); - }); - it('Instant.fromEpochMilliseconds is a Function', () => { - equal(typeof Instant.fromEpochMilliseconds, 'function'); - }); - it('Instant.fromEpochNanoseconds is a Function', () => { - equal(typeof Instant.fromEpochNanoseconds, 'function'); - }); - it('Instant.from is a Function', () => { - equal(typeof Instant.from, 'function'); - }); - it('Instant.compare is a Function', () => { - equal(typeof Instant.compare, 'function'); - }); - }); - describe('Construction', () => { - it('can construct', () => { - const epochMillis = Date.UTC(1976, 10, 18, 14, 23, 30, 123); - const epochNanos = BigInt(epochMillis) * BigInt(1e6) + BigInt(456789); - const instant = new Instant(epochNanos); - assert(instant); - equal(typeof instant, 'object'); - equal(instant.epochSeconds, Math.floor(Date.UTC(1976, 10, 18, 14, 23, 30, 123) / 1e3), 'epochSeconds'); - equal(instant.epochMilliseconds, Date.UTC(1976, 10, 18, 14, 23, 30, 123), 'epochMilliseconds'); - }); - it('constructs from string', () => equal(`${new Instant('0')}`, '1970-01-01T00:00:00Z')); - it('throws on number', () => throws(() => new Instant(1234), TypeError)); - it('throws on string that does not convert to BigInt', () => throws(() => new Instant('abc123'), SyntaxError)); - }); - describe('instant.toString() works', () => { - it('`1976-11-18T14:23:30.123456789Z`.toString()', () => { - const iso = '1976-11-18T14:23:30.123456789Z'; - const instant = Instant.from(iso); - assert(instant); - equal(`${instant}`, iso); - }); - it('`1963-02-13T09:36:29.123456789Z`.toString()', () => { - const iso = '1963-02-13T09:36:29.123456789Z'; - const instant = Instant.from(iso); - assert(instant); - equal(`${instant}`, iso); - }); - it('optional time zone parameter UTC', () => { - const inst = Instant.from('1976-11-18T14:23:30.123456789Z'); - const timeZone = Temporal.TimeZone.from('UTC'); - equal(inst.toString({ timeZone }), '1976-11-18T14:23:30.123456789+00:00'); - }); - it('optional time zone parameter non-UTC', () => { - const inst = Instant.from('1976-11-18T14:23:30.123456789Z'); - const timeZone = Temporal.TimeZone.from('America/New_York'); - equal(inst.toString({ timeZone }), '1976-11-18T09:23:30.123456789-05:00'); - }); - it('sub-minute offset', () => { - const inst = Instant.from('1900-01-01T12:00Z'); - const timeZone = Temporal.TimeZone.from('Europe/Amsterdam'); - equal(inst.toString({ timeZone }), '1900-01-01T12:19:32+00:20'); - }); - const i1 = Instant.from('1976-11-18T15:23Z'); - const i2 = Instant.from('1976-11-18T15:23:30Z'); - const i3 = Instant.from('1976-11-18T15:23:30.1234Z'); - it('default is to emit seconds and drop trailing zeros after the decimal', () => { - equal(i1.toString(), '1976-11-18T15:23:00Z'); - equal(i2.toString(), '1976-11-18T15:23:30Z'); - equal(i3.toString(), '1976-11-18T15:23:30.1234Z'); - }); - it('truncates to minute', () => { - [i1, i2, i3].forEach((i) => equal(i.toString({ smallestUnit: 'minute' }), '1976-11-18T15:23Z')); - }); - it('other smallestUnits are aliases for fractional digits', () => { - equal(i3.toString({ smallestUnit: 'second' }), i3.toString({ fractionalSecondDigits: 0 })); - equal(i3.toString({ smallestUnit: 'millisecond' }), i3.toString({ fractionalSecondDigits: 3 })); - equal(i3.toString({ smallestUnit: 'microsecond' }), i3.toString({ fractionalSecondDigits: 6 })); - equal(i3.toString({ smallestUnit: 'nanosecond' }), i3.toString({ fractionalSecondDigits: 9 })); - }); - it('throws on invalid or disallowed smallestUnit', () => { - ['era', 'year', 'month', 'day', 'hour', 'nonsense'].forEach((smallestUnit) => - throws(() => i1.toString({ smallestUnit }), RangeError) - ); - }); - it('accepts plural units', () => { - equal(i3.toString({ smallestUnit: 'minutes' }), i3.toString({ smallestUnit: 'minute' })); - equal(i3.toString({ smallestUnit: 'seconds' }), i3.toString({ smallestUnit: 'second' })); - equal(i3.toString({ smallestUnit: 'milliseconds' }), i3.toString({ smallestUnit: 'millisecond' })); - equal(i3.toString({ smallestUnit: 'microseconds' }), i3.toString({ smallestUnit: 'microsecond' })); - equal(i3.toString({ smallestUnit: 'nanoseconds' }), i3.toString({ smallestUnit: 'nanosecond' })); - }); - it('truncates or pads to 2 places', () => { - const options = { fractionalSecondDigits: 2 }; - equal(i1.toString(options), '1976-11-18T15:23:00.00Z'); - equal(i2.toString(options), '1976-11-18T15:23:30.00Z'); - equal(i3.toString(options), '1976-11-18T15:23:30.12Z'); - }); - it('pads to 7 places', () => { - const options = { fractionalSecondDigits: 7 }; - equal(i1.toString(options), '1976-11-18T15:23:00.0000000Z'); - equal(i2.toString(options), '1976-11-18T15:23:30.0000000Z'); - equal(i3.toString(options), '1976-11-18T15:23:30.1234000Z'); - }); - it('auto is the default', () => { - [i1, i2, i3].forEach((i) => equal(i.toString({ fractionalSecondDigits: 'auto' }), i.toString())); - }); - it('throws on out of range or invalid fractionalSecondDigits', () => { - [-1, 10, Infinity, NaN, 'not-auto'].forEach((fractionalSecondDigits) => - throws(() => i1.toString({ fractionalSecondDigits }), RangeError) - ); - }); - it('accepts and truncates fractional fractionalSecondDigits', () => { - equal(i3.toString({ fractionalSecondDigits: 5.5 }), '1976-11-18T15:23:30.12340Z'); - }); - it('smallestUnit overrides fractionalSecondDigits', () => { - equal(i3.toString({ smallestUnit: 'minute', fractionalSecondDigits: 9 }), '1976-11-18T15:23Z'); - }); - it('throws on invalid roundingMode', () => { - throws(() => i1.toString({ roundingMode: 'cile' }), RangeError); - }); - it('rounds to nearest', () => { - equal(i2.toString({ smallestUnit: 'minute', roundingMode: 'halfExpand' }), '1976-11-18T15:24Z'); - equal(i3.toString({ fractionalSecondDigits: 3, roundingMode: 'halfExpand' }), '1976-11-18T15:23:30.123Z'); - }); - it('rounds up', () => { - equal(i2.toString({ smallestUnit: 'minute', roundingMode: 'ceil' }), '1976-11-18T15:24Z'); - equal(i3.toString({ fractionalSecondDigits: 3, roundingMode: 'ceil' }), '1976-11-18T15:23:30.124Z'); - }); - it('rounds down', () => { - ['floor', 'trunc'].forEach((roundingMode) => { - equal(i2.toString({ smallestUnit: 'minute', roundingMode }), '1976-11-18T15:23Z'); - equal(i3.toString({ fractionalSecondDigits: 3, roundingMode }), '1976-11-18T15:23:30.123Z'); - }); - }); - it('rounding down is towards the Big Bang, not towards 1 BCE', () => { - const i4 = Instant.from('-000099-12-15T12:00:00.5Z'); - equal(i4.toString({ smallestUnit: 'second', roundingMode: 'floor' }), '-000099-12-15T12:00:00Z'); - }); - it('rounding can affect all units', () => { - const i5 = Instant.from('1999-12-31T23:59:59.999999999Z'); - equal(i5.toString({ fractionalSecondDigits: 8, roundingMode: 'halfExpand' }), '2000-01-01T00:00:00.00000000Z'); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => i1.toString(badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(i1.toString(options), '1976-11-18T15:23:00Z')); - }); - }); - describe('Instant.toJSON() works', () => { - it('`1976-11-18T15:23:30.123456789+01:00`.toJSON()', () => { - const inst = Instant.from('1976-11-18T15:23:30.123456789+01:00'); - assert(inst); - equal(inst.toJSON(), '1976-11-18T14:23:30.123456789Z'); - }); - it('`1963-02-13T10:36:29.123456789+01:00`.toJSON()', () => { - const inst = Instant.from('1963-02-13T10:36:29.123456789+01:00'); - assert(inst); - equal(inst.toJSON(), '1963-02-13T09:36:29.123456789Z'); - }); - it('argument is ignored', () => { - const inst = Instant.from('1976-11-18T15:23:30.123456789+01:00'); - equal(inst.toJSON('+01:00'), inst.toJSON()); - }); - }); - describe('Instant.epochSeconds works', () => { - it('post-epoch', () => { - const epochMs = Date.UTC(1976, 10, 18, 15, 23, 30, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochSeconds, Math.trunc(epochMs / 1e3)); - equal(typeof inst.epochSeconds, 'number'); - }); - it('pre-epoch', () => { - const epochMs = Date.UTC(1963, 1, 13, 9, 36, 29, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochSeconds, Math.trunc(epochMs / 1e3)); - equal(typeof inst.epochSeconds, 'number'); - }); - }); - describe('Instant.fromEpochSeconds() works', () => { - it('1976-11-18T15:23:30', () => { - const epochSeconds = Math.floor(Date.UTC(1976, 10, 18, 15, 23, 30, 123) / 1e3); - const instant = Instant.fromEpochSeconds(epochSeconds); - equal(instant.epochSeconds, epochSeconds); - }); - it('1963-02-13T09:36:29', () => { - const epochSeconds = Math.floor(Date.UTC(1963, 1, 13, 9, 36, 29, 123) / 1e3); - const instant = Instant.fromEpochSeconds(epochSeconds); - equal(instant.epochSeconds, epochSeconds); - }); - }); - describe('Instant.epochMilliseconds() works', () => { - it('post-epoch', () => { - const epochMs = Date.UTC(1976, 10, 18, 15, 23, 30, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochMilliseconds, epochMs); - equal(typeof inst.epochMilliseconds, 'number'); - }); - it('pre-epoch', () => { - const epochMs = Date.UTC(1963, 1, 13, 9, 36, 29, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochMilliseconds, epochMs); - equal(typeof inst.epochMilliseconds, 'number'); - }); - }); - describe('Instant.fromEpochMilliseconds() works', () => { - it('1976-11-18T15:23:30.123', () => { - const epochMilliseconds = Date.UTC(1976, 10, 18, 15, 23, 30, 123); - const instant = Instant.fromEpochMilliseconds(epochMilliseconds); - equal(instant.epochMilliseconds, epochMilliseconds); - }); - it('1963-02-13T09:36:29.123', () => { - const epochMilliseconds = Date.UTC(1963, 1, 13, 9, 36, 29, 123); - const instant = Instant.fromEpochMilliseconds(epochMilliseconds); - equal(instant.epochMilliseconds, epochMilliseconds); - }); - }); - describe('Instant.epochMicroseconds works', () => { - it('post-epoch', () => { - const epochMs = Date.UTC(1976, 10, 18, 15, 23, 30, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochMicroseconds, BigInt(epochMs) * BigInt(1e3)); - equal(typeof inst.epochMicroseconds, 'bigint'); - }); - it('pre-epoch', () => { - const epochMs = Date.UTC(1963, 1, 13, 9, 36, 29, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochMicroseconds, BigInt(epochMs) * BigInt(1e3)); - equal(typeof inst.epochMicroseconds, 'bigint'); - }); - }); - describe('Instant.fromEpochMicroseconds() works', () => { - it('1976-11-18T15:23:30.123456', () => { - const epochMicroseconds = BigInt(Date.UTC(1976, 10, 18, 15, 23, 30, 123)) * BigInt(1e3) + BigInt(456); - const instant = Instant.fromEpochMicroseconds(epochMicroseconds); - equal(instant.epochMicroseconds, epochMicroseconds); - }); - it('1963-02-13T09:36:29.123456', () => { - const epochMicroseconds = BigInt(Date.UTC(1963, 1, 13, 9, 36, 29, 123)) * BigInt(1e3) + BigInt(456); - const instant = Instant.fromEpochMicroseconds(epochMicroseconds); - equal(instant.epochMicroseconds, epochMicroseconds); - }); - }); - describe('Instant.epochNanoseconds works', () => { - it('post-epoch', () => { - const epochMs = Date.UTC(1976, 10, 18, 15, 23, 30, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochNanoseconds, epochNs); - equal(typeof inst.epochNanoseconds, 'bigint'); - }); - it('pre-epoch', () => { - const epochMs = Date.UTC(1963, 1, 13, 9, 36, 29, 123); - const epochNs = BigInt(epochMs) * BigInt(1e6); - const inst = new Instant(epochNs); - equal(inst.epochNanoseconds, epochNs); - equal(typeof inst.epochNanoseconds, 'bigint'); - }); - }); - describe('Instant.fromEpochNanoseconds() works', () => { - it('1976-11-18T15:23:30.123456789', () => { - const epochNanoseconds = BigInt(Date.UTC(1976, 10, 18, 15, 23, 30, 123)) * BigInt(1e6) + BigInt(456789); - const instant = Instant.fromEpochNanoseconds(epochNanoseconds); - equal(instant.epochNanoseconds, epochNanoseconds); - }); - it('1963-02-13T09:36:29.123456789', () => { - const epochNanoseconds = BigInt(Date.UTC(1963, 1, 13, 9, 36, 29, 123)) * BigInt(1e6) + BigInt(456789); - const instant = Instant.fromEpochNanoseconds(epochNanoseconds); - equal(instant.epochNanoseconds, epochNanoseconds); - }); - it('-1n', () => { - const instant = Instant.fromEpochNanoseconds(-1n); - equal(`${instant}`, '1969-12-31T23:59:59.999999999Z'); - }); - }); - describe('Instant.from() works', () => { - it('1976-11-18T15:23Z', () => { - equal(Instant.from('1976-11-18T15:23Z').epochMilliseconds, Date.UTC(1976, 10, 18, 15, 23)); - }); - it('1976-11-18T15:23:30Z', () => { - equal(Instant.from('1976-11-18T15:23:30Z').epochMilliseconds, Date.UTC(1976, 10, 18, 15, 23, 30)); - }); - it('1976-11-18T15:23:30.123Z', () => { - equal(Instant.from('1976-11-18T15:23:30.123Z').epochMilliseconds, Date.UTC(1976, 10, 18, 15, 23, 30, 123)); - }); - it('1976-11-18T15:23:30.123456Z', () => { - equal( - Instant.from('1976-11-18T15:23:30.123456Z').epochMicroseconds, - BigInt(Date.UTC(1976, 10, 18, 15, 23, 30, 123)) * BigInt(1e3) + BigInt(456) - ); - }); - it('1976-11-18T15:23:30.123456789Z', () => { - equal( - Instant.from('1976-11-18T15:23:30.123456789Z').epochNanoseconds, - BigInt(Date.UTC(1976, 10, 18, 15, 23, 30, 123)) * BigInt(1e6) + BigInt(456789) - ); - }); - it('2020-02-12T11:42-08:00', () => { - equal( - Instant.from('2020-02-12T11:42-08:00').epochNanoseconds, - BigInt(Date.UTC(2020, 1, 12, 19, 42)) * BigInt(1e6) - ); - }); - it('2020-02-12T11:42-08:00[America/Vancouver]', () => { - equal( - Instant.from('2020-02-12T11:42-08:00[America/Vancouver]').epochNanoseconds, - BigInt(Date.UTC(2020, 1, 12, 19, 42)) * BigInt(1e6) - ); - }); - it('2020-02-12T11:42+01:00', () => { - equal( - Instant.from('2020-02-12T11:42+01:00').epochNanoseconds, - BigInt(Date.UTC(2020, 1, 12, 10, 42)) * BigInt(1e6) - ); - }); - it('2020-02-12T11:42+01:00[Europe/Amsterdam]', () => { - equal( - Instant.from('2020-02-12T11:42+01:00[Europe/Amsterdam]').epochNanoseconds, - BigInt(Date.UTC(2020, 1, 12, 10, 42)) * BigInt(1e6) - ); - }); - it('2019-02-16T23:45-02:00[America/Sao_Paulo]', () => { - equal( - Instant.from('2019-02-16T23:45-02:00[America/Sao_Paulo]').epochNanoseconds, - BigInt(Date.UTC(2019, 1, 17, 1, 45)) * BigInt(1e6) - ); - }); - it('2019-02-16T23:45-03:00[America/Sao_Paulo]', () => { - equal( - Instant.from('2019-02-16T23:45-03:00[America/Sao_Paulo]').epochNanoseconds, - BigInt(Date.UTC(2019, 1, 17, 2, 45)) * BigInt(1e6) - ); - }); - it('sub-minute offset', () => { - equal( - Instant.from('1900-01-01T12:19:32+00:19:32[Europe/Amsterdam]').epochNanoseconds, - BigInt(Date.UTC(1900, 0, 1, 12)) * BigInt(1e6) - ); - }); - it('throws when offset not provided', () => { - throws(() => Instant.from('2019-02-16T23:45[America/Sao_Paulo]'), RangeError); - }); - it('ignores the bracketed IANA time zone when the offset is incorrect', () => { - equal( - Instant.from('2019-02-16T23:45-04:00[America/Sao_Paulo]').epochNanoseconds, - BigInt(Date.UTC(2019, 1, 17, 3, 45)) * BigInt(1e6) - ); - }); - it('Instant.from(string-convertible) converts to string', () => { - const obj = { - toString() { - return '2020-02-12T11:42+01:00[Europe/Amsterdam]'; - } - }; - equal(`${Instant.from(obj)}`, '2020-02-12T10:42:00Z'); - }); - it('Instant.from(1) throws', () => throws(() => Instant.from(1), RangeError)); - it('Instant.from(-1) throws', () => throws(() => Instant.from(-1), RangeError)); - it('Instant.from(1n) throws', () => throws(() => Instant.from(1n), RangeError)); - it('Instant.from(-1n) throws', () => throws(() => Instant.from(-1n), RangeError)); - it('Instant.from({}) throws', () => throws(() => Instant.from({}), RangeError)); - it('Instant.from(instant) is not the same object', () => { - const inst = Instant.from('2020-02-12T11:42+01:00[Europe/Amsterdam]'); - notEqual(Instant.from(inst), inst); - }); - it('Instant.from(ISO string leap second) is constrained', () => { - equal(`${Instant.from('2016-12-31T23:59:60Z')}`, '2016-12-31T23:59:59Z'); - }); - it('variant time separators', () => { - equal(`${Instant.from('1976-11-18t15:23Z')}`, '1976-11-18T15:23:00Z'); - equal(`${Instant.from('1976-11-18 15:23Z')}`, '1976-11-18T15:23:00Z'); - }); - it('variant UTC designator', () => { - equal(`${Instant.from('1976-11-18T15:23z')}`, '1976-11-18T15:23:00Z'); - }); - it('any number of decimal places', () => { - equal(`${Instant.from('1976-11-18T15:23:30.1Z')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('1976-11-18T15:23:30.12Z')}`, '1976-11-18T15:23:30.12Z'); - equal(`${Instant.from('1976-11-18T15:23:30.123Z')}`, '1976-11-18T15:23:30.123Z'); - equal(`${Instant.from('1976-11-18T15:23:30.1234Z')}`, '1976-11-18T15:23:30.1234Z'); - equal(`${Instant.from('1976-11-18T15:23:30.12345Z')}`, '1976-11-18T15:23:30.12345Z'); - equal(`${Instant.from('1976-11-18T15:23:30.123456Z')}`, '1976-11-18T15:23:30.123456Z'); - equal(`${Instant.from('1976-11-18T15:23:30.1234567Z')}`, '1976-11-18T15:23:30.1234567Z'); - equal(`${Instant.from('1976-11-18T15:23:30.12345678Z')}`, '1976-11-18T15:23:30.12345678Z'); - equal(`${Instant.from('1976-11-18T15:23:30.123456789Z')}`, '1976-11-18T15:23:30.123456789Z'); - }); - it('variant decimal separator', () => { - equal(`${Instant.from('1976-11-18T15:23:30,12Z')}`, '1976-11-18T15:23:30.12Z'); - }); - it('variant minus sign', () => { - equal(`${Instant.from('1976-11-18T15:23:30.12\u221202:00')}`, '1976-11-18T17:23:30.12Z'); - equal(`${Instant.from('\u2212009999-11-18T15:23:30.12Z')}`, '-009999-11-18T15:23:30.12Z'); - }); - it('mixture of basic and extended format', () => { - equal(`${Instant.from('19761118T15:23:30.1+00:00')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('1976-11-18T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('1976-11-18T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('1976-11-18T152330.1+0000')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('19761118T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('19761118T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('+0019761118T15:23:30.1+00:00')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('+001976-11-18T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('+001976-11-18T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('+001976-11-18T152330.1+0000')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('+0019761118T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('+0019761118T152330.1+00:00')}`, '1976-11-18T15:23:30.1Z'); - equal(`${Instant.from('+0019761118T152330.1+0000')}`, '1976-11-18T15:23:30.1Z'); - }); - it('optional parts', () => { - equal(`${Instant.from('1976-11-18T15:23:30+00')}`, '1976-11-18T15:23:30Z'); - equal(`${Instant.from('1976-11-18T15Z')}`, '1976-11-18T15:00:00Z'); - }); - it('ignores any specified calendar', () => - equal(`${Instant.from('1976-11-18T15:23:30.123456789Z[u-ca=discord]')}`, '1976-11-18T15:23:30.123456789Z')); - it('no junk at end of string', () => throws(() => Instant.from('1976-11-18T15:23:30.123456789Zjunk'), RangeError)); - }); - describe('Instant.add works', () => { - const inst = Instant.from('1969-12-25T12:23:45.678901234Z'); - describe('cross epoch in ms', () => { - const one = inst.subtract({ hours: 240, nanoseconds: 800 }); - const two = inst.add({ hours: 240, nanoseconds: 800 }); - const three = two.subtract({ hours: 480, nanoseconds: 1600 }); - const four = one.add({ hours: 480, nanoseconds: 1600 }); - it(`(${inst}).subtract({ hours: 240, nanoseconds: 800 }) = ${one}`, () => - equal(`${one}`, '1969-12-15T12:23:45.678900434Z')); - it(`(${inst}).add({ hours: 240, nanoseconds: 800 }) = ${two}`, () => - equal(`${two}`, '1970-01-04T12:23:45.678902034Z')); - it(`(${two}).subtract({ hours: 480, nanoseconds: 1600 }) = ${one}`, () => assert(three.equals(one))); - it(`(${one}).add({ hours: 480, nanoseconds: 1600 }) = ${two}`, () => assert(four.equals(two))); - }); - it('inst.add(durationObj)', () => { - const later = inst.add(Temporal.Duration.from('PT240H0.000000800S')); - equal(`${later}`, '1970-01-04T12:23:45.678902034Z'); - }); - it('casts argument', () => { - equal(`${inst.add('PT240H0.000000800S')}`, '1970-01-04T12:23:45.678902034Z'); - }); - it('invalid to add years, months, weeks, or days', () => { - throws(() => inst.add({ years: 1 }), RangeError); - throws(() => inst.add({ months: 1 }), RangeError); - throws(() => inst.add({ weeks: 1 }), RangeError); - throws(() => inst.add({ days: 1 }), RangeError); - }); - it('mixed positive and negative values always throw', () => { - throws(() => inst.add({ hours: 1, minutes: -30 }), RangeError); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => inst.add({}), TypeError); - throws(() => inst.add({ hour: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${inst.add({ hour: 1, minutes: 1 })}`, '1969-12-25T12:24:45.678901234Z'); - }); - }); - describe('Instant.subtract works', () => { - const inst = Instant.from('1969-12-25T12:23:45.678901234Z'); - it('inst.subtract(durationObj)', () => { - const earlier = inst.subtract(Temporal.Duration.from('PT240H0.000000800S')); - equal(`${earlier}`, '1969-12-15T12:23:45.678900434Z'); - }); - it('casts argument', () => { - equal(`${inst.subtract('PT240H0.000000800S')}`, '1969-12-15T12:23:45.678900434Z'); - }); - it('invalid to subtract years, months, weeks, or days', () => { - throws(() => inst.subtract({ years: 1 }), RangeError); - throws(() => inst.subtract({ months: 1 }), RangeError); - throws(() => inst.subtract({ weeks: 1 }), RangeError); - throws(() => inst.subtract({ days: 1 }), RangeError); - }); - it('mixed positive and negative values always throw', () => { - throws(() => inst.subtract({ hours: 1, minutes: -30 }), RangeError); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => inst.subtract({}), TypeError); - throws(() => inst.subtract({ hour: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${inst.subtract({ hour: 1, minutes: 1 })}`, '1969-12-25T12:22:45.678901234Z'); - }); - }); - describe('Instant.compare works', () => { - const i1 = Instant.from('1963-02-13T09:36:29.123456789Z'); - const i2 = Instant.from('1976-11-18T15:23:30.123456789Z'); - const i3 = Instant.from('1981-12-15T14:34:31.987654321Z'); - it('pre epoch equal', () => equal(Instant.compare(i1, Instant.from(i1)), 0)); - it('epoch equal', () => equal(Instant.compare(i2, Instant.from(i2)), 0)); - it('cross epoch smaller/larger', () => equal(Instant.compare(i1, i2), -1)); - it('cross epoch larger/smaller', () => equal(Instant.compare(i2, i1), 1)); - it('epoch smaller/larger', () => equal(Instant.compare(i2, i3), -1)); - it('epoch larger/smaller', () => equal(Instant.compare(i3, i2), 1)); - it('casts first argument', () => equal(Instant.compare(i1, i1.toString()), 0)); - it('casts second argument', () => equal(Instant.compare(i2.toString(), i2), 0)); - it('only casts from a string', () => { - throws(() => Instant.compare(i2.epochNanoseconds, i2), RangeError); - throws(() => Instant.compare({}, i2), RangeError); - }); - }); - describe('Instant.equals works', () => { - const i1 = Instant.from('1963-02-13T09:36:29.123456789Z'); - const i2 = Instant.from('1976-11-18T15:23:30.123456789Z'); - const i3 = Instant.from('1981-12-15T14:34:31.987654321Z'); - it('pre epoch equal', () => assert(i1.equals(i1))); - it('epoch equal', () => assert(i2.equals(i2))); - it('cross epoch unequal', () => assert(!i1.equals(i2))); - it('epoch unequal', () => assert(!i2.equals(i3))); - it('casts argument', () => assert(i1.equals('1963-02-13T09:36:29.123456789Z'))); - it('casts only from string', () => { - throws(() => i1.equals(i1.epochNanoseconds), RangeError); - throws(() => i1.equals({}), RangeError); - }); - }); - describe("Comparison operators don't work", () => { - const i1 = Instant.from('1963-02-13T09:36:29.123456789Z'); - const i1again = Instant.from('1963-02-13T09:36:29.123456789Z'); - const i2 = Instant.from('1976-11-18T15:23:30.123456789Z'); - it('=== is object equality', () => equal(i1, i1)); - it('!== is object equality', () => notEqual(i1, i1again)); - it('<', () => throws(() => i1 < i2)); - it('>', () => throws(() => i1 > i2)); - it('<=', () => throws(() => i1 <= i2)); - it('>=', () => throws(() => i1 >= i2)); - }); - describe('Instant.since() works', () => { - const earlier = Instant.from('1976-11-18T15:23:30.123456789Z'); - const later = Instant.from('2019-10-29T10:46:38.271986102Z'); - const diff = later.since(earlier); - it(`(${earlier}).since(${later}) == (${later}).since(${earlier}).negated()`, () => - equal(`${earlier.since(later)}`, `${diff.negated()}`)); - it(`(${later}).since(${earlier}) == (${earlier}).until(${later})`, () => - equal(`${earlier.until(later)}`, `${diff}`)); - it(`(${earlier}).add(${diff}) == (${later})`, () => assert(earlier.add(diff).equals(later))); - it(`(${later}).subtract(${diff}) == (${earlier})`, () => assert(later.subtract(diff).equals(earlier))); - it('casts argument from string', () => { - equal(`${later.since(earlier.toString())}`, `${diff}`); - }); - it('only casts from a string', () => { - throws(() => later.since(earlier.epochNanoseconds), RangeError); - throws(() => earlier.since({}), RangeError); - }); - const feb20 = Instant.from('2020-02-01T00:00Z'); - const feb21 = Instant.from('2021-02-01T00:00Z'); - it('defaults to returning seconds', () => { - equal(`${feb21.since(feb20)}`, 'PT31622400S'); - equal(`${feb21.since(feb20, { largestUnit: 'auto' })}`, 'PT31622400S'); - equal(`${feb21.since(feb20, { largestUnit: 'seconds' })}`, 'PT31622400S'); - equal(`${Instant.from('2021-02-01T00:00:00.000000001Z').since(feb20)}`, 'PT31622400.000000001S'); - equal(`${feb21.since(Instant.from('2020-02-01T00:00:00.000000001Z'))}`, 'PT31622399.999999999S'); - }); - it('can return minutes and hours', () => { - equal(`${feb21.since(feb20, { largestUnit: 'hours' })}`, 'PT8784H'); - equal(`${feb21.since(feb20, { largestUnit: 'minutes' })}`, 'PT527040M'); - }); - it('can return subseconds', () => { - const later = feb20.add({ hours: 24, milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = later.since(feb20, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 86400250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = later.since(feb20, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 86400250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = later.since(feb20, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 86400250250250); - }); - it('cannot return days, weeks, months, and years', () => { - throws(() => feb21.since(feb20, { largestUnit: 'days' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'weeks' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'months' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'years' }), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb21.since(feb20, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb21.since(feb20, options)}`, 'PT31622400S')); - }); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'year', 'month', 'week', 'day', 'years', 'months', 'weeks', 'days', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => later.since(earlier, { smallestUnit }), RangeError); - } - ); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = ['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds']; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => later.since(earlier, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than seconds', () => { - equal(`${later.since(earlier, { smallestUnit: 'hours', roundingMode: 'halfExpand' })}`, 'PT376435H'); - equal(`${later.since(earlier, { smallestUnit: 'minutes', roundingMode: 'halfExpand' })}`, 'PT22586123M'); - }); - it('throws on invalid roundingMode', () => { - throws(() => later.since(earlier, { roundingMode: 'cile' }), RangeError); - }); - const largestUnit = 'hours'; - const incrementOneNearest = [ - ['hours', 'PT376435H'], - ['minutes', 'PT376435H23M'], - ['seconds', 'PT376435H23M8S'], - ['milliseconds', 'PT376435H23M8.149S'], - ['microseconds', 'PT376435H23M8.148529S'], - ['nanoseconds', 'PT376435H23M8.148529313S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${later.since(earlier, { largestUnit, smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { largestUnit, smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['hours', 'PT376436H', '-PT376435H'], - ['minutes', 'PT376435H24M', '-PT376435H23M'], - ['seconds', 'PT376435H23M9S', '-PT376435H23M8S'], - ['milliseconds', 'PT376435H23M8.149S', '-PT376435H23M8.148S'], - ['microseconds', 'PT376435H23M8.14853S', '-PT376435H23M8.148529S'], - ['nanoseconds', 'PT376435H23M8.148529313S', '-PT376435H23M8.148529313S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { largestUnit, smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { largestUnit, smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['hours', 'PT376435H', '-PT376436H'], - ['minutes', 'PT376435H23M', '-PT376435H24M'], - ['seconds', 'PT376435H23M8S', '-PT376435H23M9S'], - ['milliseconds', 'PT376435H23M8.148S', '-PT376435H23M8.149S'], - ['microseconds', 'PT376435H23M8.148529S', '-PT376435H23M8.14853S'], - ['nanoseconds', 'PT376435H23M8.148529313S', '-PT376435H23M8.148529313S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { largestUnit, smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { largestUnit, smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['hours', 'PT376435H'], - ['minutes', 'PT376435H23M'], - ['seconds', 'PT376435H23M8S'], - ['milliseconds', 'PT376435H23M8.148S'], - ['microseconds', 'PT376435H23M8.148529S'], - ['nanoseconds', 'PT376435H23M8.148529313S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { largestUnit, smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { largestUnit, smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${later.since(earlier, { largestUnit, smallestUnit: 'milliseconds' })}`, 'PT376435H23M8.148S'); - equal(`${later.since(earlier, { largestUnit, smallestUnit: 'microseconds' })}`, 'PT376435H23M8.148529S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${later.since(earlier, { - largestUnit, - smallestUnit: 'hours', - roundingIncrement: 3, - roundingMode: 'halfExpand' - })}`, - 'PT376434H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${later.since(earlier, { - largestUnit, - smallestUnit: 'minutes', - roundingIncrement: 30, - roundingMode: 'halfExpand' - })}`, - 'PT376435H30M' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${later.since(earlier, { - largestUnit, - smallestUnit: 'seconds', - roundingIncrement: 15, - roundingMode: 'halfExpand' - })}`, - 'PT376435H23M15S' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${later.since(earlier, { - largestUnit, - smallestUnit: 'milliseconds', - roundingIncrement: 10, - roundingMode: 'halfExpand' - })}`, - 'PT376435H23M8.15S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${later.since(earlier, { - largestUnit, - smallestUnit: 'microseconds', - roundingIncrement: 10, - roundingMode: 'halfExpand' - })}`, - 'PT376435H23M8.14853S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${later.since(earlier, { - largestUnit, - smallestUnit: 'nanoseconds', - roundingIncrement: 10, - roundingMode: 'halfExpand' - })}`, - 'PT376435H23M8.14852931S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { largestUnit, smallestUnit: 'hours', roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { largestUnit, smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { largestUnit, smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => later.since(earlier, { largestUnit, smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => later.since(earlier, { largestUnit, smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { largestUnit, smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws( - () => later.since(earlier, { largestUnit, smallestUnit: 'milliseconds', roundingIncrement: 29 }), - RangeError - ); - throws( - () => later.since(earlier, { largestUnit, smallestUnit: 'microseconds', roundingIncrement: 29 }), - RangeError - ); - throws( - () => later.since(earlier, { largestUnit, smallestUnit: 'nanoseconds', roundingIncrement: 29 }), - RangeError - ); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => later.since(earlier, { largestUnit, smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => later.since(earlier, { largestUnit, smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => later.since(earlier, { largestUnit, smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws( - () => later.since(earlier, { largestUnit, smallestUnit: 'milliseconds', roundingIncrement: 1000 }), - RangeError - ); - throws( - () => later.since(earlier, { largestUnit, smallestUnit: 'microseconds', roundingIncrement: 1000 }), - RangeError - ); - throws( - () => later.since(earlier, { largestUnit, smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), - RangeError - ); - }); - it('accepts singular units', () => { - equal(`${later.since(earlier, { largestUnit: 'hour' })}`, `${later.since(earlier, { largestUnit: 'hours' })}`); - equal( - `${later.since(earlier, { largestUnit, smallestUnit: 'hour' })}`, - `${later.since(earlier, { largestUnit, smallestUnit: 'hours' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'minute' })}`, - `${later.since(earlier, { largestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { largestUnit, smallestUnit: 'minute' })}`, - `${later.since(earlier, { largestUnit, smallestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'second' })}`, - `${later.since(earlier, { largestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit, smallestUnit: 'second' })}`, - `${later.since(earlier, { largestUnit, smallestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'millisecond' })}`, - `${later.since(earlier, { largestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit, smallestUnit: 'millisecond' })}`, - `${later.since(earlier, { largestUnit, smallestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'microsecond' })}`, - `${later.since(earlier, { largestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit, smallestUnit: 'microsecond' })}`, - `${later.since(earlier, { largestUnit, smallestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'nanosecond' })}`, - `${later.since(earlier, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit, smallestUnit: 'nanosecond' })}`, - `${later.since(earlier, { largestUnit, smallestUnit: 'nanoseconds' })}` - ); - }); - }); - describe('Instant.until() works', () => { - const earlier = Instant.from('1969-07-24T16:50:35.123456789Z'); - const later = Instant.from('2019-10-29T10:46:38.271986102Z'); - const diff = earlier.until(later); - it(`(${later}).until(${earlier}) == (${earlier}).until(${later}).negated()`, () => - equal(`${later.until(earlier)}`, `${diff.negated()}`)); - it(`(${earlier}).until(${later}) == (${later}).since(${earlier})`, () => - equal(`${later.since(earlier)}`, `${diff}`)); - it(`(${earlier}).add(${diff}) == (${later})`, () => assert(earlier.add(diff).equals(later))); - it(`(${later}).subtract(${diff}) == (${earlier})`, () => assert(later.subtract(diff).equals(earlier))); - it('casts argument from string', () => { - equal(`${earlier.until(later.toString())}`, `${diff}`); - }); - it('only casts from a string', () => { - throws(() => earlier.until(later.epochNanoseconds), RangeError); - throws(() => earlier.until({}), RangeError); - }); - const feb20 = Instant.from('2020-02-01T00:00Z'); - const feb21 = Instant.from('2021-02-01T00:00Z'); - it('defaults to returning seconds', () => { - equal(`${feb20.until(feb21)}`, 'PT31622400S'); - equal(`${feb20.until(feb21, { largestUnit: 'auto' })}`, 'PT31622400S'); - equal(`${feb20.until(feb21, { largestUnit: 'seconds' })}`, 'PT31622400S'); - equal(`${feb20.until(Instant.from('2021-02-01T00:00:00.000000001Z'))}`, 'PT31622400.000000001S'); - equal(`${Instant.from('2020-02-01T00:00:00.000000001Z').until(feb21)}`, 'PT31622399.999999999S'); - }); - it('can return minutes and hours', () => { - equal(`${feb20.until(feb21, { largestUnit: 'hours' })}`, 'PT8784H'); - equal(`${feb20.until(feb21, { largestUnit: 'minutes' })}`, 'PT527040M'); - }); - it('can return subseconds', () => { - const later = feb20.add({ hours: 24, milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = feb20.until(later, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 86400250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = feb20.until(later, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 86400250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = feb20.until(later, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 86400250250250); - }); - it('cannot return days, weeks, months, and years', () => { - throws(() => feb20.until(feb21, { largestUnit: 'days' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'weeks' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'months' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'years' }), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb20.until(feb21, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb20.until(feb21, options)}`, 'PT31622400S')); - }); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'year', 'month', 'week', 'day', 'years', 'months', 'weeks', 'days', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => earlier.until(later, { smallestUnit }), RangeError); - } - ); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = ['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds']; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => earlier.until(later, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than seconds', () => { - equal(`${earlier.until(later, { smallestUnit: 'hours', roundingMode: 'halfExpand' })}`, 'PT440610H'); - equal(`${earlier.until(later, { smallestUnit: 'minutes', roundingMode: 'halfExpand' })}`, 'PT26436596M'); - }); - it('throws on invalid roundingMode', () => { - throws(() => earlier.until(later, { roundingMode: 'cile' }), RangeError); - }); - const largestUnit = 'hours'; - const incrementOneNearest = [ - ['hours', 'PT440610H'], - ['minutes', 'PT440609H56M'], - ['seconds', 'PT440609H56M3S'], - ['milliseconds', 'PT440609H56M3.149S'], - ['microseconds', 'PT440609H56M3.148529S'], - ['nanoseconds', 'PT440609H56M3.148529313S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${earlier.until(later, { largestUnit, smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { largestUnit, smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['hours', 'PT440610H', '-PT440609H'], - ['minutes', 'PT440609H57M', '-PT440609H56M'], - ['seconds', 'PT440609H56M4S', '-PT440609H56M3S'], - ['milliseconds', 'PT440609H56M3.149S', '-PT440609H56M3.148S'], - ['microseconds', 'PT440609H56M3.14853S', '-PT440609H56M3.148529S'], - ['nanoseconds', 'PT440609H56M3.148529313S', '-PT440609H56M3.148529313S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { largestUnit, smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { largestUnit, smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['hours', 'PT440609H', '-PT440610H'], - ['minutes', 'PT440609H56M', '-PT440609H57M'], - ['seconds', 'PT440609H56M3S', '-PT440609H56M4S'], - ['milliseconds', 'PT440609H56M3.148S', '-PT440609H56M3.149S'], - ['microseconds', 'PT440609H56M3.148529S', '-PT440609H56M3.14853S'], - ['nanoseconds', 'PT440609H56M3.148529313S', '-PT440609H56M3.148529313S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { largestUnit, smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { largestUnit, smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['hours', 'PT440609H'], - ['minutes', 'PT440609H56M'], - ['seconds', 'PT440609H56M3S'], - ['milliseconds', 'PT440609H56M3.148S'], - ['microseconds', 'PT440609H56M3.148529S'], - ['nanoseconds', 'PT440609H56M3.148529313S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { largestUnit, smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { largestUnit, smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${earlier.until(later, { largestUnit, smallestUnit: 'milliseconds' })}`, 'PT440609H56M3.148S'); - equal(`${earlier.until(later, { largestUnit, smallestUnit: 'microseconds' })}`, 'PT440609H56M3.148529S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${earlier.until(later, { - largestUnit, - smallestUnit: 'hours', - roundingIncrement: 4, - roundingMode: 'halfExpand' - })}`, - 'PT440608H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${earlier.until(later, { - largestUnit, - smallestUnit: 'minutes', - roundingIncrement: 30, - roundingMode: 'halfExpand' - })}`, - 'PT440610H' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${earlier.until(later, { - largestUnit, - smallestUnit: 'seconds', - roundingIncrement: 15, - roundingMode: 'halfExpand' - })}`, - 'PT440609H56M' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${earlier.until(later, { - largestUnit, - smallestUnit: 'milliseconds', - roundingIncrement: 10, - roundingMode: 'halfExpand' - })}`, - 'PT440609H56M3.15S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${earlier.until(later, { - largestUnit, - smallestUnit: 'microseconds', - roundingIncrement: 10, - roundingMode: 'halfExpand' - })}`, - 'PT440609H56M3.14853S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${earlier.until(later, { - largestUnit, - smallestUnit: 'nanoseconds', - roundingIncrement: 10, - roundingMode: 'halfExpand' - })}`, - 'PT440609H56M3.14852931S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { largestUnit, smallestUnit: 'hours', roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { largestUnit, smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { largestUnit, smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => earlier.until(later, { largestUnit, smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => earlier.until(later, { largestUnit, smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { largestUnit, smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws( - () => earlier.until(later, { largestUnit, smallestUnit: 'milliseconds', roundingIncrement: 29 }), - RangeError - ); - throws( - () => earlier.until(later, { largestUnit, smallestUnit: 'microseconds', roundingIncrement: 29 }), - RangeError - ); - throws( - () => earlier.until(later, { largestUnit, smallestUnit: 'nanoseconds', roundingIncrement: 29 }), - RangeError - ); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => earlier.until(later, { largestUnit, smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => earlier.until(later, { largestUnit, smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => earlier.until(later, { largestUnit, smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws( - () => earlier.until(later, { largestUnit, smallestUnit: 'milliseconds', roundingIncrement: 1000 }), - RangeError - ); - throws( - () => earlier.until(later, { largestUnit, smallestUnit: 'microseconds', roundingIncrement: 1000 }), - RangeError - ); - throws( - () => earlier.until(later, { largestUnit, smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), - RangeError - ); - }); - it('accepts singular units', () => { - equal(`${earlier.until(later, { largestUnit: 'hour' })}`, `${earlier.until(later, { largestUnit: 'hours' })}`); - equal( - `${earlier.until(later, { largestUnit, smallestUnit: 'hour' })}`, - `${earlier.until(later, { largestUnit, smallestUnit: 'hours' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'minute' })}`, - `${earlier.until(later, { largestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { largestUnit, smallestUnit: 'minute' })}`, - `${earlier.until(later, { largestUnit, smallestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'second' })}`, - `${earlier.until(later, { largestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit, smallestUnit: 'second' })}`, - `${earlier.until(later, { largestUnit, smallestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'millisecond' })}`, - `${earlier.until(later, { largestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit, smallestUnit: 'millisecond' })}`, - `${earlier.until(later, { largestUnit, smallestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'microsecond' })}`, - `${earlier.until(later, { largestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit, smallestUnit: 'microsecond' })}`, - `${earlier.until(later, { largestUnit, smallestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'nanosecond' })}`, - `${earlier.until(later, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit, smallestUnit: 'nanosecond' })}`, - `${earlier.until(later, { largestUnit, smallestUnit: 'nanoseconds' })}` - ); - }); - }); - describe('Instant.round works', () => { - const inst = Instant.from('1976-11-18T14:23:30.123456789Z'); - it('throws without parameter', () => { - throws(() => inst.round(), TypeError); - }); - it('throws without required smallestUnit parameter', () => { - throws(() => inst.round({}), RangeError); - throws(() => inst.round({ roundingIncrement: 1, roundingMode: 'ceil' }), RangeError); - }); - it('throws on disallowed or invalid smallestUnit (object param)', () => { - ['era', 'year', 'month', 'week', 'day', 'years', 'months', 'weeks', 'days', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => inst.round({ smallestUnit }), RangeError); - } - ); - }); - it('throws on disallowed or invalid smallestUnit (string param)', () => { - ['era', 'year', 'month', 'week', 'day', 'years', 'months', 'weeks', 'days', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => inst.round(smallestUnit), RangeError); - } - ); - }); - it('throws on invalid roundingMode', () => { - throws(() => inst.round({ smallestUnit: 'second', roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['hour', '1976-11-18T14:00:00Z'], - ['minute', '1976-11-18T14:24:00Z'], - ['second', '1976-11-18T14:23:30Z'], - ['millisecond', '1976-11-18T14:23:30.123Z'], - ['microsecond', '1976-11-18T14:23:30.123457Z'], - ['nanosecond', '1976-11-18T14:23:30.123456789Z'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - it(`rounds to nearest ${smallestUnit}`, () => - equal(`${inst.round({ smallestUnit, roundingMode: 'halfExpand' })}`, expected)); - }); - const incrementOneCeil = [ - ['hour', '1976-11-18T15:00:00Z'], - ['minute', '1976-11-18T14:24:00Z'], - ['second', '1976-11-18T14:23:31Z'], - ['millisecond', '1976-11-18T14:23:30.124Z'], - ['microsecond', '1976-11-18T14:23:30.123457Z'], - ['nanosecond', '1976-11-18T14:23:30.123456789Z'] - ]; - incrementOneCeil.forEach(([smallestUnit, expected]) => { - it(`rounds up to ${smallestUnit}`, () => - equal(`${inst.round({ smallestUnit, roundingMode: 'ceil' })}`, expected)); - }); - const incrementOneFloor = [ - ['hour', '1976-11-18T14:00:00Z'], - ['minute', '1976-11-18T14:23:00Z'], - ['second', '1976-11-18T14:23:30Z'], - ['millisecond', '1976-11-18T14:23:30.123Z'], - ['microsecond', '1976-11-18T14:23:30.123456Z'], - ['nanosecond', '1976-11-18T14:23:30.123456789Z'] - ]; - incrementOneFloor.forEach(([smallestUnit, expected]) => { - it(`rounds down to ${smallestUnit}`, () => - equal(`${inst.round({ smallestUnit, roundingMode: 'floor' })}`, expected)); - it(`truncates to ${smallestUnit}`, () => - equal(`${inst.round({ smallestUnit, roundingMode: 'trunc' })}`, expected)); - }); - it('nearest is the default', () => { - equal(`${inst.round({ smallestUnit: 'minute' })}`, '1976-11-18T14:24:00Z'); - equal(`${inst.round({ smallestUnit: 'second' })}`, '1976-11-18T14:23:30Z'); - }); - it('rounding down is towards the Big Bang, not towards the epoch', () => { - const inst2 = Instant.from('1969-12-15T12:00:00.5Z'); - const smallestUnit = 'second'; - equal(`${inst2.round({ smallestUnit, roundingMode: 'ceil' })}`, '1969-12-15T12:00:01Z'); - equal(`${inst2.round({ smallestUnit, roundingMode: 'floor' })}`, '1969-12-15T12:00:00Z'); - equal(`${inst2.round({ smallestUnit, roundingMode: 'trunc' })}`, '1969-12-15T12:00:00Z'); - equal(`${inst2.round({ smallestUnit, roundingMode: 'halfExpand' })}`, '1969-12-15T12:00:01Z'); - }); - it('rounds to an increment of hours', () => { - equal(`${inst.round({ smallestUnit: 'hour', roundingIncrement: 4 })}`, '1976-11-18T16:00:00Z'); - }); - it('rounds to an increment of minutes', () => { - equal(`${inst.round({ smallestUnit: 'minute', roundingIncrement: 15 })}`, '1976-11-18T14:30:00Z'); - }); - it('rounds to an increment of seconds', () => { - equal(`${inst.round({ smallestUnit: 'second', roundingIncrement: 30 })}`, '1976-11-18T14:23:30Z'); - }); - it('rounds to an increment of milliseconds', () => { - equal(`${inst.round({ smallestUnit: 'millisecond', roundingIncrement: 10 })}`, '1976-11-18T14:23:30.12Z'); - }); - it('rounds to an increment of microseconds', () => { - equal(`${inst.round({ smallestUnit: 'microsecond', roundingIncrement: 10 })}`, '1976-11-18T14:23:30.12346Z'); - }); - it('rounds to an increment of nanoseconds', () => { - equal(`${inst.round({ smallestUnit: 'nanosecond', roundingIncrement: 10 })}`, '1976-11-18T14:23:30.12345679Z'); - }); - it('rounds to days by specifying increment of 86400 seconds in various units', () => { - const expected = '1976-11-19T00:00:00Z'; - equal(`${inst.round({ smallestUnit: 'hour', roundingIncrement: 24 })}`, expected); - equal(`${inst.round({ smallestUnit: 'minute', roundingIncrement: 1440 })}`, expected); - equal(`${inst.round({ smallestUnit: 'second', roundingIncrement: 86400 })}`, expected); - equal(`${inst.round({ smallestUnit: 'millisecond', roundingIncrement: 86400e3 })}`, expected); - equal(`${inst.round({ smallestUnit: 'microsecond', roundingIncrement: 86400e6 })}`, expected); - equal(`${inst.round({ smallestUnit: 'nanosecond', roundingIncrement: 86400e9 })}`, expected); - }); - it('allows increments that divide evenly into solar days', () => { - assert(inst.round({ smallestUnit: 'second', roundingIncrement: 864 }) instanceof Instant); - }); - it('throws on increments that do not divide evenly into solar days', () => { - throws(() => inst.round({ smallestUnit: 'hour', roundingIncrement: 7 }), RangeError); - throws(() => inst.round({ smallestUnit: 'minute', roundingIncrement: 29 }), RangeError); - throws(() => inst.round({ smallestUnit: 'second', roundingIncrement: 29 }), RangeError); - throws(() => inst.round({ smallestUnit: 'millisecond', roundingIncrement: 29 }), RangeError); - throws(() => inst.round({ smallestUnit: 'microsecond', roundingIncrement: 29 }), RangeError); - throws(() => inst.round({ smallestUnit: 'nanosecond', roundingIncrement: 29 }), RangeError); - }); - it('accepts plural units', () => { - ['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(inst.round({ smallestUnit }).equals(inst.round({ smallestUnit: `${smallestUnit}s` }))); - }); - }); - it('accepts string parameter as shortcut for {smallestUnit}', () => { - ['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(inst.round(smallestUnit).equals(inst.round({ smallestUnit }))); - }); - }); - }); - describe('Min/max range', () => { - it('constructing from ns', () => { - const limit = 8_640_000_000_000_000_000_000n; - throws(() => new Instant(-limit - 1n), RangeError); - throws(() => new Instant(limit + 1n), RangeError); - equal(`${new Instant(-limit)}`, '-271821-04-20T00:00:00Z'); - equal(`${new Instant(limit)}`, '+275760-09-13T00:00:00Z'); - }); - it('constructing from ms', () => { - const limit = 86400e11; - throws(() => Instant.fromEpochMilliseconds(-limit - 1), RangeError); - throws(() => Instant.fromEpochMilliseconds(limit + 1), RangeError); - equal(`${Instant.fromEpochMilliseconds(-limit)}`, '-271821-04-20T00:00:00Z'); - equal(`${Instant.fromEpochMilliseconds(limit)}`, '+275760-09-13T00:00:00Z'); - }); - it('constructing from ISO string', () => { - throws(() => Instant.from('-271821-04-19T23:59:59.999999999Z'), RangeError); - throws(() => Instant.from('+275760-09-13T00:00:00.000000001Z'), RangeError); - equal(`${Instant.from('-271821-04-20T00:00Z')}`, '-271821-04-20T00:00:00Z'); - equal(`${Instant.from('+275760-09-13T00:00Z')}`, '+275760-09-13T00:00:00Z'); - }); - it('converting from DateTime', () => { - const min = Temporal.PlainDateTime.from('-271821-04-19T00:00:00.000000001'); - const max = Temporal.PlainDateTime.from('+275760-09-13T23:59:59.999999999'); - const utc = Temporal.TimeZone.from('UTC'); - throws(() => utc.getInstantFor(min), RangeError); - throws(() => utc.getInstantFor(max), RangeError); - }); - it('adding and subtracting beyond limit', () => { - const min = Instant.from('-271821-04-20T00:00Z'); - const max = Instant.from('+275760-09-13T00:00Z'); - throws(() => min.subtract({ nanoseconds: 1 }), RangeError); - throws(() => max.add({ nanoseconds: 1 }), RangeError); - }); - }); - describe('Instant.toZonedDateTimeISO() works', () => { - const inst = Instant.from('1976-11-18T14:23:30.123456789Z'); - it('throws without parameter', () => { - throws(() => inst.toZonedDateTimeISO(), RangeError); - }); - it('time zone parameter UTC', () => { - const tz = Temporal.TimeZone.from('UTC'); - const zdt = inst.toZonedDateTimeISO(tz); - equal(inst.epochNanoseconds, zdt.epochNanoseconds); - equal(`${zdt}`, '1976-11-18T14:23:30.123456789+00:00[UTC]'); - }); - it('time zone parameter non-UTC', () => { - const tz = Temporal.TimeZone.from('America/New_York'); - const zdt = inst.toZonedDateTimeISO(tz); - equal(inst.epochNanoseconds, zdt.epochNanoseconds); - equal(`${zdt}`, '1976-11-18T09:23:30.123456789-05:00[America/New_York]'); - }); - }); - describe('Instant.toZonedDateTime() works', () => { - const inst = Instant.from('1976-11-18T14:23:30.123456789Z'); - it('throws without parameter', () => { - throws(() => inst.toZonedDateTime(), TypeError); - }); - it('throws with a string parameter', () => { - throws(() => inst.toZonedDateTime('Asia/Singapore'), TypeError); - }); - it('time zone parameter UTC', () => { - const timeZone = Temporal.TimeZone.from('UTC'); - const zdt = inst.toZonedDateTime({ timeZone, calendar: 'gregory' }); - equal(inst.epochNanoseconds, zdt.epochNanoseconds); - equal(`${zdt}`, '1976-11-18T14:23:30.123456789+00:00[UTC][u-ca=gregory]'); - }); - it('time zone parameter non-UTC', () => { - const timeZone = Temporal.TimeZone.from('America/New_York'); - const zdt = inst.toZonedDateTime({ timeZone, calendar: 'gregory' }); - equal(inst.epochNanoseconds, zdt.epochNanoseconds); - equal(`${zdt}`, '1976-11-18T09:23:30.123456789-05:00[America/New_York][u-ca=gregory]'); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/intl.js b/packages/temporal-polyfill/tests/intl.js deleted file mode 100644 index 7bac586d..00000000 --- a/packages/temporal-polyfill/tests/intl.js +++ /dev/null @@ -1,1912 +0,0 @@ - -import { assert } from 'chai'; -const { deepEqual, strictEqual: equal, throws } = assert; - -import { Temporal, Intl } from 'temporal-polyfill/impl'; - -describe('Intl', () => { - // TODO: move these to their respective test files. - - function maybeGetWeekdayOnlyFormat() { - const fmt = new Intl.DateTimeFormat('en', { weekday: 'long', timeZone: 'Europe/Vienna' }); - if ( - ['era', 'year', 'month', 'day', 'hour', 'minute', 'second', 'timeZoneName'].some( - (prop) => prop in fmt.resolvedOptions() - ) - ) { - it.skip('no weekday-only format available', () => {}); - return null; - } - return fmt; - } - - describe('instant.toLocaleString()', () => { - const instant = Temporal.Instant.from('1976-11-18T14:23:30Z'); - it(`(${instant.toString()}).toLocaleString('en-US', { timeZone: 'America/New_York' })`, () => - equal(`${instant.toLocaleString('en', { timeZone: 'America/New_York' })}`, '11/18/1976, 9:23:30 AM')); - it(`(${instant.toString()}).toLocaleString('de-AT', { timeZone: 'Europe/Vienna' })`, () => - equal(`${instant.toLocaleString('de', { timeZone: 'Europe/Vienna' })}`, '18.11.1976, 15:23:30')); - const fmt = maybeGetWeekdayOnlyFormat(); - if (fmt) it('uses only the options in resolvedOptions', () => equal(fmt.format(instant), 'Thursday')); - it('outputs timeZoneName if requested', () => { - const str = instant.toLocaleString('en', { timeZone: 'America/New_York', timeZoneName: 'short' }); - assert(str.includes('EST')); - }); - }); - describe('zoneddatetime.toLocaleString()', () => { - const zdt = Temporal.ZonedDateTime.from('1976-11-18T15:23:30+01:00[Europe/Vienna]'); - it(`(${zdt}).toLocaleString('en-US')`, () => equal(zdt.toLocaleString('en'), '11/18/1976, 3:23:30 PM GMT+1')); - it(`(${zdt}).toLocaleString('de-AT')`, () => equal(zdt.toLocaleString('de'), '18.11.1976, 15:23:30 MEZ')); - const fmt = maybeGetWeekdayOnlyFormat(); - if (fmt) it('uses only the options in resolvedOptions', () => equal(fmt.format(zdt), 'Thursday')); - it('can override the style of the time zone name', () => { - equal( - zdt.toLocaleString('en', { timeZoneName: 'long' }), - '11/18/1976, 3:23:30 PM Central European Standard Time' - ); - }); - it("works if the time zone given in options agrees with the object's time zone", () => { - equal(zdt.toLocaleString('en', { timeZone: 'Europe/Vienna' }), '11/18/1976, 3:23:30 PM GMT+1'); - }); - it("throws if the time zone given in options disagrees with the object's time zone", () => { - throws(() => zdt.toLocaleString('en', { timeZone: 'America/New_York' }), RangeError); - }); - it("works when the object's calendar is the same as the locale's calendar", () => { - const zdt = new Temporal.ZonedDateTime(0n, 'UTC', 'japanese'); - const result = zdt.toLocaleString('en-US-u-ca-japanese'); - assert(result === '1/1/45, 12:00:00 AM UTC' || result === '1/1/45 S, 12:00:00 AM UTC'); - }); - it("adopts the locale's calendar when the object's calendar is ISO", () => { - const zdt = Temporal.ZonedDateTime.from('1976-11-18T15:23:30+00:00[UTC]'); - const result = zdt.toLocaleString('en-US-u-ca-japanese'); - assert(result === '11/18/51, 3:23:30 PM UTC' || result === '11/18/51 S, 3:23:30 PM UTC'); - }); - it('throws when the calendars are different and not ISO', () => { - const zdt = new Temporal.ZonedDateTime(0n, 'UTC', 'gregory'); - throws(() => zdt.toLocaleString('en-US-u-ca-japanese')); - }); - }); - describe('datetime.toLocaleString()', () => { - const datetime = Temporal.PlainDateTime.from('1976-11-18T15:23:30'); - it(`(${datetime.toString()}).toLocaleString('en-US', { timeZone: 'America/New_York' })`, () => - equal(`${datetime.toLocaleString('en', { timeZone: 'America/New_York' })}`, '11/18/1976, 3:23:30 PM')); - it(`(${datetime.toString()}).toLocaleString('de-AT', { timeZone: 'Europe/Vienna' })`, () => - equal(`${datetime.toLocaleString('de', { timeZone: 'Europe/Vienna' })}`, '18.11.1976, 15:23:30')); - const fmt = maybeGetWeekdayOnlyFormat(); - if (fmt) it('uses only the options in resolvedOptions', () => equal(fmt.format(datetime), 'Thursday')); - it('should ignore units not in the data type', () => { - equal(datetime.toLocaleString('en', { timeZoneName: 'long' }), '11/18/1976, 3:23:30 PM'); - }); - it('should use compatible disambiguation option', () => { - const dstStart = new Temporal.PlainDateTime(2020, 3, 8, 2, 30); - equal(`${dstStart.toLocaleString('en', { timeZone: 'America/Los_Angeles' })}`, '3/8/2020, 3:30:00 AM'); - }); - it("works when the object's calendar is the same as the locale's calendar", () => { - const dt = Temporal.PlainDateTime.from({ - era: 'showa', - eraYear: 51, - month: 11, - day: 18, - hour: 15, - minute: 23, - second: 30, - calendar: 'japanese' - }); - const result = dt.toLocaleString('en-US-u-ca-japanese'); - assert(result === '11/18/51, 3:23:30 PM' || result === '11/18/51 S, 3:23:30 PM'); - }); - it("adopts the locale's calendar when the object's calendar is ISO", () => { - const dt = Temporal.PlainDateTime.from('1976-11-18T15:23:30'); - const result = dt.toLocaleString('en-US-u-ca-japanese'); - assert(result === '11/18/51, 3:23:30 PM' || result === '11/18/51 S, 3:23:30 PM'); - }); - it('throws when the calendars are different and not ISO', () => { - const dt = Temporal.PlainDateTime.from({ - year: 1976, - month: 11, - day: 18, - hour: 15, - minute: 23, - second: 30, - calendar: 'gregory' - }); - throws(() => dt.toLocaleString('en-US-u-ca-japanese')); - }); - }); - describe('time.toLocaleString()', () => { - const time = Temporal.PlainTime.from('1976-11-18T15:23:30'); - it(`(${time.toString()}).toLocaleString('en-US', { timeZone: 'America/New_York' })`, () => - equal(`${time.toLocaleString('en', { timeZone: 'America/New_York' })}`, '3:23:30 PM')); - it(`(${time.toString()}).toLocaleString('de-AT', { timeZone: 'Europe/Vienna' })`, () => - equal(`${time.toLocaleString('de', { timeZone: 'Europe/Vienna' })}`, '15:23:30')); - it('should ignore units not in the data type', () => { - equal(time.toLocaleString('en', { timeZoneName: 'long' }), '3:23:30 PM'); - equal(time.toLocaleString('en', { year: 'numeric' }), '3:23:30 PM'); - equal(time.toLocaleString('en', { month: 'numeric' }), '3:23:30 PM'); - equal(time.toLocaleString('en', { day: 'numeric' }), '3:23:30 PM'); - equal(time.toLocaleString('en', { weekday: 'long' }), '3:23:30 PM'); - }); - }); - describe('date.toLocaleString()', () => { - const date = Temporal.PlainDate.from('1976-11-18T15:23:30'); - it(`(${date.toString()}).toLocaleString('en-US', { timeZone: 'America/New_York' })`, () => - equal(`${date.toLocaleString('en', { timeZone: 'America/New_York' })}`, '11/18/1976')); - it(`(${date.toString()}).toLocaleString('de-AT', { timeZone: 'Europe/Vienna' })`, () => - equal(`${date.toLocaleString('de', { timeZone: 'Europe/Vienna' })}`, '18.11.1976')); - const fmt = maybeGetWeekdayOnlyFormat(); - if (fmt) it('uses only the options in resolvedOptions', () => equal(fmt.format(date), 'Thursday')); - it('should ignore units not in the data type', () => { - equal(date.toLocaleString('en', { timeZoneName: 'long' }), '11/18/1976'); - equal(date.toLocaleString('en', { hour: 'numeric' }), '11/18/1976'); - equal(date.toLocaleString('en', { minute: 'numeric' }), '11/18/1976'); - equal(date.toLocaleString('en', { second: 'numeric' }), '11/18/1976'); - }); - it("works when the object's calendar is the same as the locale's calendar", () => { - const d = Temporal.PlainDate.from({ era: 'showa', eraYear: 51, month: 11, day: 18, calendar: 'japanese' }); - const result = d.toLocaleString('en-US-u-ca-japanese'); - assert(result === '11/18/51' || result === '11/18/51 S'); - }); - it("adopts the locale's calendar when the object's calendar is ISO", () => { - const d = Temporal.PlainDate.from('1976-11-18'); - const result = d.toLocaleString('en-US-u-ca-japanese'); - assert(result === '11/18/51' || result === '11/18/51 S'); - }); - it('throws when the calendars are different and not ISO', () => { - const d = Temporal.PlainDate.from({ year: 1976, month: 11, day: 18, calendar: 'gregory' }); - throws(() => d.toLocaleString('en-US-u-ca-japanese')); - }); - }); - describe('yearmonth.toLocaleString()', () => { - const calendar = new Intl.DateTimeFormat('en').resolvedOptions().calendar; - const yearmonth = Temporal.PlainYearMonth.from({ year: 1976, month: 11, calendar }); - it(`(${yearmonth.toString()}).toLocaleString('en-US', { timeZone: 'America/New_York' })`, () => - equal(`${yearmonth.toLocaleString('en', { timeZone: 'America/New_York' })}`, '11/1976')); - it(`(${yearmonth.toString()}).toLocaleString('de-AT', { timeZone: 'Europe/Vienna' })`, () => - equal(`${yearmonth.toLocaleString('de', { timeZone: 'Europe/Vienna', calendar })}`, '11.1976')); - it('should ignore units not in the data type', () => { - equal(yearmonth.toLocaleString('en', { timeZoneName: 'long' }), '11/1976'); - equal(yearmonth.toLocaleString('en', { day: 'numeric' }), '11/1976'); - equal(yearmonth.toLocaleString('en', { hour: 'numeric' }), '11/1976'); - equal(yearmonth.toLocaleString('en', { minute: 'numeric' }), '11/1976'); - equal(yearmonth.toLocaleString('en', { second: 'numeric' }), '11/1976'); - equal(yearmonth.toLocaleString('en', { weekday: 'long' }), '11/1976'); - }); - it("works when the object's calendar is the same as the locale's calendar", () => { - const ym = Temporal.PlainYearMonth.from({ era: 'showa', eraYear: 51, month: 11, calendar: 'japanese' }); - const result = ym.toLocaleString('en-US-u-ca-japanese'); - assert(result === '11/51' || result === '11/51 S'); - }); - it('throws when the calendar is not equal to the locale calendar', () => { - const ymISO = Temporal.PlainYearMonth.from({ year: 1976, month: 11 }); - throws(() => ymISO.toLocaleString('en-US-u-ca-japanese'), RangeError); - }); - }); - describe('monthday.toLocaleString()', () => { - const calendar = new Intl.DateTimeFormat('en').resolvedOptions().calendar; - const monthday = Temporal.PlainMonthDay.from({ monthCode: 'M11', day: 18, calendar }); - it(`(${monthday.toString()}).toLocaleString('en-US', { timeZone: 'America/New_York' })`, () => - equal(`${monthday.toLocaleString('en', { timeZone: 'America/New_York' })}`, '11/18')); - it(`(${monthday.toString()}).toLocaleString('de-AT', { timeZone: 'Europe/Vienna' })`, () => - equal(`${monthday.toLocaleString('de', { timeZone: 'Europe/Vienna', calendar })}`, '18.11.')); - it('should ignore units not in the data type', () => { - equal(monthday.toLocaleString('en', { timeZoneName: 'long' }), '11/18'); - equal(monthday.toLocaleString('en', { year: 'numeric' }), '11/18'); - equal(monthday.toLocaleString('en', { hour: 'numeric' }), '11/18'); - equal(monthday.toLocaleString('en', { minute: 'numeric' }), '11/18'); - equal(monthday.toLocaleString('en', { second: 'numeric' }), '11/18'); - equal(monthday.toLocaleString('en', { weekday: 'long' }), '11/18'); - }); - it("works when the object's calendar is the same as the locale's calendar", () => { - const md = Temporal.PlainMonthDay.from({ monthCode: 'M11', day: 18, calendar: 'japanese' }); - equal(`${md.toLocaleString('en-US-u-ca-japanese')}`, '11/18'); - }); - it('throws when the calendar is not equal to the locale calendar', () => { - const mdISO = Temporal.PlainMonthDay.from({ month: 11, day: 18 }); - throws(() => mdISO.toLocaleString('en-US-u-ca-japanese'), RangeError); - }); - }); - - describe('Non-ISO Calendars', () => { - const testChineseData = new Date('2001-02-01T00:00Z').toLocaleString('en-US-u-ca-chinese', { - day: 'numeric', - month: 'numeric', - year: 'numeric', - era: 'short', - timeZone: 'UTC' - }); - const hasOutdatedChineseIcuData = !testChineseData.endsWith('2001'); - const itOrSkip = (id) => ((id === 'chinese' || id === 'dangi') && hasOutdatedChineseIcuData ? it.skip : it); - const nodeVersion = process.versions.node.split('.')[0]; - - it('verify that Intl.DateTimeFormat.formatToParts output matches snapshot data', () => { - // This test isn't testing Temporal. Instead, it's verifying that the - // output of Intl.DateTimeFormat.formatToParts for non-ISO calendars - // hasn't changed. There are a number of outstanding bugs in this output - // that, when fixed, will break other tests. So this test is a signal that - // other tests are broken because the comparison data needs to be updated, - // not necessarily because Temporal is broken. - const getLocalizedDates = (isoString) => { - const calendars = [ - 'iso8601', - 'buddhist', - 'chinese', - 'coptic', - 'dangi', - 'ethioaa', - 'ethiopic', - 'gregory', - 'hebrew', - 'indian', - 'islamic', - 'islamic-umalqura', - 'islamic-tbla', - 'islamic-civil', - 'islamic-rgsa', - 'islamicc', - 'japanese', - 'persian', - 'roc' - ]; - const date = new Date(isoString); - return calendars - .map((id) => `${id}: ${date.toLocaleDateString(`en-US-u-ca-${id}`, { timeZone: 'UTC' })}`) - .join('\n'); - }; - const year2000Content = getLocalizedDates('2000-01-01T00:00Z'); - // to generate snapshot: ` '${year2000Content.replaceAll('\n', "\\n' +\n '")}',\n` - const year1Content = getLocalizedDates('0001-01-01T00:00Z'); - // to generate snapshot: ` '${year1Content.replaceAll('\n', "\\n' +\n '")}',\n` - - const year2000Snapshots = { - node12: - 'iso8601: 1/1/2000\n' + - 'buddhist: 1/1/2543\n' + - 'chinese: 11/25/16\n' + - 'coptic: 4/22/1716\n' + - 'dangi: 11/25/16\n' + - 'ethioaa: 4/22/7492\n' + - 'ethiopic: 4/22/1992\n' + - 'gregory: 1/1/2000\n' + - 'hebrew: 4/23/5760\n' + - 'indian: 10/11/1921\n' + - 'islamic: 9/25/1420\n' + - 'islamic-umalqura: 9/24/1420\n' + - 'islamic-tbla: 9/25/1420\n' + - 'islamic-civil: 9/24/1420\n' + - 'islamic-rgsa: 9/25/1420\n' + - 'islamicc: 9/24/1420\n' + - 'japanese: 1/1/12\n' + - 'persian: 10/11/1378\n' + - 'roc: 1/1/89', - node14: - 'iso8601: 1/1/2000\n' + - 'buddhist: 1/1/2543 BE\n' + - 'chinese: 11/25/1999\n' + - 'coptic: 4/22/1716 ERA1\n' + - 'dangi: 11/25/1999\n' + - 'ethioaa: 4/22/7492 ERA0\n' + - 'ethiopic: 4/22/1992 ERA1\n' + - 'gregory: 1/1/2000\n' + - 'hebrew: 23 Tevet 5760\n' + - 'indian: 10/11/1921 Saka\n' + - 'islamic: 9/25/1420 AH\n' + - 'islamic-umalqura: 9/24/1420 AH\n' + - 'islamic-tbla: 9/25/1420 AH\n' + - 'islamic-civil: 9/24/1420 AH\n' + - 'islamic-rgsa: 9/25/1420 AH\n' + - 'islamicc: 9/24/1420 AH\n' + - 'japanese: 1/1/12 H\n' + - 'persian: 10/11/1378 AP\n' + - 'roc: 1/1/89 Minguo', - node16: - 'iso8601: 1/1/2000\n' + - 'buddhist: 1/1/2543 BE\n' + - 'chinese: 11/25/1999\n' + - 'coptic: 4/22/1716 ERA1\n' + - 'dangi: 11/25/1999\n' + - 'ethioaa: 4/22/7492 ERA0\n' + - 'ethiopic: 4/22/1992 ERA1\n' + - 'gregory: 1/1/2000\n' + - 'hebrew: 23 Tevet 5760\n' + - 'indian: 10/11/1921 Saka\n' + - 'islamic: 9/25/1420 AH\n' + - 'islamic-umalqura: 9/24/1420 AH\n' + - 'islamic-tbla: 9/25/1420 AH\n' + - 'islamic-civil: 9/24/1420 AH\n' + - 'islamic-rgsa: 9/25/1420 AH\n' + - 'islamicc: 9/24/1420 AH\n' + - 'japanese: 1/1/12 H\n' + - 'persian: 10/11/1378 AP\n' + - 'roc: 1/1/89 Minguo', - node17: - 'iso8601: 1/1/2000\n' + - 'buddhist: 1/1/2543 BE\n' + - 'chinese: 11/25/1999\n' + - 'coptic: 4/22/1716 ERA1\n' + - 'dangi: 11/25/1999\n' + - 'ethioaa: 4/22/7492 ERA0\n' + - 'ethiopic: 4/22/1992 ERA1\n' + - 'gregory: 1/1/2000\n' + - 'hebrew: 23 Tevet 5760\n' + - 'indian: 10/11/1921 Saka\n' + - 'islamic: 9/25/1420 AH\n' + - 'islamic-umalqura: 9/24/1420 AH\n' + - 'islamic-tbla: 9/25/1420 AH\n' + - 'islamic-civil: 9/24/1420 AH\n' + - 'islamic-rgsa: 9/25/1420 AH\n' + - 'islamicc: 9/24/1420 AH\n' + - 'japanese: 1/1/12 H\n' + - 'persian: 10/11/1378 AP\n' + - 'roc: 1/1/89 Minguo' - }; - year2000Snapshots.other = year2000Snapshots.node17; - equal(year2000Content, year2000Snapshots[`node${nodeVersion}`] || year2000Snapshots.other); - - const year1Snapshots = { - node12: - 'iso8601: 1/1/1\n' + - 'buddhist: 1/3/544\n' + - 'chinese: 11/21/57\n' + - 'coptic: 5/8/284\n' + - 'dangi: 11/21/57\n' + - 'ethioaa: 5/8/5493\n' + - 'ethiopic: 5/8/5493\n' + - 'gregory: 1/1/1\n' + - 'hebrew: 4/18/3761\n' + - 'indian: 10/11/-78\n' + - 'islamic: -7/20/-639\n' + - 'islamic-umalqura: 5/18/-640\n' + - 'islamic-tbla: 5/19/-640\n' + - 'islamic-civil: 5/18/-640\n' + - 'islamic-rgsa: -7/20/-639\n' + - 'islamicc: 5/18/-640\n' + - 'japanese: 1/3/-643\n' + - 'persian: 10/11/-621\n' + - 'roc: 1/3/1911', - node14: - 'iso8601: 1/1/1\n' + - 'buddhist: 1/3/544 BE\n' + - 'chinese: 11/21/0\n' + - 'coptic: 5/8/284 ERA0\n' + - 'dangi: 11/21/0\n' + - 'ethioaa: 5/8/5493 ERA0\n' + - 'ethiopic: 5/8/5493 ERA0\n' + - 'gregory: 1/1/1\n' + - 'hebrew: 18 Tevet 3761\n' + - 'indian: 10/11/-78 Saka\n' + - 'islamic: 5/20/-640 AH\n' + - 'islamic-umalqura: 5/18/-640 AH\n' + - 'islamic-tbla: 5/19/-640 AH\n' + - 'islamic-civil: 5/18/-640 AH\n' + - 'islamic-rgsa: 5/20/-640 AH\n' + - 'islamicc: 5/18/-640 AH\n' + - 'japanese: 1/3/-643 Taika (645–650)\n' + - 'persian: 10/11/-621 AP\n' + - 'roc: 1/3/1911 B.R.O.C.', - node16: - 'iso8601: 1/1/1\n' + - 'buddhist: 1/3/544 BE\n' + - 'chinese: 11/21/0\n' + - 'coptic: 5/8/284 ERA0\n' + - 'dangi: 11/21/0\n' + - 'ethioaa: 5/8/5493 ERA0\n' + - 'ethiopic: 5/8/5493 ERA0\n' + - 'gregory: 1/1/1\n' + - 'hebrew: 18 Tevet 3761\n' + - 'indian: 10/11/-78 Saka\n' + - 'islamic: 5/20/-640 AH\n' + - 'islamic-umalqura: 5/18/-640 AH\n' + - 'islamic-tbla: 5/19/-640 AH\n' + - 'islamic-civil: 5/18/-640 AH\n' + - 'islamic-rgsa: 5/20/-640 AH\n' + - 'islamicc: 5/18/-640 AH\n' + - 'japanese: 1/3/-643 Taika (645–650)\n' + - 'persian: 10/11/-621 AP\n' + - 'roc: 1/3/1911 B.R.O.C.', - node17: - 'iso8601: 1/1/1\n' + - 'buddhist: 1/3/544 BE\n' + - 'chinese: 11/21/0\n' + - 'coptic: 5/8/284 ERA0\n' + - 'dangi: 11/21/0\n' + - 'ethioaa: 5/8/5493 ERA0\n' + - 'ethiopic: 5/8/5493 ERA0\n' + - 'gregory: 1/1/1\n' + - 'hebrew: 18 Tevet 3761\n' + - 'indian: 10/11/-78 Saka\n' + - 'islamic: 5/20/-640 AH\n' + - 'islamic-umalqura: 5/18/-640 AH\n' + - 'islamic-tbla: 5/19/-640 AH\n' + - 'islamic-civil: 5/18/-640 AH\n' + - 'islamic-rgsa: 5/20/-640 AH\n' + - 'islamicc: 5/18/-640 AH\n' + - 'japanese: 1/3/-643 Taika (645–650)\n' + - 'persian: 10/11/-621 AP\n' + - 'roc: 1/3/1911 B.R.O.C.' - }; - year1Snapshots.other = year1Snapshots.node17; - equal( - // [fullcalendar/temporal] - // a workaround to normalize output on certain node environments - year1Content.replace('Before R.O.C.', 'B.R.O.C.'), - year1Snapshots[`node${nodeVersion}`] || year1Snapshots.other, - ); - }); - - const fromWithCases = { - iso8601: { year2000: { year: 2000, month: 1, day: 1 }, year1: { year: 1, month: 1, day: 1 } }, - buddhist: { - year2000: { year: 2543, month: 1, day: 1, era: 'be' }, - // Pre-1582 (ISO) dates are broken by https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - year1: RangeError - // year1: { year: 544, month: 1, day: 1, era: 'be' } - }, - chinese: { - year2000: { year: 1999, month: 11, day: 25 }, - // There's a 3bis (4th month) leap month in this year - year1: { year: 0, month: 12, monthCode: 'M11', day: 21 } - }, - coptic: { - year2000: { year: 1716, month: 4, day: 22, era: 'era1' }, - year1: { year: -283, eraYear: 284, month: 5, day: 8, era: 'era0' } - }, - dangi: { - year2000: { year: 1999, month: 11, day: 25 }, - // There's a 3bis (4th month) leap month in this year - year1: { year: 0, month: 12, monthCode: 'M11', day: 21 } - }, - ethioaa: { - year2000: { year: 7492, month: 4, day: 22, era: 'era0' }, - year1: { year: 5493, month: 5, day: 8, era: 'era0' } - }, - ethiopic: { - year2000: { eraYear: 1992, year: 7492, month: 4, day: 22, era: 'era1' }, - year1: { year: 5493, month: 5, day: 8, era: 'era0' } - }, - gregory: { - year2000: { year: 2000, month: 1, day: 1, era: 'ce' }, - year1: { year: 1, month: 1, day: 1, era: 'ce' } - }, - hebrew: { year2000: { year: 5760, month: 4, day: 23 }, year1: { year: 3761, month: 4, day: 18 } }, - indian: { - year2000: { year: 1921, month: 10, day: 11, era: 'saka' }, - // with() fails due to https://bugs.chromium.org/p/v8/issues/detail?id=10529 - // from() succeeds because the bug only gets triggered before 1/1/1 ISO. - // Fixed in later versions of Node 14/15/16 - year1: { - with: { node12: RangeError, year: -78, month: 10, day: 11, era: 'saka' }, - from: { year: -78, month: 10, day: 11, era: 'saka' } - } - }, - // Older islamic dates will fail due to https://bugs.chromium.org/p/v8/issues/detail?id=10527 - // Fixed in later versions of Node 14/15/16 - islamic: { - year2000: { year: 1420, month: 9, day: 25, era: 'ah' }, - year1: { node12: RangeError, year: -640, month: 5, day: 20, era: 'ah' } - }, - 'islamic-umalqura': { - year2000: { year: 1420, month: 9, day: 24, era: 'ah' }, - year1: { year: -640, month: 5, day: 18, era: 'ah' } - }, - 'islamic-tbla': { - year2000: { year: 1420, month: 9, day: 25, era: 'ah' }, - year1: { year: -640, month: 5, day: 19, era: 'ah' } - }, - 'islamic-civil': { - year2000: { year: 1420, month: 9, day: 24, era: 'ah' }, - year1: { year: -640, month: 5, day: 18, era: 'ah' } - }, - 'islamic-rgsa': { - year2000: { year: 1420, month: 9, day: 25, era: 'ah' }, - year1: { node12: RangeError, year: -640, month: 5, day: 20, era: 'ah' } - }, - islamicc: { - year2000: { year: 1420, month: 9, day: 24, era: 'ah' }, - year1: { year: -640, month: 5, day: 18, era: 'ah' } - }, - japanese: { - year2000: { year: 2000, eraYear: 12, month: 1, day: 1, era: 'heisei' }, - // Pre-1582 dates are broken by https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - year1: RangeError - // year1: { year: 1, eraYear: 1, month: 1, day: 1, era: 'ce' } - }, - persian: { - year2000: { year: 1378, month: 10, day: 11, era: 'ap' }, - year1: { year: -621, month: 10, day: 11, era: 'ap' } - }, - roc: { - year2000: { year: 89, month: 1, day: 1, era: 'minguo' }, - // Pre-1582 dates are broken by https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - year1: RangeError - // year1: { year: -1910, eraYear: 1911, month: 1, day: 3, era: 'before-roc' } - } - }; - // The current non-ISO calendar implementation is quite slow because it's - // not calculating calendar info directly but is parsing the output of - // `Intl.DateTimeFormat.formatToParts`. The advantage of this approach for a - // non-production polyfill is that the results of Temporal will always match - // the results of legacy Date and Intl calls. The downside is that it's - // slooooooooow! To help diagnose and fix perf issues in future PRs, we're - // leaving logging code below which would normally have been removed. To - // measure perf, just set logPerf=true. - const logPerf = false; - let totalNow = 0; - for (let [id, tests] of Object.entries(fromWithCases)) { - const dates = { - year2000: Temporal.PlainDate.from('2000-01-01'), - year1: Temporal.PlainDate.from('0001-01-01') - }; - for (const [name, date] of Object.entries(dates)) { - const getValues = (type) => { - let val = tests[name]; - if (val[type]) val = val[type]; - return val; - }; - const fromValues = getValues('from'); - const fromErrorExpected = - fromValues === RangeError || (nodeVersion === '12' && fromValues.node12 === RangeError); - itOrSkip(id)(`from: ${id} ${name} ${fromErrorExpected ? ' (throws)' : ''}`, () => { - const now = globalThis.performance ? globalThis.performance.now() : Date.now(); - const values = fromValues; - if (fromErrorExpected) { - // Some calendars will fail due to Chromium bugs noted in the test definitions - throws(() => { - const inCal = date.withCalendar(id); - Temporal.PlainDate.from({ - calendar: id, - year: inCal.year, - day: inCal.day, - monthCode: inCal.monthCode - }); - }, RangeError); - return; - } - const inCal = date.withCalendar(id); - equal(`${name} ${id} day: ${inCal.day}`, `${name} ${id} day: ${values.day}`); - if (values.eraYear === undefined && values.era !== undefined) values.eraYear = values.year; - - equal(`${name} ${id} eraYear: ${inCal.eraYear}`, `${name} ${id} eraYear: ${values.eraYear}`); - equal(`${name} ${id} era: ${inCal.era}`, `${name} ${id} era: ${values.era}`); - equal(`${name} ${id} year: ${inCal.year}`, `${name} ${id} year: ${values.year}`); - - equal(`${name} ${id} month: ${inCal.month}`, `${name} ${id} month: ${values.month}`); - if (values.monthCode === undefined) values.monthCode = `M${values.month.toString().padStart(2, '0')}`; - equal(`${name} ${id} monthCode: ${inCal.monthCode}`, `${name} ${id} monthCode: ${values.monthCode}`); - - if (values.era) { - // Now reverse the operation: create using calendar dates and verify - // that the same ISO date is returned. - const dateRoundtrip1 = Temporal.PlainDate.from({ - calendar: id, - eraYear: values.eraYear, - era: values.era, - day: values.day, - monthCode: values.monthCode - }); - equal(dateRoundtrip1.toString(), inCal.toString()); - - // ensure that mismatches of year vs. era/eraYear are caught - throws( - () => - Temporal.PlainDate.from({ - calendar: id, - eraYear: values.eraYear, - era: values.era, - day: values.day, - monthCode: values.monthCode, - year: values.year + 1 - }), - RangeError - ); - } - const dateRoundtrip2 = Temporal.PlainDate.from({ - calendar: id, - year: values.year, - day: values.day, - monthCode: values.monthCode - }); - equal(dateRoundtrip2.toString(), inCal.toString()); - const dateRoundtrip3 = Temporal.PlainDate.from({ - calendar: id, - year: values.year, - day: values.day, - month: values.month - }); - equal(dateRoundtrip3.toString(), inCal.toString()); - const dateRoundtrip4 = Temporal.PlainDate.from({ - calendar: id, - year: values.year, - day: values.day, - monthCode: values.monthCode - }); - equal(dateRoundtrip4.toString(), inCal.toString()); - // ensure that mismatches of month vs. monthCode are caught - throws( - () => - Temporal.PlainDate.from({ - calendar: id, - day: values.day, - month: values.month === 1 ? 2 : values.month - 1, - monthCode: values.monthCode, - year: values.year - }), - RangeError - ); - const ms = (globalThis.performance ? globalThis.performance.now() : Date.now()) - now; - totalNow += ms; - // eslint-disable-next-line no-console - if (logPerf) console.log(`from: ${id} ${name}: ${ms.toFixed(2)}ms, total: ${totalNow.toFixed(2)}ms`); - }); - const withValues = getValues('with'); - const withErrorExpected = - withValues === RangeError || (nodeVersion === '12' && withValues.node12 === RangeError); - itOrSkip(id)(`with: ${id} ${name} ${withErrorExpected ? ' (throws)' : ''}`, () => { - const now = globalThis.performance ? globalThis.performance.now() : Date.now(); - - // [fullcalendar/temporal] - // NOTE: we assume error will occur during .withCalendar, not .with - // this is better, because we don't want an obj to fail randomly after instantiation: - // pd = new Temporal.PlainDate(1, 1, 1, 'japanese') // works - // pd.day // fails! - // - let inCal; - if (withErrorExpected) { - // Some calendars will fail due to Chromium bugs noted in the test definitions - throws(() => { - inCal = date.withCalendar(id); - inCal.with({ day: 1 }).year - }, RangeError); - return; - } else { - inCal = date.withCalendar(id); - } - - const afterWithDay = inCal.with({ day: 1 }); - let t = '(after setting day)'; - equal(`${t} year: ${afterWithDay.year}`, `${t} year: ${inCal.year}`); - equal(`${t} month: ${afterWithDay.month}`, `${t} month: ${inCal.month}`); - equal(`${t} day: ${afterWithDay.day}`, `${t} day: 1`); - const afterWithMonth = afterWithDay.with({ month: 1 }); - t = '(after setting month)'; - equal(`${t} year: ${afterWithMonth.year}`, `${t} year: ${inCal.year}`); - equal(`${t} month: ${afterWithMonth.month}`, `${t} month: 1`); - equal(`${t} day: ${afterWithMonth.day}`, `${t} day: 1`); - // FYI: we're using 2220 here because it's larger than the ISO year 1582 - // in all calendars affected by https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - const afterWithYear = afterWithMonth.with({ year: 2220 }); - t = '(after setting year)'; - equal(`${t} year: ${afterWithYear.year}`, `${t} year: 2220`); - equal(`${t} month: ${afterWithYear.month}`, `${t} month: 1`); - equal(`${t} day: ${afterWithYear.day}`, `${t} day: 1`); - const ms = (globalThis.performance ? globalThis.performance.now() : Date.now()) - now; - totalNow += ms; - // eslint-disable-next-line no-console - if (logPerf) console.log(`with: ${id} ${name}: ${ms.toFixed(2)}ms, total: ${totalNow.toFixed(2)}ms`); - }); - } - } - /* - // This code below is useful for generating the snapshot content below in - // case more variations are needed. - year1Content = ['iso8601', 'buddhist', 'chinese', 'coptic', 'dangi', 'ethioaa', 'ethiopic', 'gregory', 'hebrew', - 'indian', 'islamic', 'islamic-umalqura', 'islamic-tbla', 'islamic-civil', 'islamic-rgsa', 'islamicc', - 'japanese', 'persian', 'roc'].map((id) => { - const end = Temporal.PlainDate.from({ year: 2000, month: 1, day: 1, calendar: id }).add({months: 6}); - const { year, month, day, monthCode, eraYear, era } = end; - const quotedId = id.includes('-') ? `'${id}'` : id; - return ` ${quotedId}: { year: ${year}, month: ${month}, day: ${day}, monthCode: 'M${monthCode - }', eraYear: ${eraYear}, era: ${era ? `'${era}'` : undefined} }`; - }).join(',\n'); - */ - const addDaysWeeksCases = { - iso8601: { year: 2000, month: 10, day: 7, monthCode: 'M10', eraYear: undefined, era: undefined }, - // See https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - buddhist: RangeError, // { year: 2000, month: 10, day: 8, monthCode: 'M10', eraYear: 2000, era: 'be' }, - chinese: { year: 2000, month: 10, day: 16, monthCode: 'M10', eraYear: undefined, era: undefined }, - coptic: { year: 2000, month: 10, day: 11, monthCode: 'M10', eraYear: 2000, era: 'era1' }, - dangi: { year: 2000, month: 10, day: 16, monthCode: 'M10', eraYear: undefined, era: undefined }, - ethioaa: { year: 2000, month: 10, day: 11, monthCode: 'M10', eraYear: 2000, era: 'era0' }, - ethiopic: { year: 2000, month: 10, day: 11, monthCode: 'M10', eraYear: 2000, era: 'era0' }, - gregory: { year: 2000, month: 10, day: 7, monthCode: 'M10', eraYear: 2000, era: 'ce' }, - hebrew: { year: 2000, month: 10, day: 14, monthCode: 'M10', eraYear: undefined, era: undefined }, - indian: { year: 2000, month: 10, day: 6, monthCode: 'M10', eraYear: 2000, era: 'saka' }, - islamic: { year: 2000, month: 10, day: 15, monthCode: 'M10', eraYear: 2000, era: 'ah' }, - 'islamic-umalqura': { year: 2000, month: 10, day: 15, monthCode: 'M10', eraYear: 2000, era: 'ah' }, - 'islamic-tbla': { year: 2000, month: 10, day: 15, monthCode: 'M10', eraYear: 2000, era: 'ah' }, - 'islamic-civil': { year: 2000, month: 10, day: 15, monthCode: 'M10', eraYear: 2000, era: 'ah' }, - 'islamic-rgsa': { year: 2000, month: 10, day: 15, monthCode: 'M10', eraYear: 2000, era: 'ah' }, - islamicc: { year: 2000, month: 10, day: 15, monthCode: 'M10', eraYear: 2000, era: 'ah' }, - japanese: { year: 2000, month: 10, day: 7, monthCode: 'M10', eraYear: 12, era: 'heisei' }, - persian: { year: 2000, month: 10, day: 5, monthCode: 'M10', eraYear: 2000, era: 'ap' }, - roc: { year: 2000, month: 10, day: 8, monthCode: 'M10', eraYear: 2000, era: 'minguo' } - }; - const addMonthsCases = { - iso8601: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: undefined, era: undefined }, - // See https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - buddhist: RangeError, // { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'be' }, - chinese: { year: 2001, month: 6, day: 1, monthCode: 'M05', eraYear: undefined, era: undefined }, - coptic: { year: 2001, month: 5, day: 1, monthCode: 'M05', eraYear: 2001, era: 'era1' }, - dangi: { year: 2001, month: 6, day: 1, monthCode: 'M05', eraYear: undefined, era: undefined }, - ethioaa: { year: 2001, month: 5, day: 1, monthCode: 'M05', eraYear: 2001, era: 'era0' }, - ethiopic: { year: 2001, month: 5, day: 1, monthCode: 'M05', eraYear: 2001, era: 'era0' }, - gregory: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ce' }, - hebrew: { year: 2001, month: 6, day: 1, monthCode: 'M05L', eraYear: undefined, era: undefined }, - indian: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'saka' }, - islamic: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ah' }, - 'islamic-umalqura': { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ah' }, - 'islamic-tbla': { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ah' }, - 'islamic-civil': { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ah' }, - 'islamic-rgsa': { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ah' }, - islamicc: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ah' }, - japanese: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 13, era: 'heisei' }, - persian: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'ap' }, - roc: { year: 2001, month: 6, day: 1, monthCode: 'M06', eraYear: 2001, era: 'minguo' } - }; - const addYearsMonthsDaysCases = Object.entries(addMonthsCases).reduce((obj, entry) => { - obj[entry[0]] = entry[1] === RangeError ? RangeError : { ...entry[1], day: 18 }; - return obj; - }, {}); - const tests = { - days: { duration: { days: 280 }, results: addDaysWeeksCases, startDate: { year: 2000, month: 1, day: 1 } }, - weeks: { duration: { weeks: 40 }, results: addDaysWeeksCases, startDate: { year: 2000, month: 1, day: 1 } }, - // 2001 is a leap year in both ICU lunisolar calendars: Hebrew and - // Chinese/Dangi. By adding 6 months we're ensuring that addition - // recognizes the leap month. - months: { duration: { months: 6 }, results: addMonthsCases, startDate: { year: 2000, month: 12, day: 1 } }, - years: { - duration: { years: 3, months: 6, days: 17 }, - results: addYearsMonthsDaysCases, - startDate: { year: 1997, month: 12, day: 1 } - } - }; - const calendars = Object.keys(addMonthsCases); - for (let id of calendars) { - for (let [unit, { duration, results, startDate }] of Object.entries(tests)) { - const values = results[id]; - duration = Temporal.Duration.from(duration); - itOrSkip(id)(`${id} add ${duration}`, () => { - const now = globalThis.performance ? globalThis.performance.now() : Date.now(); - if (values === RangeError) { - throws(() => Temporal.PlainDate.from({ ...startDate, calendar: id })); - return; - } - const start = Temporal.PlainDate.from({ ...startDate, calendar: id }); - const end = start.add(duration); - equal(`add ${unit} ${id} day: ${end.day}`, `add ${unit} ${id} day: ${values.day}`); - equal(`add ${unit} ${id} eraYear: ${end.eraYear}`, `add ${unit} ${id} eraYear: ${values.eraYear}`); - equal(`add ${unit} ${id} era: ${end.era}`, `add ${unit} ${id} era: ${values.era}`); - equal(`add ${unit} ${id} year: ${end.year}`, `add ${unit} ${id} year: ${values.year}`); - equal(`add ${unit} ${id} month: ${end.month}`, `add ${unit} ${id} month: ${values.month}`); - equal(`add ${unit} ${id} monthCode: ${end.monthCode}`, `add ${unit} ${id} monthCode: ${values.monthCode}`); - const calculatedStart = end.subtract(duration); - equal(`start ${calculatedStart.toString()}`, `start ${start.toString()}`); - const diff = start.until(end, { largestUnit: unit }); - equal(`diff ${unit} ${id}: ${diff}`, `diff ${unit} ${id}: ${duration}`); - - if (unit === 'months') { - const startYesterday = start.subtract({ days: 1 }); - let endYesterday = startYesterday.add(duration); - equal( - `add from end-of-month ${unit} ${id} day (initial): ${endYesterday.day}`, - `add from end-of-month ${unit} ${id} day (initial): ${Math.min( - startYesterday.day, - endYesterday.daysInMonth - )}` - ); - // Now advance to the first day of the next month, which should be - // the same as the expected end date above. - let endYesterdayNextDay = endYesterday.add({ days: 1 }); - while (endYesterdayNextDay.day !== 1) { - // It's possible that we may be more than one day off in some - // calendars, e.g. when original start date was March 1, so day - // before was Feb 28, so adding P6M to Feb 28 will be Oct 28, so - // need to advance three days. - endYesterdayNextDay = endYesterdayNextDay.add({ days: 1 }); - } - equal( - `add from end-of-month ${unit} ${id} day: ${endYesterdayNextDay.day}`, - `add from end-of-month ${unit} ${id} day: ${values.day}` - ); - equal( - `add from end-of-month ${unit} ${id} eraYear: ${endYesterdayNextDay.eraYear}`, - `add from end-of-month ${unit} ${id} eraYear: ${values.eraYear}` - ); - equal( - `add from end-of-month ${unit} ${id} era: ${endYesterdayNextDay.era}`, - `add from end-of-month ${unit} ${id} era: ${values.era}` - ); - equal( - `add from end-of-month ${unit} ${id} year: ${endYesterdayNextDay.year}`, - `add from end-of-month ${unit} ${id} year: ${values.year}` - ); - equal( - `add from end-of-month ${unit} ${id} month: ${endYesterdayNextDay.month}`, - `add from end-of-month ${unit} ${id} month: ${values.month}` - ); - equal( - `add from end-of-month ${unit} ${id} monthCode: ${endYesterdayNextDay.monthCode}`, - `add from end-of-month ${unit} ${id} monthCode: ${values.monthCode}` - ); - - // Now test the reverse operation: subtracting from the last day of - // the previous month. - const endReverse = endYesterdayNextDay.subtract({ days: 1 }); - const startReverse = endReverse.subtract(duration); - equal( - `subtract from end-of-month ${unit} ${id} day (initial): ${startReverse.day}`, - `subtract from end-of-month ${unit} ${id} day (initial): ${Math.min( - endReverse.day, - startReverse.daysInMonth - )}` - ); - // Now advance to the first day of the next month, which should be - // the same as the original start date above. - let startReverseNextDay = startReverse.add({ days: 1 }); - while (startReverseNextDay.day !== 1) { - // It's possible that we may be more than one day off in some - // calendars, e.g. when original start date was March 1, so day - // before was Feb 28, so adding P6M to Feb 28 will be Oct 28, so - // need to advance three days. - startReverseNextDay = startReverseNextDay.add({ days: 1 }); - } - equal( - `subtract from end-of-month ${unit} ${id} day: ${startReverseNextDay.day}`, - `subtract from end-of-month ${unit} ${id} day: ${start.day}` - ); - equal( - `subtract from end-of-month ${unit} ${id} eraYear: ${startReverseNextDay.eraYear}`, - `subtract from end-of-month ${unit} ${id} eraYear: ${start.eraYear}` - ); - equal( - `subtract from end-of-month ${unit} ${id} era: ${startReverseNextDay.era}`, - `subtract from end-of-month ${unit} ${id} era: ${start.era}` - ); - equal( - `subtract from end-of-month ${unit} ${id} year: ${startReverseNextDay.year}`, - `subtract from end-of-month ${unit} ${id} year: ${start.year}` - ); - equal( - `subtract from end-of-month ${unit} ${id} month: ${startReverseNextDay.month}`, - `subtract from end-of-month ${unit} ${id} month: ${start.month}` - ); - equal( - `subtract from end-of-month ${unit} ${id} monthCode: ${startReverseNextDay.monthCode}`, - `subtract from end-of-month ${unit} ${id} monthCode: ${start.monthCode}` - ); - } - - const ms = (globalThis.performance ? globalThis.performance.now() : Date.now()) - now; - totalNow += ms; - // eslint-disable-next-line no-console - if (logPerf) console.log(`${id} add ${duration}: ${ms.toFixed(2)}ms, total: ${totalNow.toFixed(2)}ms`); - }); - } - } - /* - // content for tests below - ['iso8601', 'buddhist', 'chinese', 'coptic', 'dangi', 'ethioaa', 'ethiopic', 'gregory', hebrew', - 'indian', 'islamic', 'islamic-umalqura', 'islamic-tbla', 'islamic-civil', 'islamic-rgsa', 'islamicc', - 'japanese', 'persian', 'roc'].map((id) => { - const date = Temporal.PlainDate.from({ year: 2001, month: 1, day: 1, calendar: id }); - const monthsInYear = date.monthsInYear; - const daysInMonthArray = []; - let { year, inLeapYear: leap } = date; - for (let i = 1; i <= monthsInYear; i++) { - const monthStart = date.with({month: i}); - const { monthCode, daysInMonth } = monthStart; - daysInMonthArray.push(monthStart.daysInMonth); - if (monthStart.monthCode.endsWith('L')) leap = `'M${monthCode}'`; - } - const quotedId = id.includes('-') ? `'${id}'` : id; - return `${quotedId}: { year: ${year}, leap: ${leap}, days: [${daysInMonthArray.join(', ')}] }`; - }).join(',\n'); - */ - const daysInMonthCases = { - iso8601: { year: 2001, leap: false, days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] }, - // Buddhist uses 4001 to avoid https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - buddhist: { year: 4001, leap: false, days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] }, - chinese: { year: 2001, leap: 'M04L', days: [30, 30, 29, 30, 29, 30, 29, 29, 30, 29, 30, 29, 30] }, - coptic: { year: 2001, leap: false, days: [30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 5] }, - dangi: { year: 2001, leap: 'M04L', days: [30, 30, 30, 29, 29, 30, 29, 29, 30, 29, 30, 29, 30] }, - ethioaa: { year: 2001, leap: false, days: [30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 5] }, - ethiopic: { year: 2001, leap: false, days: [30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 5] }, - gregory: { year: 2001, leap: false, days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] }, - hebrew: { year: 2001, leap: 'M05L', days: [30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29] }, - indian: { year: 2001, leap: false, days: [30, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30] }, - islamic: { year: 2001, leap: false, days: [29, 30, 29, 29, 30, 29, 30, 30, 29, 30, 30, 29] }, - 'islamic-umalqura': { year: 2001, leap: true, days: [30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30] }, - 'islamic-tbla': { year: 2001, leap: true, days: [30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30] }, - 'islamic-civil': { year: 2001, leap: true, days: [30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30] }, - 'islamic-rgsa': { year: 2001, leap: false, days: [29, 30, 29, 29, 30, 29, 30, 30, 29, 30, 30, 29] }, - islamicc: { year: 2001, leap: true, days: [30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30] }, - japanese: { year: 2001, leap: false, days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] }, - persian: { year: 2001, leap: false, days: [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29] }, - roc: { year: 2001, leap: true, days: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] } - }; - totalNow = 0; - for (let id of calendars) { - let { year, leap, days } = daysInMonthCases[id]; - let date = - hasOutdatedChineseIcuData && (id === 'chinese' || id === 'dangi') - ? undefined - : Temporal.PlainDate.from({ year, month: 1, day: 1, calendar: id }); - itOrSkip(id)(`${id} leap year check for year ${year}`, () => { - if (typeof leap === 'boolean') { - equal(date.inLeapYear, leap); - } else { - equal(date.inLeapYear, true); - const leapMonth = date.with({ monthCode: leap }); - equal(leapMonth.monthCode, leap); - } - }); - itOrSkip(id)(`${id} months check for year ${year}`, () => { - const now = globalThis.performance ? globalThis.performance.now() : Date.now(); - const { monthsInYear } = date; - equal(monthsInYear, days.length); - // This loop counts backwards so we'll have the right test for the month - // before a leap month in lunisolar calendars. - for (let i = monthsInYear, leapMonthIndex = undefined, monthStart = undefined; i >= 1; i--) { - monthStart = monthStart ? monthStart.add({ months: -1 }) : date.add({ months: monthsInYear - 1 }); - const { month, monthCode, daysInMonth } = monthStart; - equal( - `${id} month ${i} (code ${monthCode}) days: ${daysInMonth}`, - `${id} month ${i} (code ${monthCode}) days: ${days[i - 1]}` - ); - if (monthCode.endsWith('L')) { - equal(date.with({ monthCode }).monthCode, monthCode); - leapMonthIndex = i; - } else { - if (leapMonthIndex && i === leapMonthIndex - 1) { - const inLeapMonth = monthStart.with({ monthCode: `M${month.toString().padStart(2, '0')}L` }); - equal(inLeapMonth.monthCode, `${monthCode}L`); - } else { - throws( - () => monthStart.with({ monthCode: `M${month.toString().padStart(2, '0')}L` }, { overflow: 'reject' }), - RangeError - ); - if (['chinese', 'dangi'].includes(id)) { - if (i === 1 || i === 12 || i === 13) { - throws(() => monthStart.with({ monthCode: `M${month.toString().padStart(2, '0')}L` }), RangeError); - } else { - // verify that non-leap "L" months are constrained down to last day of previous month - const fakeL = monthStart.with({ monthCode: `M${month.toString().padStart(2, '0')}L`, day: 5 }); - equal(`fake leap month ${fakeL.monthCode}`, `fake leap month M${month.toString().padStart(2, '0')}`); - equal(fakeL.day, fakeL.daysInMonth); - } - } - } - if (!['chinese', 'dangi', 'hebrew'].includes(id)) { - // leap months should only be allowed for lunisolar calendars - throws(() => monthStart.with({ monthCode: `M${month.toString().padStart(2, '0')}L` }), RangeError); - } - } - throws(() => monthStart.with({ day: daysInMonth + 1 }, { overflow: 'reject' }), RangeError); - const oneDayPastMonthEnd = monthStart.with({ day: daysInMonth + 1 }); - equal(oneDayPastMonthEnd.day, daysInMonth); - } - const ms = (globalThis.performance ? globalThis.performance.now() : Date.now()) - now; - totalNow += ms; - // eslint-disable-next-line no-console - if (logPerf) console.log(`${id} months check ${id}: ${ms.toFixed(2)}ms, total: ${totalNow.toFixed(2)}ms`); - }); - } - const monthDayCases = [ - { calendar: 'iso8601', isoReferenceYear: 1972, year: 2004, month: 2, day: 29 }, - // Buddhist calendar suffers pre-node15 https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 - { calendar: 'buddhist', nodeBefore15: RangeError, isoReferenceYear: 1972, year: 2004, month: 2, day: 29 }, - { calendar: 'chinese', isoReferenceYear: 1963, year: 2001, month: 5, monthCode: 'M04L', day: 15 }, - { calendar: 'chinese', isoReferenceYear: 1971, year: 2000, month: 6, day: 30 }, - { calendar: 'coptic', isoReferenceYear: 1971, year: 2006, month: 13, day: 6 }, - { calendar: 'dangi', isoReferenceYear: 1963, year: 2001, month: 5, monthCode: 'M04L', day: 15 }, - { calendar: 'dangi', isoReferenceYear: 1971, year: 2000, month: 6, day: 30 }, - { calendar: 'ethiopic', isoReferenceYear: 1971, year: 2006, month: 13, day: 6 }, - { calendar: 'ethioaa', isoReferenceYear: 1971, year: 2006, month: 13, day: 6 }, - { calendar: 'gregory', isoReferenceYear: 1972, year: 2004, month: 2, day: 29 }, - { calendar: 'hebrew', isoReferenceYear: 1970, year: 5779, month: 6, monthCode: 'M05L', day: 15 }, - { calendar: 'hebrew', isoReferenceYear: 1971, year: 5776, month: 2, day: 30 }, - { calendar: 'hebrew', isoReferenceYear: 1971, year: 5772, month: 3, day: 30 }, - { calendar: 'indian', isoReferenceYear: 1968, year: 2002, month: 1, day: 31 }, - { calendar: 'islamic', isoReferenceYear: 1970, year: 2001, month: 1, day: 30 }, - { calendar: 'islamic-umalqura', isoReferenceYear: 1969, year: 2001, month: 1, day: 30 }, - { calendar: 'islamic-tbla', isoReferenceYear: 1971, year: 2001, month: 1, day: 30 }, - { calendar: 'islamic-civil', isoReferenceYear: 1971, year: 2001, month: 1, day: 30 }, - { calendar: 'islamic-rgsa', isoReferenceYear: 1970, year: 2001, month: 1, day: 30 }, - { calendar: 'islamicc', isoReferenceYear: 1971, year: 2001, month: 1, day: 30 }, - { calendar: 'japanese', isoReferenceYear: 1972, year: 2004, month: 2, day: 29 }, - { calendar: 'persian', isoReferenceYear: 1972, year: 2004, month: 12, day: 30 }, - { calendar: 'roc', isoReferenceYear: 1972, year: 93, month: 2, day: 29 } - ]; - let i = 0; - for (let test of monthDayCases) { - const id = test.calendar; - itOrSkip(`monthDay works for ${id} - ${++i}: ${test.monthCode || test.month}/${test.day}`, () => { - const errorExpected = - test === RangeError || ((nodeVersion === '14' || nodeVersion === '12') && test.nodeBefore15 === RangeError); - if (errorExpected) { - throws(() => Temporal.PlainMonthDay.from({ year, month, day, calendar })); - return; - } - if (test.monthCode === undefined) test.monthCode = `M${test.month.toString().padStart(2, '0')}`; - const { calendar, monthCode, month, day, year, isoReferenceYear } = test; - const md = Temporal.PlainMonthDay.from({ year, month, day, calendar }); - const isoString = md.toString(); - const mdFromIso = Temporal.PlainMonthDay.from(isoString); - equal(mdFromIso, md); - const isoFields = md.getISOFields(); - equal(md.monthCode, monthCode); - equal(md.day, day); - equal(isoFields.isoYear, isoReferenceYear); - const md2 = Temporal.PlainMonthDay.from({ monthCode, day, calendar }); - const isoFields2 = md2.getISOFields(); - equal(md2.monthCode, monthCode); - equal(md2.day, day); - equal(isoFields2.isoYear, isoReferenceYear); - equal(md.equals(md2), true); - throws(() => { - Temporal.PlainMonthDay.from({ monthCode: 'M15', day: 1, calendar }, { overflow: 'reject' }); - }, RangeError); - throws(() => { - Temporal.PlainMonthDay.from({ monthCode: 'M15', day: 1, calendar }); - }, RangeError); - throws(() => { - Temporal.PlainMonthDay.from({ year, month: 15, day: 1, calendar }, { overflow: 'reject' }); - }, RangeError); - const constrained = Temporal.PlainMonthDay.from({ year, month: 15, day: 1, calendar }); - const { monthCode: monthCodeConstrained } = constrained; - assert(monthCodeConstrained === 'M12' || monthCodeConstrained === 'M13'); - }); - } - }); - - describe('Indian calendar', () => { - it('throws in Node 12 & 14 before 1 CE', () => { - // Dates before ISO 1 fail due to https://bugs.chromium.org/p/v8/issues/detail?id=10529 - // Fixed in Node 15 - const vulnerableToBceBug = - new Date('0000-01-01T00:00Z').toLocaleDateString('en-US-u-ca-indian', { timeZone: 'UTC' }) !== '10/11/-79 Saka'; - if (vulnerableToBceBug) { - throws(() => Temporal.PlainDate.from('0000-01-01').withCalendar('indian').day, RangeError); - } - }); - it('handles leap days', () => { - const leapYearFirstDay = Temporal.PlainDate.from('2004-03-21[u-ca=indian]'); - equal(leapYearFirstDay.year, 2004 - 78); - equal(leapYearFirstDay.month, 1); - equal(leapYearFirstDay.day, 1); - - const leapYearLastDay = leapYearFirstDay.with({ day: 31 }); - equal(leapYearLastDay.year, 2004 - 78); - equal(leapYearLastDay.month, 1); - equal(leapYearLastDay.day, 31); - }); - it('handles non-leap years', () => { - const nonLeapYearFirstDay = Temporal.PlainDate.from('2005-03-22[u-ca=indian]'); - equal(nonLeapYearFirstDay.year, 2005 - 78); - equal(nonLeapYearFirstDay.month, 1); - equal(nonLeapYearFirstDay.day, 1); - - const leapYearLastDay = nonLeapYearFirstDay.with({ day: 31 }); - equal(leapYearLastDay.year, 2005 - 78); - equal(leapYearLastDay.month, 1); - equal(leapYearLastDay.day, 30); - - throws(() => nonLeapYearFirstDay.with({ day: 31 }, { overflow: 'reject' })); - }); - }); - - describe('Japanese eras', () => { - it('Reiwa (2019-)', () => { - let date = Temporal.PlainDate.from({ era: 'reiwa', eraYear: 2, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '2020-01-01[u-ca=japanese]'); - }); - it('Heisei (1989-2019)', () => { - let date = Temporal.PlainDate.from({ era: 'heisei', eraYear: 2, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1990-01-01[u-ca=japanese]'); - }); - it('Showa (1926-1989)', () => { - let date = Temporal.PlainDate.from({ era: 'showa', eraYear: 2, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1927-01-01[u-ca=japanese]'); - }); - it('Taisho (1912-1926)', () => { - let date = Temporal.PlainDate.from({ era: 'taisho', eraYear: 2, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1913-01-01[u-ca=japanese]'); - }); - it('Meiji (1868-1912)', () => { - let date = Temporal.PlainDate.from({ era: 'meiji', eraYear: 2, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1869-01-01[u-ca=japanese]'); - }); - it('Dates in same year before Japanese era starts will resolve to previous era', () => { - let date = Temporal.PlainDate.from({ era: 'reiwa', eraYear: 1, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '2019-01-01[u-ca=japanese]'); - equal(date.era, 'heisei'); - equal(date.eraYear, 31); - date = Temporal.PlainDate.from({ era: 'heisei', eraYear: 1, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1989-01-01[u-ca=japanese]'); - equal(date.era, 'showa'); - equal(date.eraYear, 64); - date = Temporal.PlainDate.from({ era: 'showa', eraYear: 1, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1926-01-01[u-ca=japanese]'); - equal(date.era, 'taisho'); - equal(date.eraYear, 15); - date = Temporal.PlainDate.from({ era: 'taisho', eraYear: 1, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1912-01-01[u-ca=japanese]'); - equal(date.era, 'meiji'); - equal(date.eraYear, 45); - date = Temporal.PlainDate.from({ era: 'meiji', eraYear: 1, month: 1, day: 1, calendar: 'japanese' }); - equal(`${date}`, '1868-01-01[u-ca=japanese]'); - equal(date.era, 'ce'); - equal(date.eraYear, 1868); - throws( - () => Temporal.PlainDate.from({ era: 'bce', eraYear: 1, month: 1, day: 1, calendar: 'japanese' }), - RangeError - ); - // uncomment & revise `throws` above if https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 is resolved - // equal(`${date}`, '+000000-01-01[u-ca=japanese]'); - // equal(date.era, 'bce'); - // equal(date.eraYear, 1); - }); - it("`with` doesn't crash when constraining dates out of bounds of the current era", () => { - // https://github.com/tc39/proposal-temporal/issues/1784 - let date = Temporal.PlainDate.from('1989-01-07') - .withCalendar(Temporal.Calendar.from('japanese')) - .with({ day: 10 }); - equal(`${date}`, '1989-01-10[u-ca=japanese]'); - }); - }); - - describe('Hebrew leap months', () => { - it('Valid leap month: Adar I 5779', () => { - let date = Temporal.PlainDate.from({ year: 5779, month: 6, day: 1, calendar: 'hebrew' }); - equal(date.month, 6); - equal(date.monthCode, 'M05L'); - equal(date.day, 1); - date = Temporal.PlainDate.from({ year: 5779, monthCode: 'M05L', day: 1, calendar: 'hebrew' }); - equal(date.month, 6); - equal(date.monthCode, 'M05L'); - equal(date.day, 1); - }); - it('Invalid leap months: e.g. M02L', () => { - for (let i = 1; i <= 12; i++) { - if (i === 5) continue; // M05L is the only valid month (Adar I) - throws( - () => - Temporal.PlainDate.from({ - year: 5779, - monthCode: `M${i.toString().padStart(2, '0')}L`, - day: 1, - calendar: 'hebrew' - }), - RangeError - ); - } - }); - it('Leap month in non-leap year (reject): Adar I 5780', () => { - throws( - () => - Temporal.PlainDate.from( - { year: 5780, monthCode: 'M05L', day: 1, calendar: 'hebrew' }, - { overflow: 'reject' } - ), - RangeError - ); - }); - it('Leap month in non-leap year (constrain): 15 Adar I 5780 => 30 Av 5780', () => { - const date = Temporal.PlainDate.from({ year: 5780, monthCode: 'M05L', day: 15, calendar: 'hebrew' }); - equal(date.month, 5); - equal(date.monthCode, 'M05'); - equal(date.day, 30); - }); - }); - - describe('DateTimeFormat', () => { - describe('supportedLocalesOf', () => { - it('should return an Array', () => assert(Array.isArray(Intl.DateTimeFormat.supportedLocalesOf()))); - }); - - // Verify that inputs to DateTimeFormat constructor are immune to mutation. - // Also verify that options properties are only read once. - const onlyOnce = (value) => { - const obj = { - calls: 0, - toString() { - if (++this.calls > 1) throw new RangeError('prop read twice'); - return value; - } - }; - return obj; - }; - const optionsAT = { - timeZone: onlyOnce('Europe/Vienna') - }; - const optionsUS = { - calls: 0, - value: 'America/New_York', - get timeZone() { - if (++this.calls > 1) throw new RangeError('prop read twice'); - return this.value; - }, - set timeZone(val) { - this.value = val; - } - }; - const localesAT = ['de-AT']; - const us = new Intl.DateTimeFormat('en-US', optionsUS); - const at = new Intl.DateTimeFormat(localesAT, optionsAT); - optionsAT.timeZone = { - toString: () => 'Bogus/Time-Zone', - toJSON: () => 'Bogus/Time-Zone' - }; - optionsUS.timeZone = 'Bogus/Time-Zone'; - const us2 = new Intl.DateTimeFormat('en-US'); - const at2 = new Intl.DateTimeFormat(localesAT); - localesAT[0] = ['invalid locale']; - const usCalendar = us.resolvedOptions().calendar; - const atCalendar = at.resolvedOptions().calendar; - const t1 = '1976-11-18T14:23:30+00:00[UTC]'; - const t2 = '2020-02-20T15:44:56-05:00[America/New_York]'; - const start = new Date('1922-12-30'); // ☭ - const end = new Date('1991-12-26'); - - describe('format', () => { - it('should work for Instant', () => { - equal(us.format(Temporal.Instant.from(t1)), '11/18/1976, 9:23:30 AM'); - equal(at.format(Temporal.Instant.from(t1)), '18.11.1976, 15:23:30'); - }); - it('should work for ZonedDateTime', () => { - equal(us2.format(Temporal.ZonedDateTime.from(t1)), '11/18/1976, 2:23:30 PM UTC'); - equal(at2.format(Temporal.ZonedDateTime.from(t1)), '18.11.1976, 14:23:30 UTC'); - }); - it('should work for DateTime', () => { - equal(us.format(Temporal.PlainDateTime.from(t1)), '11/18/1976, 2:23:30 PM'); - equal(at.format(Temporal.PlainDateTime.from(t1)), '18.11.1976, 14:23:30'); - }); - it('should work for Time', () => { - equal(us.format(Temporal.PlainTime.from(t1)), '2:23:30 PM'); - equal(at.format(Temporal.PlainTime.from(t1)), '14:23:30'); - }); - it('should work for Date', () => { - equal(us.format(Temporal.PlainDate.from(t1)), '11/18/1976'); - equal(at.format(Temporal.PlainDate.from(t1)), '18.11.1976'); - }); - it('should work for YearMonth', () => { - const t = Temporal.PlainDate.from(t1); - equal(us.format(t.withCalendar(usCalendar).toPlainYearMonth()), '11/1976'); - equal(at.format(t.withCalendar(atCalendar).toPlainYearMonth()), '11.1976'); - }); - it('should work for MonthDay', () => { - const t = Temporal.PlainDate.from(t1); - equal(us.format(t.withCalendar(usCalendar).toPlainMonthDay()), '11/18'); - equal(at.format(t.withCalendar(atCalendar).toPlainMonthDay()), '18.11.'); - }); - it('should not break legacy Date', () => { - equal(us.format(start), '12/29/1922'); - equal(at.format(start), '30.12.1922'); - }); - }); - describe('formatToParts', () => { - it('should work for Instant', () => { - deepEqual(us.formatToParts(Temporal.Instant.from(t2)), [ - { type: 'month', value: '2' }, - { type: 'literal', value: '/' }, - { type: 'day', value: '20' }, - { type: 'literal', value: '/' }, - { type: 'year', value: '2020' }, - { type: 'literal', value: ', ' }, - { type: 'hour', value: '3' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' }, - { type: 'literal', value: ' ' }, - { type: 'dayPeriod', value: 'PM' } - ]); - deepEqual(at.formatToParts(Temporal.Instant.from(t2)), [ - { type: 'day', value: '20' }, - { type: 'literal', value: '.' }, - { type: 'month', value: '2' }, - { type: 'literal', value: '.' }, - { type: 'year', value: '2020' }, - { type: 'literal', value: ', ' }, - { type: 'hour', value: '21' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' } - ]); - }); - it('should work for ZonedDateTime', () => { - deepEqual(us2.formatToParts(Temporal.ZonedDateTime.from(t2)), [ - { type: 'month', value: '2' }, - { type: 'literal', value: '/' }, - { type: 'day', value: '20' }, - { type: 'literal', value: '/' }, - { type: 'year', value: '2020' }, - { type: 'literal', value: ', ' }, - { type: 'hour', value: '3' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' }, - { type: 'literal', value: ' ' }, - { type: 'dayPeriod', value: 'PM' }, - { type: 'literal', value: ' ' }, - { type: 'timeZoneName', value: 'EST' } - ]); - deepEqual(at2.formatToParts(Temporal.ZonedDateTime.from(t2)), [ - { type: 'day', value: '20' }, - { type: 'literal', value: '.' }, - { type: 'month', value: '2' }, - { type: 'literal', value: '.' }, - { type: 'year', value: '2020' }, - { type: 'literal', value: ', ' }, - { type: 'hour', value: '15' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' }, - { type: 'literal', value: ' ' }, - { type: 'timeZoneName', value: 'GMT-5' } - ]); - }); - it('should work for DateTime', () => { - deepEqual(us.formatToParts(Temporal.PlainDateTime.from(t2)), [ - { type: 'month', value: '2' }, - { type: 'literal', value: '/' }, - { type: 'day', value: '20' }, - { type: 'literal', value: '/' }, - { type: 'year', value: '2020' }, - { type: 'literal', value: ', ' }, - { type: 'hour', value: '3' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' }, - { type: 'literal', value: ' ' }, - { type: 'dayPeriod', value: 'PM' } - ]); - deepEqual(at.formatToParts(Temporal.PlainDateTime.from(t2)), [ - { type: 'day', value: '20' }, - { type: 'literal', value: '.' }, - { type: 'month', value: '2' }, - { type: 'literal', value: '.' }, - { type: 'year', value: '2020' }, - { type: 'literal', value: ', ' }, - { type: 'hour', value: '15' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' } - ]); - }); - it('should work for Time', () => { - deepEqual(us.formatToParts(Temporal.PlainTime.from(t2)), [ - { type: 'hour', value: '3' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' }, - { type: 'literal', value: ' ' }, - { type: 'dayPeriod', value: 'PM' } - ]); - deepEqual(at.formatToParts(Temporal.PlainTime.from(t2)), [ - { type: 'hour', value: '15' }, - { type: 'literal', value: ':' }, - { type: 'minute', value: '44' }, - { type: 'literal', value: ':' }, - { type: 'second', value: '56' } - ]); - }); - it('should work for Date', () => { - deepEqual(us.formatToParts(Temporal.PlainDate.from(t2)), [ - { type: 'month', value: '2' }, - { type: 'literal', value: '/' }, - { type: 'day', value: '20' }, - { type: 'literal', value: '/' }, - { type: 'year', value: '2020' } - ]); - deepEqual(at.formatToParts(Temporal.PlainDate.from(t2)), [ - { type: 'day', value: '20' }, - { type: 'literal', value: '.' }, - { type: 'month', value: '2' }, - { type: 'literal', value: '.' }, - { type: 'year', value: '2020' } - ]); - }); - it('should work for YearMonth', () => { - const t = Temporal.PlainDate.from(t2); - deepEqual(us.formatToParts(t.withCalendar(usCalendar).toPlainYearMonth()), [ - { type: 'month', value: '2' }, - { type: 'literal', value: '/' }, - { type: 'year', value: '2020' } - ]); - deepEqual(at.formatToParts(t.withCalendar(atCalendar).toPlainYearMonth()), [ - { type: 'month', value: '2' }, - { type: 'literal', value: '.' }, - { type: 'year', value: '2020' } - ]); - }); - it('should work for MonthDay', () => { - const t = Temporal.PlainDate.from(t2); - deepEqual(us.formatToParts(t.withCalendar(usCalendar).toPlainMonthDay()), [ - { type: 'month', value: '2' }, - { type: 'literal', value: '/' }, - { type: 'day', value: '20' } - ]); - deepEqual(at.formatToParts(t.withCalendar(atCalendar).toPlainMonthDay()), [ - { type: 'day', value: '20' }, - { type: 'literal', value: '.' }, - { type: 'month', value: '2' }, - { type: 'literal', value: '.' } - ]); - }); - it('should not break legacy Date', () => { - deepEqual(us.formatToParts(end), [ - { type: 'month', value: '12' }, - { type: 'literal', value: '/' }, - { type: 'day', value: '25' }, - { type: 'literal', value: '/' }, - { type: 'year', value: '1991' } - ]); - deepEqual(at.formatToParts(end), [ - { type: 'day', value: '26' }, - { type: 'literal', value: '.' }, - { type: 'month', value: '12' }, - { type: 'literal', value: '.' }, - { type: 'year', value: '1991' } - ]); - }); - }); - describe('formatRange', () => { - it('should work for Instant', () => { - equal( - us.formatRange(Temporal.Instant.from(t1), Temporal.Instant.from(t2)), - '11/18/1976, 9:23:30 AM – 2/20/2020, 3:44:56 PM' - ); - equal( - at.formatRange(Temporal.Instant.from(t1), Temporal.Instant.from(t2)), - '18.11.1976, 15:23:30 – 20.2.2020, 21:44:56' - ); - }); - it('should work for ZonedDateTime', () => { - const zdt1 = Temporal.ZonedDateTime.from(t1); - const zdt2 = Temporal.ZonedDateTime.from(t2).withTimeZone(zdt1.timeZone); - equal(us2.formatRange(zdt1, zdt2), '11/18/1976, 2:23:30 PM UTC – 2/20/2020, 8:44:56 PM UTC'); - equal(at2.formatRange(zdt1, zdt2), '18.11.1976, 14:23:30 UTC – 20.2.2020, 20:44:56 UTC'); - }); - it('should work for DateTime', () => { - equal( - us.formatRange(Temporal.PlainDateTime.from(t1), Temporal.PlainDateTime.from(t2)), - '11/18/1976, 2:23:30 PM – 2/20/2020, 3:44:56 PM' - ); - equal( - at.formatRange(Temporal.PlainDateTime.from(t1), Temporal.PlainDateTime.from(t2)), - '18.11.1976, 14:23:30 – 20.2.2020, 15:44:56' - ); - }); - it('should work for Time', () => { - equal(us.formatRange(Temporal.PlainTime.from(t1), Temporal.PlainTime.from(t2)), '2:23:30 PM – 3:44:56 PM'); - equal(at.formatRange(Temporal.PlainTime.from(t1), Temporal.PlainTime.from(t2)), '14:23:30 – 15:44:56'); - }); - it('should work for Date', () => { - equal(us.formatRange(Temporal.PlainDate.from(t1), Temporal.PlainDate.from(t2)), '11/18/1976 – 2/20/2020'); - equal(at.formatRange(Temporal.PlainDate.from(t1), Temporal.PlainDate.from(t2)), '18.11.1976 – 20.02.2020'); - }); - it('should work for YearMonth', () => { - const date1 = Temporal.PlainDate.from(t1); - const date2 = Temporal.PlainDate.from(t2); - equal( - us.formatRange( - date1.withCalendar(usCalendar).toPlainYearMonth(), - date2.withCalendar(usCalendar).toPlainYearMonth() - ), - '11/1976 – 2/2020' - ); - equal( - at.formatRange( - date1.withCalendar(atCalendar).toPlainYearMonth(), - date2.withCalendar(atCalendar).toPlainYearMonth() - ), - '11.1976 – 02.2020' - ); - }); - it('should work for MonthDay', () => { - const date1 = Temporal.PlainDate.from(t1); - const date2 = Temporal.PlainDate.from(t2); - equal( - us.formatRange( - date2.withCalendar(usCalendar).toPlainMonthDay(), - date1.withCalendar(usCalendar).toPlainMonthDay() - ), - '2/20 – 11/18' - ); - equal( - at.formatRange( - date2.withCalendar(atCalendar).toPlainMonthDay(), - date1.withCalendar(atCalendar).toPlainMonthDay() - ), - '20.02. – 18.11.' - ); - }); - it('should not break legacy Date', () => { - equal(us.formatRange(start, end), '12/29/1922 – 12/25/1991'); - equal(at.formatRange(start, end), '30.12.1922 – 26.12.1991'); - }); - it('should throw a TypeError when called with dissimilar types', () => - throws(() => us.formatRange(Temporal.Instant.from(t1), Temporal.PlainDateTime.from(t2)), TypeError)); - it('should throw a RangeError when called with different calendars', () => { - throws( - () => - us.formatRange(Temporal.PlainDateTime.from(t1), Temporal.PlainDateTime.from(t2).withCalendar('japanese')), - RangeError - ); - throws( - () => us.formatRange(Temporal.PlainDate.from(t1), Temporal.PlainDate.from(t2).withCalendar('japanese')), - RangeError - ); - }); - it('throws for two ZonedDateTimes with different time zones', () => { - throws(() => us2.formatRange(Temporal.ZonedDateTime.from(t1), Temporal.ZonedDateTime.from(t2)), RangeError); - }); - }); - describe('formatRangeToParts', () => { - it('should work for Instant', () => { - deepEqual(us.formatRangeToParts(Temporal.Instant.from(t1), Temporal.Instant.from(t2)), [ - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ', ', source: 'startRange' }, - { type: 'hour', value: '9', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' ', source: 'startRange' }, - { type: 'dayPeriod', value: 'AM', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' }, - { type: 'literal', value: ', ', source: 'endRange' }, - { type: 'hour', value: '3', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' }, - { type: 'literal', value: ' ', source: 'endRange' }, - { type: 'dayPeriod', value: 'PM', source: 'endRange' } - ]); - deepEqual(at.formatRangeToParts(Temporal.Instant.from(t1), Temporal.Instant.from(t2)), [ - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ', ', source: 'startRange' }, - { type: 'hour', value: '15', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' }, - { type: 'literal', value: ', ', source: 'endRange' }, - { type: 'hour', value: '21', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' } - ]); - }); - it('should work for ZonedDateTime', () => { - const zdt1 = Temporal.ZonedDateTime.from(t1); - const zdt2 = Temporal.ZonedDateTime.from(t2).withTimeZone(zdt1.timeZone); - deepEqual(us2.formatRangeToParts(zdt1, zdt2), [ - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ', ', source: 'startRange' }, - { type: 'hour', value: '2', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' ', source: 'startRange' }, - { type: 'dayPeriod', value: 'PM', source: 'startRange' }, - { type: 'literal', value: ' ', source: 'startRange' }, - { type: 'timeZoneName', value: 'UTC', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' }, - { type: 'literal', value: ', ', source: 'endRange' }, - { type: 'hour', value: '8', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' }, - { type: 'literal', value: ' ', source: 'endRange' }, - { type: 'dayPeriod', value: 'PM', source: 'endRange' }, - { type: 'literal', value: ' ', source: 'endRange' }, - { type: 'timeZoneName', value: 'UTC', source: 'endRange' } - ]); - deepEqual(at2.formatRangeToParts(zdt1, zdt2), [ - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ', ', source: 'startRange' }, - { type: 'hour', value: '14', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' ', source: 'startRange' }, - { type: 'timeZoneName', value: 'UTC', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' }, - { type: 'literal', value: ', ', source: 'endRange' }, - { type: 'hour', value: '20', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' }, - { type: 'literal', value: ' ', source: 'endRange' }, - { type: 'timeZoneName', value: 'UTC', source: 'endRange' } - ]); - }); - it('should work for DateTime', () => { - deepEqual(us.formatRangeToParts(Temporal.PlainDateTime.from(t1), Temporal.PlainDateTime.from(t2)), [ - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ', ', source: 'startRange' }, - { type: 'hour', value: '2', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' ', source: 'startRange' }, - { type: 'dayPeriod', value: 'PM', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' }, - { type: 'literal', value: ', ', source: 'endRange' }, - { type: 'hour', value: '3', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' }, - { type: 'literal', value: ' ', source: 'endRange' }, - { type: 'dayPeriod', value: 'PM', source: 'endRange' } - ]); - deepEqual(at.formatRangeToParts(Temporal.PlainDateTime.from(t1), Temporal.PlainDateTime.from(t2)), [ - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ', ', source: 'startRange' }, - { type: 'hour', value: '14', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' }, - { type: 'literal', value: ', ', source: 'endRange' }, - { type: 'hour', value: '15', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' } - ]); - }); - it('should work for Time', () => { - deepEqual(us.formatRangeToParts(Temporal.PlainTime.from(t1), Temporal.PlainTime.from(t2)), [ - { type: 'hour', value: '2', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' ', source: 'startRange' }, - { type: 'dayPeriod', value: 'PM', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'hour', value: '3', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' }, - { type: 'literal', value: ' ', source: 'endRange' }, - { type: 'dayPeriod', value: 'PM', source: 'endRange' } - ]); - deepEqual(at.formatRangeToParts(Temporal.PlainTime.from(t1), Temporal.PlainTime.from(t2)), [ - { type: 'hour', value: '14', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'minute', value: '23', source: 'startRange' }, - { type: 'literal', value: ':', source: 'startRange' }, - { type: 'second', value: '30', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'hour', value: '15', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'minute', value: '44', source: 'endRange' }, - { type: 'literal', value: ':', source: 'endRange' }, - { type: 'second', value: '56', source: 'endRange' } - ]); - }); - it('should work for Date', () => { - deepEqual(us.formatRangeToParts(Temporal.PlainDate.from(t1), Temporal.PlainDate.from(t2)), [ - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' } - ]); - deepEqual(at.formatRangeToParts(Temporal.PlainDate.from(t1), Temporal.PlainDate.from(t2)), [ - { type: 'day', value: '18', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'day', value: '20', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'month', value: '02', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' } - ]); - }); - it('should work for YearMonth', () => { - const date1 = Temporal.PlainDate.from(t1); - const date2 = Temporal.PlainDate.from(t2); - deepEqual( - us.formatRangeToParts( - date1.withCalendar(usCalendar).toPlainYearMonth(), - date2.withCalendar(usCalendar).toPlainYearMonth() - ), - [ - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '2', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' } - ] - ); - deepEqual( - at.formatRangeToParts( - date1.withCalendar(atCalendar).toPlainYearMonth(), - date2.withCalendar(atCalendar).toPlainYearMonth() - ), - [ - { type: 'month', value: '11', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'year', value: '1976', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '02', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'year', value: '2020', source: 'endRange' } - ] - ); - }); - it('should work for MonthDay', () => { - const date1 = Temporal.PlainDate.from(t1); - const date2 = Temporal.PlainDate.from(t2); - deepEqual( - us.formatRangeToParts( - date2.withCalendar(usCalendar).toPlainMonthDay(), - date1.withCalendar(usCalendar).toPlainMonthDay() - ), - [ - { type: 'month', value: '2', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'day', value: '20', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '11', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'day', value: '18', source: 'endRange' } - ] - ); - deepEqual( - at.formatRangeToParts( - date2.withCalendar(atCalendar).toPlainMonthDay(), - date1.withCalendar(atCalendar).toPlainMonthDay() - ), - [ - { type: 'day', value: '20', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'month', value: '02', source: 'startRange' }, - { type: 'literal', value: '. – ', source: 'shared' }, - { type: 'day', value: '18', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'month', value: '11', source: 'endRange' }, - { type: 'literal', value: '.', source: 'shared' } - ] - ); - }); - it('should not break legacy Date', () => { - deepEqual(us.formatRangeToParts(start, end), [ - { type: 'month', value: '12', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'day', value: '29', source: 'startRange' }, - { type: 'literal', value: '/', source: 'startRange' }, - { type: 'year', value: '1922', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'month', value: '12', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'day', value: '25', source: 'endRange' }, - { type: 'literal', value: '/', source: 'endRange' }, - { type: 'year', value: '1991', source: 'endRange' } - ]); - deepEqual(at.formatRangeToParts(start, end), [ - { type: 'day', value: '30', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'month', value: '12', source: 'startRange' }, - { type: 'literal', value: '.', source: 'startRange' }, - { type: 'year', value: '1922', source: 'startRange' }, - { type: 'literal', value: ' – ', source: 'shared' }, - { type: 'day', value: '26', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'month', value: '12', source: 'endRange' }, - { type: 'literal', value: '.', source: 'endRange' }, - { type: 'year', value: '1991', source: 'endRange' } - ]); - }); - it('should throw a TypeError when called with dissimilar types', () => - throws(() => at.formatRangeToParts(Temporal.Instant.from(t1), Temporal.PlainDateTime.from(t2)), TypeError)); - it('should throw a RangeError when called with different calendars', () => { - throws( - () => - at.formatRangeToParts( - Temporal.PlainDateTime.from(t1), - Temporal.PlainDateTime.from(t2).withCalendar('japanese') - ), - RangeError - ); - throws( - () => - at.formatRangeToParts(Temporal.PlainDate.from(t1), Temporal.PlainDate.from(t2).withCalendar('japanese')), - RangeError - ); - }); - it('throws for two ZonedDateTimes with different time zones', () => { - throws( - () => us2.formatRangeToParts(Temporal.ZonedDateTime.from(t1), Temporal.ZonedDateTime.from(t2)), - RangeError - ); - }); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/largeInt.js b/packages/temporal-polyfill/tests/largeInt.js deleted file mode 100644 index 16821f55..00000000 --- a/packages/temporal-polyfill/tests/largeInt.js +++ /dev/null @@ -1,88 +0,0 @@ -import { createLargeInt } from '../src/utils/largeInt' - -describe('LargeInt', () => { - describe('adding', () => { - it('positive by positive', () => { - expect(createLargeInt(12392922812381123123n).add(9228123).toBigInt()) - .toBe(12392922812381123123n + 9228123n) - }) - it('positive by negative', () => { - expect(createLargeInt(12392922812381123123n).add(-9228123).toBigInt()) - .toBe(12392922812381123123n - 9228123n) - }) - it('negative by positive', () => { - expect(createLargeInt(-12392922812381123123n).add(9228123).toBigInt()) - .toBe(-12392922812381123123n + 9228123n) - }) - it('negative by negative', () => { - expect(createLargeInt(-12392922812381123123n).add(-9228123).toBigInt()) - .toBe(-12392922812381123123n - 9228123n) - }) - }) - describe('subtracting', () => { - it('positive by positive', () => { - expect(createLargeInt(12392922812381123123n).sub(9228123).toBigInt()) - .toBe(12392922812381123123n - 9228123n) - }) - it('positive by positive wrap', () => { - expect( - createLargeInt(12392922812381123123n) - .sub(createLargeInt(56843732763n)).toBigInt() - ).toBe(12392922812381123123n - 56843732763n) - }) - it('positive by negative wrap', () => { - expect( - createLargeInt(12392922812381123123n) - .sub(createLargeInt(-56843732763n)).toBigInt() - ).toBe(12392922812381123123n + 56843732763n) - }) - it('negative by positive wrap', () => { - expect( - createLargeInt(-12392922812381123123n) - .sub(createLargeInt(56843732763n)).toBigInt() - ).toBe(-12392922812381123123n - 56843732763n) - }) - it('negative by negative wrap', () => { - expect( - createLargeInt(-12392922812381123123n) - .sub(createLargeInt(-56843732763n)).toBigInt() - ).toBe(-12392922812381123123n + 56843732763n) - }) - }) - describe('multiplying', () => { - it('positive by positive', () => { - expect(createLargeInt(812381123123n).mult(92223).toBigInt()) - .toBe(812381123123n * 92223n) - }) - it('positive by negative', () => { - expect(createLargeInt(812381123123n).mult(-92223).toBigInt()) - .toBe(812381123123n * -92223n) - }) - it('negative by positive', () => { - expect(createLargeInt(-812381123123n).mult(92223).toBigInt()) - .toBe(-812381123123n * 92223n) - }) - it('negative by negative', () => { - expect(createLargeInt(-812381123123n).mult(-92223).toBigInt()) - .toBe(-812381123123n * -92223n) - }) - }) - describe('dividing', () => { - it('positive by positive', () => { - expect(createLargeInt(812381123123n).div(92223).toBigInt()) - .toBe(812381123123n / 92223n) - }) - it('positive by negative', () => { - expect(createLargeInt(812381123123n).div(-92223).toBigInt()) - .toBe(812381123123n / -92223n) - }) - it('negative by positive', () => { - expect(createLargeInt(-812381123123n).div(92223).toBigInt()) - .toBe(-812381123123n / 92223n) - }) - it('negative by negative', () => { - expect(createLargeInt(-812381123123n).div(-92223).toBigInt()) - .toBe(-812381123123n / -92223n) - }) - }) -}) diff --git a/packages/temporal-polyfill/tests/now.js b/packages/temporal-polyfill/tests/now.js deleted file mode 100644 index 65e75b97..00000000 --- a/packages/temporal-polyfill/tests/now.js +++ /dev/null @@ -1,104 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; - -describe('Temporal.Now', () => { - describe('Structure', () => { - it('Temporal.Now is an object', () => equal(typeof Temporal.Now, 'object')); - it('Temporal.Now has 9 properties', () => equal(Object.keys(Temporal.Now).length, 9)); - it('Temporal.Now.instant is a function', () => equal(typeof Temporal.Now.instant, 'function')); - it('Temporal.Now.plainDateTime is a function', () => equal(typeof Temporal.Now.plainDateTime, 'function')); - it('Temporal.Now.plainDateTimeISO is a function', () => equal(typeof Temporal.Now.plainDateTimeISO, 'function')); - it('Temporal.Now.plainDate is a function', () => equal(typeof Temporal.Now.plainDate, 'function')); - it('Temporal.Now.plainDateISO is a function', () => equal(typeof Temporal.Now.plainDateISO, 'function')); - it('Temporal.Now.plainTimeISO is a function', () => equal(typeof Temporal.Now.plainTimeISO, 'function')); - it('Temporal.Now.timeZone is a function', () => equal(typeof Temporal.Now.timeZone, 'function')); - it('Temporal.Now.zonedDateTimeISO is a function', () => equal(typeof Temporal.Now.zonedDateTimeISO, 'function')); - it('Temporal.Now.zonedDateTime is a function', () => equal(typeof Temporal.Now.zonedDateTime, 'function')); - it('Temporal.Now has a toStringTag', () => equal(Temporal.Now.toString(), '[object Temporal.Now]')); - }); - describe('Temporal.Now.instant()', () => { - it('Temporal.Now.instant() returns an Instant', () => assert(Temporal.Now.instant() instanceof Temporal.Instant)); - }); - describe('Temporal.Now.plainDateTimeISO()', () => { - it('returns a DateTime in the ISO calendar', () => { - const dt = Temporal.Now.plainDateTimeISO(); - assert(dt instanceof Temporal.PlainDateTime); - equal(dt.calendar.id, 'iso8601'); - }); - }); - describe('Temporal.Now.plainDateTime()', () => { - it('returns a DateTime in the correct calendar', () => { - const dt = Temporal.Now.plainDateTime('gregory'); - assert(dt instanceof Temporal.PlainDateTime); - equal(dt.calendar.id, 'gregory'); - }); - it('requires a calendar', () => throws(() => Temporal.Now.plainDateTime(), RangeError)); - }); - describe('Temporal.Now.zonedDateTimeISO()', () => { - it('returns a ZonedDateTime in the correct calendar and system time zone', () => { - const zdt = Temporal.Now.zonedDateTimeISO(); - const tz = Temporal.Now.timeZone(); - assert(zdt instanceof Temporal.ZonedDateTime); - assert(zdt.calendar instanceof Temporal.Calendar); - equal(zdt.calendar.id, 'iso8601'); - assert(zdt.timeZone instanceof Temporal.TimeZone); - equal(zdt.timeZone.id, tz.id); - }); - it('returns a ZonedDateTime in the correct calendar and specific time zone', () => { - const zdt = Temporal.Now.zonedDateTimeISO('America/Los_Angeles'); - assert(zdt instanceof Temporal.ZonedDateTime); - assert(zdt.calendar instanceof Temporal.Calendar); - equal(zdt.calendar.id, 'iso8601'); - assert(zdt.timeZone instanceof Temporal.TimeZone); - equal(zdt.timeZone.id, 'America/Los_Angeles'); - }); - }); - describe('Temporal.Now.zonedDateTime()', () => { - it('returns a ZonedDateTime in the correct calendar and system time zone', () => { - const zdt = Temporal.Now.zonedDateTime('gregory'); - const tz = Temporal.Now.timeZone(); - assert(zdt instanceof Temporal.ZonedDateTime); - assert(zdt.calendar instanceof Temporal.Calendar); - equal(zdt.calendar.id, 'gregory'); - assert(zdt.timeZone instanceof Temporal.TimeZone); - equal(zdt.timeZone.id, tz.id); - }); - it('returns a ZonedDateTime in the correct calendar and specific time zone', () => { - const zdt = Temporal.Now.zonedDateTime('gregory', 'America/Los_Angeles'); - assert(zdt instanceof Temporal.ZonedDateTime); - assert(zdt.calendar instanceof Temporal.Calendar); - equal(zdt.calendar.id, 'gregory'); - assert(zdt.timeZone instanceof Temporal.TimeZone); - equal(zdt.timeZone.id, 'America/Los_Angeles'); - }); - it('requires a calendar', () => throws(() => Temporal.Now.zonedDateTime(), RangeError)); - }); - describe('Temporal.Now.plainDateISO()', () => { - it('returns a Date in the ISO calendar', () => { - const d = Temporal.Now.plainDateISO(); - assert(d instanceof Temporal.PlainDate); - equal(d.calendar.id, 'iso8601'); - }); - }); - describe('Temporal.Now.plainDate()', () => { - it('returns a Date in the correct calendar', () => { - const d = Temporal.Now.plainDate('gregory'); - assert(d instanceof Temporal.PlainDate); - equal(d.calendar.id, 'gregory'); - }); - it('requires a calendar', () => throws(() => Temporal.Now.plainDate(), RangeError)); - }); - describe('Temporal.Now.plainTimeISO()', () => { - it('Temporal.Now.plainTimeISO() returns a Time', () => { - const t = Temporal.Now.plainTimeISO(); - assert(t instanceof Temporal.PlainTime); - equal(t.calendar.id, 'iso8601'); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/plainDate.js b/packages/temporal-polyfill/tests/plainDate.js deleted file mode 100644 index 768218bc..00000000 --- a/packages/temporal-polyfill/tests/plainDate.js +++ /dev/null @@ -1,1138 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, notStrictEqual: notEqual, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { PlainDate } = Temporal; - -describe('Date', () => { - describe('Structure', () => { - it('Date is a Function', () => { - equal(typeof PlainDate, 'function'); - }); - it('Date has a prototype', () => { - assert(PlainDate.prototype); - equal(typeof PlainDate.prototype, 'object'); - }); - describe('Date.prototype', () => { - it('Date.prototype has year', () => { - assert('year' in PlainDate.prototype); - }); - it('Date.prototype has month', () => { - assert('month' in PlainDate.prototype); - }); - it('Date.prototype has monthCode', () => { - assert('monthCode' in PlainDate.prototype); - }); - it('Date.prototype has day', () => { - assert('day' in PlainDate.prototype); - }); - it('Date.prototype has dayOfWeek', () => { - assert('dayOfWeek' in PlainDate.prototype); - }); - it('Date.prototype has dayOfYear', () => { - assert('dayOfYear' in PlainDate.prototype); - }); - it('Date.prototype has weekOfYear', () => { - assert('weekOfYear' in PlainDate.prototype); - }); - it('Date.prototype has daysInWeek', () => { - assert('daysInWeek' in PlainDate.prototype); - }); - it('Date.prototype has monthsInYear', () => { - assert('monthsInYear' in PlainDate.prototype); - }); - it('Date.prototype.with is a Function', () => { - equal(typeof PlainDate.prototype.with, 'function'); - }); - it('Date.prototype.add is a Function', () => { - equal(typeof PlainDate.prototype.add, 'function'); - }); - it('Date.prototype.subtract is a Function', () => { - equal(typeof PlainDate.prototype.subtract, 'function'); - }); - it('Date.prototype.until is a Function', () => { - equal(typeof PlainDate.prototype.until, 'function'); - }); - it('Date.prototype.since is a Function', () => { - equal(typeof PlainDate.prototype.since, 'function'); - }); - it('Date.prototype.equals is a Function', () => { - equal(typeof PlainDate.prototype.equals, 'function'); - }); - it('Date.prototype.toPlainDateTime is a Function', () => { - equal(typeof PlainDate.prototype.toPlainDateTime, 'function'); - }); - it('Date.prototype.toZonedDateTime is a Function', () => { - equal(typeof PlainDate.prototype.toZonedDateTime, 'function'); - }); - it('Date.prototype.toPlainYearMonth is a Function', () => { - equal(typeof PlainDate.prototype.toPlainYearMonth, 'function'); - }); - it('Date.prototype.toPlainMonthDay is a Function', () => { - equal(typeof PlainDate.prototype.toPlainMonthDay, 'function'); - }); - it('Date.prototype.getISOFields is a Function', () => { - equal(typeof PlainDate.prototype.getISOFields, 'function'); - }); - it('Date.prototype.toString is a Function', () => { - equal(typeof PlainDate.prototype.toString, 'function'); - }); - it('Date.prototype.toJSON is a Function', () => { - equal(typeof PlainDate.prototype.toJSON, 'function'); - }); - }); - it('Date.from is a Function', () => { - equal(typeof PlainDate.from, 'function'); - }); - it('Date.compare is a Function', () => { - equal(typeof PlainDate.compare, 'function'); - }); - }); - describe('Construction', () => { - let date; - const calendar = Temporal.Calendar.from('iso8601'); - it('date can be constructed', () => { - date = new PlainDate(1976, 11, 18, calendar); - assert(date); - equal(typeof date, 'object'); - }); - it('date.year is 1976', () => equal(date.year, 1976)); - it('date.month is 11', () => equal(date.month, 11)); - it('date.monthCode is "M11"', () => equal(date.monthCode, 'M11')); - it('date.day is 18', () => equal(date.day, 18)); - it('date.calendar is the object', () => equal(date.calendar, calendar)); - it('date.dayOfWeek is 4', () => equal(date.dayOfWeek, 4)); - it('date.dayOfYear is 323', () => equal(date.dayOfYear, 323)); - it('date.weekOfYear is 47', () => equal(date.weekOfYear, 47)); - it('date.daysInWeek is 7', () => equal(date.daysInWeek, 7)); - it('date.monthsInYear is 12', () => equal(date.monthsInYear, 12)); - it('`${date}` is 1976-11-18', () => equal(`${date}`, '1976-11-18')); - }); - describe('date fields', () => { - const date = new PlainDate(2019, 10, 6); - const datetime = { year: 2019, month: 10, monthCode: 'M10', day: 1, hour: 14, minute: 20, second: 36 }; - const fromed = new PlainDate(2019, 10, 1); - it(`(${date}).dayOfWeek === 7`, () => equal(date.dayOfWeek, 7)); - it(`Temporal.PlainDate.from(${date}) is not the same object)`, () => notEqual(PlainDate.from(date), date)); - it(`Temporal.PlainDate.from(${JSON.stringify(datetime)}) instanceof Temporal.date`, () => - assert(PlainDate.from(datetime) instanceof PlainDate)); - it(`Temporal.PlainDate.from(${JSON.stringify(datetime)}) === (${fromed})`, () => - assert(PlainDate.from(datetime).equals(fromed))); - }); - describe('.with manipulation', () => { - const original = new PlainDate(1976, 11, 18); - it('date.with({ year: 2019 } works', () => { - const date = original.with({ year: 2019 }); - equal(`${date}`, '2019-11-18'); - }); - it('date.with({ month: 5 } works', () => { - const date = original.with({ month: 5 }); - equal(`${date}`, '1976-05-18'); - }); - it('date.with({ monthCode: "M05" }) works', () => { - equal(`${original.with({ monthCode: 'M05' })}`, '1976-05-18'); - }); - it('month and monthCode must agree', () => { - throws(() => original.with({ month: 5, monthCode: 'M06' }), RangeError); - }); - it('date.with({ day: 17 } works', () => { - const date = original.with({ day: 17 }); - equal(`${date}`, '1976-11-17'); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => original.with({ day: 17 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => original.with({ day: 17 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${original.with({ day: 17 }, options)}`, '1976-11-17')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => original.with({}), TypeError); - throws(() => original.with({ months: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${original.with({ months: 12, day: 15 })}`, '1976-11-15'); - }); - it('date.with(string) throws', () => { - throws(() => original.with('2019-05-17'), TypeError); - throws(() => original.with('2019-05-17T12:34'), TypeError); - throws(() => original.with('2019-05-17T12:34Z'), TypeError); - throws(() => original.with('18:05:42.577'), TypeError); - throws(() => original.with('42'), TypeError); - }); - it('throws with calendar property', () => { - throws(() => original.with({ year: 2021, calendar: 'iso8601' }), TypeError); - }); - it('throws with timeZone property', () => { - throws(() => original.with({ year: 2021, timeZone: 'UTC' }), TypeError); - }); - }); - describe('Date.toPlainDateTime() works', () => { - const date = PlainDate.from('1976-11-18'); - const dt = date.toPlainDateTime(Temporal.PlainTime.from('11:30:23')); - it('returns a Temporal.PlainDateTime', () => assert(dt instanceof Temporal.PlainDateTime)); - it('combines the date and time', () => equal(`${dt}`, '1976-11-18T11:30:23')); - it('casts argument', () => { - equal(`${date.toPlainDateTime({ hour: 11, minute: 30, second: 23 })}`, '1976-11-18T11:30:23'); - equal(`${date.toPlainDateTime('11:30:23')}`, '1976-11-18T11:30:23'); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => date.toPlainDateTime({}), TypeError); - throws(() => date.toPlainDateTime({ minutes: 30 }), TypeError); - }); - it('optional argument defaults to midnight', () => { - equal(`${date.toPlainDateTime()}`, '1976-11-18T00:00:00'); - }); - }); - describe('Date.toZonedDateTime()', function () { - it('works', () => { - const date = PlainDate.from('2020-01-01'); - const time = Temporal.PlainTime.from('12:00'); - const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = date.toZonedDateTime({ timeZone: tz, plainTime: time }); - equal(`${zdt}`, '2020-01-01T12:00:00-08:00[America/Los_Angeles]'); - }); - it('works with time omitted (timeZone argument)', () => { - const date = PlainDate.from('2020-01-01'); - const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = date.toZonedDateTime(tz); - equal(`${zdt}`, '2020-01-01T00:00:00-08:00[America/Los_Angeles]'); - }); - it('works with time omitted (timeZone property)', () => { - const date = PlainDate.from('2020-01-01'); - const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = date.toZonedDateTime({ timeZone: tz }); - equal(`${zdt}`, '2020-01-01T00:00:00-08:00[America/Los_Angeles]'); - }); - it('casts timeZone property', () => { - const date = PlainDate.from('2020-07-08'); - const time = Temporal.PlainTime.from('12:00'); - const zdt = date.toZonedDateTime({ timeZone: 'America/Los_Angeles', plainTime: time }); - equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); - }); - it('casts time property', () => { - const date = PlainDate.from('2020-07-08'); - const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = date.toZonedDateTime({ timeZone: tz, plainTime: '12:00' }); - equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); - }); - }); - describe('date.until() works', () => { - const date = new PlainDate(1969, 7, 24); - it('date.until({ year: 1969, month: 7, day: 24 })', () => { - const duration = date.until(PlainDate.from({ year: 1969, month: 10, day: 5 })); - - equal(duration.years, 0); - equal(duration.months, 0); - equal(duration.weeks, 0); - equal(duration.days, 73); - equal(duration.hours, 0); - equal(duration.minutes, 0); - equal(duration.seconds, 0); - equal(duration.milliseconds, 0); - equal(duration.microseconds, 0); - equal(duration.nanoseconds, 0); - }); - it('date.until(later) === later.since(date)', () => { - const later = PlainDate.from({ year: 1996, month: 3, day: 3 }); - equal(`${date.until(later)}`, `${later.since(date)}`); - }); - it('date.until({ year: 2019, month: 7, day: 24 }, { largestUnit: "years" })', () => { - const later = PlainDate.from({ year: 2019, month: 7, day: 24 }); - const duration = date.until(later, { largestUnit: 'years' }); - equal(duration.years, 50); - equal(duration.months, 0); - equal(duration.weeks, 0); - equal(duration.days, 0); - equal(duration.hours, 0); - equal(duration.minutes, 0); - equal(duration.seconds, 0); - equal(duration.milliseconds, 0); - equal(duration.microseconds, 0); - equal(duration.nanoseconds, 0); - }); - it('casts argument', () => { - equal(`${date.until({ year: 2019, month: 7, day: 24 })}`, 'P18262D'); - equal(`${date.until('2019-07-24')}`, 'P18262D'); - }); - it('takes days per month into account', () => { - const date1 = PlainDate.from('2019-01-01'); - const date2 = PlainDate.from('2019-02-01'); - const date3 = PlainDate.from('2019-03-01'); - equal(`${date1.until(date2)}`, 'P31D'); - equal(`${date2.until(date3)}`, 'P28D'); - - const date4 = PlainDate.from('2020-02-01'); - const date5 = PlainDate.from('2020-03-01'); - equal(`${date4.until(date5)}`, 'P29D'); - }); - it('takes days per year into account', () => { - const date1 = PlainDate.from('2019-01-01'); - const date2 = PlainDate.from('2019-06-01'); - const date3 = PlainDate.from('2020-01-01'); - const date4 = PlainDate.from('2020-06-01'); - const date5 = PlainDate.from('2021-01-01'); - const date6 = PlainDate.from('2021-06-01'); - equal(`${date1.until(date3)}`, 'P365D'); - equal(`${date3.until(date5)}`, 'P366D'); - equal(`${date2.until(date4)}`, 'P366D'); - equal(`${date4.until(date6)}`, 'P365D'); - }); - const feb20 = PlainDate.from('2020-02-01'); - const feb21 = PlainDate.from('2021-02-01'); - it('defaults to returning days', () => { - equal(`${feb20.until(feb21)}`, 'P366D'); - equal(`${feb20.until(feb21, { largestUnit: 'auto' })}`, 'P366D'); - equal(`${feb20.until(feb21, { largestUnit: 'days' })}`, 'P366D'); - }); - it('can return higher units', () => { - equal(`${feb20.until(feb21, { largestUnit: 'years' })}`, 'P1Y'); - equal(`${feb20.until(feb21, { largestUnit: 'months' })}`, 'P12M'); - equal(`${feb20.until(feb21, { largestUnit: 'weeks' })}`, 'P52W2D'); - }); - it('cannot return lower units', () => { - ['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds'].forEach((largestUnit) => - throws(() => feb20.until(feb21, { largestUnit }), RangeError) - ); - }); - it('does not include higher units than necessary', () => { - const lastFeb20 = PlainDate.from('2020-02-29'); - const lastFeb21 = PlainDate.from('2021-02-28'); - equal(`${lastFeb20.until(lastFeb21)}`, 'P365D'); - equal(`${lastFeb20.until(lastFeb21, { largestUnit: 'months' })}`, 'P12M'); - equal(`${lastFeb20.until(lastFeb21, { largestUnit: 'years' })}`, 'P1Y'); - }); - it('weeks and months are mutually exclusive', () => { - const laterDate = date.add({ days: 42 }); - const weeksDifference = date.until(laterDate, { largestUnit: 'weeks' }); - notEqual(weeksDifference.weeks, 0); - equal(weeksDifference.months, 0); - const monthsDifference = date.until(laterDate, { largestUnit: 'months' }); - equal(monthsDifference.weeks, 0); - notEqual(monthsDifference.months, 0); - }); - it('no two different calendars', () => { - const date1 = new PlainDate(2000, 1, 1); - const date2 = new PlainDate(2000, 1, 1, Temporal.Calendar.from('japanese')); - throws(() => date1.until(date2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb20.until(feb21, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb20.until(feb21, options)}`, 'P366D')); - }); - const earlier = PlainDate.from('2019-01-08'); - const later = PlainDate.from('2021-09-07'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => earlier.until(later, { smallestUnit }), RangeError); - } - ); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = ['years', 'months', 'weeks', 'days']; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => earlier.until(later, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than days', () => { - equal(`${earlier.until(later, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P3Y'); - equal(`${earlier.until(later, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P32M'); - equal(`${earlier.until(later, { smallestUnit: 'weeks', roundingMode: 'halfExpand' })}`, 'P139W'); - }); - it('throws on invalid roundingMode', () => { - throws(() => earlier.until(later, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P32M'], - ['weeks', 'P139W'], - ['days', 'P973D'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P32M', '-P31M'], - ['weeks', 'P139W', '-P139W'], - ['days', 'P973D', '-P973D'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P31M', '-P32M'], - ['weeks', 'P139W', '-P139W'], - ['days', 'P973D', '-P973D'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P31M'], - ['weeks', 'P139W'], - ['days', 'P973D'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${earlier.until(later, { smallestUnit: 'years' })}`, 'P2Y'); - equal(`${later.until(earlier, { smallestUnit: 'years' })}`, '-P2Y'); - }); - it('rounds to an increment of years', () => { - equal( - `${earlier.until(later, { smallestUnit: 'years', roundingIncrement: 4, roundingMode: 'halfExpand' })}`, - 'P4Y' - ); - }); - it('rounds to an increment of months', () => { - equal( - `${earlier.until(later, { smallestUnit: 'months', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P30M' - ); - }); - it('rounds to an increment of weeks', () => { - equal( - `${earlier.until(later, { smallestUnit: 'weeks', roundingIncrement: 12, roundingMode: 'halfExpand' })}`, - 'P144W' - ); - }); - it('rounds to an increment of days', () => { - equal( - `${earlier.until(later, { smallestUnit: 'days', roundingIncrement: 100, roundingMode: 'halfExpand' })}`, - 'P1000D' - ); - }); - it('accepts singular units', () => { - equal(`${earlier.until(later, { largestUnit: 'year' })}`, `${earlier.until(later, { largestUnit: 'years' })}`); - equal(`${earlier.until(later, { smallestUnit: 'year' })}`, `${earlier.until(later, { smallestUnit: 'years' })}`); - equal(`${earlier.until(later, { largestUnit: 'month' })}`, `${earlier.until(later, { largestUnit: 'months' })}`); - equal( - `${earlier.until(later, { smallestUnit: 'month' })}`, - `${earlier.until(later, { smallestUnit: 'months' })}` - ); - equal(`${earlier.until(later, { largestUnit: 'day' })}`, `${earlier.until(later, { largestUnit: 'days' })}`); - equal(`${earlier.until(later, { smallestUnit: 'day' })}`, `${earlier.until(later, { smallestUnit: 'days' })}`); - }); - it('rounds relative to the receiver', () => { - const date1 = Temporal.PlainDate.from('2019-01-01'); - const date2 = Temporal.PlainDate.from('2019-02-15'); - equal(`${date1.until(date2, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P2M'); - equal(`${date2.until(date1, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, '-P1M'); - }); - }); - describe('order of operations in until - TODO: add since', () => { - const cases = [ - ['2019-03-01', '2019-01-29', 'P1M1D'], - ['2019-01-29', '2019-03-01', '-P1M3D'], - ['2019-03-29', '2019-01-30', 'P1M29D'], - ['2019-01-30', '2019-03-29', '-P1M29D'], - ['2019-03-30', '2019-01-31', 'P1M30D'], - ['2019-01-31', '2019-03-30', '-P1M28D'], - ['2019-03-31', '2019-01-31', 'P2M'], - ['2019-01-31', '2019-03-31', '-P2M'] - ]; - for (const [end, start, expected] of cases) { - it(`${start} until ${end} => ${expected}`, () => { - const result = PlainDate.from(start).until(end, { largestUnit: 'months' }); - equal(result.toString(), expected); - }); - } - }); - describe('date.since() works', () => { - const date = new PlainDate(1976, 11, 18); - it('date.since({ year: 1976, month: 10, day: 5 })', () => { - const duration = date.since(PlainDate.from({ year: 1976, month: 10, day: 5 })); - - equal(duration.years, 0); - equal(duration.months, 0); - equal(duration.weeks, 0); - equal(duration.days, 44); - equal(duration.hours, 0); - equal(duration.minutes, 0); - equal(duration.seconds, 0); - equal(duration.milliseconds, 0); - equal(duration.microseconds, 0); - equal(duration.nanoseconds, 0); - }); - it('date.since(earlier) === earlier.until(date)', () => { - const earlier = PlainDate.from({ year: 1966, month: 3, day: 3 }); - equal(`${date.since(earlier)}`, `${earlier.until(date)}`); - }); - it('date.since({ year: 2019, month: 11, day: 18 }, { largestUnit: "years" })', () => { - const later = PlainDate.from({ year: 2019, month: 11, day: 18 }); - const duration = later.since(date, { largestUnit: 'years' }); - equal(duration.years, 43); - equal(duration.months, 0); - equal(duration.weeks, 0); - equal(duration.days, 0); - equal(duration.hours, 0); - equal(duration.minutes, 0); - equal(duration.seconds, 0); - equal(duration.milliseconds, 0); - equal(duration.microseconds, 0); - equal(duration.nanoseconds, 0); - }); - it('casts argument', () => { - equal(`${date.since({ year: 2019, month: 11, day: 5 })}`, '-P15692D'); - equal(`${date.since('2019-11-05')}`, '-P15692D'); - }); - it('takes days per month into account', () => { - const date1 = PlainDate.from('2019-01-01'); - const date2 = PlainDate.from('2019-02-01'); - const date3 = PlainDate.from('2019-03-01'); - equal(`${date2.since(date1)}`, 'P31D'); - equal(`${date3.since(date2)}`, 'P28D'); - - const date4 = PlainDate.from('2020-02-01'); - const date5 = PlainDate.from('2020-03-01'); - equal(`${date5.since(date4)}`, 'P29D'); - }); - it('takes days per year into account', () => { - const date1 = PlainDate.from('2019-01-01'); - const date2 = PlainDate.from('2019-06-01'); - const date3 = PlainDate.from('2020-01-01'); - const date4 = PlainDate.from('2020-06-01'); - const date5 = PlainDate.from('2021-01-01'); - const date6 = PlainDate.from('2021-06-01'); - equal(`${date3.since(date1)}`, 'P365D'); - equal(`${date5.since(date3)}`, 'P366D'); - equal(`${date4.since(date2)}`, 'P366D'); - equal(`${date6.since(date4)}`, 'P365D'); - }); - const feb20 = PlainDate.from('2020-02-01'); - const feb21 = PlainDate.from('2021-02-01'); - it('defaults to returning days', () => { - equal(`${feb21.since(feb20)}`, 'P366D'); - equal(`${feb21.since(feb20, { largestUnit: 'auto' })}`, 'P366D'); - equal(`${feb21.since(feb20, { largestUnit: 'days' })}`, 'P366D'); - }); - it('can return higher units', () => { - equal(`${feb21.since(feb20, { largestUnit: 'years' })}`, 'P1Y'); - equal(`${feb21.since(feb20, { largestUnit: 'months' })}`, 'P12M'); - equal(`${feb21.since(feb20, { largestUnit: 'weeks' })}`, 'P52W2D'); - }); - it('cannot return lower units', () => { - throws(() => feb21.since(feb20, { largestUnit: 'hours' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'minutes' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'seconds' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'milliseconds' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'microseconds' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'nanoseconds' }), RangeError); - }); - it('does not include higher units than necessary', () => { - const lastFeb20 = PlainDate.from('2020-02-29'); - const lastFeb21 = PlainDate.from('2021-02-28'); - equal(`${lastFeb21.since(lastFeb20)}`, 'P365D'); - equal(`${lastFeb21.since(lastFeb20, { largestUnit: 'months' })}`, 'P11M28D'); - equal(`${lastFeb21.since(lastFeb20, { largestUnit: 'years' })}`, 'P11M28D'); - }); - it('weeks and months are mutually exclusive', () => { - const laterDate = date.add({ days: 42 }); - const weeksDifference = laterDate.since(date, { largestUnit: 'weeks' }); - notEqual(weeksDifference.weeks, 0); - equal(weeksDifference.months, 0); - const monthsDifference = laterDate.since(date, { largestUnit: 'months' }); - equal(monthsDifference.weeks, 0); - notEqual(monthsDifference.months, 0); - }); - it('no two different calendars', () => { - const date1 = new PlainDate(2000, 1, 1); - const date2 = new PlainDate(2000, 1, 1, Temporal.Calendar.from('japanese')); - throws(() => date1.since(date2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb21.since(feb20, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb21.since(feb20, options)}`, 'P366D')); - }); - const earlier = PlainDate.from('2019-01-08'); - const later = PlainDate.from('2021-09-07'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => later.since(earlier, { smallestUnit }), RangeError); - } - ); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = ['years', 'months', 'weeks', 'days']; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => later.since(earlier, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than days', () => { - equal(`${later.since(earlier, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P3Y'); - equal(`${later.since(earlier, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P32M'); - equal(`${later.since(earlier, { smallestUnit: 'weeks', roundingMode: 'halfExpand' })}`, 'P139W'); - }); - it('throws on invalid roundingMode', () => { - throws(() => later.since(earlier, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P32M'], - ['weeks', 'P139W'], - ['days', 'P973D'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P32M', '-P31M'], - ['weeks', 'P139W', '-P139W'], - ['days', 'P973D', '-P973D'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P31M', '-P32M'], - ['weeks', 'P139W', '-P139W'], - ['days', 'P973D', '-P973D'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P31M'], - ['weeks', 'P139W'], - ['days', 'P973D'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${later.since(earlier, { smallestUnit: 'years' })}`, 'P2Y'); - equal(`${earlier.since(later, { smallestUnit: 'years' })}`, '-P2Y'); - }); - it('rounds to an increment of years', () => { - equal( - `${later.since(earlier, { smallestUnit: 'years', roundingIncrement: 4, roundingMode: 'halfExpand' })}`, - 'P4Y' - ); - }); - it('rounds to an increment of months', () => { - equal( - `${later.since(earlier, { smallestUnit: 'months', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P30M' - ); - }); - it('rounds to an increment of weeks', () => { - equal( - `${later.since(earlier, { smallestUnit: 'weeks', roundingIncrement: 12, roundingMode: 'halfExpand' })}`, - 'P144W' - ); - }); - it('rounds to an increment of days', () => { - equal( - `${later.since(earlier, { smallestUnit: 'days', roundingIncrement: 100, roundingMode: 'halfExpand' })}`, - 'P1000D' - ); - }); - it('accepts singular units', () => { - equal(`${later.since(earlier, { largestUnit: 'year' })}`, `${later.since(earlier, { largestUnit: 'years' })}`); - equal(`${later.since(earlier, { smallestUnit: 'year' })}`, `${later.since(earlier, { smallestUnit: 'years' })}`); - equal(`${later.since(earlier, { largestUnit: 'month' })}`, `${later.since(earlier, { largestUnit: 'months' })}`); - equal( - `${later.since(earlier, { smallestUnit: 'month' })}`, - `${later.since(earlier, { smallestUnit: 'months' })}` - ); - equal(`${later.since(earlier, { largestUnit: 'day' })}`, `${later.since(earlier, { largestUnit: 'days' })}`); - equal(`${later.since(earlier, { smallestUnit: 'day' })}`, `${later.since(earlier, { smallestUnit: 'days' })}`); - }); - it('rounds relative to the receiver', () => { - const date1 = PlainDate.from('2019-01-01'); - const date2 = PlainDate.from('2019-02-15'); - equal(`${date2.since(date1, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P1M'); - equal(`${date1.since(date2, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, '-P2M'); - }); - }); - describe('date.add() works', () => { - let date = new PlainDate(1976, 11, 18); - it('date.add({ years: 43 })', () => { - equal(`${date.add({ years: 43 })}`, '2019-11-18'); - }); - it('date.add({ months: 3 })', () => { - equal(`${date.add({ months: 3 })}`, '1977-02-18'); - }); - it('date.add({ days: 20 })', () => { - equal(`${date.add({ days: 20 })}`, '1976-12-08'); - }); - it('new Date(2019, 1, 31).add({ months: 1 })', () => { - equal(`${new PlainDate(2019, 1, 31).add({ months: 1 })}`, '2019-02-28'); - }); - it('date.add(durationObj)', () => { - equal(`${date.add(Temporal.Duration.from('P43Y'))}`, '2019-11-18'); - }); - it('casts argument', () => { - equal(`${date.add('P43Y')}`, '2019-11-18'); - }); - it('constrain when overflowing result', () => { - const jan31 = PlainDate.from('2020-01-31'); - equal(`${jan31.add({ months: 1 })}`, '2020-02-29'); - equal(`${jan31.add({ months: 1 }, { overflow: 'constrain' })}`, '2020-02-29'); - }); - it('throw when overflowing result with reject', () => { - const jan31 = PlainDate.from('2020-01-31'); - throws(() => jan31.add({ months: 1 }, { overflow: 'reject' }), RangeError); - }); - it('symmetrical with regard to negative durations', () => { - equal(`${PlainDate.from('2019-11-18').add({ years: -43 })}`, '1976-11-18'); - equal(`${PlainDate.from('1977-02-18').add({ months: -3 })}`, '1976-11-18'); - equal(`${PlainDate.from('1976-12-08').add({ days: -20 })}`, '1976-11-18'); - equal(`${PlainDate.from('2019-02-28').add({ months: -1 })}`, '2019-01-28'); - }); - it("ignores lower units that don't balance up to a day", () => { - equal(`${date.add({ hours: 1 })}`, '1976-11-18'); - equal(`${date.add({ minutes: 1 })}`, '1976-11-18'); - equal(`${date.add({ seconds: 1 })}`, '1976-11-18'); - equal(`${date.add({ milliseconds: 1 })}`, '1976-11-18'); - equal(`${date.add({ microseconds: 1 })}`, '1976-11-18'); - equal(`${date.add({ nanoseconds: 1 })}`, '1976-11-18'); - }); - it('adds lower units that balance up to a day or more', () => { - equal(`${date.add({ hours: 24 })}`, '1976-11-19'); - equal(`${date.add({ hours: 36 })}`, '1976-11-19'); - equal(`${date.add({ hours: 48 })}`, '1976-11-20'); - equal(`${date.add({ minutes: 1440 })}`, '1976-11-19'); - equal(`${date.add({ seconds: 86400 })}`, '1976-11-19'); - equal(`${date.add({ milliseconds: 86400_000 })}`, '1976-11-19'); - equal(`${date.add({ microseconds: 86400_000_000 })}`, '1976-11-19'); - equal(`${date.add({ nanoseconds: 86400_000_000_000 })}`, '1976-11-19'); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => date.add({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => date.add({ months: 1, days: -30 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => date.add({ months: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${date.add({ months: 1 }, options)}`, '1976-12-18')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => date.add({}), TypeError); - throws(() => date.add({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${date.add({ month: 1, days: 1 })}`, '1976-11-19'); - }); - }); - describe('date.subtract() works', () => { - const date = PlainDate.from('2019-11-18'); - it('date.subtract({ years: 43 })', () => { - equal(`${date.subtract({ years: 43 })}`, '1976-11-18'); - }); - it('date.subtract({ months: 11 })', () => { - equal(`${date.subtract({ months: 11 })}`, '2018-12-18'); - }); - it('date.subtract({ days: 20 })', () => { - equal(`${date.subtract({ days: 20 })}`, '2019-10-29'); - }); - it('Date.from("2019-02-28").subtract({ months: 1 })', () => { - equal(`${PlainDate.from('2019-02-28').subtract({ months: 1 })}`, '2019-01-28'); - }); - it('Date.subtract(durationObj)', () => { - equal(`${date.subtract(Temporal.Duration.from('P43Y'))}`, '1976-11-18'); - }); - it('casts argument', () => { - equal(`${date.subtract('P43Y')}`, '1976-11-18'); - }); - it('constrain when overflowing result', () => { - const mar31 = PlainDate.from('2020-03-31'); - equal(`${mar31.subtract({ months: 1 })}`, '2020-02-29'); - equal(`${mar31.subtract({ months: 1 }, { overflow: 'constrain' })}`, '2020-02-29'); - }); - it('throw when overflowing result with reject', () => { - const mar31 = PlainDate.from('2020-03-31'); - throws(() => mar31.subtract({ months: 1 }, { overflow: 'reject' }), RangeError); - }); - it('symmetrical with regard to negative durations', () => { - equal(`${PlainDate.from('1976-11-18').subtract({ years: -43 })}`, '2019-11-18'); - equal(`${PlainDate.from('2018-12-18').subtract({ months: -11 })}`, '2019-11-18'); - equal(`${PlainDate.from('2019-10-29').subtract({ days: -20 })}`, '2019-11-18'); - equal(`${PlainDate.from('2019-01-28').subtract({ months: -1 })}`, '2019-02-28'); - }); - it("ignores lower units that don't balance up to a day", () => { - equal(`${date.subtract({ hours: 1 })}`, '2019-11-18'); - equal(`${date.subtract({ minutes: 1 })}`, '2019-11-18'); - equal(`${date.subtract({ seconds: 1 })}`, '2019-11-18'); - equal(`${date.subtract({ milliseconds: 1 })}`, '2019-11-18'); - equal(`${date.subtract({ microseconds: 1 })}`, '2019-11-18'); - equal(`${date.subtract({ nanoseconds: 1 })}`, '2019-11-18'); - }); - it('subtracts lower units that balance up to a day or more', () => { - equal(`${date.subtract({ hours: 24 })}`, '2019-11-17'); - equal(`${date.subtract({ hours: 36 })}`, '2019-11-17'); - equal(`${date.subtract({ hours: 48 })}`, '2019-11-16'); - equal(`${date.subtract({ minutes: 1440 })}`, '2019-11-17'); - equal(`${date.subtract({ seconds: 86400 })}`, '2019-11-17'); - equal(`${date.subtract({ milliseconds: 86400_000 })}`, '2019-11-17'); - equal(`${date.subtract({ microseconds: 86400_000_000 })}`, '2019-11-17'); - equal(`${date.subtract({ nanoseconds: 86400_000_000_000 })}`, '2019-11-17'); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => date.subtract({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => date.subtract({ months: 1, days: -30 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => date.subtract({ months: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${date.subtract({ months: 1 }, options)}`, '2019-10-18')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => date.subtract({}), TypeError); - throws(() => date.subtract({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${date.subtract({ month: 1, days: 1 })}`, '2019-11-17'); - }); - }); - describe('date.toString() works', () => { - it('new Date(1976, 11, 18).toString()', () => { - equal(new PlainDate(1976, 11, 18).toString(), '1976-11-18'); - }); - it('new Date(1914, 2, 23).toString()', () => { - equal(new PlainDate(1914, 2, 23).toString(), '1914-02-23'); - }); - const d = new PlainDate(1976, 11, 18); - it('shows only non-ISO calendar if calendarName = auto', () => { - equal(d.toString({ calendarName: 'auto' }), '1976-11-18'); - equal(d.withCalendar('gregory').toString({ calendarName: 'auto' }), '1976-11-18[u-ca=gregory]'); - }); - it('shows ISO calendar if calendarName = always', () => { - equal(d.toString({ calendarName: 'always' }), '1976-11-18[u-ca=iso8601]'); - }); - it('omits non-ISO calendar if calendarName = never', () => { - equal(d.withCalendar('gregory').toString({ calendarName: 'never' }), '1976-11-18'); - }); - it('default is calendar = auto', () => { - equal(d.toString(), '1976-11-18'); - equal(d.withCalendar('gregory').toString(), '1976-11-18[u-ca=gregory]'); - }); - it('throws on invalid calendar', () => { - ['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => { - throws(() => d.toString({ calendarName }), RangeError); - }); - }); - }); - describe('Date.from() works', () => { - it('Date.from("1976-11-18")', () => { - const date = PlainDate.from('1976-11-18'); - equal(date.year, 1976); - equal(date.month, 11); - equal(date.day, 18); - }); - it('Date.from("2019-06-30")', () => { - const date = PlainDate.from('2019-06-30'); - equal(date.year, 2019); - equal(date.month, 6); - equal(date.day, 30); - }); - it('Date.from("+000050-06-30")', () => { - const date = PlainDate.from('+000050-06-30'); - equal(date.year, 50); - equal(date.month, 6); - equal(date.day, 30); - }); - it('Date.from("+010583-06-30")', () => { - const date = PlainDate.from('+010583-06-30'); - equal(date.year, 10583); - equal(date.month, 6); - equal(date.day, 30); - }); - it('Date.from("-010583-06-30")', () => { - const date = PlainDate.from('-010583-06-30'); - equal(date.year, -10583); - equal(date.month, 6); - equal(date.day, 30); - }); - it('Date.from("-000333-06-30")', () => { - const date = PlainDate.from('-000333-06-30'); - equal(date.year, -333); - equal(date.month, 6); - equal(date.day, 30); - }); - it('Date.from(1976-11-18) is not the same object', () => { - const orig = new PlainDate(1976, 11, 18); - const actual = PlainDate.from(orig); - notEqual(actual, orig); - }); - it('Date.from({ year: 1976, month: 11, day: 18 }) == 1976-11-18', () => - equal(`${PlainDate.from({ year: 1976, month: 11, day: 18 })}`, '1976-11-18')); - it('can be constructed with month and without monthCode', () => - equal(`${PlainDate.from({ year: 1976, month: 11, day: 18 })}`, '1976-11-18')); - it('can be constructed with monthCode and without month', () => - equal(`${PlainDate.from({ year: 1976, monthCode: 'M11', day: 18 })}`, '1976-11-18')); - it('month and monthCode must agree', () => - throws(() => PlainDate.from({ year: 1976, month: 11, monthCode: 'M12', day: 18 }), RangeError)); - it('Date.from({ year: 2019, day: 15 }) throws', () => - throws(() => PlainDate.from({ year: 2019, day: 15 }), TypeError)); - it('Date.from({ month: 12 }) throws', () => throws(() => PlainDate.from({ month: 12 }), TypeError)); - it('object must contain at least the required correctly-spelled properties', () => { - throws(() => PlainDate.from({}), TypeError); - throws(() => PlainDate.from({ year: 1976, months: 11, day: 18 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${PlainDate.from({ year: 1976, month: 11, day: 18, days: 15 })}`, '1976-11-18'); - }); - it('Date.from(required prop undefined) throws', () => - throws(() => PlainDate.from({ year: undefined, month: 11, day: 18 }), TypeError)); - it('Date.from(number) is converted to string', () => PlainDate.from(19761118).equals(PlainDate.from('19761118'))); - it('basic format', () => { - equal(`${PlainDate.from('19761118')}`, '1976-11-18'); - equal(`${PlainDate.from('+0019761118')}`, '1976-11-18'); - }); - it('mixture of basic and extended format', () => { - equal(`${PlainDate.from('1976-11-18T152330.1+00:00')}`, '1976-11-18'); - equal(`${PlainDate.from('19761118T15:23:30.1+00:00')}`, '1976-11-18'); - equal(`${PlainDate.from('1976-11-18T15:23:30.1+0000')}`, '1976-11-18'); - equal(`${PlainDate.from('1976-11-18T152330.1+0000')}`, '1976-11-18'); - equal(`${PlainDate.from('19761118T15:23:30.1+0000')}`, '1976-11-18'); - equal(`${PlainDate.from('19761118T152330.1+00:00')}`, '1976-11-18'); - equal(`${PlainDate.from('19761118T152330.1+0000')}`, '1976-11-18'); - equal(`${PlainDate.from('+001976-11-18T152330.1+00:00')}`, '1976-11-18'); - equal(`${PlainDate.from('+0019761118T15:23:30.1+00:00')}`, '1976-11-18'); - equal(`${PlainDate.from('+001976-11-18T15:23:30.1+0000')}`, '1976-11-18'); - equal(`${PlainDate.from('+001976-11-18T152330.1+0000')}`, '1976-11-18'); - equal(`${PlainDate.from('+0019761118T15:23:30.1+0000')}`, '1976-11-18'); - equal(`${PlainDate.from('+0019761118T152330.1+00:00')}`, '1976-11-18'); - equal(`${PlainDate.from('+0019761118T152330.1+0000')}`, '1976-11-18'); - }); - it('no junk at end of string', () => throws(() => PlainDate.from('1976-11-18junk'), RangeError)); - it('ignores if a timezone is specified', () => - equal(`${PlainDate.from('2020-01-01[Asia/Kolkata]')}`, '2020-01-01')); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => PlainDate.from({ year: 1976, month: 11, day: 18 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${PlainDate.from({ year: 1976, month: 11, day: 18 }, options)}`, '1976-11-18') - ); - }); - describe('Overflow', () => { - const bad = { year: 2019, month: 1, day: 32 }; - it('reject', () => throws(() => PlainDate.from(bad, { overflow: 'reject' }), RangeError)); - it('constrain', () => { - equal(`${PlainDate.from(bad)}`, '2019-01-31'); - equal(`${PlainDate.from(bad, { overflow: 'constrain' })}`, '2019-01-31'); - }); - it('throw when bad overflow', () => { - [new PlainDate(1976, 11, 18), { year: 2019, month: 1, day: 1 }, '2019-01-31'].forEach((input) => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainDate.from(input, { overflow }), RangeError) - ); - }); - }); - it('constrain has no effect on invalid ISO string', () => { - throws(() => PlainDate.from('2020-13-34', { overflow: 'constrain' }), RangeError); - }); - }); - }); - describe('Date.compare works', () => { - const d1 = PlainDate.from('1976-11-18'); - const d2 = PlainDate.from('2019-06-30'); - it('equal', () => equal(PlainDate.compare(d1, d1), 0)); - it('smaller/larger', () => equal(PlainDate.compare(d1, d2), -1)); - it('larger/smaller', () => equal(PlainDate.compare(d2, d1), 1)); - it('casts first argument', () => { - equal(PlainDate.compare({ year: 1976, month: 11, day: 18 }, d2), -1); - equal(PlainDate.compare('1976-11-18', d2), -1); - }); - it('casts second argument', () => { - equal(PlainDate.compare(d1, { year: 2019, month: 6, day: 30 }), -1); - equal(PlainDate.compare(d1, '2019-06-30'), -1); - }); - it('object must contain at least the required properties', () => { - throws(() => PlainDate.compare({ year: 1976 }, d2), TypeError); - throws(() => PlainDate.compare(d1, { year: 2019 }), TypeError); - }); - }); - describe('Date.equal works', () => { - const d1 = PlainDate.from('1976-11-18'); - const d2 = PlainDate.from('2019-06-30'); - it('equal', () => assert(d1.equals(d1))); - it('unequal', () => assert(!d1.equals(d2))); - it('casts argument', () => { - assert(!d2.equals({ year: 1976, month: 11, day: 18 })); - assert(!d2.equals('1976-11-18')); - }); - it('object must contain at least the required properties', () => { - throws(() => d2.equals({ year: 1976 }), TypeError); - }); - }); - describe("Comparison operators don't work", () => { - const d1 = PlainDate.from('1963-02-13'); - const d1again = PlainDate.from('1963-02-13'); - const d2 = PlainDate.from('1976-11-18'); - it('=== is object equality', () => equal(d1, d1)); - it('!== is object equality', () => notEqual(d1, d1again)); - it('<', () => throws(() => d1 < d2)); - it('>', () => throws(() => d1 > d2)); - it('<=', () => throws(() => d1 <= d2)); - it('>=', () => throws(() => d1 >= d2)); - }); - describe('Min/max range', () => { - it('constructing from numbers', () => { - throws(() => new PlainDate(-271821, 4, 18), RangeError); - throws(() => new PlainDate(275760, 9, 14), RangeError); - equal(`${new PlainDate(-271821, 4, 19)}`, '-271821-04-19'); - equal(`${new PlainDate(275760, 9, 13)}`, '+275760-09-13'); - }); - it('constructing from property bag', () => { - const tooEarly = { year: -271821, month: 4, day: 18 }; - const tooLate = { year: 275760, month: 9, day: 14 }; - ['reject', 'constrain'].forEach((overflow) => { - [tooEarly, tooLate].forEach((props) => { - throws(() => PlainDate.from(props, { overflow }), RangeError); - }); - }); - equal(`${PlainDate.from({ year: -271821, month: 4, day: 19 })}`, '-271821-04-19'); - equal(`${PlainDate.from({ year: 275760, month: 9, day: 13 })}`, '+275760-09-13'); - }); - it('constructing from ISO string', () => { - ['reject', 'constrain'].forEach((overflow) => { - ['-271821-04-18', '+275760-09-14'].forEach((str) => { - throws(() => PlainDate.from(str, { overflow }), RangeError); - }); - }); - equal(`${PlainDate.from('-271821-04-19')}`, '-271821-04-19'); - equal(`${PlainDate.from('+275760-09-13')}`, '+275760-09-13'); - }); - it('converting from DateTime', () => { - const min = Temporal.PlainDateTime.from('-271821-04-19T00:00:00.000000001'); - const max = Temporal.PlainDateTime.from('+275760-09-13T23:59:59.999999999'); - equal(`${min.toPlainDate()}`, '-271821-04-19'); - equal(`${max.toPlainDate()}`, '+275760-09-13'); - }); - it('converting from YearMonth', () => { - const min = Temporal.PlainYearMonth.from('-271821-04'); - const max = Temporal.PlainYearMonth.from('+275760-09'); - throws(() => min.toPlainDate({ day: 1 }), RangeError); - throws(() => max.toPlainDate({ day: 30 }), RangeError); - equal(`${min.toPlainDate({ day: 19 })}`, '-271821-04-19'); - equal(`${max.toPlainDate({ day: 13 })}`, '+275760-09-13'); - }); - it('converting from MonthDay', () => { - const jan1 = Temporal.PlainMonthDay.from('01-01'); - const dec31 = Temporal.PlainMonthDay.from('12-31'); - const minYear = -271821; - const maxYear = 275760; - throws(() => jan1.toPlainDate({ year: minYear }), RangeError); - throws(() => dec31.toPlainDate({ year: maxYear }), RangeError); - equal(`${jan1.toPlainDate({ year: minYear + 1 })}`, '-271820-01-01'); - equal(`${dec31.toPlainDate({ year: maxYear - 1 })}`, '+275759-12-31'); - }); - it('adding and subtracting beyond limit', () => { - const min = PlainDate.from('-271821-04-19'); - const max = PlainDate.from('+275760-09-13'); - ['reject', 'constrain'].forEach((overflow) => { - throws(() => min.subtract({ days: 1 }, { overflow }), RangeError); - throws(() => max.add({ days: 1 }, { overflow }), RangeError); - }); - }); - }); - describe('date.getISOFields() works', () => { - const d1 = PlainDate.from('1976-11-18'); - const fields = d1.getISOFields(); - it('fields', () => { - equal(fields.isoYear, 1976); - equal(fields.isoMonth, 11); - equal(fields.isoDay, 18); - equal(fields.calendar.id, 'iso8601'); - }); - it('enumerable', () => { - const fields2 = { ...fields }; - equal(fields2.isoYear, 1976); - equal(fields2.isoMonth, 11); - equal(fields2.isoDay, 18); - equal(fields2.calendar, fields.calendar); - }); - it('as input to constructor', () => { - const d2 = new PlainDate(fields.isoYear, fields.isoMonth, fields.isoDay, fields.calendar); - assert(d2.equals(d1)); - }); - }); - describe('date.withCalendar()', () => { - const d1 = PlainDate.from('1976-11-18'); - it('works', () => { - const calendar = Temporal.Calendar.from('iso8601'); - equal(`${d1.withCalendar(calendar)}`, '1976-11-18'); - }); - it('casts its argument', () => { - equal(`${d1.withCalendar('iso8601')}`, '1976-11-18'); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/plainDateTime.js b/packages/temporal-polyfill/tests/plainDateTime.js deleted file mode 100644 index 97a082e0..00000000 --- a/packages/temporal-polyfill/tests/plainDateTime.js +++ /dev/null @@ -1,1774 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, notStrictEqual: notEqual, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { PlainDateTime } = Temporal; - -describe('DateTime', () => { - describe('Structure', () => { - it('DateTime is a Function', () => { - equal(typeof PlainDateTime, 'function'); - }); - it('DateTime has a prototype', () => { - assert(PlainDateTime.prototype); - equal(typeof PlainDateTime.prototype, 'object'); - }); - describe('DateTime.prototype', () => { - it('DateTime.prototype has year', () => { - assert('year' in PlainDateTime.prototype); - }); - it('DateTime.prototype has month', () => { - assert('month' in PlainDateTime.prototype); - }); - it('DateTime.prototype has monthCode', () => { - assert('monthCode' in PlainDateTime.prototype); - }); - it('DateTime.prototype has day', () => { - assert('day' in PlainDateTime.prototype); - }); - it('DateTime.prototype has hour', () => { - assert('hour' in PlainDateTime.prototype); - }); - it('DateTime.prototype has minute', () => { - assert('minute' in PlainDateTime.prototype); - }); - it('DateTime.prototype has second', () => { - assert('second' in PlainDateTime.prototype); - }); - it('DateTime.prototype has millisecond', () => { - assert('millisecond' in PlainDateTime.prototype); - }); - it('DateTime.prototype has microsecond', () => { - assert('microsecond' in PlainDateTime.prototype); - }); - it('DateTime.prototype has nanosecond', () => { - assert('nanosecond' in PlainDateTime.prototype); - }); - it('DateTime.prototype has dayOfWeek', () => { - assert('dayOfWeek' in PlainDateTime.prototype); - }); - it('DateTime.prototype has dayOfYear', () => { - assert('dayOfYear' in PlainDateTime.prototype); - }); - it('DateTime.prototype has weekOfYear', () => { - assert('weekOfYear' in PlainDateTime.prototype); - }); - it('DateTime.prototype has daysInWeek', () => { - assert('daysInWeek' in PlainDateTime.prototype); - }); - it('DateTime.prototype has monthsInYear', () => { - assert('monthsInYear' in PlainDateTime.prototype); - }); - it('DateTime.prototype.with is a Function', () => { - equal(typeof PlainDateTime.prototype.with, 'function'); - }); - it('DateTime.prototype.add is a Function', () => { - equal(typeof PlainDateTime.prototype.add, 'function'); - }); - it('DateTime.prototype.subtract is a Function', () => { - equal(typeof PlainDateTime.prototype.subtract, 'function'); - }); - it('DateTime.prototype.until is a Function', () => { - equal(typeof PlainDateTime.prototype.until, 'function'); - }); - it('DateTime.prototype.since is a Function', () => { - equal(typeof PlainDateTime.prototype.since, 'function'); - }); - it('DateTime.prototype.round is a Function', () => { - equal(typeof PlainDateTime.prototype.round, 'function'); - }); - it('DateTime.prototype.equals is a Function', () => { - equal(typeof PlainDateTime.prototype.equals, 'function'); - }); - it('DateTime.prototype.toZonedDateTime is a Function', () => { - equal(typeof PlainDateTime.prototype.toZonedDateTime, 'function'); - }); - it('DateTime.prototype.toPlainDate is a Function', () => { - equal(typeof PlainDateTime.prototype.toPlainDate, 'function'); - }); - it('DateTime.prototype.toPlainTime is a Function', () => { - equal(typeof PlainDateTime.prototype.toPlainTime, 'function'); - }); - it('DateTime.prototype.getISOFields is a Function', () => { - equal(typeof PlainDateTime.prototype.getISOFields, 'function'); - }); - it('DateTime.prototype.toString is a Function', () => { - equal(typeof PlainDateTime.prototype.toString, 'function'); - }); - it('DateTime.prototype.toJSON is a Function', () => { - equal(typeof PlainDateTime.prototype.toJSON, 'function'); - }); - }); - it('DateTime.from is a Function', () => { - equal(typeof PlainDateTime.from, 'function'); - }); - it('DateTime.compare is a Function', () => { - equal(typeof PlainDateTime.compare, 'function'); - }); - }); - describe('Construction', () => { - describe('new DateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar)', () => { - let datetime; - const calendar = Temporal.Calendar.from('iso8601'); - it('datetime can be constructed', () => { - datetime = new PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar); - assert(datetime); - equal(typeof datetime, 'object'); - }); - it('datetime.year is 1976', () => equal(datetime.year, 1976)); - it('datetime.month is 11', () => equal(datetime.month, 11)); - it('datetime.monthCode is "M11"', () => equal(datetime.monthCode, 'M11')); - it('datetime.day is 18', () => equal(datetime.day, 18)); - it('datetime.hour is 15', () => equal(datetime.hour, 15)); - it('datetime.minute is 23', () => equal(datetime.minute, 23)); - it('datetime.second is 30', () => equal(datetime.second, 30)); - it('datetime.millisecond is 123', () => equal(datetime.millisecond, 123)); - it('datetime.microsecond is 456', () => equal(datetime.microsecond, 456)); - it('datetime.nanosecond is 789', () => equal(datetime.nanosecond, 789)); - it('datetime.calendar is the object', () => equal(datetime.calendar, calendar)); - it('datetime.dayOfWeek is 4', () => equal(datetime.dayOfWeek, 4)); - it('datetime.dayOfYear is 323', () => equal(datetime.dayOfYear, 323)); - it('datetime.weekOfYear is 47', () => equal(datetime.weekOfYear, 47)); - it('datetime.daysInWeek is 7', () => equal(datetime.daysInWeek, 7)); - it('datetime.monthsInYear is 12', () => equal(datetime.monthsInYear, 12)); - it('`${datetime}` is 1976-11-18T15:23:30.123456789', () => equal(`${datetime}`, '1976-11-18T15:23:30.123456789')); - }); - describe('new DateTime(1976, 11, 18, 15, 23, 30, 123, 456)', () => { - let datetime; - it('datetime can be constructed', () => { - datetime = new PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456); - assert(datetime); - equal(typeof datetime, 'object'); - }); - it('datetime.year is 1976', () => equal(datetime.year, 1976)); - it('datetime.month is 11', () => equal(datetime.month, 11)); - it('datetime.monthCode is "M11"', () => equal(datetime.monthCode, 'M11')); - it('datetime.day is 18', () => equal(datetime.day, 18)); - it('datetime.hour is 15', () => equal(datetime.hour, 15)); - it('datetime.minute is 23', () => equal(datetime.minute, 23)); - it('datetime.second is 30', () => equal(datetime.second, 30)); - it('datetime.millisecond is 123', () => equal(datetime.millisecond, 123)); - it('datetime.microsecond is 456', () => equal(datetime.microsecond, 456)); - it('datetime.nanosecond is 0', () => equal(datetime.nanosecond, 0)); - it('datetime.dayOfWeek is 4', () => equal(datetime.dayOfWeek, 4)); - it('datetime.dayOfYear is 323', () => equal(datetime.dayOfYear, 323)); - it('datetime.weekOfYear is 47', () => equal(datetime.weekOfYear, 47)); - it('datetime.daysInWeek is 7', () => equal(datetime.daysInWeek, 7)); - it('datetime.monthsInYear is 12', () => equal(datetime.monthsInYear, 12)); - it('`${datetime}` is 1976-11-18T15:23:30.123456', () => equal(`${datetime}`, '1976-11-18T15:23:30.123456')); - }); - describe('new DateTime(1976, 11, 18, 15, 23, 30, 123)', () => { - let datetime; - it('datetime can be constructed', () => { - datetime = new PlainDateTime(1976, 11, 18, 15, 23, 30, 123); - assert(datetime); - equal(typeof datetime, 'object'); - }); - it('datetime.year is 1976', () => equal(datetime.year, 1976)); - it('datetime.month is 11', () => equal(datetime.month, 11)); - it('datetime.monthCode is "M11"', () => equal(datetime.monthCode, 'M11')); - it('datetime.day is 18', () => equal(datetime.day, 18)); - it('datetime.hour is 15', () => equal(datetime.hour, 15)); - it('datetime.minute is 23', () => equal(datetime.minute, 23)); - it('datetime.second is 30', () => equal(datetime.second, 30)); - it('datetime.millisecond is 123', () => equal(datetime.millisecond, 123)); - it('datetime.microsecond is 0', () => equal(datetime.microsecond, 0)); - it('datetime.nanosecond is 0', () => equal(datetime.nanosecond, 0)); - it('datetime.dayOfWeek is 4', () => equal(datetime.dayOfWeek, 4)); - it('datetime.dayOfYear is 323', () => equal(datetime.dayOfYear, 323)); - it('datetime.weekOfYear is 47', () => equal(datetime.weekOfYear, 47)); - it('datetime.daysInWeek is 7', () => equal(datetime.daysInWeek, 7)); - it('datetime.monthsInYear is 12', () => equal(datetime.monthsInYear, 12)); - it('`${datetime}` is 1976-11-18T15:23:30.123', () => equal(`${datetime}`, '1976-11-18T15:23:30.123')); - }); - describe('new DateTime(1976, 11, 18, 15, 23, 30)', () => { - let datetime; - it('datetime can be constructed', () => { - datetime = new PlainDateTime(1976, 11, 18, 15, 23, 30); - assert(datetime); - equal(typeof datetime, 'object'); - }); - it('datetime.year is 1976', () => equal(datetime.year, 1976)); - it('datetime.month is 11', () => equal(datetime.month, 11)); - it('datetime.monthCode is "M11"', () => equal(datetime.monthCode, 'M11')); - it('datetime.day is 18', () => equal(datetime.day, 18)); - it('datetime.hour is 15', () => equal(datetime.hour, 15)); - it('datetime.minute is 23', () => equal(datetime.minute, 23)); - it('datetime.second is 30', () => equal(datetime.second, 30)); - it('datetime.millisecond is 0', () => equal(datetime.millisecond, 0)); - it('datetime.microsecond is 0', () => equal(datetime.microsecond, 0)); - it('datetime.nanosecond is 0', () => equal(datetime.nanosecond, 0)); - it('datetime.dayOfWeek is 4', () => equal(datetime.dayOfWeek, 4)); - it('datetime.dayOfYear is 323', () => equal(datetime.dayOfYear, 323)); - it('datetime.weekOfYear is 47', () => equal(datetime.weekOfYear, 47)); - it('datetime.daysInWeek is 7', () => equal(datetime.daysInWeek, 7)); - it('datetime.monthsInYear is 12', () => equal(datetime.monthsInYear, 12)); - it('`${datetime}` is 1976-11-18T15:23:30', () => equal(`${datetime}`, '1976-11-18T15:23:30')); - }); - describe('new DateTime(1976, 11, 18, 15, 23)', () => { - let datetime; - it('datetime can be constructed', () => { - datetime = new PlainDateTime(1976, 11, 18, 15, 23); - assert(datetime); - equal(typeof datetime, 'object'); - }); - it('datetime.year is 1976', () => equal(datetime.year, 1976)); - it('datetime.month is 11', () => equal(datetime.month, 11)); - it('datetime.monthCode is "M11"', () => equal(datetime.monthCode, 'M11')); - it('datetime.day is 18', () => equal(datetime.day, 18)); - it('datetime.hour is 15', () => equal(datetime.hour, 15)); - it('datetime.minute is 23', () => equal(datetime.minute, 23)); - it('datetime.second is 0', () => equal(datetime.second, 0)); - it('datetime.millisecond is 0', () => equal(datetime.millisecond, 0)); - it('datetime.microsecond is 0', () => equal(datetime.microsecond, 0)); - it('datetime.nanosecond is 0', () => equal(datetime.nanosecond, 0)); - it('datetime.dayOfWeek is 4', () => equal(datetime.dayOfWeek, 4)); - it('datetime.dayOfYear is 323', () => equal(datetime.dayOfYear, 323)); - it('datetime.weekOfYear is 47', () => equal(datetime.weekOfYear, 47)); - it('datetime.daysInWeek is 7', () => equal(datetime.daysInWeek, 7)); - it('datetime.monthsInYear is 12', () => equal(datetime.monthsInYear, 12)); - it('`${datetime}` is 1976-11-18T15:23:00', () => equal(`${datetime}`, '1976-11-18T15:23:00')); - }); - describe('new DateTime(1976, 11, 18, 15)', () => { - const datetime = new PlainDateTime(1976, 11, 18, 15); - it('`${datetime}` is 1976-11-18T15:00:00', () => equal(`${datetime}`, '1976-11-18T15:00:00')); - }); - describe('new DateTime(1976, 11, 18)', () => { - const datetime = new PlainDateTime(1976, 11, 18); - it('`${datetime}` is 1976-11-18T00:00:00', () => equal(`${datetime}`, '1976-11-18T00:00:00')); - }); - describe('constructor treats -0 as 0', () => { - it('ignores the sign of -0', () => { - const datetime = new PlainDateTime(1976, 11, 18, -0, -0, -0, -0, -0); - equal(datetime.hour, 0); - equal(datetime.minute, 0); - equal(datetime.second, 0); - equal(datetime.millisecond, 0); - equal(datetime.microsecond, 0); - equal(datetime.nanosecond, 0); - }); - }); - }); - describe('.with manipulation', () => { - const datetime = new PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); - it('datetime.with({ year: 2019 } works', () => { - equal(`${datetime.with({ year: 2019 })}`, '2019-11-18T15:23:30.123456789'); - }); - it('datetime.with({ month: 5 } works', () => { - equal(`${datetime.with({ month: 5 })}`, '1976-05-18T15:23:30.123456789'); - }); - it('datetime.with({ monthCode: "M05" } works', () => { - equal(`${datetime.with({ monthCode: 'M05' })}`, '1976-05-18T15:23:30.123456789'); - }); - it('month and monthCode must agree', () => { - throws(() => datetime.with({ month: 5, monthCode: 'M06' }), RangeError); - }); - it('datetime.with({ day: 5 } works', () => { - equal(`${datetime.with({ day: 5 })}`, '1976-11-05T15:23:30.123456789'); - }); - it('datetime.with({ hour: 5 } works', () => { - equal(`${datetime.with({ hour: 5 })}`, '1976-11-18T05:23:30.123456789'); - }); - it('datetime.with({ minute: 5 } works', () => { - equal(`${datetime.with({ minute: 5 })}`, '1976-11-18T15:05:30.123456789'); - }); - it('datetime.with({ second: 5 } works', () => { - equal(`${datetime.with({ second: 5 })}`, '1976-11-18T15:23:05.123456789'); - }); - it('datetime.with({ millisecond: 5 } works', () => { - equal(`${datetime.with({ millisecond: 5 })}`, '1976-11-18T15:23:30.005456789'); - }); - it('datetime.with({ microsecond: 5 } works', () => { - equal(`${datetime.with({ microsecond: 5 })}`, '1976-11-18T15:23:30.123005789'); - }); - it('datetime.with({ nanosecond: 5 } works', () => { - equal(`${datetime.with({ nanosecond: 5 })}`, '1976-11-18T15:23:30.123456005'); - }); - it('datetime.with({ month: 5, second: 15 } works', () => { - equal(`${datetime.with({ month: 5, second: 15 })}`, '1976-05-18T15:23:15.123456789'); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => datetime.with({ day: 5 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => datetime.with({ day: 5 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${datetime.with({ day: 5 }, options)}`, '1976-11-05T15:23:30.123456789') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => datetime.with({}), TypeError); - throws(() => datetime.with({ months: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${datetime.with({ month: 12, days: 15 })}`, '1976-12-18T15:23:30.123456789'); - }); - it('datetime.with(string) throws', () => { - throws(() => datetime.with('12:00'), TypeError); - throws(() => datetime.with('1995-04-07'), TypeError); - throws(() => datetime.with('2019-05-17T12:34:56.007007007'), TypeError); - throws(() => datetime.with('2019-05-17T12:34:56.007007007Z'), TypeError); - throws(() => datetime.with('42'), TypeError); - }); - it('throws with calendar property', () => { - throws(() => datetime.with({ year: 2021, calendar: 'iso8601' }), TypeError); - }); - it('throws with timeZone property', () => { - throws(() => datetime.with({ year: 2021, timeZone: 'UTC' }), TypeError); - }); - }); - describe('.withPlainTime manipulation', () => { - const dt = Temporal.PlainDateTime.from('2015-12-07T03:24:30.000003500'); - it('datetime.withPlainTime({ hour: 10 }) works', () => { - equal(`${dt.withPlainTime({ hour: 10 })}`, '2015-12-07T10:00:00'); - }); - it('datetime.withPlainTime(time) works', () => { - const time = Temporal.PlainTime.from('11:22'); - equal(`${dt.withPlainTime(time)}`, '2015-12-07T11:22:00'); - }); - it("datetime.withPlainTime('12:34') works", () => { - equal(`${dt.withPlainTime('12:34')}`, '2015-12-07T12:34:00'); - }); - it('datetime.withPlainTime() defaults to midnight', () => { - equal(`${dt.withPlainTime()}`, '2015-12-07T00:00:00'); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => dt.withPlainTime({}), TypeError); - throws(() => dt.withPlainTime({ minutes: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${dt.withPlainTime({ hour: 10, seconds: 123 })}`, '2015-12-07T10:00:00'); - }); - }); - describe('.withPlainDate manipulation', () => { - const dt = Temporal.PlainDateTime.from('1995-12-07T03:24:30'); - it('datetime.withPlainDate({ year: 2000, month: 6, day: 1 }) works', () => { - equal(`${dt.withPlainDate({ year: 2000, month: 6, day: 1 })}`, '2000-06-01T03:24:30'); - }); - it('datetime.withPlainDate(plainDate) works', () => { - const date = Temporal.PlainDate.from('2020-01-23'); - equal(`${dt.withPlainDate(date)}`, '2020-01-23T03:24:30'); - }); - it("datetime.withPlainDate('2018-09-15') works", () => { - equal(`${dt.withPlainDate('2018-09-15')}`, '2018-09-15T03:24:30'); - }); - it('result contains a non-ISO calendar if present in the input', () => { - equal(`${dt.withCalendar('japanese').withPlainDate('2008-09-06')}`, '2008-09-06T03:24:30[u-ca=japanese]'); - }); - it('calendar is unchanged if input has ISO calendar', () => { - equal(`${dt.withPlainDate('2008-09-06[u-ca=japanese]')}`, '2008-09-06T03:24:30[u-ca=japanese]'); - }); - it('throws if both `this` and `other` have a non-ISO calendar', () => { - throws(() => dt.withCalendar('gregory').withPlainDate('2008-09-06[u-ca=japanese]'), RangeError); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => dt.withPlainDate({}), TypeError); - throws(() => dt.withPlainDate({ months: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${dt.withPlainDate({ year: 2000, month: 6, day: 1, months: 123 })}`, '2000-06-01T03:24:30'); - }); - }); - describe('DateTime.compare() works', () => { - const dt1 = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - const dt2 = PlainDateTime.from('2019-10-29T10:46:38.271986102'); - it('equal', () => equal(PlainDateTime.compare(dt1, dt1), 0)); - it('smaller/larger', () => equal(PlainDateTime.compare(dt1, dt2), -1)); - it('larger/smaller', () => equal(PlainDateTime.compare(dt2, dt1), 1)); - it('casts first argument', () => { - equal(PlainDateTime.compare({ year: 1976, month: 11, day: 18, hour: 15 }, dt2), -1); - equal(PlainDateTime.compare('1976-11-18T15:23:30.123456789', dt2), -1); - }); - it('casts second argument', () => { - equal(PlainDateTime.compare(dt1, { year: 2019, month: 10, day: 29, hour: 10 }), -1); - equal(PlainDateTime.compare(dt1, '2019-10-29T10:46:38.271986102'), -1); - }); - it('object must contain at least the required properties', () => { - throws(() => PlainDateTime.compare({ year: 1976 }, dt2), TypeError); - throws(() => PlainDateTime.compare(dt1, { year: 2019 }), TypeError); - }); - }); - describe('DateTime.equals() works', () => { - const dt1 = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - const dt2 = PlainDateTime.from('2019-10-29T10:46:38.271986102'); - it('equal', () => assert(dt1.equals(dt1))); - it('unequal', () => assert(!dt1.equals(dt2))); - it('casts argument', () => { - assert(!dt2.equals({ year: 1976, month: 11, day: 18, hour: 15 })); - assert(!dt2.equals('1976-11-18T15:23:30.123456789')); - }); - it('object must contain at least the required properties', () => { - throws(() => dt2.equals({ year: 1976 }), TypeError); - }); - }); - describe("Comparison operators don't work", () => { - const dt1 = PlainDateTime.from('1963-02-13T09:36:29.123456789'); - const dt1again = PlainDateTime.from('1963-02-13T09:36:29.123456789'); - const dt2 = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - it('=== is object equality', () => equal(dt1, dt1)); - it('!== is object equality', () => notEqual(dt1, dt1again)); - it('<', () => throws(() => dt1 < dt2)); - it('>', () => throws(() => dt1 > dt2)); - it('<=', () => throws(() => dt1 <= dt2)); - it('>=', () => throws(() => dt1 >= dt2)); - }); - describe('date/time maths', () => { - const earlier = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - const later = PlainDateTime.from('2019-10-29T10:46:38.271986102'); - ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'].forEach((largestUnit) => { - const diff = later.since(earlier, { largestUnit }); - it(`(${earlier}).since(${later}) == (${later}).since(${earlier}).negated()`, () => - equal(`${earlier.since(later, { largestUnit })}`, `${diff.negated()}`)); - it(`(${earlier}).until(${later}) == (${later}).since(${earlier})`, () => - equal(`${earlier.until(later, { largestUnit })}`, `${diff}`)); - it(`(${earlier}).add(${diff}) == (${later})`, () => assert(earlier.add(diff).equals(later))); - it(`(${later}).subtract(${diff}) == (${earlier})`, () => assert(later.subtract(diff).equals(earlier))); - it('symmetrical with regard to negative durations', () => { - assert(earlier.subtract(diff.negated()).equals(later)); - assert(later.add(diff.negated()).equals(earlier)); - }); - }); - }); - describe('date/time maths: hours overflow', () => { - it('subtract result', () => { - const later = PlainDateTime.from('2019-10-29T10:46:38.271986102'); - const earlier = later.subtract({ hours: 12 }); - equal(`${earlier}`, '2019-10-28T22:46:38.271986102'); - }); - it('add result', () => { - const earlier = PlainDateTime.from('2020-05-31T23:12:38.271986102'); - const later = earlier.add({ hours: 2 }); - equal(`${later}`, '2020-06-01T01:12:38.271986102'); - }); - it('symmetrical with regard to negative durations', () => { - equal( - `${PlainDateTime.from('2019-10-29T10:46:38.271986102').add({ hours: -12 })}`, - '2019-10-28T22:46:38.271986102' - ); - equal( - `${PlainDateTime.from('2020-05-31T23:12:38.271986102').subtract({ hours: -2 })}`, - '2020-06-01T01:12:38.271986102' - ); - }); - }); - describe('DateTime.add() works', () => { - const jan31 = PlainDateTime.from('2020-01-31T15:00'); - it('constrain when ambiguous result', () => { - equal(`${jan31.add({ months: 1 })}`, '2020-02-29T15:00:00'); - equal(`${jan31.add({ months: 1 }, { overflow: 'constrain' })}`, '2020-02-29T15:00:00'); - }); - it('symmetrical with regard to negative durations in the time part', () => { - equal(`${jan31.add({ minutes: -30 })}`, '2020-01-31T14:30:00'); - equal(`${jan31.add({ seconds: -30 })}`, '2020-01-31T14:59:30'); - }); - it('throw when ambiguous result with reject', () => { - throws(() => jan31.add({ months: 1 }, { overflow: 'reject' }), RangeError); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainDateTime.from('2019-11-18T15:00').add({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => jan31.add({ hours: 1, minutes: -30 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => jan31.add({ years: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${jan31.add({ years: 1 }, options)}`, '2021-01-31T15:00:00') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => jan31.add({}), TypeError); - throws(() => jan31.add({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${jan31.add({ month: 1, days: 1 })}`, '2020-02-01T15:00:00'); - }); - it('casts argument', () => { - equal(`${jan31.add(Temporal.Duration.from('P1MT1S'))}`, '2020-02-29T15:00:01'); - equal(`${jan31.add('P1MT1S')}`, '2020-02-29T15:00:01'); - }); - }); - describe('date.subtract() works', () => { - const mar31 = PlainDateTime.from('2020-03-31T15:00'); - it('constrain when ambiguous result', () => { - equal(`${mar31.subtract({ months: 1 })}`, '2020-02-29T15:00:00'); - equal(`${mar31.subtract({ months: 1 }, { overflow: 'constrain' })}`, '2020-02-29T15:00:00'); - }); - it('symmetrical with regard to negative durations in the time part', () => { - equal(`${mar31.subtract({ minutes: -30 })}`, '2020-03-31T15:30:00'); - equal(`${mar31.subtract({ seconds: -30 })}`, '2020-03-31T15:00:30'); - }); - it('throw when ambiguous result with reject', () => { - throws(() => mar31.subtract({ months: 1 }, { overflow: 'reject' }), RangeError); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainDateTime.from('2019-11-18T15:00').subtract({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => mar31.add({ hours: 1, minutes: -30 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => mar31.subtract({ years: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${mar31.subtract({ years: 1 }, options)}`, '2019-03-31T15:00:00') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => mar31.subtract({}), TypeError); - throws(() => mar31.subtract({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${mar31.subtract({ month: 1, days: 1 })}`, '2020-03-30T15:00:00'); - }); - it('casts argument', () => { - equal(`${mar31.subtract(Temporal.Duration.from('P1MT1S'))}`, '2020-02-29T14:59:59'); - equal(`${mar31.subtract('P1MT1S')}`, '2020-02-29T14:59:59'); - }); - }); - describe('DateTime.until()', () => { - const dt = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - it('dt.until(later) === later.since(dt)', () => { - const later = PlainDateTime.from({ year: 2016, month: 3, day: 3, hour: 18 }); - equal(`${dt.until(later)}`, `${later.since(dt)}`); - }); - it('casts argument', () => { - equal(`${dt.until({ year: 2019, month: 10, day: 29, hour: 10 })}`, 'P15684DT18H36M29.876543211S'); - equal(`${dt.until('2019-10-29T10:46:38.271986102')}`, 'P15684DT19H23M8.148529313S'); - }); - const feb20 = PlainDateTime.from('2020-02-01T00:00'); - const feb21 = PlainDateTime.from('2021-02-01T00:00'); - it('defaults to returning days', () => { - equal(`${feb20.until(feb21)}`, 'P366D'); - equal(`${feb20.until(feb21, { largestUnit: 'auto' })}`, 'P366D'); - equal(`${feb20.until(feb21, { largestUnit: 'days' })}`, 'P366D'); - equal(`${feb20.until(PlainDateTime.from('2021-02-01T00:00:00.000000001'))}`, 'P366DT0.000000001S'); - equal(`${PlainDateTime.from('2020-02-01T00:00:00.000000001').until(feb21)}`, 'P365DT23H59M59.999999999S'); - }); - it('can return lower or higher units', () => { - equal(`${feb20.until(feb21, { largestUnit: 'years' })}`, 'P1Y'); - equal(`${feb20.until(feb21, { largestUnit: 'months' })}`, 'P12M'); - equal(`${feb20.until(feb21, { largestUnit: 'hours' })}`, 'PT8784H'); - equal(`${feb20.until(feb21, { largestUnit: 'minutes' })}`, 'PT527040M'); - equal(`${feb20.until(feb21, { largestUnit: 'seconds' })}`, 'PT31622400S'); - }); - it('can return subseconds', () => { - const later = feb20.add({ days: 1, milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = feb20.until(later, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 86400250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = feb20.until(later, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 86400250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = feb20.until(later, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 86400250250250); - }); - it('does not include higher units than necessary', () => { - const lastFeb20 = PlainDateTime.from('2020-02-29T00:00'); - const lastFeb21 = PlainDateTime.from('2021-02-28T00:00'); - equal(`${lastFeb20.until(lastFeb21)}`, 'P365D'); - equal(`${lastFeb20.until(lastFeb21, { largestUnit: 'months' })}`, 'P12M'); - equal(`${lastFeb20.until(lastFeb21, { largestUnit: 'years' })}`, 'P1Y'); - }); - it('weeks and months are mutually exclusive', () => { - const laterDateTime = dt.add({ days: 42, hours: 3 }); - const weeksDifference = dt.until(laterDateTime, { largestUnit: 'weeks' }); - notEqual(weeksDifference.weeks, 0); - equal(weeksDifference.months, 0); - const monthsDifference = dt.until(laterDateTime, { largestUnit: 'months' }); - equal(monthsDifference.weeks, 0); - notEqual(monthsDifference.months, 0); - }); - it('no two different calendars', () => { - const dt1 = new PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0); - const dt2 = new PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0, Temporal.Calendar.from('japanese')); - throws(() => dt1.until(dt2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb20.until(feb21, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb20.until(feb21, options)}`, 'P366D')); - }); - const earlier = PlainDateTime.from('2019-01-08T08:22:36.123456789'); - const later = PlainDateTime.from('2021-09-07T12:39:40.987654321'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'nonsense'].forEach((smallestUnit) => { - throws(() => earlier.until(later, { smallestUnit }), RangeError); - }); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = [ - 'years', - 'months', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ]; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => earlier.until(later, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than days', () => { - equal(`${earlier.until(later, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P3Y'); - equal(`${earlier.until(later, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P32M'); - equal(`${earlier.until(later, { smallestUnit: 'weeks', roundingMode: 'halfExpand' })}`, 'P139W'); - }); - it('throws on invalid roundingMode', () => { - throws(() => earlier.until(later, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P32M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'P973DT4H'], - ['minutes', 'P973DT4H17M'], - ['seconds', 'P973DT4H17M5S'], - ['milliseconds', 'P973DT4H17M4.864S'], - ['microseconds', 'P973DT4H17M4.864198S'], - ['nanoseconds', 'P973DT4H17M4.864197532S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P32M', '-P31M'], - ['weeks', 'P140W', '-P139W'], - ['days', 'P974D', '-P973D'], - ['hours', 'P973DT5H', '-P973DT4H'], - ['minutes', 'P973DT4H18M', '-P973DT4H17M'], - ['seconds', 'P973DT4H17M5S', '-P973DT4H17M4S'], - ['milliseconds', 'P973DT4H17M4.865S', '-P973DT4H17M4.864S'], - ['microseconds', 'P973DT4H17M4.864198S', '-P973DT4H17M4.864197S'], - ['nanoseconds', 'P973DT4H17M4.864197532S', '-P973DT4H17M4.864197532S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P31M', '-P32M'], - ['weeks', 'P139W', '-P140W'], - ['days', 'P973D', '-P974D'], - ['hours', 'P973DT4H', '-P973DT5H'], - ['minutes', 'P973DT4H17M', '-P973DT4H18M'], - ['seconds', 'P973DT4H17M4S', '-P973DT4H17M5S'], - ['milliseconds', 'P973DT4H17M4.864S', '-P973DT4H17M4.865S'], - ['microseconds', 'P973DT4H17M4.864197S', '-P973DT4H17M4.864198S'], - ['nanoseconds', 'P973DT4H17M4.864197532S', '-P973DT4H17M4.864197532S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P31M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'P973DT4H'], - ['minutes', 'P973DT4H17M'], - ['seconds', 'P973DT4H17M4S'], - ['milliseconds', 'P973DT4H17M4.864S'], - ['microseconds', 'P973DT4H17M4.864197S'], - ['nanoseconds', 'P973DT4H17M4.864197532S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${earlier.until(later, { smallestUnit: 'minutes' })}`, 'P973DT4H17M'); - equal(`${earlier.until(later, { smallestUnit: 'seconds' })}`, 'P973DT4H17M4S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 3, roundingMode: 'halfExpand' })}`, - 'P973DT3H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 30, roundingMode: 'halfExpand' })}`, - 'P973DT4H30M' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 15, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M4.86S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M4.8642S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M4.86419753S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { smallestUnit: 'hours', roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 1000 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 1000 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), RangeError); - }); - it('accepts singular units', () => { - equal(`${earlier.until(later, { largestUnit: 'year' })}`, `${earlier.until(later, { largestUnit: 'years' })}`); - equal(`${earlier.until(later, { smallestUnit: 'year' })}`, `${earlier.until(later, { smallestUnit: 'years' })}`); - equal(`${earlier.until(later, { largestUnit: 'month' })}`, `${earlier.until(later, { largestUnit: 'months' })}`); - equal( - `${earlier.until(later, { smallestUnit: 'month' })}`, - `${earlier.until(later, { smallestUnit: 'months' })}` - ); - equal(`${earlier.until(later, { largestUnit: 'day' })}`, `${earlier.until(later, { largestUnit: 'days' })}`); - equal(`${earlier.until(later, { smallestUnit: 'day' })}`, `${earlier.until(later, { smallestUnit: 'days' })}`); - equal(`${earlier.until(later, { largestUnit: 'hour' })}`, `${earlier.until(later, { largestUnit: 'hours' })}`); - equal(`${earlier.until(later, { smallestUnit: 'hour' })}`, `${earlier.until(later, { smallestUnit: 'hours' })}`); - equal( - `${earlier.until(later, { largestUnit: 'minute' })}`, - `${earlier.until(later, { largestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'minute' })}`, - `${earlier.until(later, { smallestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'second' })}`, - `${earlier.until(later, { largestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'second' })}`, - `${earlier.until(later, { smallestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'millisecond' })}`, - `${earlier.until(later, { largestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'millisecond' })}`, - `${earlier.until(later, { smallestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'microsecond' })}`, - `${earlier.until(later, { largestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'microsecond' })}`, - `${earlier.until(later, { smallestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'nanosecond' })}`, - `${earlier.until(later, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'nanosecond' })}`, - `${earlier.until(later, { smallestUnit: 'nanoseconds' })}` - ); - }); - it('rounds relative to the receiver', () => { - const dt1 = PlainDateTime.from('2019-01-01'); - const dt2 = PlainDateTime.from('2020-07-02'); - equal(`${dt1.until(dt2, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P2Y'); - equal(`${dt2.until(dt1, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, '-P1Y'); - }); - }); - describe('DateTime.since()', () => { - const dt = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - it('dt.since(earlier) === earlier.until(dt)', () => { - const earlier = PlainDateTime.from({ year: 1966, month: 3, day: 3, hour: 18 }); - equal(`${dt.since(earlier)}`, `${earlier.until(dt)}`); - }); - it('casts argument', () => { - equal(`${dt.since({ year: 2019, month: 10, day: 29, hour: 10 })}`, '-P15684DT18H36M29.876543211S'); - equal(`${dt.since('2019-10-29T10:46:38.271986102')}`, '-P15684DT19H23M8.148529313S'); - }); - const feb20 = PlainDateTime.from('2020-02-01T00:00'); - const feb21 = PlainDateTime.from('2021-02-01T00:00'); - it('defaults to returning days', () => { - equal(`${feb21.since(feb20)}`, 'P366D'); - equal(`${feb21.since(feb20, { largestUnit: 'auto' })}`, 'P366D'); - equal(`${feb21.since(feb20, { largestUnit: 'days' })}`, 'P366D'); - equal(`${PlainDateTime.from('2021-02-01T00:00:00.000000001').since(feb20)}`, 'P366DT0.000000001S'); - equal(`${feb21.since(PlainDateTime.from('2020-02-01T00:00:00.000000001'))}`, 'P365DT23H59M59.999999999S'); - }); - it('can return lower or higher units', () => { - equal(`${feb21.since(feb20, { largestUnit: 'years' })}`, 'P1Y'); - equal(`${feb21.since(feb20, { largestUnit: 'months' })}`, 'P12M'); - equal(`${feb21.since(feb20, { largestUnit: 'hours' })}`, 'PT8784H'); - equal(`${feb21.since(feb20, { largestUnit: 'minutes' })}`, 'PT527040M'); - equal(`${feb21.since(feb20, { largestUnit: 'seconds' })}`, 'PT31622400S'); - }); - it('can return subseconds', () => { - const later = feb20.add({ days: 1, milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = later.since(feb20, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 86400250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = later.since(feb20, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 86400250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = later.since(feb20, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 86400250250250); - }); - it('does not include higher units than necessary', () => { - const lastFeb20 = PlainDateTime.from('2020-02-29T00:00'); - const lastFeb21 = PlainDateTime.from('2021-02-28T00:00'); - equal(`${lastFeb21.since(lastFeb20)}`, 'P365D'); - equal(`${lastFeb21.since(lastFeb20, { largestUnit: 'months' })}`, 'P11M28D'); - equal(`${lastFeb21.since(lastFeb20, { largestUnit: 'years' })}`, 'P11M28D'); - }); - it('weeks and months are mutually exclusive', () => { - const laterDateTime = dt.add({ days: 42, hours: 3 }); - const weeksDifference = laterDateTime.since(dt, { largestUnit: 'weeks' }); - notEqual(weeksDifference.weeks, 0); - equal(weeksDifference.months, 0); - const monthsDifference = laterDateTime.since(dt, { largestUnit: 'months' }); - equal(monthsDifference.weeks, 0); - notEqual(monthsDifference.months, 0); - }); - it('no two different calendars', () => { - const dt1 = new PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0); - const dt2 = new PlainDateTime(2000, 1, 1, 0, 0, 0, 0, 0, 0, Temporal.Calendar.from('japanese')); - throws(() => dt1.since(dt2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb21.since(feb20, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb21.since(feb20, options)}`, 'P366D')); - }); - const earlier = PlainDateTime.from('2019-01-08T08:22:36.123456789'); - const later = PlainDateTime.from('2021-09-07T12:39:40.987654321'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'nonsense'].forEach((smallestUnit) => { - throws(() => later.since(earlier, { smallestUnit }), RangeError); - }); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = [ - 'years', - 'months', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ]; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => later.since(earlier, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than days', () => { - equal(`${later.since(earlier, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P3Y'); - equal(`${later.since(earlier, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P32M'); - equal(`${later.since(earlier, { smallestUnit: 'weeks', roundingMode: 'halfExpand' })}`, 'P139W'); - }); - it('throws on invalid roundingMode', () => { - throws(() => later.since(earlier, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P32M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'P973DT4H'], - ['minutes', 'P973DT4H17M'], - ['seconds', 'P973DT4H17M5S'], - ['milliseconds', 'P973DT4H17M4.864S'], - ['microseconds', 'P973DT4H17M4.864198S'], - ['nanoseconds', 'P973DT4H17M4.864197532S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P32M', '-P31M'], - ['weeks', 'P140W', '-P139W'], - ['days', 'P974D', '-P973D'], - ['hours', 'P973DT5H', '-P973DT4H'], - ['minutes', 'P973DT4H18M', '-P973DT4H17M'], - ['seconds', 'P973DT4H17M5S', '-P973DT4H17M4S'], - ['milliseconds', 'P973DT4H17M4.865S', '-P973DT4H17M4.864S'], - ['microseconds', 'P973DT4H17M4.864198S', '-P973DT4H17M4.864197S'], - ['nanoseconds', 'P973DT4H17M4.864197532S', '-P973DT4H17M4.864197532S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P31M', '-P32M'], - ['weeks', 'P139W', '-P140W'], - ['days', 'P973D', '-P974D'], - ['hours', 'P973DT4H', '-P973DT5H'], - ['minutes', 'P973DT4H17M', '-P973DT4H18M'], - ['seconds', 'P973DT4H17M4S', '-P973DT4H17M5S'], - ['milliseconds', 'P973DT4H17M4.864S', '-P973DT4H17M4.865S'], - ['microseconds', 'P973DT4H17M4.864197S', '-P973DT4H17M4.864198S'], - ['nanoseconds', 'P973DT4H17M4.864197532S', '-P973DT4H17M4.864197532S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P31M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'P973DT4H'], - ['minutes', 'P973DT4H17M'], - ['seconds', 'P973DT4H17M4S'], - ['milliseconds', 'P973DT4H17M4.864S'], - ['microseconds', 'P973DT4H17M4.864197S'], - ['nanoseconds', 'P973DT4H17M4.864197532S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${later.since(earlier, { smallestUnit: 'minutes' })}`, 'P973DT4H17M'); - equal(`${later.since(earlier, { smallestUnit: 'seconds' })}`, 'P973DT4H17M4S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 3, roundingMode: 'halfExpand' })}`, - 'P973DT3H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 30, roundingMode: 'halfExpand' })}`, - 'P973DT4H30M' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 15, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M4.86S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M4.8642S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'P973DT4H17M4.86419753S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { smallestUnit: 'hours', roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 1000 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 1000 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), RangeError); - }); - it('accepts singular units', () => { - equal(`${later.since(earlier, { largestUnit: 'year' })}`, `${later.since(earlier, { largestUnit: 'years' })}`); - equal(`${later.since(earlier, { smallestUnit: 'year' })}`, `${later.since(earlier, { smallestUnit: 'years' })}`); - equal(`${later.since(earlier, { largestUnit: 'month' })}`, `${later.since(earlier, { largestUnit: 'months' })}`); - equal( - `${later.since(earlier, { smallestUnit: 'month' })}`, - `${later.since(earlier, { smallestUnit: 'months' })}` - ); - equal(`${later.since(earlier, { largestUnit: 'day' })}`, `${later.since(earlier, { largestUnit: 'days' })}`); - equal(`${later.since(earlier, { smallestUnit: 'day' })}`, `${later.since(earlier, { smallestUnit: 'days' })}`); - equal(`${later.since(earlier, { largestUnit: 'hour' })}`, `${later.since(earlier, { largestUnit: 'hours' })}`); - equal(`${later.since(earlier, { smallestUnit: 'hour' })}`, `${later.since(earlier, { smallestUnit: 'hours' })}`); - equal( - `${later.since(earlier, { largestUnit: 'minute' })}`, - `${later.since(earlier, { largestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'minute' })}`, - `${later.since(earlier, { smallestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'second' })}`, - `${later.since(earlier, { largestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'second' })}`, - `${later.since(earlier, { smallestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'millisecond' })}`, - `${later.since(earlier, { largestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'millisecond' })}`, - `${later.since(earlier, { smallestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'microsecond' })}`, - `${later.since(earlier, { largestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'microsecond' })}`, - `${later.since(earlier, { smallestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'nanosecond' })}`, - `${later.since(earlier, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'nanosecond' })}`, - `${later.since(earlier, { smallestUnit: 'nanoseconds' })}` - ); - }); - it('rounds relative to the receiver', () => { - const dt1 = PlainDateTime.from('2019-01-01'); - const dt2 = PlainDateTime.from('2020-07-02'); - equal(`${dt2.since(dt1, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P1Y'); - equal(`${dt1.since(dt2, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, '-P2Y'); - }); - }); - describe('DateTime.round works', () => { - const dt = PlainDateTime.from('1976-11-18T14:23:30.123456789'); - it('throws without parameter', () => { - throws(() => dt.round(), TypeError); - }); - it('throws without required smallestUnit parameter', () => { - throws(() => dt.round({}), RangeError); - throws(() => dt.round({ roundingIncrement: 1, roundingMode: 'ceil' }), RangeError); - }); - it('throws on disallowed or invalid smallestUnit (object param)', () => { - ['era', 'year', 'month', 'week', 'years', 'months', 'weeks', 'nonsense'].forEach((smallestUnit) => { - throws(() => dt.round({ smallestUnit }), RangeError); - }); - }); - it('throws on disallowed or invalid smallestUnit (string param)', () => { - ['era', 'year', 'month', 'week', 'years', 'months', 'weeks', 'nonsense'].forEach((smallestUnit) => { - throws(() => dt.round(smallestUnit), RangeError); - }); - }); - it('throws on invalid roundingMode', () => { - throws(() => dt.round({ smallestUnit: 'second', roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['day', '1976-11-19T00:00:00'], - ['hour', '1976-11-18T14:00:00'], - ['minute', '1976-11-18T14:24:00'], - ['second', '1976-11-18T14:23:30'], - ['millisecond', '1976-11-18T14:23:30.123'], - ['microsecond', '1976-11-18T14:23:30.123457'], - ['nanosecond', '1976-11-18T14:23:30.123456789'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - it(`rounds to nearest ${smallestUnit}`, () => - equal(`${dt.round({ smallestUnit, roundingMode: 'halfExpand' })}`, expected)); - }); - const incrementOneCeil = [ - ['day', '1976-11-19T00:00:00'], - ['hour', '1976-11-18T15:00:00'], - ['minute', '1976-11-18T14:24:00'], - ['second', '1976-11-18T14:23:31'], - ['millisecond', '1976-11-18T14:23:30.124'], - ['microsecond', '1976-11-18T14:23:30.123457'], - ['nanosecond', '1976-11-18T14:23:30.123456789'] - ]; - incrementOneCeil.forEach(([smallestUnit, expected]) => { - it(`rounds up to ${smallestUnit}`, () => equal(`${dt.round({ smallestUnit, roundingMode: 'ceil' })}`, expected)); - }); - const incrementOneFloor = [ - ['day', '1976-11-18T00:00:00'], - ['hour', '1976-11-18T14:00:00'], - ['minute', '1976-11-18T14:23:00'], - ['second', '1976-11-18T14:23:30'], - ['millisecond', '1976-11-18T14:23:30.123'], - ['microsecond', '1976-11-18T14:23:30.123456'], - ['nanosecond', '1976-11-18T14:23:30.123456789'] - ]; - incrementOneFloor.forEach(([smallestUnit, expected]) => { - it(`rounds down to ${smallestUnit}`, () => - equal(`${dt.round({ smallestUnit, roundingMode: 'floor' })}`, expected)); - it(`truncates to ${smallestUnit}`, () => equal(`${dt.round({ smallestUnit, roundingMode: 'trunc' })}`, expected)); - }); - it('halfExpand is the default', () => { - equal(`${dt.round({ smallestUnit: 'minute' })}`, '1976-11-18T14:24:00'); - equal(`${dt.round({ smallestUnit: 'second' })}`, '1976-11-18T14:23:30'); - }); - it('rounding down is towards the Big Bang, not towards 1 BCE', () => { - const dt2 = PlainDateTime.from('-000099-12-15T12:00:00.5'); - const smallestUnit = 'second'; - equal(`${dt2.round({ smallestUnit, roundingMode: 'ceil' })}`, '-000099-12-15T12:00:01'); - equal(`${dt2.round({ smallestUnit, roundingMode: 'floor' })}`, '-000099-12-15T12:00:00'); - equal(`${dt2.round({ smallestUnit, roundingMode: 'trunc' })}`, '-000099-12-15T12:00:00'); - equal(`${dt2.round({ smallestUnit, roundingMode: 'halfExpand' })}`, '-000099-12-15T12:00:01'); - }); - it('rounds to an increment of hours', () => { - equal(`${dt.round({ smallestUnit: 'hour', roundingIncrement: 4 })}`, '1976-11-18T16:00:00'); - }); - it('rounds to an increment of minutes', () => { - equal(`${dt.round({ smallestUnit: 'minute', roundingIncrement: 15 })}`, '1976-11-18T14:30:00'); - }); - it('rounds to an increment of seconds', () => { - equal(`${dt.round({ smallestUnit: 'second', roundingIncrement: 30 })}`, '1976-11-18T14:23:30'); - }); - it('rounds to an increment of milliseconds', () => { - equal(`${dt.round({ smallestUnit: 'millisecond', roundingIncrement: 10 })}`, '1976-11-18T14:23:30.12'); - }); - it('rounds to an increment of microseconds', () => { - equal(`${dt.round({ smallestUnit: 'microsecond', roundingIncrement: 10 })}`, '1976-11-18T14:23:30.12346'); - }); - it('rounds to an increment of nanoseconds', () => { - equal(`${dt.round({ smallestUnit: 'nanosecond', roundingIncrement: 10 })}`, '1976-11-18T14:23:30.12345679'); - }); - it('1 day is a valid increment', () => { - equal(`${dt.round({ smallestUnit: 'day', roundingIncrement: 1 })}`, '1976-11-19T00:00:00'); - }); - it('valid hour increments divide into 24', () => { - const smallestUnit = 'hour'; - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - assert(dt.round({ smallestUnit, roundingIncrement }) instanceof PlainDateTime); - }); - }); - ['minute', 'second'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - assert(dt.round({ smallestUnit, roundingIncrement }) instanceof PlainDateTime); - }); - }); - }); - ['millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - assert(dt.round({ smallestUnit, roundingIncrement }) instanceof PlainDateTime); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => dt.round({ smallestUnit: 'day', roundingIncrement: 29 }), RangeError); - throws(() => dt.round({ smallestUnit: 'hour', roundingIncrement: 29 }), RangeError); - throws(() => dt.round({ smallestUnit: 'minute', roundingIncrement: 29 }), RangeError); - throws(() => dt.round({ smallestUnit: 'second', roundingIncrement: 29 }), RangeError); - throws(() => dt.round({ smallestUnit: 'millisecond', roundingIncrement: 29 }), RangeError); - throws(() => dt.round({ smallestUnit: 'microsecond', roundingIncrement: 29 }), RangeError); - throws(() => dt.round({ smallestUnit: 'nanosecond', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => dt.round({ smallestUnit: 'hour', roundingIncrement: 24 }), RangeError); - throws(() => dt.round({ smallestUnit: 'minute', roundingIncrement: 60 }), RangeError); - throws(() => dt.round({ smallestUnit: 'second', roundingIncrement: 60 }), RangeError); - throws(() => dt.round({ smallestUnit: 'millisecond', roundingIncrement: 1000 }), RangeError); - throws(() => dt.round({ smallestUnit: 'microsecond', roundingIncrement: 1000 }), RangeError); - throws(() => dt.round({ smallestUnit: 'nanosecond', roundingIncrement: 1000 }), RangeError); - }); - const bal = PlainDateTime.from('1976-11-18T23:59:59.999999999'); - ['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond'].forEach((smallestUnit) => { - it(`balances to next ${smallestUnit}`, () => { - equal(`${bal.round({ smallestUnit })}`, '1976-11-19T00:00:00'); - }); - }); - it('accepts plural units', () => { - ['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(dt.round({ smallestUnit }).equals(dt.round({ smallestUnit: `${smallestUnit}s` }))); - }); - }); - it('accepts string parameter as shortcut for {smallestUnit}', () => { - ['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(dt.round(smallestUnit).equals(dt.round({ smallestUnit }))); - }); - }); - }); - describe('DateTime.from() works', () => { - it('DateTime.from("1976-11-18 15:23:30")', () => - equal(`${PlainDateTime.from('1976-11-18 15:23:30')}`, '1976-11-18T15:23:30')); - it('DateTime.from("1976-11-18 15:23:30.001")', () => - equal(`${PlainDateTime.from('1976-11-18 15:23:30.001')}`, '1976-11-18T15:23:30.001')); - it('DateTime.from("1976-11-18 15:23:30.001123")', () => - equal(`${PlainDateTime.from('1976-11-18 15:23:30.001123')}`, '1976-11-18T15:23:30.001123')); - it('DateTime.from("1976-11-18 15:23:30.001123456")', () => - equal(`${PlainDateTime.from('1976-11-18 15:23:30.001123456')}`, '1976-11-18T15:23:30.001123456')); - it('DateTime.from(1976-11-18) is not the same object', () => { - const orig = new PlainDateTime(1976, 11, 18, 15, 23, 20, 123, 456, 789); - const actual = PlainDateTime.from(orig); - notEqual(actual, orig); - }); - it('DateTime.from({ year: 1976, month: 11, day: 18 }) == 1976-11-18T00:00:00', () => - equal(`${PlainDateTime.from({ year: 1976, month: 11, monthCode: 'M11', day: 18 })}`, '1976-11-18T00:00:00')); - it('can be constructed with month and without monthCode', () => - equal(`${PlainDateTime.from({ year: 1976, month: 11, day: 18 })}`, '1976-11-18T00:00:00')); - it('can be constructed with monthCode and without month', () => - equal(`${PlainDateTime.from({ year: 1976, monthCode: 'M11', day: 18 })}`, '1976-11-18T00:00:00')); - it('month and monthCode must agree', () => - throws(() => PlainDateTime.from({ year: 1976, month: 11, monthCode: 'M12', day: 18 }), RangeError)); - it('DateTime.from({ year: 1976, month: 11, day: 18, millisecond: 123 }) == 1976-11-18T00:00:00.123', () => - equal(`${PlainDateTime.from({ year: 1976, month: 11, day: 18, millisecond: 123 })}`, '1976-11-18T00:00:00.123')); - it('DateTime.from({ year: 1976, day: 18, hour: 15, minute: 23, second: 30, millisecond: 123 }) throws', () => - throws( - () => PlainDateTime.from({ year: 1976, day: 18, hour: 15, minute: 23, second: 30, millisecond: 123 }), - TypeError - )); - it('DateTime.from({}) throws', () => throws(() => PlainDateTime.from({}), TypeError)); - it('DateTime.from(required prop undefined) throws', () => - throws(() => PlainDateTime.from({ year: 1976, month: undefined, monthCode: undefined, day: 18 }), TypeError)); - it('DateTime.from(ISO string leap second) is constrained', () => { - equal(`${PlainDateTime.from('2016-12-31T23:59:60')}`, '2016-12-31T23:59:59'); - }); - it('DateTime.from(number) is converted to string', () => - assert(PlainDateTime.from(19761118).equals(PlainDateTime.from('19761118')))); - describe('Overflow', () => { - const bad = { year: 2019, month: 1, day: 32 }; - it('reject', () => throws(() => PlainDateTime.from(bad, { overflow: 'reject' }), RangeError)); - it('constrain', () => { - equal(`${PlainDateTime.from(bad)}`, '2019-01-31T00:00:00'); - equal(`${PlainDateTime.from(bad, { overflow: 'constrain' })}`, '2019-01-31T00:00:00'); - }); - it('throw when bad overflow', () => { - [new PlainDateTime(1976, 11, 18, 15, 23), { year: 2019, month: 1, day: 1 }, '2019-01-31T00:00'].forEach( - (input) => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainDateTime.from(input, { overflow }), RangeError) - ); - } - ); - }); - const leap = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 }; - it('reject leap second', () => throws(() => PlainDateTime.from(leap, { overflow: 'reject' }), RangeError)); - it('constrain leap second', () => equal(`${PlainDateTime.from(leap)}`, '2016-12-31T23:59:59')); - it('constrain has no effect on invalid ISO string', () => { - throws(() => PlainDateTime.from('2020-13-34T24:60', { overflow: 'constrain' }), RangeError); - }); - }); - it('Z not supported', () => { - throws(() => PlainDateTime.from('2019-10-01T09:00:00Z'), RangeError); - throws(() => PlainDateTime.from('2019-10-01T09:00:00Z[Europe/Berlin]'), RangeError); - }); - it('variant time separators', () => { - equal(`${PlainDateTime.from('1976-11-18t15:23')}`, '1976-11-18T15:23:00'); - equal(`${PlainDateTime.from('1976-11-18 15:23')}`, '1976-11-18T15:23:00'); - }); - it('any number of decimal places', () => { - equal(`${PlainDateTime.from('1976-11-18T15:23:30.1')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.12')}`, '1976-11-18T15:23:30.12'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.123')}`, '1976-11-18T15:23:30.123'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.1234')}`, '1976-11-18T15:23:30.1234'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.12345')}`, '1976-11-18T15:23:30.12345'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.123456')}`, '1976-11-18T15:23:30.123456'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.1234567')}`, '1976-11-18T15:23:30.1234567'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.12345678')}`, '1976-11-18T15:23:30.12345678'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.123456789')}`, '1976-11-18T15:23:30.123456789'); - }); - it('variant decimal separator', () => { - equal(`${PlainDateTime.from('1976-11-18T15:23:30,12')}`, '1976-11-18T15:23:30.12'); - }); - it('variant minus sign', () => { - equal(`${PlainDateTime.from('1976-11-18T15:23:30.12\u221202:00')}`, '1976-11-18T15:23:30.12'); - equal(`${PlainDateTime.from('\u2212009999-11-18T15:23:30.12')}`, '-009999-11-18T15:23:30.12'); - }); - it('mixture of basic and extended format', () => { - equal(`${PlainDateTime.from('1976-11-18T152330.1+00:00')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('19761118T15:23:30.1+00:00')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('1976-11-18T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('1976-11-18T152330.1+0000')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('19761118T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('19761118T152330.1+00:00')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('19761118T152330.1+0000')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('+001976-11-18T152330.1+00:00')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('+0019761118T15:23:30.1+00:00')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('+001976-11-18T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('+001976-11-18T152330.1+0000')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('+0019761118T15:23:30.1+0000')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('+0019761118T152330.1+00:00')}`, '1976-11-18T15:23:30.1'); - equal(`${PlainDateTime.from('+0019761118T152330.1+0000')}`, '1976-11-18T15:23:30.1'); - }); - it('optional parts', () => { - equal(`${PlainDateTime.from('1976-11-18T15:23:30+00')}`, '1976-11-18T15:23:30'); - equal(`${PlainDateTime.from('1976-11-18T15')}`, '1976-11-18T15:00:00'); - equal(`${PlainDateTime.from('1976-11-18')}`, '1976-11-18T00:00:00'); - }); - it('no junk at end of string', () => - throws(() => PlainDateTime.from('1976-11-18T15:23:30.123456789junk'), RangeError)); - it('ignores if a timezone is specified', () => - equal(`${PlainDateTime.from('2020-01-01T01:23:45[Asia/Kolkata]')}`, '2020-01-01T01:23:45')); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => PlainDateTime.from({ year: 1976, month: 11, day: 18 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${PlainDateTime.from({ year: 1976, month: 11, day: 18 }, options)}`, '1976-11-18T00:00:00') - ); - }); - it('object must contain at least the required correctly-spelled properties', () => { - throws(() => PlainDateTime.from({}), TypeError); - throws(() => PlainDateTime.from({ year: 1976, months: 11, day: 18 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${PlainDateTime.from({ year: 1976, month: 11, day: 18, hours: 12 })}`, '1976-11-18T00:00:00'); - }); - }); - describe('DateTime.toZonedDateTime()', () => { - it('works', () => { - const dt = Temporal.PlainDateTime.from('2020-01-01T00:00'); - const zdt = dt.toZonedDateTime('America/Los_Angeles'); - equal(zdt.toString(), '2020-01-01T00:00:00-08:00[America/Los_Angeles]'); - }); - it('works with disambiguation option', () => { - const dt = Temporal.PlainDateTime.from('2020-03-08T02:00'); - const zdt = dt.toZonedDateTime('America/Los_Angeles', { disambiguation: 'earlier' }); - equal(zdt.toString(), '2020-03-08T01:00:00-08:00[America/Los_Angeles]'); - }); - it('datetime with multiple instants - Fall DST in Brazil', () => { - const dt = PlainDateTime.from('2019-02-16T23:45'); - equal(`${dt.toZonedDateTime('America/Sao_Paulo')}`, '2019-02-16T23:45:00-02:00[America/Sao_Paulo]'); - equal( - `${dt.toZonedDateTime('America/Sao_Paulo', { disambiguation: 'compatible' })}`, - '2019-02-16T23:45:00-02:00[America/Sao_Paulo]' - ); - equal( - `${dt.toZonedDateTime('America/Sao_Paulo', { disambiguation: 'earlier' })}`, - '2019-02-16T23:45:00-02:00[America/Sao_Paulo]' - ); - equal( - `${dt.toZonedDateTime('America/Sao_Paulo', { disambiguation: 'later' })}`, - '2019-02-16T23:45:00-03:00[America/Sao_Paulo]' - ); - throws(() => dt.toZonedDateTime('America/Sao_Paulo', { disambiguation: 'reject' }), RangeError); - }); - it('datetime with multiple instants - Spring DST in Los Angeles', () => { - const dt = PlainDateTime.from('2020-03-08T02:30'); - equal(`${dt.toZonedDateTime('America/Los_Angeles')}`, '2020-03-08T03:30:00-07:00[America/Los_Angeles]'); - equal( - `${dt.toZonedDateTime('America/Los_Angeles', { disambiguation: 'compatible' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - equal( - `${dt.toZonedDateTime('America/Los_Angeles', { disambiguation: 'earlier' })}`, - '2020-03-08T01:30:00-08:00[America/Los_Angeles]' - ); - equal( - `${dt.toZonedDateTime('America/Los_Angeles', { disambiguation: 'later' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - throws(() => dt.toZonedDateTime('America/Los_Angeles', { disambiguation: 'reject' }), RangeError); - }); - it('outside of Instant range', () => { - const max = Temporal.PlainDateTime.from('+275760-09-13T23:59:59.999999999'); - throws(() => max.toZonedDateTime('America/Godthab'), RangeError); - }); - it('throws on bad disambiguation', () => { - ['', 'EARLIER', 'xyz', 3, null].forEach((disambiguation) => - throws(() => PlainDateTime.from('2019-10-29T10:46').toZonedDateTime('UTC', { disambiguation }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - const dt = PlainDateTime.from('2019-10-29T10:46:38.271986102'); - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => dt.toZonedDateTime('America/Sao_Paulo', badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal( - `${dt.toZonedDateTime('America/Sao_Paulo', options)}`, - '2019-10-29T10:46:38.271986102-03:00[America/Sao_Paulo]' - ) - ); - }); - }); - describe('Min/max range', () => { - it('constructing from numbers', () => { - throws(() => new PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 0), RangeError); - throws(() => new PlainDateTime(275760, 9, 14, 0, 0, 0, 0, 0, 0), RangeError); - equal(`${new PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1)}`, '-271821-04-19T00:00:00.000000001'); - equal(`${new PlainDateTime(275760, 9, 13, 23, 59, 59, 999, 999, 999)}`, '+275760-09-13T23:59:59.999999999'); - }); - it('constructing from property bag', () => { - const tooEarly = { year: -271821, month: 4, day: 19 }; - const tooLate = { year: 275760, month: 9, day: 14 }; - ['reject', 'constrain'].forEach((overflow) => { - [tooEarly, tooLate].forEach((props) => { - throws(() => PlainDateTime.from(props, { overflow }), RangeError); - }); - }); - equal( - `${PlainDateTime.from({ year: -271821, month: 4, day: 19, nanosecond: 1 })}`, - '-271821-04-19T00:00:00.000000001' - ); - equal( - `${PlainDateTime.from({ - year: 275760, - month: 9, - day: 13, - hour: 23, - minute: 59, - second: 59, - millisecond: 999, - microsecond: 999, - nanosecond: 999 - })}`, - '+275760-09-13T23:59:59.999999999' - ); - }); - it('constructing from ISO string', () => { - ['reject', 'constrain'].forEach((overflow) => { - ['-271821-04-19T00:00', '+275760-09-14T00:00'].forEach((str) => { - throws(() => PlainDateTime.from(str, { overflow }), RangeError); - }); - }); - equal(`${PlainDateTime.from('-271821-04-19T00:00:00.000000001')}`, '-271821-04-19T00:00:00.000000001'); - equal(`${PlainDateTime.from('+275760-09-13T23:59:59.999999999')}`, '+275760-09-13T23:59:59.999999999'); - }); - it('converting from Instant', () => { - const min = Temporal.Instant.from('-271821-04-20T00:00Z'); - const offsetMin = Temporal.TimeZone.from('-23:59'); - equal(`${offsetMin.getPlainDateTimeFor(min, 'iso8601')}`, '-271821-04-19T00:01:00'); - const max = Temporal.Instant.from('+275760-09-13T00:00Z'); - const offsetMax = Temporal.TimeZone.from('+23:59'); - equal(`${offsetMax.getPlainDateTimeFor(max, 'iso8601')}`, '+275760-09-13T23:59:00'); - }); - it('converting from Date and Time', () => { - const midnight = Temporal.PlainTime.from('00:00'); - const firstNs = Temporal.PlainTime.from('00:00:00.000000001'); - const lastNs = Temporal.PlainTime.from('23:59:59.999999999'); - const min = Temporal.PlainDate.from('-271821-04-19'); - const max = Temporal.PlainDate.from('+275760-09-13'); - throws(() => min.toPlainDateTime(midnight), RangeError); - throws(() => midnight.toPlainDateTime(min), RangeError); - equal(`${min.toPlainDateTime(firstNs)}`, '-271821-04-19T00:00:00.000000001'); - equal(`${firstNs.toPlainDateTime(min)}`, '-271821-04-19T00:00:00.000000001'); - equal(`${max.toPlainDateTime(lastNs)}`, '+275760-09-13T23:59:59.999999999'); - equal(`${lastNs.toPlainDateTime(max)}`, '+275760-09-13T23:59:59.999999999'); - }); - it('adding and subtracting beyond limit', () => { - const min = PlainDateTime.from('-271821-04-19T00:00:00.000000001'); - const max = PlainDateTime.from('+275760-09-13T23:59:59.999999999'); - ['reject', 'constrain'].forEach((overflow) => { - throws(() => min.subtract({ nanoseconds: 1 }, { overflow }), RangeError); - throws(() => max.add({ nanoseconds: 1 }, { overflow }), RangeError); - }); - }); - it('rounding beyond limit', () => { - const min = PlainDateTime.from('-271821-04-19T00:00:00.000000001'); - const max = PlainDateTime.from('+275760-09-13T23:59:59.999999999'); - ['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond'].forEach((smallestUnit) => { - throws(() => min.round({ smallestUnit, roundingMode: 'floor' }), RangeError); - throws(() => max.round({ smallestUnit, roundingMode: 'ceil' }), RangeError); - }); - }); - }); - describe('dateTime.getISOFields() works', () => { - const dt1 = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - const fields = dt1.getISOFields(); - it('fields', () => { - equal(fields.isoYear, 1976); - equal(fields.isoMonth, 11); - equal(fields.isoDay, 18); - equal(fields.isoHour, 15); - equal(fields.isoMinute, 23); - equal(fields.isoSecond, 30); - equal(fields.isoMillisecond, 123); - equal(fields.isoMicrosecond, 456); - equal(fields.isoNanosecond, 789); - equal(fields.calendar.id, 'iso8601'); - }); - it('enumerable', () => { - const fields2 = { ...fields }; - equal(fields2.isoYear, 1976); - equal(fields2.isoMonth, 11); - equal(fields2.isoDay, 18); - equal(fields2.isoHour, 15); - equal(fields2.isoMinute, 23); - equal(fields2.isoSecond, 30); - equal(fields2.isoMillisecond, 123); - equal(fields2.isoMicrosecond, 456); - equal(fields2.isoNanosecond, 789); - equal(fields2.calendar, fields.calendar); - }); - it('as input to constructor', () => { - const dt2 = new PlainDateTime( - fields.isoYear, - fields.isoMonth, - fields.isoDay, - fields.isoHour, - fields.isoMinute, - fields.isoSecond, - fields.isoMillisecond, - fields.isoMicrosecond, - fields.isoNanosecond, - fields.calendar - ); - assert(dt2.equals(dt1)); - }); - }); - describe('dateTime.withCalendar()', () => { - const dt1 = PlainDateTime.from('1976-11-18T15:23:30.123456789'); - it('works', () => { - const calendar = Temporal.Calendar.from('iso8601'); - equal(`${dt1.withCalendar(calendar)}`, '1976-11-18T15:23:30.123456789'); - }); - it('casts its argument', () => { - equal(`${dt1.withCalendar('iso8601')}`, '1976-11-18T15:23:30.123456789'); - }); - }); - describe('dateTime.toString()', () => { - const dt1 = PlainDateTime.from('1976-11-18T15:23'); - const dt2 = PlainDateTime.from('1976-11-18T15:23:30'); - const dt3 = PlainDateTime.from('1976-11-18T15:23:30.1234'); - it('default is to emit seconds and drop trailing zeros after the decimal', () => { - equal(dt1.toString(), '1976-11-18T15:23:00'); - equal(dt2.toString(), '1976-11-18T15:23:30'); - equal(dt3.toString(), '1976-11-18T15:23:30.1234'); - }); - it('shows only non-ISO calendar if calendarName = auto', () => { - equal(dt1.toString({ calendarName: 'auto' }), '1976-11-18T15:23:00'); - equal(dt1.withCalendar('gregory').toString({ calendarName: 'auto' }), '1976-11-18T15:23:00[u-ca=gregory]'); - }); - it('shows ISO calendar if calendarName = always', () => { - equal(dt1.toString({ calendarName: 'always' }), '1976-11-18T15:23:00[u-ca=iso8601]'); - }); - it('omits non-ISO calendar if calendarName = never', () => { - equal(dt1.withCalendar('gregory').toString({ calendarName: 'never' }), '1976-11-18T15:23:00'); - }); - it('default is calendar = auto', () => { - equal(dt1.toString(), '1976-11-18T15:23:00'); - equal(dt1.withCalendar('gregory').toString(), '1976-11-18T15:23:00[u-ca=gregory]'); - }); - it('throws on invalid calendar', () => { - ['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => { - throws(() => dt1.toString({ calendarName }), RangeError); - }); - }); - it('truncates to minute', () => { - [dt1, dt2, dt3].forEach((dt) => equal(dt.toString({ smallestUnit: 'minute' }), '1976-11-18T15:23')); - }); - it('other smallestUnits are aliases for fractional digits', () => { - equal(dt3.toString({ smallestUnit: 'second' }), dt3.toString({ fractionalSecondDigits: 0 })); - equal(dt3.toString({ smallestUnit: 'millisecond' }), dt3.toString({ fractionalSecondDigits: 3 })); - equal(dt3.toString({ smallestUnit: 'microsecond' }), dt3.toString({ fractionalSecondDigits: 6 })); - equal(dt3.toString({ smallestUnit: 'nanosecond' }), dt3.toString({ fractionalSecondDigits: 9 })); - }); - it('throws on invalid or disallowed smallestUnit', () => { - ['era', 'year', 'month', 'day', 'hour', 'nonsense'].forEach((smallestUnit) => - throws(() => dt1.toString({ smallestUnit }), RangeError) - ); - }); - it('accepts plural units', () => { - equal(dt3.toString({ smallestUnit: 'minutes' }), dt3.toString({ smallestUnit: 'minute' })); - equal(dt3.toString({ smallestUnit: 'seconds' }), dt3.toString({ smallestUnit: 'second' })); - equal(dt3.toString({ smallestUnit: 'milliseconds' }), dt3.toString({ smallestUnit: 'millisecond' })); - equal(dt3.toString({ smallestUnit: 'microseconds' }), dt3.toString({ smallestUnit: 'microsecond' })); - equal(dt3.toString({ smallestUnit: 'nanoseconds' }), dt3.toString({ smallestUnit: 'nanosecond' })); - }); - it('truncates or pads to 2 places', () => { - const options = { fractionalSecondDigits: 2 }; - equal(dt1.toString(options), '1976-11-18T15:23:00.00'); - equal(dt2.toString(options), '1976-11-18T15:23:30.00'); - equal(dt3.toString(options), '1976-11-18T15:23:30.12'); - }); - it('pads to 7 places', () => { - const options = { fractionalSecondDigits: 7 }; - equal(dt1.toString(options), '1976-11-18T15:23:00.0000000'); - equal(dt2.toString(options), '1976-11-18T15:23:30.0000000'); - equal(dt3.toString(options), '1976-11-18T15:23:30.1234000'); - }); - it('auto is the default', () => { - [dt1, dt2, dt3].forEach((dt) => equal(dt.toString({ fractionalSecondDigits: 'auto' }), dt.toString())); - }); - it('throws on out of range or invalid fractionalSecondDigits', () => { - [-1, 10, Infinity, NaN, 'not-auto'].forEach((fractionalSecondDigits) => - throws(() => dt1.toString({ fractionalSecondDigits }), RangeError) - ); - }); - it('accepts and truncates fractional fractionalSecondDigits', () => { - equal(dt3.toString({ fractionalSecondDigits: 5.5 }), '1976-11-18T15:23:30.12340'); - }); - it('smallestUnit overrides fractionalSecondDigits', () => { - equal(dt3.toString({ smallestUnit: 'minute', fractionalSecondDigits: 9 }), '1976-11-18T15:23'); - }); - it('throws on invalid roundingMode', () => { - throws(() => dt1.toString({ roundingMode: 'cile' }), RangeError); - }); - it('rounds to nearest', () => { - equal(dt2.toString({ smallestUnit: 'minute', roundingMode: 'halfExpand' }), '1976-11-18T15:24'); - equal(dt3.toString({ fractionalSecondDigits: 3, roundingMode: 'halfExpand' }), '1976-11-18T15:23:30.123'); - }); - it('rounds up', () => { - equal(dt2.toString({ smallestUnit: 'minute', roundingMode: 'ceil' }), '1976-11-18T15:24'); - equal(dt3.toString({ fractionalSecondDigits: 3, roundingMode: 'ceil' }), '1976-11-18T15:23:30.124'); - }); - it('rounds down', () => { - ['floor', 'trunc'].forEach((roundingMode) => { - equal(dt2.toString({ smallestUnit: 'minute', roundingMode }), '1976-11-18T15:23'); - equal(dt3.toString({ fractionalSecondDigits: 3, roundingMode }), '1976-11-18T15:23:30.123'); - }); - }); - it('rounding down is towards the Big Bang, not towards 1 BCE', () => { - const dt4 = PlainDateTime.from('-000099-12-15T12:00:00.5'); - equal(dt4.toString({ smallestUnit: 'second', roundingMode: 'floor' }), '-000099-12-15T12:00:00'); - }); - it('rounding can affect all units', () => { - const dt5 = PlainDateTime.from('1999-12-31T23:59:59.999999999'); - equal(dt5.toString({ fractionalSecondDigits: 8, roundingMode: 'halfExpand' }), '2000-01-01T00:00:00.00000000'); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => dt1.toString(badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(dt1.toString(options), '1976-11-18T15:23:00')); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/plainMonthDay.js b/packages/temporal-polyfill/tests/plainMonthDay.js deleted file mode 100644 index 2b524586..00000000 --- a/packages/temporal-polyfill/tests/plainMonthDay.js +++ /dev/null @@ -1,348 +0,0 @@ - -import { assert } from 'chai'; -const { throws, strictEqual: equal, notStrictEqual: notEqual } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { PlainMonthDay } = Temporal; - -describe('MonthDay', () => { - describe('Structure', () => { - it('MonthDay is a Function', () => { - equal(typeof PlainMonthDay, 'function'); - }); - it('MonthDay has a prototype', () => { - assert(PlainMonthDay.prototype); - equal(typeof PlainMonthDay.prototype, 'object'); - }); - describe('MonthDay.prototype', () => { - it('MonthDay.prototype has monthCode', () => { - assert('monthCode' in PlainMonthDay.prototype); - }); - it('MonthDay.prototype.equals is a Function', () => { - equal(typeof PlainMonthDay.prototype.equals, 'function'); - }); - it('MonthDay.prototype.toString is a Function', () => { - equal(typeof PlainMonthDay.prototype.toString, 'function'); - }); - it('MonthDay.prototype.getISOFields is a Function', () => { - equal(typeof PlainMonthDay.prototype.getISOFields, 'function'); - }); - }); - }); - describe('Construction', () => { - it('Leap day', () => equal(`${new PlainMonthDay(2, 29)}`, '02-29')); - describe('.from()', () => { - it('MonthDay.from(10-01) == 10-01', () => equal(`${PlainMonthDay.from('10-01')}`, '10-01')); - it('Z not supported', () => { - throws(() => PlainMonthDay.from('2019-10-01T09:00:00Z'), RangeError); - }); - it("MonthDay.from('11-18') == (11-18)", () => equal(`${PlainMonthDay.from('11-18')}`, '11-18')); - it("MonthDay.from('1976-11-18') == (11-18)", () => equal(`${PlainMonthDay.from('1976-11-18')}`, '11-18')); - it('MonthDay.from({ monthCode: "M11", day: 18 }) == 11-18', () => - equal(`${PlainMonthDay.from({ monthCode: 'M11', day: 18 })}`, '11-18')); - it('ignores year when determining the ISO reference year from month/day', () => { - const one = PlainMonthDay.from({ year: 2019, month: 11, day: 18 }); - const two = PlainMonthDay.from({ year: 1979, month: 11, day: 18 }); - equal(one.getISOFields().isoYear, two.getISOFields().isoYear); - }); - it('ignores era/eraYear when determining the ISO reference year from month/day', () => { - const one = PlainMonthDay.from({ era: 'ce', eraYear: 2019, month: 11, day: 18, calendar: 'gregory' }); - const two = PlainMonthDay.from({ era: 'ce', eraYear: 1979, month: 11, day: 18, calendar: 'gregory' }); - equal(one.getISOFields().isoYear, two.getISOFields().isoYear); - }); - it('ignores year when determining the ISO reference year from monthCode/day', () => { - const one = PlainMonthDay.from({ year: 2019, monthCode: 'M11', day: 18 }); - const two = PlainMonthDay.from({ year: 1979, monthCode: 'M11', day: 18 }); - equal(one.getISOFields().isoYear, two.getISOFields().isoYear); - }); - it('ignores era/eraYear when determining the ISO reference year from monthCode/day', () => { - const one = PlainMonthDay.from({ era: 'ce', eraYear: 2019, monthCode: 'M11', day: 18, calendar: 'gregory' }); - const two = PlainMonthDay.from({ era: 'ce', eraYear: 1979, monthCode: 'M11', day: 18, calendar: 'gregory' }); - equal(one.getISOFields().isoYear, two.getISOFields().isoYear); - }); - it('MonthDay.from(11-18) is not the same object', () => { - const orig = new PlainMonthDay(11, 18); - const actu = PlainMonthDay.from(orig); - notEqual(actu, orig); - }); - it('ignores year when determining the ISO reference year from other Temporal object', () => { - const plainDate1 = Temporal.PlainDate.from('2019-11-18'); - const plainDate2 = Temporal.PlainDate.from('1976-11-18'); - const one = PlainMonthDay.from(plainDate1); - const two = PlainMonthDay.from(plainDate2); - equal(one.getISOFields().isoYear, two.getISOFields().isoYear); - }); - it('MonthDay.from({month, day}) allowed if calendar absent', () => - equal(`${PlainMonthDay.from({ month: 11, day: 18 })}`, '11-18')); - it('MonthDay.from({month, day}) not allowed in explicit ISO calendar', () => - throws(() => PlainMonthDay.from({ month: 11, day: 18, calendar: 'iso8601' }), TypeError)); - it('MonthDay.from({month, day}) not allowed in other calendar', () => - throws(() => PlainMonthDay.from({ month: 11, day: 18, calendar: 'gregory' }), TypeError)); - it('MonthDay.from({year, month, day}) allowed in other calendar', () => { - equal( - `${PlainMonthDay.from({ year: 1970, month: 11, day: 18, calendar: 'gregory' })}`, - '1972-11-18[u-ca=gregory]' - ); - }); - it('MonthDay.from({era, eraYear, month, day}) allowed in other calendar', () => { - equal( - `${PlainMonthDay.from({ era: 'ce', eraYear: 1970, month: 11, day: 18, calendar: 'gregory' })}`, - '1972-11-18[u-ca=gregory]' - ); - }); - it('MonthDay.from({ day: 15 }) throws', () => throws(() => PlainMonthDay.from({ day: 15 }), TypeError)); - it('MonthDay.from({ monthCode: "M12" }) throws', () => - throws(() => PlainMonthDay.from({ monthCode: 'M12' }), TypeError)); - it('MonthDay.from({}) throws', () => throws(() => PlainMonthDay.from({}), TypeError)); - it('MonthDay.from(required prop undefined) throws', () => - throws(() => PlainMonthDay.from({ monthCode: undefined, day: 15 }), TypeError)); - it('MonthDay.from(number) is converted to string', () => - assert(PlainMonthDay.from(1201).equals(PlainMonthDay.from('12-01')))); - it('basic format', () => { - equal(`${PlainMonthDay.from('1118')}`, '11-18'); - }); - it('mixture of basic and extended format', () => { - equal(`${PlainMonthDay.from('1976-11-18T152330.1+00:00')}`, '11-18'); - equal(`${PlainMonthDay.from('19761118T15:23:30.1+00:00')}`, '11-18'); - equal(`${PlainMonthDay.from('1976-11-18T15:23:30.1+0000')}`, '11-18'); - equal(`${PlainMonthDay.from('1976-11-18T152330.1+0000')}`, '11-18'); - equal(`${PlainMonthDay.from('19761118T15:23:30.1+0000')}`, '11-18'); - equal(`${PlainMonthDay.from('19761118T152330.1+00:00')}`, '11-18'); - equal(`${PlainMonthDay.from('19761118T152330.1+0000')}`, '11-18'); - equal(`${PlainMonthDay.from('+001976-11-18T152330.1+00:00')}`, '11-18'); - equal(`${PlainMonthDay.from('+0019761118T15:23:30.1+00:00')}`, '11-18'); - equal(`${PlainMonthDay.from('+001976-11-18T15:23:30.1+0000')}`, '11-18'); - equal(`${PlainMonthDay.from('+001976-11-18T152330.1+0000')}`, '11-18'); - equal(`${PlainMonthDay.from('+0019761118T15:23:30.1+0000')}`, '11-18'); - equal(`${PlainMonthDay.from('+0019761118T152330.1+00:00')}`, '11-18'); - equal(`${PlainMonthDay.from('+0019761118T152330.1+0000')}`, '11-18'); - }); - it('optional parts', () => { - equal(`${PlainMonthDay.from('1976-11-18T15:23')}`, '11-18'); - equal(`${PlainMonthDay.from('1976-11-18T15')}`, '11-18'); - equal(`${PlainMonthDay.from('1976-11-18')}`, '11-18'); - }); - it('RFC 3339 month-day syntax', () => { - equal(`${PlainMonthDay.from('--11-18')}`, '11-18'); - equal(`${PlainMonthDay.from('--1118')}`, '11-18'); - }); - it('ignores year when determining the ISO reference year from string', () => { - const one = PlainMonthDay.from('2019-11-18'); - const two = PlainMonthDay.from('1976-11-18'); - equal(one.getISOFields().isoYear, two.getISOFields().isoYear); - }); - it('no junk at end of string', () => throws(() => PlainMonthDay.from('11-18junk'), RangeError)); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => PlainMonthDay.from({ month: 11, day: 18 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${PlainMonthDay.from({ month: 11, day: 18 }, options)}`, '11-18') - ); - }); - describe('Overflow', () => { - const bad = { month: 1, day: 32 }; - it('reject', () => throws(() => PlainMonthDay.from(bad, { overflow: 'reject' }), RangeError)); - it('constrain', () => { - equal(`${PlainMonthDay.from(bad)}`, '01-31'); - equal(`${PlainMonthDay.from(bad, { overflow: 'constrain' })}`, '01-31'); - }); - it('throw on bad overflow', () => { - [new PlainMonthDay(11, 18), { month: 1, day: 1 }, '01-31'].forEach((input) => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainMonthDay.from(input, { overflow }), RangeError) - ); - }); - }); - it('constrain has no effect on invalid ISO string', () => { - throws(() => PlainMonthDay.from('13-34', { overflow: 'constrain' }), RangeError); - }); - }); - describe('Leap day', () => { - ['reject', 'constrain'].forEach((overflow) => - it(overflow, () => equal(`${PlainMonthDay.from({ month: 2, day: 29 }, { overflow })}`, '02-29')) - ); - it("rejects when year isn't a leap year", () => - throws(() => PlainMonthDay.from({ month: 2, day: 29, year: 2001 }, { overflow: 'reject' }), RangeError)); - it('constrains non-leap year', () => - equal(`${PlainMonthDay.from({ month: 2, day: 29, year: 2001 }, { overflow: 'constrain' })}`, '02-28')); - }); - describe('Leap day with calendar', () => { - it('requires year with calendar', () => - throws( - () => PlainMonthDay.from({ month: 2, day: 29, calendar: 'iso8601' }, { overflow: 'reject' }), - TypeError - )); - it('rejects leap day with non-leap year', () => - throws( - () => PlainMonthDay.from({ month: 2, day: 29, year: 2001, calendar: 'iso8601' }, { overflow: 'reject' }), - RangeError - )); - it('constrains leap day', () => - equal( - `${PlainMonthDay.from({ month: 2, day: 29, year: 2001, calendar: 'iso8601' }, { overflow: 'constrain' })}`, - '02-28' - )); - it('accepts leap day with monthCode', () => - equal( - `${PlainMonthDay.from({ monthCode: 'M02', day: 29, calendar: 'iso8601' }, { overflow: 'reject' })}`, - '02-29' - )); - }); - it('object must contain at least the required correctly-spelled properties', () => { - throws(() => PlainMonthDay.from({}), TypeError); - throws(() => PlainMonthDay.from({ months: 12, day: 31 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${PlainMonthDay.from({ month: 12, day: 1, days: 31 })}`, '12-01'); - }); - }); - describe('getters', () => { - let md = new PlainMonthDay(1, 15); - it("(1-15).monthCode === '1'", () => { - equal(md.monthCode, 'M01'); - }); - it("(1-15).day === '15'", () => { - equal(`${md.day}`, '15'); - }); - it('month is undefined', () => equal(md.month, undefined)); - }); - describe('.with()', () => { - const md = PlainMonthDay.from('01-22'); - it('with(12-)', () => equal(`${md.with({ monthCode: 'M12' })}`, '12-22')); - it('with(-15)', () => equal(`${md.with({ day: 15 })}`, '01-15')); - }); - }); - describe('MonthDay.with()', () => { - const md = PlainMonthDay.from('01-15'); - it('with({monthCode})', () => equal(`${md.with({ monthCode: 'M12' })}`, '12-15')); - it('with({month}) not accepted', () => { - throws(() => md.with({ month: 12 }), TypeError); - }); - it('with({month, monthCode}) accepted', () => equal(`${md.with({ month: 12, monthCode: 'M12' })}`, '12-15')); - it('month and monthCode must agree', () => { - throws(() => md.with({ month: 12, monthCode: 'M11' }), RangeError); - }); - it('with({year, month}) accepted', () => equal(`${md.with({ year: 2000, month: 12 })}`, '12-15')); - it('throws on bad overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => md.with({ day: 1 }, { overflow }), RangeError) - ); - }); - it('throws with calendar property', () => { - throws(() => md.with({ day: 1, calendar: 'iso8601' }), TypeError); - }); - it('throws with timeZone property', () => { - throws(() => md.with({ day: 1, timeZone: 'UTC' }), TypeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => md.with({ day: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${md.with({ day: 1 }, options)}`, '01-01')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => md.with({}), TypeError); - throws(() => md.with({ months: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${md.with({ monthCode: 'M12', days: 1 })}`, '12-15'); - }); - it('year is ignored when determining ISO reference year', () => { - equal(md.with({ year: 1900 }).getISOFields().isoYear, md.getISOFields().isoYear); - }); - }); - describe('MonthDay.equals()', () => { - const md1 = PlainMonthDay.from('01-22'); - const md2 = PlainMonthDay.from('12-15'); - it('equal', () => assert(md1.equals(md1))); - it('unequal', () => assert(!md1.equals(md2))); - it('casts argument', () => { - assert(md1.equals('01-22')); - assert(md1.equals({ month: 1, day: 22 })); - }); - it('object must contain at least the required properties', () => { - throws(() => md1.equals({ month: 1 }), TypeError); - }); - it('takes [[ISOYear]] into account', () => { - const iso = Temporal.Calendar.from('iso8601'); - const md1 = new PlainMonthDay(1, 1, iso, 1972); - const md2 = new PlainMonthDay(1, 1, iso, 2000); - assert(!md1.equals(md2)); - }); - }); - describe("Comparison operators don't work", () => { - const md1 = PlainMonthDay.from('02-13'); - const md1again = PlainMonthDay.from('02-13'); - const md2 = PlainMonthDay.from('11-18'); - it('=== is object equality', () => equal(md1, md1)); - it('!== is object equality', () => notEqual(md1, md1again)); - it('<', () => throws(() => md1 < md2)); - it('>', () => throws(() => md1 > md2)); - it('<=', () => throws(() => md1 <= md2)); - it('>=', () => throws(() => md1 >= md2)); - }); - describe('MonthDay.toPlainDate()', () => { - const md = PlainMonthDay.from('01-22'); - it("doesn't take a primitive argument", () => { - [2002, '2002', false, 2002n, Symbol('2002'), null].forEach((bad) => { - throws(() => md.toPlainDate(bad), TypeError); - }); - }); - it('takes an object argument with year property', () => { - equal(`${md.toPlainDate({ year: 2002 })}`, '2002-01-22'); - }); - it('needs at least a year property on the object in the ISO calendar', () => { - throws(() => md.toPlainDate({ something: 'nothing' }), TypeError); - }); - it("throws if the MonthDay doesn't exist in the year", () => { - const leapDay = PlainMonthDay.from('02-29'); - throws(() => leapDay.toPlainDate({ year: 2019 }), RangeError); - }); - }); - describe('MonthDay.toString()', () => { - const md1 = PlainMonthDay.from('11-18'); - const md2 = PlainMonthDay.from({ monthCode: 'M11', day: 18, calendar: 'gregory' }); - it('shows only non-ISO calendar if calendarName = auto', () => { - equal(md1.toString({ calendarName: 'auto' }), '11-18'); - equal(md2.toString({ calendarName: 'auto' }), '1972-11-18[u-ca=gregory]'); - }); - it('shows ISO calendar if calendarName = always', () => { - equal(md1.toString({ calendarName: 'always' }), '11-18[u-ca=iso8601]'); - }); - it('omits non-ISO calendar, but not year, if calendarName = never', () => { - equal(md1.toString({ calendarName: 'never' }), '11-18'); - equal(md2.toString({ calendarName: 'never' }), '1972-11-18'); - }); - it('default is calendar = auto', () => { - equal(md1.toString(), '11-18'); - equal(md2.toString(), '1972-11-18[u-ca=gregory]'); - }); - it('throws on invalid calendar', () => { - ['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => { - throws(() => md1.toString({ calendarName }), RangeError); - }); - }); - }); - describe('monthDay.getISOFields() works', () => { - const md1 = PlainMonthDay.from('11-18'); - const fields = md1.getISOFields(); - it('fields', () => { - equal(fields.isoMonth, 11); - equal(fields.isoDay, 18); - equal(fields.calendar.id, 'iso8601'); - equal(typeof fields.isoYear, 'number'); - }); - it('enumerable', () => { - const fields2 = { ...fields }; - equal(fields2.isoMonth, 11); - equal(fields2.isoDay, 18); - equal(fields2.calendar, fields.calendar); - equal(typeof fields2.isoYear, 'number'); - }); - it('as input to constructor', () => { - const md2 = new PlainMonthDay(fields.isoMonth, fields.isoDay, fields.calendar, fields.isoYear); - assert(md2.equals(md1)); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/plainTime.js b/packages/temporal-polyfill/tests/plainTime.js deleted file mode 100644 index 4470fa5e..00000000 --- a/packages/temporal-polyfill/tests/plainTime.js +++ /dev/null @@ -1,1386 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, notStrictEqual: notEqual, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { PlainTime, PlainDateTime } = Temporal; - -describe('Time', () => { - describe('Structure', () => { - it('Time is a Function', () => { - equal(typeof PlainTime, 'function'); - }); - it('Time has a prototype', () => { - assert(PlainTime.prototype); - equal(typeof PlainTime.prototype, 'object'); - }); - describe('Time.prototype', () => { - it('Time.prototype has calendar', () => { - assert('calendar' in PlainTime.prototype); - }); - it('Time.prototype has hour', () => { - assert('hour' in PlainTime.prototype); - }); - it('Time.prototype has minute', () => { - assert('minute' in PlainTime.prototype); - }); - it('Time.prototype has second', () => { - assert('second' in PlainTime.prototype); - }); - it('Time.prototype has millisecond', () => { - assert('millisecond' in PlainTime.prototype); - }); - it('Time.prototype has microsecond', () => { - assert('microsecond' in PlainTime.prototype); - }); - it('Time.prototype has nanosecond', () => { - assert('nanosecond' in PlainTime.prototype); - }); - it('Time.prototype.with is a Function', () => { - equal(typeof PlainTime.prototype.with, 'function'); - }); - it('Time.prototype.add is a Function', () => { - equal(typeof PlainTime.prototype.add, 'function'); - }); - it('Time.prototype.subtract is a Function', () => { - equal(typeof PlainTime.prototype.subtract, 'function'); - }); - it('Time.prototype.until is a Function', () => { - equal(typeof PlainTime.prototype.until, 'function'); - }); - it('Time.prototype.since is a Function', () => { - equal(typeof PlainTime.prototype.since, 'function'); - }); - it('Time.prototype.round is a Function', () => { - equal(typeof PlainTime.prototype.round, 'function'); - }); - it('Time.prototype.equals is a Function', () => { - equal(typeof PlainTime.prototype.equals, 'function'); - }); - it('Time.prototype.toPlainDateTime is a Function', () => { - equal(typeof PlainTime.prototype.toPlainDateTime, 'function'); - }); - it('Time.prototype.toZonedDateTime is a Function', () => { - equal(typeof PlainTime.prototype.toZonedDateTime, 'function'); - }); - it('Time.prototype.getISOFields is a Function', () => { - equal(typeof PlainTime.prototype.getISOFields, 'function'); - }); - it('Time.prototype.toString is a Function', () => { - equal(typeof PlainTime.prototype.toString, 'function'); - }); - it('Time.prototype.toJSON is a Function', () => { - equal(typeof PlainTime.prototype.toJSON, 'function'); - }); - }); - it('Time.from is a Function', () => { - equal(typeof PlainTime.from, 'function'); - }); - it('Time.compare is a Function', () => { - equal(typeof PlainTime.compare, 'function'); - }); - }); - describe('Construction', () => { - describe('complete', () => { - let time; - it('time can be constructed', () => { - time = new PlainTime(15, 23, 30, 123, 456, 789); - assert(time); - equal(typeof time, 'object'); - }); - it('time.hour is 15', () => equal(time.hour, 15)); - it('time.minute is 23', () => equal(time.minute, 23)); - it('time.second is 30', () => equal(time.second, 30)); - it('time.millisecond is 123', () => equal(time.millisecond, 123)); - it('time.microsecond is 456', () => equal(time.microsecond, 456)); - it('time.nanosecond is 789', () => equal(time.nanosecond, 789)); - it('time.calendar.id is iso8601', () => equal(time.calendar.id, 'iso8601')); - it('`${time}` is 15:23:30.123456789', () => equal(`${time}`, '15:23:30.123456789')); - }); - describe('missing nanosecond', () => { - let time; - it('time can be constructed', () => { - time = new PlainTime(15, 23, 30, 123, 456); - assert(time); - equal(typeof time, 'object'); - }); - it('time.hour is 15', () => equal(time.hour, 15)); - it('time.minute is 23', () => equal(time.minute, 23)); - it('time.second is 30', () => equal(time.second, 30)); - it('time.millisecond is 123', () => equal(time.millisecond, 123)); - it('time.microsecond is 456', () => equal(time.microsecond, 456)); - it('time.nanosecond is 0', () => equal(time.nanosecond, 0)); - it('`${time}` is 15:23:30.123456', () => equal(`${time}`, '15:23:30.123456')); - }); - describe('missing microsecond', () => { - let time; - it('time can be constructed', () => { - time = new PlainTime(15, 23, 30, 123); - assert(time); - equal(typeof time, 'object'); - }); - it('time.hour is 15', () => equal(time.hour, 15)); - it('time.minute is 23', () => equal(time.minute, 23)); - it('time.second is 30', () => equal(time.second, 30)); - it('time.millisecond is 123', () => equal(time.millisecond, 123)); - it('time.microsecond is 0', () => equal(time.microsecond, 0)); - it('time.nanosecond is 0', () => equal(time.nanosecond, 0)); - it('`${time}` is 15:23:30.123', () => equal(`${time}`, '15:23:30.123')); - }); - describe('missing millisecond', () => { - let time; - it('time can be constructed', () => { - time = new PlainTime(15, 23, 30); - assert(time); - equal(typeof time, 'object'); - }); - it('time.hour is 15', () => equal(time.hour, 15)); - it('time.minute is 23', () => equal(time.minute, 23)); - it('time.second is 30', () => equal(time.second, 30)); - it('time.millisecond is 0', () => equal(time.millisecond, 0)); - it('time.microsecond is 0', () => equal(time.microsecond, 0)); - it('time.nanosecond is 0', () => equal(time.nanosecond, 0)); - it('`${time}` is 15:23:30', () => equal(`${time}`, '15:23:30')); - }); - describe('missing second', () => { - let time; - it('time can be constructed', () => { - time = new PlainTime(15, 23); - assert(time); - equal(typeof time, 'object'); - }); - it('time.hour is 15', () => equal(time.hour, 15)); - it('time.minute is 23', () => equal(time.minute, 23)); - it('time.second is 0', () => equal(time.second, 0)); - it('time.millisecond is 0', () => equal(time.millisecond, 0)); - it('time.microsecond is 0', () => equal(time.microsecond, 0)); - it('time.nanosecond is 0', () => equal(time.nanosecond, 0)); - it('`${time}` is 15:23:00', () => equal(`${time}`, '15:23:00')); - }); - describe('missing minute', () => { - const time = new PlainTime(15); - it('`${time}` is 15:00:00', () => equal(`${time}`, '15:00:00')); - }); - describe('missing all parameters', () => { - const time = new PlainTime(); - it('`${time}` is 00:00:00', () => equal(`${time}`, '00:00:00')); - }); - }); - describe('.with manipulation', () => { - const time = new PlainTime(15, 23, 30, 123, 456, 789); - it('time.with({ hour: 3 } works', () => { - equal(`${time.with({ hour: 3 })}`, '03:23:30.123456789'); - }); - it('time.with({ minute: 3 } works', () => { - equal(`${time.with({ minute: 3 })}`, '15:03:30.123456789'); - }); - it('time.with({ second: 3 } works', () => { - equal(`${time.with({ second: 3 })}`, '15:23:03.123456789'); - }); - it('time.with({ millisecond: 3 } works', () => { - equal(`${time.with({ millisecond: 3 })}`, '15:23:30.003456789'); - }); - it('time.with({ microsecond: 3 } works', () => { - equal(`${time.with({ microsecond: 3 })}`, '15:23:30.123003789'); - }); - it('time.with({ nanosecond: 3 } works', () => { - equal(`${time.with({ nanosecond: 3 })}`, '15:23:30.123456003'); - }); - it('time.with({ minute: 8, nanosecond: 3 } works', () => { - equal(`${time.with({ minute: 8, nanosecond: 3 })}`, '15:08:30.123456003'); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => time.with({ hour: 3 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => time.with({ hour: 3 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${time.with({ hour: 3 }, options)}`, '03:23:30.123456789')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => time.with({}), TypeError); - throws(() => time.with({ minutes: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${time.with({ minutes: 1, hour: 1 })}`, '01:23:30.123456789'); - }); - it('time.with(string) throws', () => { - throws(() => time.with('18:05:42.577'), TypeError); - throws(() => time.with('2019-05-17T18:05:42.577'), TypeError); - throws(() => time.with('2019-05-17T18:05:42.577Z'), TypeError); - throws(() => time.with('2019-05-17'), TypeError); - throws(() => time.with('42'), TypeError); - }); - it('throws with calendar property', () => { - throws(() => time.with({ hour: 21, calendar: 'iso8601' }), TypeError); - }); - it('throws with timeZone property', () => { - throws(() => time.with({ hour: 21, timeZone: 'UTC' }), TypeError); - }); - }); - describe('time.toPlainDateTime() works', () => { - const time = PlainTime.from('11:30:23.123456789'); - const dt = time.toPlainDateTime(Temporal.PlainDate.from('1976-11-18')); - it('returns a Temporal.PlainDateTime', () => assert(dt instanceof Temporal.PlainDateTime)); - it('combines the date and time', () => equal(`${dt}`, '1976-11-18T11:30:23.123456789')); - it('casts argument', () => { - equal(`${time.toPlainDateTime({ year: 1976, month: 11, day: 18 })}`, '1976-11-18T11:30:23.123456789'); - equal(`${time.toPlainDateTime('1976-11-18')}`, '1976-11-18T11:30:23.123456789'); - }); - it('object must contain at least the required properties', () => { - throws(() => time.toPlainDateTime({ year: 1976 }), TypeError); - }); - }); - describe('time.toZonedDateTime()', function () { - it('works', () => { - const time = PlainTime.from('12:00'); - const date = Temporal.PlainDate.from('2020-01-01'); - const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = time.toZonedDateTime({ timeZone: tz, plainDate: date }); - equal(`${zdt}`, '2020-01-01T12:00:00-08:00[America/Los_Angeles]'); - }); - it('casts timeZone property', () => { - const time = PlainTime.from('12:00'); - const date = Temporal.PlainDate.from('2020-07-08'); - const zdt = time.toZonedDateTime({ timeZone: 'America/Los_Angeles', plainDate: date }); - equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); - }); - it('casts date property', () => { - const time = PlainTime.from('12:00'); - const tz = Temporal.TimeZone.from('America/Los_Angeles'); - const zdt = time.toZonedDateTime({ timeZone: tz, plainDate: '2020-07-08' }); - equal(`${zdt}`, '2020-07-08T12:00:00-07:00[America/Los_Angeles]'); - }); - }); - describe('time.until() works', () => { - const time = new PlainTime(15, 23, 30, 123, 456, 789); - const one = new PlainTime(16, 23, 30, 123, 456, 789); - it(`(${time}).until(${one}) => PT1H`, () => { - const duration = time.until(one); - equal(`${duration}`, 'PT1H'); - }); - const two = new PlainTime(17, 0, 30, 123, 456, 789); - it(`(${time}).until(${two}) => PT1H37M`, () => { - const duration = time.until(two); - equal(`${duration}`, 'PT1H37M'); - }); - it(`(${two}).until(${time}) => -PT1H37M`, () => equal(`${two.until(time)}`, '-PT1H37M')); - it(`(${time}).until(${two}) === (${two}).since(${time})`, () => equal(`${time.until(two)}`, `${two.since(time)}`)); - it('casts argument', () => { - equal(`${time.until({ hour: 16, minute: 34 })}`, 'PT1H10M29.876543211S'); - equal(`${time.until('16:34')}`, 'PT1H10M29.876543211S'); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => time.until({}), TypeError); - throws(() => time.until({ minutes: 30 }), TypeError); - }); - const time1 = PlainTime.from('10:23:15'); - const time2 = PlainTime.from('17:15:57'); - it('the default largest unit is at least hours', () => { - equal(`${time1.until(time2)}`, 'PT6H52M42S'); - equal(`${time1.until(time2, { largestUnit: 'auto' })}`, 'PT6H52M42S'); - equal(`${time1.until(time2, { largestUnit: 'hours' })}`, 'PT6H52M42S'); - }); - it('higher units are not allowed', () => { - throws(() => time1.until(time2, { largestUnit: 'days' }), RangeError); - throws(() => time1.until(time2, { largestUnit: 'weeks' }), RangeError); - throws(() => time1.until(time2, { largestUnit: 'months' }), RangeError); - throws(() => time1.until(time2, { largestUnit: 'years' }), RangeError); - }); - it('can return lower units', () => { - equal(`${time1.until(time2, { largestUnit: 'minutes' })}`, 'PT412M42S'); - equal(`${time1.until(time2, { largestUnit: 'seconds' })}`, 'PT24762S'); - }); - it('can return subseconds', () => { - const time3 = time2.add({ milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = time1.until(time3, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 24762250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = time1.until(time3, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 24762250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = time1.until(time3, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 24762250250250); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => time.until(one, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${time.until(one, options)}`, 'PT1H')); - }); - const earlier = PlainTime.from('08:22:36.123456789'); - const later = PlainTime.from('12:39:40.987654321'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'years', 'months', 'weeks', 'days', 'year', 'month', 'week', 'day', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => earlier.until(later, { smallestUnit }), RangeError); - } - ); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = ['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds']; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => earlier.until(later, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('throws on invalid roundingMode', () => { - throws(() => earlier.until(later, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['hours', 'PT4H'], - ['minutes', 'PT4H17M'], - ['seconds', 'PT4H17M5S'], - ['milliseconds', 'PT4H17M4.864S'], - ['microseconds', 'PT4H17M4.864198S'], - ['nanoseconds', 'PT4H17M4.864197532S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['hours', 'PT5H', '-PT4H'], - ['minutes', 'PT4H18M', '-PT4H17M'], - ['seconds', 'PT4H17M5S', '-PT4H17M4S'], - ['milliseconds', 'PT4H17M4.865S', '-PT4H17M4.864S'], - ['microseconds', 'PT4H17M4.864198S', '-PT4H17M4.864197S'], - ['nanoseconds', 'PT4H17M4.864197532S', '-PT4H17M4.864197532S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['hours', 'PT4H', '-PT5H'], - ['minutes', 'PT4H17M', '-PT4H18M'], - ['seconds', 'PT4H17M4S', '-PT4H17M5S'], - ['milliseconds', 'PT4H17M4.864S', '-PT4H17M4.865S'], - ['microseconds', 'PT4H17M4.864197S', '-PT4H17M4.864198S'], - ['nanoseconds', 'PT4H17M4.864197532S', '-PT4H17M4.864197532S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['hours', 'PT4H'], - ['minutes', 'PT4H17M'], - ['seconds', 'PT4H17M4S'], - ['milliseconds', 'PT4H17M4.864S'], - ['microseconds', 'PT4H17M4.864197S'], - ['nanoseconds', 'PT4H17M4.864197532S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${earlier.until(later, { smallestUnit: 'minutes' })}`, 'PT4H17M'); - equal(`${earlier.until(later, { smallestUnit: 'seconds' })}`, 'PT4H17M4S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 3, roundingMode: 'halfExpand' })}`, - 'PT3H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 30, roundingMode: 'halfExpand' })}`, - 'PT4H30M' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 15, roundingMode: 'halfExpand' })}`, - 'PT4H17M' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT4H17M4.86S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT4H17M4.8642S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT4H17M4.86419753S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { smallestUnit: 'hours', roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 1000 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 1000 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), RangeError); - }); - it('accepts singular units', () => { - equal(`${earlier.until(later, { largestUnit: 'hour' })}`, `${earlier.until(later, { largestUnit: 'hours' })}`); - equal(`${earlier.until(later, { smallestUnit: 'hour' })}`, `${earlier.until(later, { smallestUnit: 'hours' })}`); - equal( - `${earlier.until(later, { largestUnit: 'minute' })}`, - `${earlier.until(later, { largestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'minute' })}`, - `${earlier.until(later, { smallestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'second' })}`, - `${earlier.until(later, { largestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'second' })}`, - `${earlier.until(later, { smallestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'millisecond' })}`, - `${earlier.until(later, { largestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'millisecond' })}`, - `${earlier.until(later, { smallestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'microsecond' })}`, - `${earlier.until(later, { largestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'microsecond' })}`, - `${earlier.until(later, { smallestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'nanosecond' })}`, - `${earlier.until(later, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'nanosecond' })}`, - `${earlier.until(later, { smallestUnit: 'nanoseconds' })}` - ); - }); - }); - describe('time.since() works', () => { - const time = new PlainTime(15, 23, 30, 123, 456, 789); - const one = new PlainTime(14, 23, 30, 123, 456, 789); - it(`(${time}).since(${one}) => PT1H`, () => { - const duration = time.since(one); - equal(`${duration}`, 'PT1H'); - }); - const two = new PlainTime(13, 30, 30, 123, 456, 789); - it(`(${time}).since(${two}) => PT1H53M`, () => { - const duration = time.since(two); - equal(`${duration}`, 'PT1H53M'); - }); - it(`(${two}).since(${time}) => -PT1H53M`, () => equal(`${two.since(time)}`, '-PT1H53M')); - it(`(${two}).since(${time}) === (${time}).until(${two})`, () => equal(`${two.since(time)}`, `${time.until(two)}`)); - it('casts argument', () => { - equal(`${time.since({ hour: 16, minute: 34 })}`, '-PT1H10M29.876543211S'); - equal(`${time.since('16:34')}`, '-PT1H10M29.876543211S'); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => time.since({}), TypeError); - throws(() => time.since({ minutes: 30 }), TypeError); - }); - const time1 = PlainTime.from('10:23:15'); - const time2 = PlainTime.from('17:15:57'); - it('the default largest unit is at least hours', () => { - equal(`${time2.since(time1)}`, 'PT6H52M42S'); - equal(`${time2.since(time1, { largestUnit: 'auto' })}`, 'PT6H52M42S'); - equal(`${time2.since(time1, { largestUnit: 'hours' })}`, 'PT6H52M42S'); - }); - it('higher units are not allowed', () => { - throws(() => time2.since(time1, { largestUnit: 'days' }), RangeError); - throws(() => time2.since(time1, { largestUnit: 'weeks' }), RangeError); - throws(() => time2.since(time1, { largestUnit: 'months' }), RangeError); - throws(() => time2.since(time1, { largestUnit: 'years' }), RangeError); - }); - it('can return lower units', () => { - equal(`${time2.since(time1, { largestUnit: 'minutes' })}`, 'PT412M42S'); - equal(`${time2.since(time1, { largestUnit: 'seconds' })}`, 'PT24762S'); - }); - it('can return subseconds', () => { - const time3 = time2.add({ milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = time3.since(time1, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 24762250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = time3.since(time1, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 24762250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = time3.since(time1, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 24762250250250); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => time.since(one, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${time.since(one, options)}`, 'PT1H')); - }); - const earlier = PlainTime.from('08:22:36.123456789'); - const later = PlainTime.from('12:39:40.987654321'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'years', 'months', 'weeks', 'days', 'year', 'month', 'week', 'day', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => later.since(earlier, { smallestUnit }), RangeError); - } - ); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = ['hours', 'minutes', 'seconds', 'milliseconds', 'microseconds', 'nanoseconds']; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => later.since(earlier, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('throws on invalid roundingMode', () => { - throws(() => later.since(earlier, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['hours', 'PT4H'], - ['minutes', 'PT4H17M'], - ['seconds', 'PT4H17M5S'], - ['milliseconds', 'PT4H17M4.864S'], - ['microseconds', 'PT4H17M4.864198S'], - ['nanoseconds', 'PT4H17M4.864197532S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['hours', 'PT5H', '-PT4H'], - ['minutes', 'PT4H18M', '-PT4H17M'], - ['seconds', 'PT4H17M5S', '-PT4H17M4S'], - ['milliseconds', 'PT4H17M4.865S', '-PT4H17M4.864S'], - ['microseconds', 'PT4H17M4.864198S', '-PT4H17M4.864197S'], - ['nanoseconds', 'PT4H17M4.864197532S', '-PT4H17M4.864197532S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['hours', 'PT4H', '-PT5H'], - ['minutes', 'PT4H17M', '-PT4H18M'], - ['seconds', 'PT4H17M4S', '-PT4H17M5S'], - ['milliseconds', 'PT4H17M4.864S', '-PT4H17M4.865S'], - ['microseconds', 'PT4H17M4.864197S', '-PT4H17M4.864198S'], - ['nanoseconds', 'PT4H17M4.864197532S', '-PT4H17M4.864197532S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['hours', 'PT4H'], - ['minutes', 'PT4H17M'], - ['seconds', 'PT4H17M4S'], - ['milliseconds', 'PT4H17M4.864S'], - ['microseconds', 'PT4H17M4.864197S'], - ['nanoseconds', 'PT4H17M4.864197532S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${later.since(earlier, { smallestUnit: 'minutes' })}`, 'PT4H17M'); - equal(`${later.since(earlier, { smallestUnit: 'seconds' })}`, 'PT4H17M4S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 3, roundingMode: 'halfExpand' })}`, - 'PT3H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 30, roundingMode: 'halfExpand' })}`, - 'PT4H30M' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 15, roundingMode: 'halfExpand' })}`, - 'PT4H17M' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT4H17M4.86S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT4H17M4.8642S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT4H17M4.86419753S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { smallestUnit: 'hours', roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 1000 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 1000 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), RangeError); - }); - it('accepts singular units', () => { - equal(`${later.since(earlier, { largestUnit: 'hour' })}`, `${later.since(earlier, { largestUnit: 'hours' })}`); - equal(`${later.since(earlier, { smallestUnit: 'hour' })}`, `${later.since(earlier, { smallestUnit: 'hours' })}`); - equal( - `${later.since(earlier, { largestUnit: 'minute' })}`, - `${later.since(earlier, { largestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'minute' })}`, - `${later.since(earlier, { smallestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'second' })}`, - `${later.since(earlier, { largestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'second' })}`, - `${later.since(earlier, { smallestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'millisecond' })}`, - `${later.since(earlier, { largestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'millisecond' })}`, - `${later.since(earlier, { smallestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'microsecond' })}`, - `${later.since(earlier, { largestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'microsecond' })}`, - `${later.since(earlier, { smallestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'nanosecond' })}`, - `${later.since(earlier, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'nanosecond' })}`, - `${later.since(earlier, { smallestUnit: 'nanoseconds' })}` - ); - }); - }); - describe('Time.round works', () => { - const time = PlainTime.from('13:46:23.123456789'); - it('throws without parameter', () => { - throws(() => time.round(), TypeError); - }); - it('throws without required smallestUnit parameter', () => { - throws(() => time.round({}), RangeError); - throws(() => time.round({ roundingIncrement: 1, roundingMode: 'ceil' }), RangeError); - }); - it('throws on disallowed or invalid smallestUnit (object param)', () => { - ['era', 'year', 'month', 'week', 'day', 'years', 'months', 'weeks', 'days', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => time.round({ smallestUnit }), RangeError); - } - ); - }); - it('throws on disallowed or invalid smallestUnit (string param)', () => { - ['era', 'year', 'month', 'week', 'day', 'years', 'months', 'weeks', 'days', 'nonsense'].forEach( - (smallestUnit) => { - throws(() => time.round(smallestUnit), RangeError); - } - ); - }); - it('throws on invalid roundingMode', () => { - throws(() => time.round({ smallestUnit: 'second', roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['hour', '14:00:00'], - ['minute', '13:46:00'], - ['second', '13:46:23'], - ['millisecond', '13:46:23.123'], - ['microsecond', '13:46:23.123457'], - ['nanosecond', '13:46:23.123456789'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - it(`rounds to nearest ${smallestUnit}`, () => - equal(`${time.round({ smallestUnit, roundingMode: 'halfExpand' })}`, expected)); - }); - const incrementOneCeil = [ - ['hour', '14:00:00'], - ['minute', '13:47:00'], - ['second', '13:46:24'], - ['millisecond', '13:46:23.124'], - ['microsecond', '13:46:23.123457'], - ['nanosecond', '13:46:23.123456789'] - ]; - incrementOneCeil.forEach(([smallestUnit, expected]) => { - it(`rounds up to ${smallestUnit}`, () => - equal(`${time.round({ smallestUnit, roundingMode: 'ceil' })}`, expected)); - }); - const incrementOneFloor = [ - ['hour', '13:00:00'], - ['minute', '13:46:00'], - ['second', '13:46:23'], - ['millisecond', '13:46:23.123'], - ['microsecond', '13:46:23.123456'], - ['nanosecond', '13:46:23.123456789'] - ]; - incrementOneFloor.forEach(([smallestUnit, expected]) => { - it(`rounds down to ${smallestUnit}`, () => - equal(`${time.round({ smallestUnit, roundingMode: 'floor' })}`, expected)); - it(`truncates to ${smallestUnit}`, () => - equal(`${time.round({ smallestUnit, roundingMode: 'trunc' })}`, expected)); - }); - it('halfExpand is the default', () => { - equal(`${time.round({ smallestUnit: 'hour' })}`, '14:00:00'); - equal(`${time.round({ smallestUnit: 'minute' })}`, '13:46:00'); - }); - it('rounds to an increment of hours', () => { - equal(`${time.round({ smallestUnit: 'hour', roundingIncrement: 3 })}`, '15:00:00'); - }); - it('rounds to an increment of minutes', () => { - equal(`${time.round({ smallestUnit: 'minute', roundingIncrement: 15 })}`, '13:45:00'); - }); - it('rounds to an increment of seconds', () => { - equal(`${time.round({ smallestUnit: 'second', roundingIncrement: 30 })}`, '13:46:30'); - }); - it('rounds to an increment of milliseconds', () => { - equal(`${time.round({ smallestUnit: 'millisecond', roundingIncrement: 10 })}`, '13:46:23.12'); - }); - it('rounds to an increment of microseconds', () => { - equal(`${time.round({ smallestUnit: 'microsecond', roundingIncrement: 10 })}`, '13:46:23.12346'); - }); - it('rounds to an increment of nanoseconds', () => { - equal(`${time.round({ smallestUnit: 'nanosecond', roundingIncrement: 10 })}`, '13:46:23.12345679'); - }); - it('valid hour increments divide into 24', () => { - const smallestUnit = 'hour'; - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - assert(time.round({ smallestUnit, roundingIncrement }) instanceof PlainTime); - }); - }); - ['minute', 'second'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - assert(time.round({ smallestUnit, roundingIncrement }) instanceof PlainTime); - }); - }); - }); - ['millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - assert(time.round({ smallestUnit, roundingIncrement }) instanceof PlainTime); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => time.round({ smallestUnit: 'hour', roundingIncrement: 29 }), RangeError); - throws(() => time.round({ smallestUnit: 'minute', roundingIncrement: 29 }), RangeError); - throws(() => time.round({ smallestUnit: 'second', roundingIncrement: 29 }), RangeError); - throws(() => time.round({ smallestUnit: 'millisecond', roundingIncrement: 29 }), RangeError); - throws(() => time.round({ smallestUnit: 'microsecond', roundingIncrement: 29 }), RangeError); - throws(() => time.round({ smallestUnit: 'nanosecond', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => time.round({ smallestUnit: 'hour', roundingIncrement: 24 }), RangeError); - throws(() => time.round({ smallestUnit: 'minute', roundingIncrement: 60 }), RangeError); - throws(() => time.round({ smallestUnit: 'second', roundingIncrement: 60 }), RangeError); - throws(() => time.round({ smallestUnit: 'millisecond', roundingIncrement: 1000 }), RangeError); - throws(() => time.round({ smallestUnit: 'microsecond', roundingIncrement: 1000 }), RangeError); - throws(() => time.round({ smallestUnit: 'nanosecond', roundingIncrement: 1000 }), RangeError); - }); - const bal = PlainTime.from('23:59:59.999999999'); - ['hour', 'minute', 'second', 'millisecond', 'microsecond'].forEach((smallestUnit) => { - it(`balances to next ${smallestUnit}`, () => { - equal(`${bal.round({ smallestUnit })}`, '00:00:00'); - }); - }); - it('accepts plural units', () => { - ['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(time.round({ smallestUnit }).equals(time.round({ smallestUnit: `${smallestUnit}s` }))); - }); - }); - it('accepts string parameter as shortcut for {smallestUnit}', () => { - ['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(time.round(smallestUnit).equals(time.round({ smallestUnit }))); - }); - }); - }); - describe('Time.compare() works', () => { - const t1 = PlainTime.from('08:44:15.321'); - const t2 = PlainTime.from('14:23:30.123'); - it('equal', () => equal(PlainTime.compare(t1, t1), 0)); - it('smaller/larger', () => equal(PlainTime.compare(t1, t2), -1)); - it('larger/smaller', () => equal(PlainTime.compare(t2, t1), 1)); - it('casts first argument', () => { - equal(PlainTime.compare({ hour: 16, minute: 34 }, t2), 1); - equal(PlainTime.compare('16:34', t2), 1); - }); - it('casts second argument', () => { - equal(PlainTime.compare(t1, { hour: 16, minute: 34 }), -1); - equal(PlainTime.compare(t1, '16:34'), -1); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => PlainTime.compare({ hours: 16 }, t2), TypeError); - throws(() => PlainTime.compare(t1, { hours: 16 }), TypeError); - }); - }); - describe('time.equals() works', () => { - const t1 = PlainTime.from('08:44:15.321'); - const t2 = PlainTime.from('14:23:30.123'); - it('equal', () => assert(t1.equals(t1))); - it('unequal', () => assert(!t1.equals(t2))); - it('casts argument', () => { - assert(t1.equals('08:44:15.321')); - assert(t1.equals({ hour: 8, minute: 44, second: 15, millisecond: 321 })); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => t1.equals({ hours: 8 }), TypeError); - }); - }); - describe("Comparison operators don't work", () => { - const t1 = PlainTime.from('09:36:29.123456789'); - const t1again = PlainTime.from('09:36:29.123456789'); - const t2 = PlainTime.from('15:23:30.123456789'); - it('=== is object equality', () => equal(t1, t1)); - it('!== is object equality', () => notEqual(t1, t1again)); - it('<', () => throws(() => t1 < t2)); - it('>', () => throws(() => t1 > t2)); - it('<=', () => throws(() => t1 <= t2)); - it('>=', () => throws(() => t1 >= t2)); - }); - describe('time.add() works', () => { - const time = new PlainTime(15, 23, 30, 123, 456, 789); - it(`(${time}).add({ hours: 16 })`, () => { - equal(`${time.add({ hours: 16 })}`, '07:23:30.123456789'); - }); - it(`(${time}).add({ minutes: 45 })`, () => { - equal(`${time.add({ minutes: 45 })}`, '16:08:30.123456789'); - }); - it(`(${time}).add({ nanoseconds: 300 })`, () => { - equal(`${time.add({ nanoseconds: 300 })}`, '15:23:30.123457089'); - }); - it('symmetric with regard to negative durations', () => { - equal(`${PlainTime.from('07:23:30.123456789').add({ hours: -16 })}`, '15:23:30.123456789'); - equal(`${PlainTime.from('16:08:30.123456789').add({ minutes: -45 })}`, '15:23:30.123456789'); - equal(`${PlainTime.from('15:23:30.123457089').add({ nanoseconds: -300 })}`, '15:23:30.123456789'); - }); - it('time.add(durationObj)', () => { - equal(`${time.add(Temporal.Duration.from('PT16H'))}`, '07:23:30.123456789'); - }); - it('casts argument', () => equal(`${time.add('PT16H')}`, '07:23:30.123456789')); - it('ignores higher units', () => { - equal(`${time.add({ days: 1 })}`, '15:23:30.123456789'); - equal(`${time.add({ months: 1 })}`, '15:23:30.123456789'); - equal(`${time.add({ years: 1 })}`, '15:23:30.123456789'); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => time.add({ hours: 1, minutes: -30 }, { overflow }), RangeError) - ); - }); - it('options is ignored', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n, {}, () => {}, undefined].forEach((options) => - equal(`${time.add({ hours: 1 }, options)}`, '16:23:30.123456789') - ); - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - equal(`${time.add({ hours: 1 }, { overflow })}`, '16:23:30.123456789') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => time.add({}), TypeError); - throws(() => time.add({ minute: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${time.add({ minute: 1, hours: 1 })}`, '16:23:30.123456789'); - }); - }); - describe('time.subtract() works', () => { - const time = PlainTime.from('15:23:30.123456789'); - it(`(${time}).subtract({ hours: 16 })`, () => equal(`${time.subtract({ hours: 16 })}`, '23:23:30.123456789')); - it(`(${time}).subtract({ minutes: 45 })`, () => equal(`${time.subtract({ minutes: 45 })}`, '14:38:30.123456789')); - it(`(${time}).subtract({ seconds: 45 })`, () => equal(`${time.subtract({ seconds: 45 })}`, '15:22:45.123456789')); - it(`(${time}).subtract({ milliseconds: 800 })`, () => - equal(`${time.subtract({ milliseconds: 800 })}`, '15:23:29.323456789')); - it(`(${time}).subtract({ microseconds: 800 })`, () => - equal(`${time.subtract({ microseconds: 800 })}`, '15:23:30.122656789')); - it(`(${time}).subtract({ nanoseconds: 800 })`, () => - equal(`${time.subtract({ nanoseconds: 800 })}`, '15:23:30.123455989')); - it('symmetric with regard to negative durations', () => { - equal(`${PlainTime.from('23:23:30.123456789').subtract({ hours: -16 })}`, '15:23:30.123456789'); - equal(`${PlainTime.from('14:38:30.123456789').subtract({ minutes: -45 })}`, '15:23:30.123456789'); - equal(`${PlainTime.from('15:22:45.123456789').subtract({ seconds: -45 })}`, '15:23:30.123456789'); - equal(`${PlainTime.from('15:23:29.323456789').subtract({ milliseconds: -800 })}`, '15:23:30.123456789'); - equal(`${PlainTime.from('15:23:30.122656789').subtract({ microseconds: -800 })}`, '15:23:30.123456789'); - equal(`${PlainTime.from('15:23:30.123455989').subtract({ nanoseconds: -800 })}`, '15:23:30.123456789'); - }); - it('time.subtract(durationObj)', () => { - equal(`${time.subtract(Temporal.Duration.from('PT16H'))}`, '23:23:30.123456789'); - }); - it('casts argument', () => equal(`${time.subtract('PT16H')}`, '23:23:30.123456789')); - it('ignores higher units', () => { - equal(`${time.subtract({ days: 1 })}`, '15:23:30.123456789'); - equal(`${time.subtract({ months: 1 })}`, '15:23:30.123456789'); - equal(`${time.subtract({ years: 1 })}`, '15:23:30.123456789'); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => time.subtract({ hours: 1, minutes: -30 }, { overflow }), RangeError) - ); - }); - it('options is ignored', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n, {}, () => {}, undefined].forEach((options) => - equal(`${time.subtract({ hours: 1 }, options)}`, '14:23:30.123456789') - ); - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - equal(`${time.subtract({ hours: 1 }, { overflow })}`, '14:23:30.123456789') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => time.subtract({}), TypeError); - throws(() => time.subtract({ minute: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${time.subtract({ minute: 1, hours: 1 })}`, '14:23:30.123456789'); - }); - }); - describe('time.toString() works', () => { - it('new Time(15, 23).toString()', () => { - equal(new PlainTime(15, 23).toString(), '15:23:00'); - }); - it('new Time(15, 23, 30).toString()', () => { - equal(new PlainTime(15, 23, 30).toString(), '15:23:30'); - }); - it('new Time(15, 23, 30, 123).toString()', () => { - equal(new PlainTime(15, 23, 30, 123).toString(), '15:23:30.123'); - }); - it('new Time(15, 23, 30, 123, 456).toString()', () => { - equal(new PlainTime(15, 23, 30, 123, 456).toString(), '15:23:30.123456'); - }); - it('new Time(15, 23, 30, 123, 456, 789).toString()', () => { - equal(new PlainTime(15, 23, 30, 123, 456, 789).toString(), '15:23:30.123456789'); - }); - const t1 = PlainTime.from('15:23'); - const t2 = PlainTime.from('15:23:30'); - const t3 = PlainTime.from('15:23:30.1234'); - it('default is to emit seconds and drop trailing zeros after the decimal', () => { - equal(t1.toString(), '15:23:00'); - equal(t2.toString(), '15:23:30'); - equal(t3.toString(), '15:23:30.1234'); - }); - it('truncates to minute', () => { - [t1, t2, t3].forEach((t) => equal(t.toString({ smallestUnit: 'minute' }), '15:23')); - }); - it('other smallestUnits are aliases for fractional digits', () => { - equal(t3.toString({ smallestUnit: 'second' }), t3.toString({ fractionalSecondDigits: 0 })); - equal(t3.toString({ smallestUnit: 'millisecond' }), t3.toString({ fractionalSecondDigits: 3 })); - equal(t3.toString({ smallestUnit: 'microsecond' }), t3.toString({ fractionalSecondDigits: 6 })); - equal(t3.toString({ smallestUnit: 'nanosecond' }), t3.toString({ fractionalSecondDigits: 9 })); - }); - it('throws on invalid or disallowed smallestUnit', () => { - ['era', 'year', 'month', 'day', 'hour', 'nonsense'].forEach((smallestUnit) => - throws(() => t1.toString({ smallestUnit }), RangeError) - ); - }); - it('accepts plural units', () => { - equal(t3.toString({ smallestUnit: 'minutes' }), t3.toString({ smallestUnit: 'minute' })); - equal(t3.toString({ smallestUnit: 'seconds' }), t3.toString({ smallestUnit: 'second' })); - equal(t3.toString({ smallestUnit: 'milliseconds' }), t3.toString({ smallestUnit: 'millisecond' })); - equal(t3.toString({ smallestUnit: 'microseconds' }), t3.toString({ smallestUnit: 'microsecond' })); - equal(t3.toString({ smallestUnit: 'nanoseconds' }), t3.toString({ smallestUnit: 'nanosecond' })); - }); - it('truncates or pads to 2 places', () => { - const options = { fractionalSecondDigits: 2 }; - equal(t1.toString(options), '15:23:00.00'); - equal(t2.toString(options), '15:23:30.00'); - equal(t3.toString(options), '15:23:30.12'); - }); - it('pads to 7 places', () => { - const options = { fractionalSecondDigits: 7 }; - equal(t1.toString(options), '15:23:00.0000000'); - equal(t2.toString(options), '15:23:30.0000000'); - equal(t3.toString(options), '15:23:30.1234000'); - }); - it('auto is the default', () => { - [t1, t2, t3].forEach((dt) => equal(dt.toString({ fractionalSecondDigits: 'auto' }), dt.toString())); - }); - it('throws on out of range or invalid fractionalSecondDigits', () => { - [-1, 10, Infinity, NaN, 'not-auto'].forEach((fractionalSecondDigits) => - throws(() => t1.toString({ fractionalSecondDigits }), RangeError) - ); - }); - it('accepts and truncates fractional fractionalSecondDigits', () => { - equal(t3.toString({ fractionalSecondDigits: 5.5 }), '15:23:30.12340'); - }); - it('smallestUnit overrides fractionalSecondDigits', () => { - equal(t3.toString({ smallestUnit: 'minute', fractionalSecondDigits: 9 }), '15:23'); - }); - it('throws on invalid roundingMode', () => { - throws(() => t1.toString({ roundingMode: 'cile' }), RangeError); - }); - it('rounds to nearest', () => { - equal(t2.toString({ smallestUnit: 'minute', roundingMode: 'halfExpand' }), '15:24'); - equal(t3.toString({ fractionalSecondDigits: 3, roundingMode: 'halfExpand' }), '15:23:30.123'); - }); - it('rounds up', () => { - equal(t2.toString({ smallestUnit: 'minute', roundingMode: 'ceil' }), '15:24'); - equal(t3.toString({ fractionalSecondDigits: 3, roundingMode: 'ceil' }), '15:23:30.124'); - }); - it('rounds down', () => { - ['floor', 'trunc'].forEach((roundingMode) => { - equal(t2.toString({ smallestUnit: 'minute', roundingMode }), '15:23'); - equal(t3.toString({ fractionalSecondDigits: 3, roundingMode }), '15:23:30.123'); - }); - }); - it('rounding can affect all units', () => { - const t4 = PlainTime.from('23:59:59.999999999'); - equal(t4.toString({ fractionalSecondDigits: 8, roundingMode: 'halfExpand' }), '00:00:00.00000000'); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => t1.toString(badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(t1.toString(options), '15:23:00')); - }); - }); - describe('Time.from() works', () => { - it('Time.from("15:23")', () => { - equal(`${PlainTime.from('15:23')}`, '15:23:00'); - }); - it('Time.from("15:23:30")', () => { - equal(`${PlainTime.from('15:23:30')}`, '15:23:30'); - }); - it('Time.from("15:23:30.123")', () => { - equal(`${PlainTime.from('15:23:30.123')}`, '15:23:30.123'); - }); - it('Time.from("15:23:30.123456")', () => { - equal(`${PlainTime.from('15:23:30.123456')}`, '15:23:30.123456'); - }); - it('Time.from("15:23:30.123456789")', () => { - equal(`${PlainTime.from('15:23:30.123456789')}`, '15:23:30.123456789'); - }); - it('Time.from({ hour: 15, minute: 23 })', () => equal(`${PlainTime.from({ hour: 15, minute: 23 })}`, '15:23:00')); - it('Time.from({ minute: 30, microsecond: 555 })', () => - equal(`${PlainTime.from({ minute: 30, microsecond: 555 })}`, '00:30:00.000555')); - it('Time.from(ISO string leap second) is constrained', () => { - equal(`${PlainTime.from('23:59:60')}`, '23:59:59'); - equal(`${PlainTime.from('23:59:60', { overflow: 'reject' })}`, '23:59:59'); - }); - it('Time.from(number) is converted to string', () => equal(`${PlainTime.from(1523)}`, `${PlainTime.from('1523')}`)); - it('Time.from(time) returns the same properties', () => { - const t = PlainTime.from('2020-02-12T11:42:00+01:00[Europe/Amsterdam]'); - equal(PlainTime.from(t).toString(), t.toString()); - }); - it('Time.from(dateTime) returns the same time properties', () => { - const dt = PlainDateTime.from('2020-02-12T11:42:00+01:00[Europe/Amsterdam]'); - equal(PlainTime.from(dt).toString(), dt.toPlainTime().toString()); - }); - it('Time.from(time) is not the same object', () => { - const t = PlainTime.from('2020-02-12T11:42:00+01:00[Europe/Amsterdam]'); - notEqual(PlainTime.from(t), t); - }); - it('Z not supported', () => { - throws(() => PlainTime.from('2019-10-01T09:00:00Z'), RangeError); - throws(() => PlainTime.from('2019-10-01T09:00:00Z[Europe/Berlin]'), RangeError); - }); - it('any number of decimal places', () => { - equal(`${PlainTime.from('1976-11-18T15:23:30.1')}`, '15:23:30.1'); - equal(`${PlainTime.from('1976-11-18T15:23:30.12')}`, '15:23:30.12'); - equal(`${PlainTime.from('1976-11-18T15:23:30.123')}`, '15:23:30.123'); - equal(`${PlainTime.from('1976-11-18T15:23:30.1234')}`, '15:23:30.1234'); - equal(`${PlainTime.from('1976-11-18T15:23:30.12345')}`, '15:23:30.12345'); - equal(`${PlainTime.from('1976-11-18T15:23:30.123456')}`, '15:23:30.123456'); - equal(`${PlainTime.from('1976-11-18T15:23:30.1234567')}`, '15:23:30.1234567'); - equal(`${PlainTime.from('1976-11-18T15:23:30.12345678')}`, '15:23:30.12345678'); - equal(`${PlainTime.from('1976-11-18T15:23:30.123456789')}`, '15:23:30.123456789'); - }); - it('variant decimal separator', () => { - equal(`${PlainTime.from('1976-11-18T15:23:30,12')}`, '15:23:30.12'); - }); - it('variant minus sign', () => { - equal(`${PlainTime.from('1976-11-18T15:23:30.12\u221202:00')}`, '15:23:30.12'); - }); - it('basic format', () => { - equal(`${PlainTime.from('152330')}`, '15:23:30'); - equal(`${PlainTime.from('152330.1')}`, '15:23:30.1'); - equal(`${PlainTime.from('152330-08')}`, '15:23:30'); - equal(`${PlainTime.from('152330.1-08')}`, '15:23:30.1'); - equal(`${PlainTime.from('152330-0800')}`, '15:23:30'); - equal(`${PlainTime.from('152330.1-0800')}`, '15:23:30.1'); - }); - it('mixture of basic and extended format', () => { - equal(`${PlainTime.from('1976-11-18T152330.1+00:00')}`, '15:23:30.1'); - equal(`${PlainTime.from('19761118T15:23:30.1+00:00')}`, '15:23:30.1'); - equal(`${PlainTime.from('1976-11-18T15:23:30.1+0000')}`, '15:23:30.1'); - equal(`${PlainTime.from('1976-11-18T152330.1+0000')}`, '15:23:30.1'); - equal(`${PlainTime.from('19761118T15:23:30.1+0000')}`, '15:23:30.1'); - equal(`${PlainTime.from('19761118T152330.1+00:00')}`, '15:23:30.1'); - equal(`${PlainTime.from('19761118T152330.1+0000')}`, '15:23:30.1'); - equal(`${PlainTime.from('+001976-11-18T152330.1+00:00')}`, '15:23:30.1'); - equal(`${PlainTime.from('+0019761118T15:23:30.1+00:00')}`, '15:23:30.1'); - equal(`${PlainTime.from('+001976-11-18T15:23:30.1+0000')}`, '15:23:30.1'); - equal(`${PlainTime.from('+001976-11-18T152330.1+0000')}`, '15:23:30.1'); - equal(`${PlainTime.from('+0019761118T15:23:30.1+0000')}`, '15:23:30.1'); - equal(`${PlainTime.from('+0019761118T152330.1+00:00')}`, '15:23:30.1'); - equal(`${PlainTime.from('+0019761118T152330.1+0000')}`, '15:23:30.1'); - }); - it('optional parts', () => { - equal(`${PlainTime.from('15')}`, '15:00:00'); - }); - it('date-only formats not allowed', () => { - throws(() => PlainTime.from('2020-12-01'), RangeError); - throws(() => PlainTime.from('20201201'), RangeError); - }); - it('time designator prefix', () => { - equal(`${PlainTime.from('T15:23:30')}`, '15:23:30'); - equal(`${PlainTime.from('t152330')}`, '15:23:30'); - }); - it('space not accepted as time designator prefix', () => { - throws(() => PlainTime.from(' 15:23:30'), RangeError); - }); - it('time designator required for ambiguous strings', () => { - // YYYY-MM or HHMM-UU - throws(() => PlainTime.from('2021-12'), RangeError); - equal(`${PlainTime.from('T2021-12')}`, '20:21:00'); - equal(`${PlainTime.from('2021-13')}`, '20:21:00'); - equal(`${PlainTime.from('0000-00')}`, '00:00:00'); - // MMDD or HHMM - throws(() => PlainTime.from('1214'), RangeError); - throws(() => PlainTime.from('0229'), RangeError); - throws(() => PlainTime.from('1130'), RangeError); - equal(`${PlainTime.from('T1214')}`, '12:14:00'); - equal(`${PlainTime.from('1314')}`, '13:14:00'); - equal(`${PlainTime.from('1232')}`, '12:32:00'); - equal(`${PlainTime.from('0230')}`, '02:30:00'); - equal(`${PlainTime.from('0631')}`, '06:31:00'); - equal(`${PlainTime.from('0000')}`, '00:00:00'); - // MM-DD or HH-UU - throws(() => PlainTime.from('12-14'), RangeError); - equal(`${PlainTime.from('T12-14')}`, '12:00:00'); - equal(`${PlainTime.from('13-14')}`, '13:00:00'); - equal(`${PlainTime.from('00-00')}`, '00:00:00'); - // YYYYMM or HHMMSS - throws(() => PlainTime.from('202112'), RangeError); - equal(`${PlainTime.from('T202112')}`, '20:21:12'); - equal(`${PlainTime.from('202113')}`, '20:21:13'); - equal(`${PlainTime.from('000000')}`, '00:00:00'); - }); - it('no junk at end of string', () => throws(() => PlainTime.from('15:23:30.100junk'), RangeError)); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => PlainTime.from({ hour: 12 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${PlainTime.from({ hour: 12 }, options)}`, '12:00:00')); - }); - describe('Overflow', () => { - const bad = { nanosecond: 1000 }; - it('reject', () => throws(() => PlainTime.from(bad, { overflow: 'reject' }), RangeError)); - it('constrain', () => { - equal(`${PlainTime.from(bad)}`, '00:00:00.000000999'); - equal(`${PlainTime.from(bad, { overflow: 'constrain' })}`, '00:00:00.000000999'); - }); - it('throw on bad overflow', () => { - [new PlainTime(15), { hour: 15 }, '15:00'].forEach((input) => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainTime.from(input, { overflow }), RangeError) - ); - }); - }); - const leap = { hour: 23, minute: 59, second: 60 }; - it('reject leap second', () => throws(() => PlainTime.from(leap, { overflow: 'reject' }), RangeError)); - it('constrain leap second', () => equal(`${PlainTime.from(leap)}`, '23:59:59')); - it('constrain has no effect on invalid ISO string', () => { - throws(() => PlainTime.from('24:60', { overflow: 'constrain' }), RangeError); - }); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => PlainTime.from({}), TypeError); - throws(() => PlainTime.from({ minutes: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${PlainTime.from({ minutes: 1, hour: 1 })}`, '01:00:00'); - }); - }); - describe('constructor treats -0 as 0', () => { - it('ignores the sign of -0', () => { - const datetime = new PlainTime(-0, -0, -0, -0, -0); - equal(datetime.hour, 0); - equal(datetime.minute, 0); - equal(datetime.second, 0); - equal(datetime.millisecond, 0); - equal(datetime.microsecond, 0); - equal(datetime.nanosecond, 0); - }); - }); - describe('time operations', () => { - const datetime = { year: 2019, month: 10, day: 1, hour: 14, minute: 20, second: 36 }; - const fromed = new PlainTime(14, 20, 36); - it(`Temporal.PlainTime.from(${JSON.stringify(datetime)}) instanceof Temporal.PlainTime`, () => - assert(PlainTime.from(datetime) instanceof PlainTime)); - it(`Temporal.PlainTime.from(${JSON.stringify(datetime)}) === ${fromed}`, () => - assert(PlainTime.from(datetime).equals(fromed))); - - const iso = '20:18:32'; - it(`Temporal.PlainTime.from("${iso}") === (${iso})`, () => equal(`${PlainTime.from(iso)}`, iso)); - }); - describe('time.getISOFields() works', () => { - const t1 = PlainTime.from('15:23:30.123456789'); - const fields = t1.getISOFields(); - it('fields', () => { - equal(fields.isoHour, 15); - equal(fields.isoMinute, 23); - equal(fields.isoSecond, 30); - equal(fields.isoMillisecond, 123); - equal(fields.isoMicrosecond, 456); - equal(fields.isoNanosecond, 789); - equal(fields.calendar.id, 'iso8601'); - }); - it('enumerable', () => { - const fields2 = { ...fields }; - equal(fields2.isoHour, 15); - equal(fields2.isoMinute, 23); - equal(fields2.isoSecond, 30); - equal(fields2.isoMillisecond, 123); - equal(fields2.isoMicrosecond, 456); - equal(fields2.calendar.id, 'iso8601'); - }); - it('as input to constructor', () => { - const t2 = new PlainTime( - fields.isoHour, - fields.isoMinute, - fields.isoSecond, - fields.isoMillisecond, - fields.isoMicrosecond, - fields.isoNanosecond - ); - assert(t1.equals(t2)); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/plainYearMonth.js b/packages/temporal-polyfill/tests/plainYearMonth.js deleted file mode 100644 index 4580c8d6..00000000 --- a/packages/temporal-polyfill/tests/plainYearMonth.js +++ /dev/null @@ -1,820 +0,0 @@ - -import { assert } from 'chai'; -const { throws, strictEqual: equal, notStrictEqual: notEqual } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { PlainYearMonth } = Temporal; - -describe('YearMonth', () => { - describe('Structure', () => { - it('YearMonth is a Function', () => { - equal(typeof PlainYearMonth, 'function'); - }); - it('YearMonth has a prototype', () => { - assert(PlainYearMonth.prototype); - equal(typeof PlainYearMonth.prototype, 'object'); - }); - describe('YearMonth.prototype', () => { - it('YearMonth.prototype has month', () => { - assert('month' in PlainYearMonth.prototype); - }); - it('YearMonth.prototype has monthCode', () => { - assert('monthCode' in PlainYearMonth.prototype); - }); - it('YearMonth.prototype.until is a Function', () => { - equal(typeof PlainYearMonth.prototype.until, 'function'); - }); - it('YearMonth.prototype.since is a Function', () => { - equal(typeof PlainYearMonth.prototype.since, 'function'); - }); - it('YearMonth.prototype.equals is a Function', () => { - equal(typeof PlainYearMonth.prototype.equals, 'function'); - }); - it('YearMonth.prototype.toString is a Function', () => { - equal(typeof PlainYearMonth.prototype.toString, 'function'); - }); - it('YearMonth.prototype.getISOFields is a Function', () => { - equal(typeof PlainYearMonth.prototype.getISOFields, 'function'); - }); - it('YearMonth.prototype has daysInYear', () => { - assert('daysInYear' in PlainYearMonth.prototype); - }); - it('YearMonth.prototype has monthsInYear', () => { - assert('monthsInYear' in PlainYearMonth.prototype); - }); - }); - it('YearMonth.compare is a Function', () => { - equal(typeof PlainYearMonth.compare, 'function'); - }); - }); - describe('Construction', () => { - let ym; - it('YearMonth can be constructed', () => { - ym = new PlainYearMonth(1976, 11); - assert(ym); - equal(typeof ym, 'object'); - }); - it('ym.year is 1976', () => equal(ym.year, 1976)); - it('ym.month is 11', () => equal(ym.month, 11)); - it('ym.monthCode is "M11"', () => equal(ym.monthCode, 'M11')); - it('ym.daysInMonth is 30', () => equal(ym.daysInMonth, 30)); - it('ym.daysInYear is 366', () => equal(ym.daysInYear, 366)); - it('ym.monthsInYear is 12', () => equal(ym.monthsInYear, 12)); - describe('.from()', () => { - it('YearMonth.from(2019-10) == 2019-10', () => equal(`${PlainYearMonth.from('2019-10')}`, '2019-10')); - it('YearMonth.from(2019-10-01T09:00:00+00:00) == 2019-10', () => - equal(`${PlainYearMonth.from('2019-10-01T09:00:00+00:00')}`, '2019-10')); - it('Z not supported', () => { - throws(() => PlainYearMonth.from('2019-10-01T09:00:00Z'), RangeError); - throws(() => PlainYearMonth.from('2019-10-01T09:00:00Z[Europe/Berlin]'), RangeError); - }); - it("YearMonth.from('1976-11') == (1976-11)", () => equal(`${PlainYearMonth.from('1976-11')}`, '1976-11')); - it("YearMonth.from('1976-11-18') == (1976-11)", () => equal(`${PlainYearMonth.from('1976-11-18')}`, '1976-11')); - it('can be constructed with monthCode and without month', () => - equal(`${PlainYearMonth.from({ year: 2019, monthCode: 'M11' })}`, '2019-11')); - it('can be constructed with month and without monthCode', () => - equal(`${PlainYearMonth.from({ year: 2019, month: 11 })}`, '2019-11')); - it('month and monthCode must agree', () => - throws(() => PlainYearMonth.from({ year: 2019, month: 11, monthCode: 'M12' }), RangeError)); - it('ignores day when determining the ISO reference day from year/month', () => { - const one = PlainYearMonth.from({ year: 2019, month: 11, day: 1 }); - const two = PlainYearMonth.from({ year: 2019, month: 11, day: 2 }); - equal(one.getISOFields().isoDay, two.getISOFields().isoDay); - }); - it('ignores day when determining the ISO reference day from year/monthCode', () => { - const one = PlainYearMonth.from({ year: 2019, monthCode: 'M11', day: 1 }); - const two = PlainYearMonth.from({ year: 2019, monthCode: 'M11', day: 2 }); - equal(one.getISOFields().isoDay, two.getISOFields().isoDay); - }); - it('ignores day when determining the ISO reference day from era/eraYear/month', () => { - const one = PlainYearMonth.from({ era: 'ce', eraYear: 2019, month: 11, day: 1, calendar: 'gregory' }); - const two = PlainYearMonth.from({ era: 'ce', eraYear: 2019, month: 11, day: 2, calendar: 'gregory' }); - equal(one.getISOFields().isoDay, two.getISOFields().isoDay); - }); - it('ignores day when determining the ISO reference day from era/eraYear/monthCode', () => { - const one = PlainYearMonth.from({ era: 'ce', eraYear: 2019, monthCode: 'M11', day: 1, calendar: 'gregory' }); - const two = PlainYearMonth.from({ era: 'ce', eraYear: 2019, monthCode: 'M11', day: 2, calendar: 'gregory' }); - equal(one.getISOFields().isoDay, two.getISOFields().isoDay); - }); - it('YearMonth.from(2019-11) is not the same object', () => { - const orig = new PlainYearMonth(2019, 11); - const actu = PlainYearMonth.from(orig); - notEqual(actu, orig); - }); - it('ignores day when determining the ISO reference day from other Temporal object', () => { - const plainDate1 = Temporal.PlainDate.from('1976-11-01'); - const plainDate2 = Temporal.PlainDate.from('1976-11-18'); - const one = PlainYearMonth.from(plainDate1); - const two = PlainYearMonth.from(plainDate2); - equal(one.getISOFields().isoDay, two.getISOFields().isoDay); - }); - it('YearMonth.from({ year: 2019 }) throws', () => throws(() => PlainYearMonth.from({ year: 2019 }), TypeError)); - it('YearMonth.from({ month: 6 }) throws', () => throws(() => PlainYearMonth.from({ month: 6 }), TypeError)); - it('YearMonth.from({ monthCode: "M06" }) throws', () => - throws(() => PlainYearMonth.from({ monthCode: 'M06' }), TypeError)); - it('YearMonth.from({}) throws', () => throws(() => PlainYearMonth.from({}), TypeError)); - it('YearMonth.from(required prop undefined) throws', () => - throws(() => PlainYearMonth.from({ year: undefined, month: 6 }), TypeError)); - it('YearMonth.from(number) is converted to string', () => - assert(PlainYearMonth.from(201906).equals(PlainYearMonth.from('201906')))); - it('basic format', () => { - equal(`${PlainYearMonth.from('197611')}`, '1976-11'); - equal(`${PlainYearMonth.from('+00197611')}`, '1976-11'); - }); - it('variant minus sign', () => { - equal(`${PlainYearMonth.from('\u2212009999-11')}`, '-009999-11'); - equal(`${PlainYearMonth.from('1976-11-18T15:23:30.1\u221202:00')}`, '1976-11'); - }); - it('mixture of basic and extended format', () => { - equal(`${PlainYearMonth.from('1976-11-18T152330.1+00:00')}`, '1976-11'); - equal(`${PlainYearMonth.from('19761118T15:23:30.1+00:00')}`, '1976-11'); - equal(`${PlainYearMonth.from('1976-11-18T15:23:30.1+0000')}`, '1976-11'); - equal(`${PlainYearMonth.from('1976-11-18T152330.1+0000')}`, '1976-11'); - equal(`${PlainYearMonth.from('19761118T15:23:30.1+0000')}`, '1976-11'); - equal(`${PlainYearMonth.from('19761118T152330.1+00:00')}`, '1976-11'); - equal(`${PlainYearMonth.from('19761118T152330.1+0000')}`, '1976-11'); - equal(`${PlainYearMonth.from('+001976-11-18T152330.1+00:00')}`, '1976-11'); - equal(`${PlainYearMonth.from('+0019761118T15:23:30.1+00:00')}`, '1976-11'); - equal(`${PlainYearMonth.from('+001976-11-18T15:23:30.1+0000')}`, '1976-11'); - equal(`${PlainYearMonth.from('+001976-11-18T152330.1+0000')}`, '1976-11'); - equal(`${PlainYearMonth.from('+0019761118T15:23:30.1+0000')}`, '1976-11'); - equal(`${PlainYearMonth.from('+0019761118T152330.1+00:00')}`, '1976-11'); - equal(`${PlainYearMonth.from('+0019761118T152330.1+0000')}`, '1976-11'); - }); - it('optional components', () => { - equal(`${PlainYearMonth.from('1976-11-18T15:23')}`, '1976-11'); - equal(`${PlainYearMonth.from('1976-11-18T15')}`, '1976-11'); - equal(`${PlainYearMonth.from('1976-11-18')}`, '1976-11'); - }); - it('ignores day when determining the ISO reference day from string', () => { - const one = PlainYearMonth.from('1976-11-01'); - const two = PlainYearMonth.from('1976-11-18'); - equal(one.getISOFields().isoDay, two.getISOFields().isoDay); - }); - it('no junk at end of string', () => throws(() => PlainYearMonth.from('1976-11junk'), RangeError)); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => PlainYearMonth.from({ year: 1976, month: 11 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${PlainYearMonth.from({ year: 1976, month: 11 }, options)}`, '1976-11') - ); - }); - describe('Overflow', () => { - const bad = { year: 2019, month: 13 }; - it('reject', () => throws(() => PlainYearMonth.from(bad, { overflow: 'reject' }), RangeError)); - it('constrain', () => { - equal(`${PlainYearMonth.from(bad)}`, '2019-12'); - equal(`${PlainYearMonth.from(bad, { overflow: 'constrain' })}`, '2019-12'); - }); - it('throw on bad overflow', () => { - [new PlainYearMonth(2019, 1), { year: 2019, month: 1 }, '2019-01'].forEach((input) => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainYearMonth.from(input, { overflow }), RangeError) - ); - }); - }); - it('constrain has no effect on invalid ISO string', () => { - throws(() => PlainYearMonth.from('2020-13', { overflow: 'constrain' }), RangeError); - }); - }); - it('object must contain at least the required correctly-spelled properties', () => { - throws(() => PlainYearMonth.from({}), TypeError); - throws(() => PlainYearMonth.from({ year: 1976, months: 11 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${PlainYearMonth.from({ year: 1976, month: 11, months: 12 })}`, '1976-11'); - }); - }); - describe('.with()', () => { - const ym = PlainYearMonth.from('2019-10'); - it('with(2020)', () => equal(`${ym.with({ year: 2020 })}`, '2020-10')); - it('with(09)', () => equal(`${ym.with({ month: 9 })}`, '2019-09')); - it('with(monthCode)', () => equal(`${ym.with({ monthCode: 'M09' })}`, '2019-09')); - it('month and monthCode must agree', () => throws(() => ym.with({ month: 9, monthCode: 'M10' }), RangeError)); - }); - }); - describe('YearMonth.with() works', () => { - const ym = PlainYearMonth.from('2019-10'); - it('throws with calendar property', () => { - throws(() => ym.with({ year: 2021, calendar: 'iso8601' }), TypeError); - }); - it('throws with timeZone property', () => { - throws(() => ym.with({ year: 2021, timeZone: 'UTC' }), TypeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => ym.with({ year: 2020 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${ym.with({ year: 2020 }, options)}`, '2020-10')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => ym.with({}), TypeError); - throws(() => ym.with({ months: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${ym.with({ month: 1, years: 2020 })}`, '2019-01'); - }); - it('day is ignored when determining ISO reference day', () => { - equal(ym.with({ year: ym.year, day: 31 }).getISOFields().isoDay, ym.getISOFields().isoDay); - }); - }); - describe('YearMonth.compare() works', () => { - const nov94 = PlainYearMonth.from('1994-11'); - const jun13 = PlainYearMonth.from('2013-06'); - it('equal', () => equal(PlainYearMonth.compare(nov94, nov94), 0)); - it('smaller/larger', () => equal(PlainYearMonth.compare(nov94, jun13), -1)); - it('larger/smaller', () => equal(PlainYearMonth.compare(jun13, nov94), 1)); - it('casts first argument', () => { - equal(PlainYearMonth.compare({ year: 1994, month: 11 }, jun13), -1); - equal(PlainYearMonth.compare('1994-11', jun13), -1); - }); - it('casts second argument', () => { - equal(PlainYearMonth.compare(nov94, { year: 2013, month: 6 }), -1); - equal(PlainYearMonth.compare(nov94, '2013-06'), -1); - }); - it('object must contain at least the required properties', () => { - throws(() => PlainYearMonth.compare({ year: 1994 }, jun13), TypeError); - throws(() => PlainYearMonth.compare(nov94, { year: 2013 }), TypeError); - }); - it('takes [[ISODay]] into account', () => { - const iso = Temporal.Calendar.from('iso8601'); - const ym1 = new PlainYearMonth(2000, 1, iso, 1); - const ym2 = new PlainYearMonth(2000, 1, iso, 2); - equal(PlainYearMonth.compare(ym1, ym2), -1); - }); - }); - describe('YearMonth.equals() works', () => { - const nov94 = PlainYearMonth.from('1994-11'); - const jun13 = PlainYearMonth.from('2013-06'); - it('equal', () => assert(nov94.equals(nov94))); - it('unequal', () => assert(!nov94.equals(jun13))); - it('casts argument', () => { - assert(nov94.equals({ year: 1994, month: 11 })); - assert(nov94.equals('1994-11')); - }); - it('object must contain at least the required properties', () => { - throws(() => nov94.equals({ year: 1994 }), TypeError); - }); - it('takes [[ISODay]] into account', () => { - const iso = Temporal.Calendar.from('iso8601'); - const ym1 = new PlainYearMonth(2000, 1, iso, 1); - const ym2 = new PlainYearMonth(2000, 1, iso, 2); - assert(!ym1.equals(ym2)); - }); - }); - describe("Comparison operators don't work", () => { - const ym1 = PlainYearMonth.from('1963-02'); - const ym1again = PlainYearMonth.from('1963-02'); - const ym2 = PlainYearMonth.from('1976-11'); - it('=== is object equality', () => equal(ym1, ym1)); - it('!== is object equality', () => notEqual(ym1, ym1again)); - it('<', () => throws(() => ym1 < ym2)); - it('>', () => throws(() => ym1 > ym2)); - it('<=', () => throws(() => ym1 <= ym2)); - it('>=', () => throws(() => ym1 >= ym2)); - }); - describe('YearMonth.until() works', () => { - const nov94 = PlainYearMonth.from('1994-11'); - const jun13 = PlainYearMonth.from('2013-06'); - const diff = nov94.until(jun13); - it(`${jun13}.until(${nov94}) == ${nov94}.until(${jun13}).negated()`, () => - equal(`${jun13.until(nov94)}`, `${diff.negated()}`)); - it(`${nov94}.add(${diff}) == ${jun13}`, () => nov94.add(diff).equals(jun13)); - it(`${jun13}.subtract(${diff}) == ${nov94}`, () => jun13.subtract(diff).equals(nov94)); - it(`${nov94}.until(${jun13}) == ${jun13}.since(${nov94})`, () => equal(`${diff}`, `${jun13.since(nov94)}`)); - it('casts argument', () => { - equal(`${nov94.until({ year: 2013, month: 6 })}`, `${diff}`); - equal(`${nov94.until('2013-06')}`, `${diff}`); - }); - it('object must contain at least the required properties', () => { - throws(() => nov94.until({ year: 2013 }), TypeError); - }); - const feb20 = PlainYearMonth.from('2020-02'); - const feb21 = PlainYearMonth.from('2021-02'); - it('defaults to returning years', () => { - equal(`${feb20.until(feb21)}`, 'P1Y'); - equal(`${feb20.until(feb21, { largestUnit: 'auto' })}`, 'P1Y'); - equal(`${feb20.until(feb21, { largestUnit: 'years' })}`, 'P1Y'); - }); - it('can return months', () => { - equal(`${feb20.until(feb21, { largestUnit: 'months' })}`, 'P12M'); - }); - it('cannot return lower units', () => { - throws(() => feb20.until(feb21, { largestUnit: 'weeks' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'days' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'hours' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'minutes' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'seconds' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'milliseconds' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'microseconds' }), RangeError); - throws(() => feb20.until(feb21, { largestUnit: 'nanoseconds' }), RangeError); - }); - it('no two different calendars', () => { - const ym1 = new PlainYearMonth(2000, 1); - const ym2 = new PlainYearMonth(2000, 1, Temporal.Calendar.from('japanese')); - throws(() => ym1.until(ym2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb20.until(feb21, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb20.until(feb21, options)}`, 'P1Y')); - }); - const earlier = PlainYearMonth.from('2019-01'); - const later = PlainYearMonth.from('2021-09'); - it('throws on disallowed or invalid smallestUnit', () => { - [ - 'era', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds', - 'nonsense' - ].forEach((smallestUnit) => { - throws(() => earlier.until(later, { smallestUnit }), RangeError); - }); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - throws(() => earlier.until(later, { largestUnit: 'months', smallestUnit: 'years' }), RangeError); - }); - it('throws on invalid roundingMode', () => { - throws(() => earlier.until(later, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P2Y8M'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P2Y8M', '-P2Y8M'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P2Y8M', '-P2Y8M'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P2Y8M'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${earlier.until(later, { smallestUnit: 'years' })}`, 'P2Y'); - equal(`${later.until(earlier, { smallestUnit: 'years' })}`, '-P2Y'); - }); - it('rounds to an increment of years', () => { - equal( - `${earlier.until(later, { smallestUnit: 'years', roundingIncrement: 4, roundingMode: 'halfExpand' })}`, - 'P4Y' - ); - }); - it('rounds to an increment of months', () => { - equal(`${earlier.until(later, { smallestUnit: 'months', roundingIncrement: 5 })}`, 'P2Y5M'); - equal( - `${earlier.until(later, { largestUnit: 'months', smallestUnit: 'months', roundingIncrement: 10 })}`, - 'P30M' - ); - }); - it('accepts singular units', () => { - equal(`${earlier.until(later, { largestUnit: 'year' })}`, `${earlier.until(later, { largestUnit: 'years' })}`); - equal(`${earlier.until(later, { smallestUnit: 'year' })}`, `${earlier.until(later, { smallestUnit: 'years' })}`); - equal(`${earlier.until(later, { largestUnit: 'month' })}`, `${earlier.until(later, { largestUnit: 'months' })}`); - equal( - `${earlier.until(later, { smallestUnit: 'month' })}`, - `${earlier.until(later, { smallestUnit: 'months' })}` - ); - }); - }); - describe('YearMonth.since() works', () => { - const nov94 = PlainYearMonth.from('1994-11'); - const jun13 = PlainYearMonth.from('2013-06'); - const diff = jun13.since(nov94); - it(`${nov94}.since(${jun13}) == ${jun13}.since(${nov94}).negated()`, () => - equal(`${nov94.since(jun13)}`, `${diff.negated()}`)); - it(`${nov94}.add(${diff}) == ${jun13}`, () => nov94.add(diff).equals(jun13)); - it(`${jun13}.subtract(${diff}) == ${nov94}`, () => jun13.subtract(diff).equals(nov94)); - it(`${jun13}.since(${nov94}) == ${nov94}.until(${jun13})`, () => equal(`${diff}`, `${nov94.until(jun13)}`)); - it('casts argument', () => { - equal(`${jun13.since({ year: 1994, month: 11 })}`, `${diff}`); - equal(`${jun13.since('1994-11')}`, `${diff}`); - }); - it('object must contain at least the required properties', () => { - throws(() => jun13.since({ year: 1994 }), TypeError); - }); - const feb20 = PlainYearMonth.from('2020-02'); - const feb21 = PlainYearMonth.from('2021-02'); - it('defaults to returning years', () => { - equal(`${feb21.since(feb20)}`, 'P1Y'); - equal(`${feb21.since(feb20, { largestUnit: 'auto' })}`, 'P1Y'); - equal(`${feb21.since(feb20, { largestUnit: 'years' })}`, 'P1Y'); - }); - it('can return months', () => { - equal(`${feb21.since(feb20, { largestUnit: 'months' })}`, 'P12M'); - }); - it('cannot return lower units', () => { - throws(() => feb21.since(feb20, { largestUnit: 'weeks' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'days' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'hours' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'minutes' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'seconds' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'milliseconds' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'microseconds' }), RangeError); - throws(() => feb21.since(feb20, { largestUnit: 'nanoseconds' }), RangeError); - }); - it('no two different calendars', () => { - const ym1 = new PlainYearMonth(2000, 1); - const ym2 = new PlainYearMonth(2000, 1, Temporal.Calendar.from('japanese')); - throws(() => ym1.since(ym2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb21.since(feb20, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb21.since(feb20, options)}`, 'P1Y')); - }); - const earlier = PlainYearMonth.from('2019-01'); - const later = PlainYearMonth.from('2021-09'); - it('throws on disallowed or invalid smallestUnit', () => { - [ - 'era', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds', - 'nonsense' - ].forEach((smallestUnit) => { - throws(() => later.since(earlier, { smallestUnit }), RangeError); - }); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - throws(() => later.since(earlier, { largestUnit: 'months', smallestUnit: 'years' }), RangeError); - }); - it('throws on invalid roundingMode', () => { - throws(() => later.since(earlier, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P2Y8M'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P2Y8M', '-P2Y8M'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P2Y8M', '-P2Y8M'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P2Y8M'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${later.since(earlier, { smallestUnit: 'years' })}`, 'P2Y'); - equal(`${earlier.since(later, { smallestUnit: 'years' })}`, '-P2Y'); - }); - it('rounds to an increment of years', () => { - equal( - `${later.since(earlier, { smallestUnit: 'years', roundingIncrement: 4, roundingMode: 'halfExpand' })}`, - 'P4Y' - ); - }); - it('rounds to an increment of months', () => { - equal(`${later.since(earlier, { smallestUnit: 'months', roundingIncrement: 5 })}`, 'P2Y5M'); - equal( - `${later.since(earlier, { largestUnit: 'months', smallestUnit: 'months', roundingIncrement: 10 })}`, - 'P30M' - ); - }); - it('accepts singular units', () => { - equal(`${later.since(earlier, { largestUnit: 'year' })}`, `${later.since(earlier, { largestUnit: 'years' })}`); - equal(`${later.since(earlier, { smallestUnit: 'year' })}`, `${later.since(earlier, { smallestUnit: 'years' })}`); - equal(`${later.since(earlier, { largestUnit: 'month' })}`, `${later.since(earlier, { largestUnit: 'months' })}`); - equal( - `${later.since(earlier, { smallestUnit: 'month' })}`, - `${later.since(earlier, { smallestUnit: 'months' })}` - ); - }); - }); - describe('YearMonth.add() works', () => { - const ym = PlainYearMonth.from('2019-11'); - it('(2019-11) plus 2 months === 2020-01', () => { - equal(`${ym.add({ months: 2 })}`, '2020-01'); - equal(`${ym.add({ months: 2 }, { overflow: 'constrain' })}`, '2020-01'); - equal(`${ym.add({ months: 2 }, { overflow: 'reject' })}`, '2020-01'); - }); - it('(2019-11) plus 1 year === 2020-11', () => { - equal(`${ym.add({ years: 1 })}`, '2020-11'); - equal(`${ym.add({ years: 1 }, { overflow: 'constrain' })}`, '2020-11'); - equal(`${ym.add({ years: 1 }, { overflow: 'reject' })}`, '2020-11'); - }); - it('symmetrical with regard to negative durations', () => { - equal(`${PlainYearMonth.from('2020-01').add({ months: -2 })}`, '2019-11'); - equal(`${PlainYearMonth.from('2020-11').add({ years: -1 })}`, '2019-11'); - }); - it('yearMonth.add(durationObj)', () => { - equal(`${ym.add(Temporal.Duration.from('P2M'))}`, '2020-01'); - }); - it('casts argument', () => equal(`${ym.add('P2M')}`, '2020-01')); - it("ignores lower units that don't balance up to the length of the month", () => { - equal(`${ym.add({ days: 1 })}`, '2019-11'); - equal(`${ym.add({ days: 29 })}`, '2019-11'); - equal(`${ym.add({ hours: 1 })}`, '2019-11'); - equal(`${ym.add({ minutes: 1 })}`, '2019-11'); - equal(`${ym.add({ seconds: 1 })}`, '2019-11'); - equal(`${ym.add({ milliseconds: 1 })}`, '2019-11'); - equal(`${ym.add({ microseconds: 1 })}`, '2019-11'); - equal(`${ym.add({ nanoseconds: 1 })}`, '2019-11'); - }); - it('adds lower units that balance up to a month or more', () => { - equal(`${ym.add({ days: 30 })}`, '2019-12'); - equal(`${ym.add({ days: 31 })}`, '2019-12'); - equal(`${ym.add({ days: 60 })}`, '2019-12'); - equal(`${ym.add({ days: 61 })}`, '2020-01'); - equal(`${ym.add({ hours: 720 })}`, '2019-12'); - equal(`${ym.add({ minutes: 43200 })}`, '2019-12'); - equal(`${ym.add({ seconds: 2592000 })}`, '2019-12'); - equal(`${ym.add({ milliseconds: 2592000_000 })}`, '2019-12'); - equal(`${ym.add({ microseconds: 2592000_000_000 })}`, '2019-12'); - equal(`${ym.add({ nanoseconds: 2592000_000_000_000 })}`, '2019-12'); - }); - it('balances days to months based on the number of days in the ISO month', () => { - equal(`${PlainYearMonth.from('2019-02').add({ days: 27 })}`, '2019-02'); - equal(`${PlainYearMonth.from('2019-02').add({ days: 28 })}`, '2019-03'); - equal(`${PlainYearMonth.from('2020-02').add({ days: 28 })}`, '2020-02'); - equal(`${PlainYearMonth.from('2020-02').add({ days: 29 })}`, '2020-03'); - equal(`${PlainYearMonth.from('2019-11').add({ days: 29 })}`, '2019-11'); - equal(`${PlainYearMonth.from('2019-11').add({ days: 30 })}`, '2019-12'); - equal(`${PlainYearMonth.from('2020-01').add({ days: 30 })}`, '2020-01'); - equal(`${PlainYearMonth.from('2020-01').add({ days: 31 })}`, '2020-02'); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => ym.add({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => ym.add({ years: 1, months: -6 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => ym.add({ months: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${ym.add({ months: 1 }, options)}`, '2019-12')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => ym.add({}), TypeError); - throws(() => ym.add({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${ym.add({ month: 1, years: 1 })}`, '2020-11'); - }); - }); - describe('YearMonth.subtract() works', () => { - const ym = PlainYearMonth.from('2019-11'); - it('(2019-11) minus 11 months === 2018-12', () => { - equal(`${ym.subtract({ months: 11 })}`, '2018-12'); - equal(`${ym.subtract({ months: 11 }, { overflow: 'constrain' })}`, '2018-12'); - equal(`${ym.subtract({ months: 11 }, { overflow: 'reject' })}`, '2018-12'); - }); - it('(2019-11) minus 12 years === 2007-11', () => { - equal(`${ym.subtract({ years: 12 })}`, '2007-11'); - equal(`${ym.subtract({ years: 12 }, { overflow: 'constrain' })}`, '2007-11'); - equal(`${ym.subtract({ years: 12 }, { overflow: 'reject' })}`, '2007-11'); - }); - it('symmetrical with regard to negative durations', () => { - equal(`${PlainYearMonth.from('2018-12').subtract({ months: -11 })}`, '2019-11'); - equal(`${PlainYearMonth.from('2007-11').subtract({ years: -12 })}`, '2019-11'); - }); - it('yearMonth.subtract(durationObj)', () => { - equal(`${ym.subtract(Temporal.Duration.from('P11M'))}`, '2018-12'); - }); - it('casts argument', () => equal(`${ym.subtract('P11M')}`, '2018-12')); - it("ignores lower units that don't balance up to the length of the month", () => { - equal(`${ym.subtract({ days: 1 })}`, '2019-11'); - equal(`${ym.subtract({ hours: 1 })}`, '2019-11'); - equal(`${ym.subtract({ minutes: 1 })}`, '2019-11'); - equal(`${ym.subtract({ seconds: 1 })}`, '2019-11'); - equal(`${ym.subtract({ milliseconds: 1 })}`, '2019-11'); - equal(`${ym.subtract({ microseconds: 1 })}`, '2019-11'); - equal(`${ym.subtract({ nanoseconds: 1 })}`, '2019-11'); - }); - it('subtracts lower units that balance up to a day or more', () => { - equal(`${ym.subtract({ days: 29 })}`, '2019-11'); - equal(`${ym.subtract({ days: 30 })}`, '2019-10'); - equal(`${ym.subtract({ days: 60 })}`, '2019-10'); - equal(`${ym.subtract({ days: 61 })}`, '2019-09'); - equal(`${ym.subtract({ hours: 720 })}`, '2019-10'); - equal(`${ym.subtract({ minutes: 43200 })}`, '2019-10'); - equal(`${ym.subtract({ seconds: 2592000 })}`, '2019-10'); - equal(`${ym.subtract({ milliseconds: 2592000_000 })}`, '2019-10'); - equal(`${ym.subtract({ microseconds: 2592000_000_000 })}`, '2019-10'); - equal(`${ym.subtract({ nanoseconds: 2592000_000_000_000 })}`, '2019-10'); - }); - it('balances days to months based on the number of days in the ISO month', () => { - equal(`${PlainYearMonth.from('2019-02').subtract({ days: 27 })}`, '2019-02'); - equal(`${PlainYearMonth.from('2019-02').subtract({ days: 28 })}`, '2019-01'); - equal(`${PlainYearMonth.from('2020-02').subtract({ days: 28 })}`, '2020-02'); - equal(`${PlainYearMonth.from('2020-02').subtract({ days: 29 })}`, '2020-01'); - equal(`${PlainYearMonth.from('2019-11').subtract({ days: 29 })}`, '2019-11'); - equal(`${PlainYearMonth.from('2019-11').subtract({ days: 30 })}`, '2019-10'); - equal(`${PlainYearMonth.from('2020-01').subtract({ days: 30 })}`, '2020-01'); - equal(`${PlainYearMonth.from('2020-01').subtract({ days: 31 })}`, '2019-12'); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => ym.subtract({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => ym.subtract({ years: 1, months: -6 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => ym.subtract({ months: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${ym.subtract({ months: 1 }, options)}`, '2019-10')); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => ym.subtract({}), TypeError); - throws(() => ym.subtract({ month: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${ym.subtract({ month: 1, years: 1 })}`, '2018-11'); - }); - }); - describe('Min/max range', () => { - it('constructing from numbers', () => { - throws(() => new PlainYearMonth(-271821, 3), RangeError); - throws(() => new PlainYearMonth(275760, 10), RangeError); - equal(`${new PlainYearMonth(-271821, 4)}`, '-271821-04'); - equal(`${new PlainYearMonth(275760, 9)}`, '+275760-09'); - }); - it('constructing from property bag', () => { - const tooEarly = { year: -271821, month: 3 }; - const tooLate = { year: 275760, month: 10 }; - ['reject', 'constrain'].forEach((overflow) => { - [tooEarly, tooLate].forEach((props) => { - throws(() => PlainYearMonth.from(props, { overflow }), RangeError); - }); - }); - equal(`${PlainYearMonth.from({ year: -271821, month: 4 })}`, '-271821-04'); - equal(`${PlainYearMonth.from({ year: 275760, month: 9 })}`, '+275760-09'); - }); - it('constructing from ISO string', () => { - ['reject', 'constrain'].forEach((overflow) => { - ['-271821-03', '+275760-10'].forEach((str) => { - throws(() => PlainYearMonth.from(str, { overflow }), RangeError); - }); - }); - equal(`${PlainYearMonth.from('-271821-04')}`, '-271821-04'); - equal(`${PlainYearMonth.from('+275760-09')}`, '+275760-09'); - }); - it('converting from Date', () => { - const min = Temporal.PlainDate.from('-271821-04-19'); - const max = Temporal.PlainDate.from('+275760-09-13'); - equal(`${min.toPlainYearMonth()}`, '-271821-04'); - equal(`${max.toPlainYearMonth()}`, '+275760-09'); - }); - it('adding and subtracting beyond limit', () => { - const min = PlainYearMonth.from('-271821-04'); - const max = PlainYearMonth.from('+275760-09'); - ['reject', 'constrain'].forEach((overflow) => { - throws(() => min.subtract({ months: 1 }, { overflow }), RangeError); - throws(() => max.add({ months: 1 }, { overflow }), RangeError); - }); - }); - }); - describe('YearMonth.with()', () => { - it('throws on bad overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => PlainYearMonth.from({ year: 2019, month: 1 }).with({ month: 2 }, { overflow }), RangeError) - ); - }); - }); - describe('YearMonth.toPlainDate()', () => { - const ym = PlainYearMonth.from('2002-01'); - it("doesn't take a primitive argument", () => { - [22, '22', false, 22n, Symbol('22'), null].forEach((bad) => { - throws(() => ym.toPlainDate(bad), TypeError); - }); - }); - it('takes an object argument with day property', () => { - equal(`${ym.toPlainDate({ day: 22 })}`, '2002-01-22'); - }); - it('needs at least a day property on the object in the ISO calendar', () => { - throws(() => ym.toPlainDate({ something: 'nothing' }), TypeError); - }); - }); - describe('YearMonth.toString()', () => { - const ym1 = PlainYearMonth.from('1976-11'); - const ym2 = PlainYearMonth.from({ year: 1976, month: 11, calendar: 'gregory' }); - it('shows only non-ISO calendar if calendarName = auto', () => { - equal(ym1.toString({ calendarName: 'auto' }), '1976-11'); - equal(ym2.toString({ calendarName: 'auto' }), '1976-11-01[u-ca=gregory]'); - }); - it('shows ISO calendar if calendarName = always', () => { - equal(ym1.toString({ calendarName: 'always' }), '1976-11[u-ca=iso8601]'); - }); - it('omits non-ISO calendar, but not day, if calendarName = never', () => { - equal(ym1.toString({ calendarName: 'never' }), '1976-11'); - equal(ym2.toString({ calendarName: 'never' }), '1976-11-01'); - }); - it('default is calendar = auto', () => { - equal(ym1.toString(), '1976-11'); - equal(ym2.toString(), '1976-11-01[u-ca=gregory]'); - }); - it('throws on invalid calendar', () => { - ['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => { - throws(() => ym1.toString({ calendarName }), RangeError); - }); - }); - }); - describe('yearMonth.getISOFields() works', () => { - const ym1 = PlainYearMonth.from('1976-11'); - const fields = ym1.getISOFields(); - it('fields', () => { - equal(fields.isoYear, 1976); - equal(fields.isoMonth, 11); - equal(fields.calendar.id, 'iso8601'); - equal(typeof fields.isoDay, 'number'); - }); - it('enumerable', () => { - const fields2 = { ...fields }; - equal(fields2.isoYear, 1976); - equal(fields2.isoMonth, 11); - equal(fields2.calendar, fields.calendar); - equal(typeof fields2.isoDay, 'number'); - }); - it('as input to constructor', () => { - const ym2 = new PlainYearMonth(fields.isoYear, fields.isoMonth, fields.calendar, fields.isoDay); - assert(ym2.equals(ym1)); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/regex.js b/packages/temporal-polyfill/tests/regex.js deleted file mode 100644 index d5cd5548..00000000 --- a/packages/temporal-polyfill/tests/regex.js +++ /dev/null @@ -1,731 +0,0 @@ - -import { assert } from 'chai'; -const { strictEqual: equal, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; - -describe('fromString regex', () => { - describe('instant', () => { - function test(isoString, components) { - it(isoString, () => { - const [y, mon, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0] = components; - const instant = Temporal.Instant.from(isoString); - const utc = Temporal.TimeZone.from('UTC'); - const datetime = utc.getPlainDateTimeFor(instant); - equal(datetime.year, y); - equal(datetime.month, mon); - equal(datetime.day, d); - equal(datetime.hour, h); - equal(datetime.minute, min); - equal(datetime.second, s); - equal(datetime.millisecond, ms); - equal(datetime.microsecond, µs); - equal(datetime.nanosecond, ns); - }); - } - function generateTest(dateTimeString, zoneString, components) { - test(`${dateTimeString}${zoneString}`, components.slice(0, 5)); - test(`${dateTimeString}:30${zoneString}`, components.slice(0, 6)); - test(`${dateTimeString}:30.123456789${zoneString}`, components); - } - describe('valid', () => { - // Without time component - test('2020-01-01Z', [2020, 1, 1, 0, 0, 0]); - // Time separators - ['T', 't', ' '].forEach((timeSep) => - generateTest(`1976-11-18${timeSep}15:23`, 'Z', [1976, 11, 18, 15, 23, 30, 123, 456, 789]) - ); - // Time zone with bracketed name - ['+01:00', '+01', '+0100', '+01:00:00', '+010000', '+01:00:00.000000000', '+010000.0'].forEach((zoneString) => { - generateTest('1976-11-18T15:23', `${zoneString}[Europe/Vienna]`, [1976, 11, 18, 14, 23, 30, 123, 456, 789]); - generateTest('1976-11-18T15:23', `+01:00[${zoneString}]`, [1976, 11, 18, 14, 23, 30, 123, 456, 789]); - }); - // Time zone with only offset - ['-04:00', '-04', '-0400', '-04:00:00', '-040000', '-04:00:00.000000000', '-040000.0'].forEach((zoneString) => - generateTest('1976-11-18T15:23', zoneString, [1976, 11, 18, 19, 23, 30, 123, 456, 789]) - ); - // Various numbers of decimal places - test('1976-11-18T15:23:30.1Z', [1976, 11, 18, 15, 23, 30, 100]); - test('1976-11-18T15:23:30.12Z', [1976, 11, 18, 15, 23, 30, 120]); - test('1976-11-18T15:23:30.123Z', [1976, 11, 18, 15, 23, 30, 123]); - test('1976-11-18T15:23:30.1234Z', [1976, 11, 18, 15, 23, 30, 123, 400]); - test('1976-11-18T15:23:30.12345Z', [1976, 11, 18, 15, 23, 30, 123, 450]); - test('1976-11-18T15:23:30.123456Z', [1976, 11, 18, 15, 23, 30, 123, 456]); - test('1976-11-18T15:23:30.1234567Z', [1976, 11, 18, 15, 23, 30, 123, 456, 700]); - test('1976-11-18T15:23:30.12345678Z', [1976, 11, 18, 15, 23, 30, 123, 456, 780]); - // Lowercase UTC designator - generateTest('1976-11-18T15:23', 'z', [1976, 11, 18, 15, 23, 30, 123, 456, 789]); - // Comma decimal separator - test('1976-11-18T15:23:30,1234Z', [1976, 11, 18, 15, 23, 30, 123, 400]); - // Unicode minus sign - ['\u221204:00', '\u221204', '\u22120400'].forEach((offset) => - test(`1976-11-18T15:23:30.1234${offset}`, [1976, 11, 18, 19, 23, 30, 123, 400]) - ); - test('\u2212009999-11-18T15:23:30.1234Z', [-9999, 11, 18, 15, 23, 30, 123, 400]); - // Mixture of basic and extended format - test('1976-11-18T152330Z', [1976, 11, 18, 15, 23, 30]); - test('1976-11-18T152330.1234Z', [1976, 11, 18, 15, 23, 30, 123, 400]); - test('19761118T15:23:30Z', [1976, 11, 18, 15, 23, 30]); - test('19761118T152330Z', [1976, 11, 18, 15, 23, 30]); - test('19761118T152330.1234Z', [1976, 11, 18, 15, 23, 30, 123, 400]); - // Representations with reduced precision - test('1976-11-18T15Z', [1976, 11, 18, 15]); - }); - describe('not valid', () => { - // Invalid month values - ['00', '13', '20', '99'].forEach((monthString) => { - const invalidIsoString = `1976-${monthString}-18T00:00:00Z`; - it(invalidIsoString, () => { - throws(() => Temporal.Instant.from(invalidIsoString), RangeError); - }); - }); - // Invalid day values - ['00', '32', '40', '99'].forEach((dayString) => { - const invalidIsoString = `1976-11-${dayString}T00:00:00Z`; - it(invalidIsoString, () => { - throws(() => Temporal.Instant.from(invalidIsoString), RangeError); - }); - }); - }); - }); - - describe('datetime', () => { - function test(isoString, components) { - it(isoString, () => { - const [y, mon, d, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0, cid = 'iso8601'] = components; - const datetime = Temporal.PlainDateTime.from(isoString); - equal(datetime.year, y); - equal(datetime.month, mon); - equal(datetime.day, d); - equal(datetime.hour, h); - equal(datetime.minute, min); - equal(datetime.second, s); - equal(datetime.millisecond, ms); - equal(datetime.microsecond, µs); - equal(datetime.nanosecond, ns); - equal(datetime.calendar.id, cid); - }); - } - function generateTest(dateTimeString, zoneString) { - const components = [1976, 11, 18, 15, 23, 30, 123, 456, 789]; - test(`${dateTimeString}${zoneString}`, components.slice(0, 5)); - test(`${dateTimeString}:30${zoneString}`, components.slice(0, 6)); - test(`${dateTimeString}:30.123456789${zoneString}`, components); - } - describe('valid', () => { - // Time separators - ['T', 't', ' '].forEach((timeSep) => generateTest(`1976-11-18${timeSep}15:23`, '')); - // Various forms of time zone - [ - '+0100[Europe/Vienna]', - '+01:00[Europe/Vienna]', - '[Europe/Vienna]', - '+01:00[Custom/Vienna]', - '-0400', - '-04:00', - '-04:00:00.000000000', - '+010000.0[Europe/Vienna]', - '+01:00[+01:00]', - '+01:00[+0100]', - '' - ].forEach((zoneString) => generateTest('1976-11-18T15:23', zoneString)); - // Various numbers of decimal places - test('1976-11-18T15:23:30.1', [1976, 11, 18, 15, 23, 30, 100]); - test('1976-11-18T15:23:30.12', [1976, 11, 18, 15, 23, 30, 120]); - test('1976-11-18T15:23:30.123', [1976, 11, 18, 15, 23, 30, 123]); - test('1976-11-18T15:23:30.1234', [1976, 11, 18, 15, 23, 30, 123, 400]); - test('1976-11-18T15:23:30.12345', [1976, 11, 18, 15, 23, 30, 123, 450]); - test('1976-11-18T15:23:30.123456', [1976, 11, 18, 15, 23, 30, 123, 456]); - test('1976-11-18T15:23:30.1234567', [1976, 11, 18, 15, 23, 30, 123, 456, 700]); - test('1976-11-18T15:23:30.12345678', [1976, 11, 18, 15, 23, 30, 123, 456, 780]); - // Comma decimal separator - test('1976-11-18T15:23:30,1234', [1976, 11, 18, 15, 23, 30, 123, 400]); - // Unicode minus sign - ['\u221204:00', '\u221204', '\u22120400'].forEach((offset) => - test(`1976-11-18T15:23:30.1234${offset}`, [1976, 11, 18, 15, 23, 30, 123, 400]) - ); - test('\u2212009999-11-18T15:23:30.1234', [-9999, 11, 18, 15, 23, 30, 123, 400]); - // Mixture of basic and extended format - test('1976-11-18T152330', [1976, 11, 18, 15, 23, 30]); - test('1976-11-18T152330.1234', [1976, 11, 18, 15, 23, 30, 123, 400]); - test('19761118T15:23:30', [1976, 11, 18, 15, 23, 30]); - test('19761118T152330', [1976, 11, 18, 15, 23, 30]); - test('19761118T152330.1234', [1976, 11, 18, 15, 23, 30, 123, 400]); - // Representations with reduced precision - test('1976-11-18T15', [1976, 11, 18, 15]); - test('1976-11-18', [1976, 11, 18]); - // Representations with calendar - ['', '+01:00[Europe/Vienna]', '+01:00[Custom/Vienna]', '[Europe/Vienna]'].forEach((zoneString) => - test(`1976-11-18T15:23:30.123456789${zoneString}[u-ca=iso8601]`, [1976, 11, 18, 15, 23, 30, 123, 456, 789]) - ); - }); - describe('not valid', () => { - // Invalid month values - ['00', '13', '20', '99'].forEach((monthString) => { - const invalidIsoString = `1976-${monthString}-18T00:00:00`; - it(invalidIsoString, () => { - throws(() => Temporal.PlainDateTime.from(invalidIsoString), RangeError); - }); - }); - // Invalid day values - ['00', '32', '40', '99'].forEach((dayString) => { - const invalidIsoString = `1976-11-${dayString}T00:00:00`; - it(invalidIsoString, () => { - throws(() => Temporal.PlainDateTime.from(invalidIsoString), RangeError); - }); - }); - }); - }); - - describe('date', () => { - function test(isoString, components) { - it(isoString, () => { - const [y, m, d, cid = 'iso8601'] = components; - const date = Temporal.PlainDate.from(isoString); - equal(date.year, y); - equal(date.month, m); - equal(date.day, d); - equal(date.calendar.id, cid); - }); - } - function generateTest(dateTimeString, zoneString) { - const components = [1976, 11, 18]; - test(`${dateTimeString}${zoneString}`, components); - test(`${dateTimeString}:30${zoneString}`, components); - test(`${dateTimeString}:30.123456789${zoneString}`, components); - } - // Time separators - ['T', 't', ' '].forEach((timeSep) => generateTest(`1976-11-18${timeSep}15:23`, '')); - // Various forms of time zone - [ - '+0100[Europe/Vienna]', - '[Europe/Vienna]', - '+01:00[Custom/Vienna]', - '-0400', - '-04:00:00.000000000', - '+01:00[+01:00]', - '+01:00[+0100]', - '' - ].forEach((zoneString) => generateTest('1976-11-18T15:23', zoneString)); - // Various numbers of decimal places - ['1', '12', '123', '1234', '12345', '123456', '1234567', '12345678'].forEach((decimals) => - test(`1976-11-18T15:23:30.${decimals}`, [1976, 11, 18]) - ); - [ - // Comma decimal separator - '1976-11-18T15:23:30,1234', - // Mixture of basic and extended format - '1976-11-18T152330', - '1976-11-18T152330.1234', - '19761118T15:23:30', - '19761118T152330', - '19761118T152330.1234' - ].forEach((str) => test(str, [1976, 11, 18])); - // Unicode minus sign - test('\u2212009999-11-18', [-9999, 11, 18]); - // Representations with reduced precision - test('1976-11-18T15', [1976, 11, 18]); - // Date-only forms - test('1976-11-18', [1976, 11, 18]); - test('19761118', [1976, 11, 18]); - test('+199999-11-18', [199999, 11, 18]); - test('+1999991118', [199999, 11, 18]); - test('-000300-11-18', [-300, 11, 18]); - test('-0003001118', [-300, 11, 18]); - test('1512-11-18', [1512, 11, 18]); - test('15121118', [1512, 11, 18]); - // Representations with calendar - ['', '+01:00[Europe/Vienna]', '[Europe/Vienna]', '+01:00[Custom/Vienna]'].forEach((zoneString) => - test(`1976-11-18T15:23:30.123456789${zoneString}[u-ca=iso8601]`, [1976, 11, 18]) - ); - test('1976-11-18[u-ca=iso8601]', [1976, 11, 18]); - }); - - describe('time', () => { - function test(isoString, components) { - it(isoString, () => { - const [h = 0, m = 0, s = 0, ms = 0, µs = 0, ns = 0] = components; - const time = Temporal.PlainTime.from(isoString); - equal(time.hour, h); - equal(time.minute, m); - equal(time.second, s); - equal(time.millisecond, ms); - equal(time.microsecond, µs); - equal(time.nanosecond, ns); - }); - } - function generateTest(dateTimeString, zoneString) { - const components = [15, 23, 30, 123, 456, 789]; - test(`${dateTimeString}${zoneString}`, components.slice(0, 2)); - test(`${dateTimeString}:30${zoneString}`, components.slice(0, 3)); - test(`${dateTimeString}:30.123456789${zoneString}`, components); - } - // Time separators - ['T', 't', ' '].forEach((timeSep) => generateTest(`1976-11-18${timeSep}15:23`, '')); - // Various forms of time zone - [ - '+0100[Europe/Vienna]', - '+01:00[Custom/Vienna]', - '-0400', - '-04:00:00.000000000', - '+010000.0[Europe/Vienna]', - '+01:00[+01:00]', - '+01:00[+0100]', - '' - ].forEach((zoneString) => generateTest('1976-11-18T15:23', zoneString)); - // Various numbers of decimal places - test('1976-11-18T15:23:30.1', [15, 23, 30, 100]); - test('1976-11-18T15:23:30.12', [15, 23, 30, 120]); - test('1976-11-18T15:23:30.123', [15, 23, 30, 123]); - test('1976-11-18T15:23:30.1234', [15, 23, 30, 123, 400]); - test('1976-11-18T15:23:30.12345', [15, 23, 30, 123, 450]); - test('1976-11-18T15:23:30.123456', [15, 23, 30, 123, 456]); - test('1976-11-18T15:23:30.1234567', [15, 23, 30, 123, 456, 700]); - test('1976-11-18T15:23:30.12345678', [15, 23, 30, 123, 456, 780]); - // Comma decimal separator - test('1976-11-18T15:23:30,1234', [15, 23, 30, 123, 400]); - // Mixture of basic and extended format - test('1976-11-18T152330', [15, 23, 30]); - test('1976-11-18T152330.1234', [15, 23, 30, 123, 400]); - test('19761118T15:23:30', [15, 23, 30]); - test('19761118T152330', [15, 23, 30]); - test('19761118T152330.1234', [15, 23, 30, 123, 400]); - // Representations with reduced precision - test('1976-11-18T15', [15]); - // Time-only forms - ['T', 't', ''].forEach((prefix) => generateTest(`${prefix}15:23`, '')); - test('T15', [15]); - test('T1523', [15, 23]); - test('T152330', [15, 23, 30]); - generateTest('15:23', ''); - ['+01:00[Europe/Vienna]', '[Europe/Vienna]', '+01:00[Custom/Vienna]', '-04:00', 'Z', ''].forEach((zoneStr) => - test(`15${zoneStr}`, [15]) - ); - // Representations with calendar - ['', '+01:00[Europe/Vienna]', '[Europe/Vienna]', '+01:00[Custom/Vienna]'].forEach((zoneString) => - test(`1976-11-18T15:23:30.123456789${zoneString}[u-ca=iso8601]`, [15, 23, 30, 123, 456, 789]) - ); - test('15:23:30.123456789[u-ca=iso8601]', [15, 23, 30, 123, 456, 789]); - }); - - describe('yearmonth', () => { - function test(isoString, components) { - it(isoString, () => { - const [y, m, cid = 'iso8601'] = components; - const yearMonth = Temporal.PlainYearMonth.from(isoString); - equal(yearMonth.year, y); - equal(yearMonth.month, m); - equal(yearMonth.calendar.id, cid); - }); - } - function generateTest(dateTimeString, zoneString) { - const components = [1976, 11]; - test(`${dateTimeString}${zoneString}`, components); - test(`${dateTimeString}:30${zoneString}`, components); - test(`${dateTimeString}:30.123456789${zoneString}`, components); - } - // Time separators - ['T', 't', ' '].forEach((timeSep) => generateTest(`1976-11-18${timeSep}15:23`, '')); - // Various forms of time zone - [ - '+0100[Europe/Vienna]', - '[Europe/Vienna]', - '+01:00[Custom/Vienna]', - '-0400', - '-04:00:00.000000000', - '+01:00:00.0[Europe/Vienna]', - '+01:00[+01:00]', - '+01:00[+0100]', - '' - ].forEach((zoneString) => generateTest('1976-11-18T15:23', zoneString)); - // Various numbers of decimal places - ['1', '12', '123', '1234', '12345', '123456', '1234567', '12345678'].forEach((decimals) => - test(`1976-11-18T15:23:30.${decimals}`, [1976, 11]) - ); - [ - // Comma decimal separator - '1976-11-18T15:23:30,1234', - // Mixture of basic and extended format - '1976-11-18T152330', - '1976-11-18T152330.1234', - '19761118T15:23:30', - '19761118T152330', - '19761118T152330.1234', - // Representations with reduced precision - '1976-11-18T15' - ].forEach((str) => test(str, [1976, 11])); - // Unicode minus sign - test('\u2212009999-11-18T15:23:30.1234', [-9999, 11]); - // Date-only forms - test('1976-11-18', [1976, 11]); - test('19761118', [1976, 11]); - test('+199999-11-18', [199999, 11]); - test('+1999991118', [199999, 11]); - test('-000300-11-18', [-300, 11]); - test('-0003001118', [-300, 11]); - test('1512-11-18', [1512, 11]); - test('15121118', [1512, 11]); - // Year-month forms - test('1976-11', [1976, 11]); - test('197611', [1976, 11]); - test('+199999-11', [199999, 11]); - test('+19999911', [199999, 11]); - test('-000300-11', [-300, 11]); - test('-00030011', [-300, 11]); - test('1512-11', [1512, 11]); - test('151211', [1512, 11]); - // Representations with calendar - ['', '+01:00[Europe/Vienna]', '[Europe/Vienna]', '+01:00[Custom/Vienna]'].forEach((zoneString) => - test(`1976-11-18T15:23:30.123456789${zoneString}[u-ca=iso8601]`, [1976, 11]) - ); - test('1976-11-01[u-ca=iso8601]', [1976, 11]); - }); - - describe('monthday', () => { - function test(isoString, components) { - it(isoString, () => { - const [m, d, cid = 'iso8601'] = components; - const monthDay = Temporal.PlainMonthDay.from(isoString); - equal(monthDay.monthCode, `M${m.toString().padStart(2, '0')}`); - equal(monthDay.day, d); - equal(monthDay.calendar.id, cid); - }); - } - function generateTest(dateTimeString, zoneString) { - const components = [11, 18]; - test(`${dateTimeString}${zoneString}`, components); - test(`${dateTimeString}:30${zoneString}`, components); - test(`${dateTimeString}:30.123456789${zoneString}`, components); - } - // Time separators - ['T', 't', ' '].forEach((timeSep) => generateTest(`1976-11-18${timeSep}15:23`, '')); - // Various forms of time zone - [ - '+0100[Europe/Vienna]', - '[Europe/Vienna]', - '+01:00[Custom/Vienna]', - '-0400', - '-04:00:00.000000000', - '+010000.0[Europe/Vienna]', - '+01:00[+01:00]', - '+01:00[+0100]', - '' - ].forEach((zoneString) => generateTest('1976-11-18T15:23', zoneString)); - // Various numbers of decimal places - ['1', '12', '123', '1234', '12345', '123456', '1234567', '12345678'].forEach((decimals) => - test(`1976-11-18T15:23:30.${decimals}`, [11, 18]) - ); - [ - // Comma decimal separator - '1976-11-18T15:23:30,1234', - // Unicode minus sign - '\u2212009999-11-18', - // Mixture of basic and extended format - '1976-11-18T152330', - '1976-11-18T152330.1234', - '19761118T15:23:30', - '19761118T152330', - '19761118T152330.1234', - // Representations with reduced precision - '1976-11-18T15', - // Date-only forms - '1976-11-18', - '19761118', - '+199999-11-18', - '+1999991118', - '-000300-11-18', - '-0003001118', - '1512-11-18', - '15121118' - ].forEach((str) => test(str, [11, 18])); - // Month-day forms - test('11-18', [11, 18]); - test('1118', [11, 18]); - test('12-13', [12, 13]); - test('1213', [12, 13]); - test('02-02', [2, 2]); - test('0202', [2, 2]); - test('01-31', [1, 31]); - test('0131', [1, 31]); - // RFC 3339 month-day form - test('--11-18', [11, 18]); - test('--1118', [11, 18]); - // Representations with calendar - ['', '+01:00[Europe/Vienna]', '[Europe/Vienna]', '+01:00[Custom/Vienna]'].forEach((zoneString) => - test(`1976-11-18T15:23:30.123456789${zoneString}[u-ca=iso8601]`, [11, 18]) - ); - test('1972-11-18[u-ca=iso8601]', [11, 18]); - }); - - describe('timezone', () => { - function test(offsetString, expectedName) { - it(offsetString, () => { - const timeZone = Temporal.TimeZone.from(offsetString); - equal(timeZone.id, expectedName); - }); - } - function generateTest(dateTimeString, zoneString, expectedName) { - test(`${dateTimeString}${zoneString}`, expectedName); - test(`${dateTimeString}:30${zoneString}`, expectedName); - test(`${dateTimeString}:30.123456789${zoneString}`, expectedName); - } - // Time separators - ['T', 't', ' '].forEach((timeSep) => generateTest(`1976-11-18${timeSep}15:23`, 'Z', 'UTC')); - // Time zone with bracketed name - ['+01:00', '+01', '+0100', '+01:00:00', '+010000', '+01:00:00.000000000', '+010000.0'].forEach((zoneString) => { - generateTest('1976-11-18T15:23', `${zoneString}[Europe/Vienna]`, 'Europe/Vienna'); - generateTest('1976-11-18T15:23', `+01:00[${zoneString}]`, '+01:00'); - }); - // Time zone with only offset - ['-04:00', '-04', '-0400', '-04:00:00', '-040000', '-04:00:00.000000000', '-040000.0'].forEach((zoneString) => - generateTest('1976-11-18T15:23', zoneString, '-04:00') - ); - // Various numbers of decimal places - ['1', '12', '123', '1234', '12345', '123456', '1234567', '12345678'].forEach((decimals) => { - test(`1976-11-18T15:23:30.${decimals}Z`, 'UTC'); - test(`1976-11-18T15:23+01:00[+01:00:00.${decimals}]`, `+01:00:00.${decimals}`); - }); - // Lowercase UTC designator - generateTest('1976-11-18T15:23', 'z', 'UTC'); - // Comma decimal separator - test('1976-11-18T15:23:30,1234Z', 'UTC'); - test('1976-11-18T15:23-04:00:00,000000000', '-04:00'); - test('1976-11-18T15:23+010000,0[Europe/Vienna]', 'Europe/Vienna'); - // Unicode minus sign - ['\u221204:00', '\u221204', '\u22120400'].forEach((offset) => test(`1976-11-18T15:23${offset}`, '-04:00')); - [ - // Mixture of basic and extended format - '1976-11-18T152330', - '1976-11-18T152330.1234', - '19761118T15:23:30', - '19761118T152330', - '19761118T152330.1234', - // Representations with reduced precision - '1976-11-18T15' - ].forEach((dateTimeString) => { - ['+01:00', '+01', '+0100', ''].forEach((zoneString) => - test(`${dateTimeString}${zoneString}[Europe/Vienna]`, 'Europe/Vienna') - ); - ['-04:00', '-04', '-0400'].forEach((zoneString) => test(`${dateTimeString}${zoneString}`, '-04:00')); - test(`${dateTimeString}Z`, 'UTC'); - }); - // Offset-only forms - test('+0000', '+00:00'); - test('-0000', '+00:00'); - test('+00:00', '+00:00'); - test('-00:00', '+00:00'); - test('+00', '+00:00'); - test('-00', '+00:00'); - test('+0300', '+03:00'); - test('-0300', '-03:00'); - test('+03:00', '+03:00'); - test('-03:00', '-03:00'); - test('+03', '+03:00'); - test('-03', '-03:00'); - test('\u22120000', '+00:00'); - test('\u221200:00', '+00:00'); - test('\u221200', '+00:00'); - test('\u22120300', '-03:00'); - test('\u221203:00', '-03:00'); - test('\u221203', '-03:00'); - test('+03:00:00', '+03:00'); - test('+030000', '+03:00'); - test('+03:00:00.000000000', '+03:00'); - test('+030000.0', '+03:00'); - test('-03:00:00', '-03:00'); - test('-030000', '-03:00'); - test('-03:00:00.000000000', '-03:00'); - test('-030000.0', '-03:00'); - // Representations with calendar - test('1976-11-18T15:23:30.123456789Z[u-ca=iso8601]', 'UTC'); - test('1976-11-18T15:23:30.123456789-04:00[u-ca=iso8601]', '-04:00'); - test('1976-11-18T15:23:30.123456789[Europe/Vienna][u-ca=iso8601]', 'Europe/Vienna'); - test('1976-11-18T15:23:30.123456789+01:00[Europe/Vienna][u-ca=iso8601]', 'Europe/Vienna'); - }); - - describe('duration', () => { - function test(isoString, components) { - it(isoString, () => { - const { y = 0, mon = 0, w = 0, d = 0, h = 0, min = 0, s = 0, ms = 0, µs = 0, ns = 0 } = components; - const duration = Temporal.Duration.from(isoString); - equal(duration.years, y); - equal(duration.months, mon); - equal(duration.weeks, w); - equal(duration.days, d); - equal(duration.hours, h); - equal(duration.minutes, min); - equal(duration.seconds, s); - equal(duration.milliseconds, ms); - equal(duration.microseconds, µs); - equal(duration.nanoseconds, ns); - }); - } - - const day = [ - ['', {}], - ['1Y', { y: 1 }], - ['2M', { mon: 2 }], - ['4W', { w: 4 }], - ['3D', { d: 3 }], - ['1Y2M', { y: 1, mon: 2 }], - ['1Y3D', { y: 1, d: 3 }], - ['2M3D', { mon: 2, d: 3 }], - ['4W3D', { w: 4, d: 3 }], - ['1Y2M3D', { y: 1, mon: 2, d: 3 }], - ['1Y2M4W3D', { y: 1, mon: 2, w: 4, d: 3 }] - ]; - const times = [ - ['', {}], - ['4H', { h: 4 }], - ['5M', { min: 5 }], - ['4H5M', { h: 4, min: 5 }] - ]; - const sec = [ - ['', {}], - ['6S', { s: 6 }], - ['7.1S', { s: 7, ms: 100 }], - ['7.12S', { s: 7, ms: 120 }], - ['7.123S', { s: 7, ms: 123 }], - ['8.1234S', { s: 8, ms: 123, µs: 400 }], - ['8.12345S', { s: 8, ms: 123, µs: 450 }], - ['8.123456S', { s: 8, ms: 123, µs: 456 }], - ['9.1234567S', { s: 9, ms: 123, µs: 456, ns: 700 }], - ['9.12345678S', { s: 9, ms: 123, µs: 456, ns: 780 }], - ['9.123456789S', { s: 9, ms: 123, µs: 456, ns: 789 }], - ['0.123S', { ms: 123 }], - ['0,123S', { ms: 123 }], - ['0.123456S', { ms: 123, µs: 456 }], - ['0,123456S', { ms: 123, µs: 456 }], - ['0.123456789S', { ms: 123, µs: 456, ns: 789 }], - ['0,123456789S', { ms: 123, µs: 456, ns: 789 }] - ]; - const tim = sec - .reduce((arr, [s, add]) => arr.concat(times.map(([p, expect]) => [`${p}${s}`, { ...expect, ...add }])), []) - .slice(1); - - day.slice(1).forEach(([p, expect]) => { - test(`P${p}`, expect); - test(`p${p}`, expect); - test(`p${p.toLowerCase()}`, expect); - }); - tim.forEach(([p, expect]) => { - test(`PT${p}`, expect); - test(`Pt${p}`, expect); - test(`pt${p.toLowerCase()}`, expect); - }); - for (let [d, dexpect] of day) { - for (let [t, texpect] of tim) { - test(`P${d}T${t}`, { ...dexpect, ...texpect }); - test(`p${d}T${t.toLowerCase()}`, { ...dexpect, ...texpect }); - test(`P${d.toLowerCase()}t${t}`, { ...dexpect, ...texpect }); - test(`p${d.toLowerCase()}t${t.toLowerCase()}`, { ...dexpect, ...texpect }); - } - } - }); - - // These can be tested again once the resolver options are accepted. - describe.skip('time zone ID', () => { - let oldTemporalTimeZoneFrom = Temporal.TimeZone.from; - let fromCalledWith; - before(() => { - Temporal.TimeZone.from = function (item) { - fromCalledWith = item; - return new Temporal.TimeZone('UTC'); - }; - }); - function testTimeZoneID(id) { - return Temporal.ZonedDateTime.from(`1970-01-01T00:00[${id}]`); - } - describe('valid', () => { - [ - '.a', - '..a', - '...', - '_', - 'a', - 'a-', - 'a-a', - 'a-aa', - 'a-aa-', - 'a-aa-a', - 'a-aa-aa', - 'a-aa-aa-', - 'Etc/.a', - 'Etc/..a', - 'Etc/...', - 'Etc/_', - 'Etc/a-a', - 'Etc/FourteenCharsZ', - 'Etc/FourteenCharsZ/FourteenCharsZ', - 'Etc/GMT-8', - 'Etc/GMT-12', - 'Etc/GMT+8', - 'Etc/GMT+12' - ].forEach((id) => { - it(id, () => { - testTimeZoneID(id); - equal(fromCalledWith, id); - }); - }); - }); - describe('not valid', () => { - [ - '.', - '..', - '-', - '3', - '-Foo', - 'Etc/.', - 'Etc/..', - 'Etc/-', - 'Etc/3', - 'Etc/-Foo', - 'Etc/😺', - 'Etc/FifteenCharsZZZ', - 'GMT-8', - 'GMT+8', - 'Foo/Etc/GMT-8' - ].forEach((id) => { - it(id, () => { - throws(() => testTimeZoneID(id), RangeError); - }); - }); - }); - after(() => { - Temporal.TimeZone.from = oldTemporalTimeZoneFrom; - }); - }); - - // These can be tested again once the resolver options are accepted. - describe.skip('calendar ID', () => { - let oldTemporalCalendarFrom = Temporal.Calendar.from; - let fromCalledWith; - before(() => { - Temporal.Calendar.from = function (item) { - fromCalledWith = item; - return new Temporal.Calendar('iso8601'); - }; - }); - function testCalendarID(id) { - return Temporal.PlainDateTime.from(`1970-01-01T00:00+00:00[UTC][u-ca=${id}]`); - } - describe('valid', () => { - ['aaa', 'aaa-aaa', 'eightZZZ', 'eightZZZ-eightZZZ'].forEach((id) => { - it(id, () => { - testCalendarID(id); - equal(fromCalledWith, id); - }); - }); - }); - describe('not valid', () => { - ['a', 'a-a', 'aa', 'aa-aa', 'foo_', 'foo.', 'ninechars', 'ninechars-ninechars'].forEach((id) => { - it(id, () => { - throws(() => testCalendarID(id), RangeError); - }); - }); - }); - after(() => { - Temporal.Calendar.from = oldTemporalCalendarFrom; - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/timeZone.js b/packages/temporal-polyfill/tests/timeZone.js deleted file mode 100644 index d003cfa5..00000000 --- a/packages/temporal-polyfill/tests/timeZone.js +++ /dev/null @@ -1,565 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { deepEqual, strictEqual: equal, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; - -describe('TimeZone', () => { - describe('Structure', () => { - it('Temporal.TimeZone is a function', () => equal(typeof Temporal.TimeZone, 'function')); - it('Temporal.TimeZone has prototype', () => equal(typeof Temporal.TimeZone.prototype, 'object')); - describe('Temporal.TimeZone.prototype', () => { - it('Temporal.TimeZone.prototype has id', () => assert('id' in Temporal.TimeZone.prototype)); - it('Temporal.TimeZone.prototype has getOffsetNanosecondsFor', () => - equal(typeof Temporal.TimeZone.prototype.getOffsetNanosecondsFor, 'function')); - it('Temporal.TimeZone.prototype has getOffsetStringFor', () => - equal(typeof Temporal.TimeZone.prototype.getOffsetStringFor, 'function')); - it('Temporal.TimeZone.prototype has getPlainDateTimeFor', () => - equal(typeof Temporal.TimeZone.prototype.getPlainDateTimeFor, 'function')); - it('Temporal.TimeZone.prototype has getInstantFor', () => - equal(typeof Temporal.TimeZone.prototype.getInstantFor, 'function')); - it('Temporal.TimeZone.prototype has getPossibleInstantsFor', () => - equal(typeof Temporal.TimeZone.prototype.getPossibleInstantsFor, 'function')); - it('Temporal.TimeZone.prototype has getNextTransition', () => - equal(typeof Temporal.TimeZone.prototype.getNextTransition, 'function')); - it('Temporal.TimeZone.prototype has getPreviousTransition', () => - equal(typeof Temporal.TimeZone.prototype.getPreviousTransition, 'function')); - it('Temporal.TimeZone.prototype has toString', () => - equal(typeof Temporal.TimeZone.prototype.toString, 'function')); - }); - it('Temporal.TimeZone has from', () => equal(typeof Temporal.TimeZone.from, 'function')); - }); - describe('Construction', () => { - test('+01:00'); - test('-01:00'); - test('+0330'); - test('-0650'); - test('-08'); - test('\u221201:00'); - test('\u22120650'); - test('\u221208'); - test('+01:00:00'); - test('-010000'); - test('+03:30:00.000000001'); - test('-033000.1'); - test('Europe/Vienna'); - test('America/New_York'); - test('Africa/CAIRO'); // capitalization - test('Asia/Ulan_Bator'); // IANA Link Name - test('UTC'); - test('GMT'); - function test(zone) { - it(`${zone} is a zone`, () => equal(typeof new Temporal.TimeZone(zone), 'object')); - } - ['+00:01.1', '-01.1'].forEach((id) => { - it(`${id} is not a zone`, () => throws(() => new Temporal.TimeZone(id), RangeError)); - }); - }); - describe('.id property', () => { - test('+01:00'); - test('-01:00'); - test('+0330', '+03:30'); - test('-0650', '-06:50'); - test('-08', '-08:00'); - test('\u221201:00', '-01:00'); - test('\u22120650', '-06:50'); - test('\u221208', '-08:00'); - test('+01:00:00', '+01:00'); - test('-010000', '-01:00'); - test('+03:30:00.000000001', '+03:30:00.000000001'); - test('-033000.1', '-03:30:00.1'); - test('Europe/Vienna'); - test('America/New_York'); - test('Africa/CAIRO', 'Africa/Cairo'); - test('Asia/Ulan_Bator', 'Asia/Ulaanbaatar'); - test('UTC'); - test('GMT', 'UTC'); - function test(zone, id = zone) { - it(`${zone} has ID ${id}`, () => equal(new Temporal.TimeZone(zone).id, id)); - } - }); - describe('TimeZone.from(identifier)', () => { - test('+01:00'); - test('-01:00'); - test('+0330'); - test('-0650'); - test('-08'); - test('\u221201:00'); - test('\u22120650'); - test('\u221208'); - test('Europe/Vienna'); - test('America/New_York'); - test('Africa/CAIRO'); - test('Asia/Ulan_Bator'); - test('UTC'); - test('GMT'); - function test(zone) { - const timezoneFrom = Temporal.TimeZone.from(zone); - const timezoneObj = new Temporal.TimeZone(zone); - it(`TimeZone.from(${zone}) is a time zone`, () => equal(typeof timezoneFrom, 'object')); - it(`TimeZone.from(${zone}) does the same thing as new TimeZone(${zone})`, () => - equal(timezoneFrom.id, timezoneObj.id)); - } - it('ZonedDateTime is accepted', () => { - const zdt = new Temporal.ZonedDateTime(0n, 'Africa/Cairo'); - const tzFrom = Temporal.TimeZone.from(zdt); - assert(tzFrom instanceof Temporal.TimeZone); - equal(tzFrom.id, 'Africa/Cairo'); - }); - it('property bag with time zone object is accepted', () => { - const tz = new Temporal.TimeZone('Africa/Cairo'); - const tzFrom = Temporal.TimeZone.from({ timeZone: tz }); - assert(tzFrom instanceof Temporal.TimeZone); - equal(tzFrom.id, 'Africa/Cairo'); - }); - it('property bag with string is accepted', () => { - const tzFrom = Temporal.TimeZone.from({ timeZone: 'Africa/Cairo' }); - assert(tzFrom instanceof Temporal.TimeZone); - equal(tzFrom.id, 'Africa/Cairo'); - }); - it('property bag with custom time zone is accepted', () => { - const custom = { id: 'Etc/Custom' }; - const tzFrom = Temporal.TimeZone.from({ timeZone: custom }); - equal(tzFrom, custom); - }); - it('throws with bad identifier', () => { - ['local', 'Z', '-08:00[America/Vancouver]', '+00:01.1', '-01.1'].forEach((bad) => { - throws(() => Temporal.TimeZone.from(bad), RangeError); - }); - }); - it('throws with bad value in property bag', () => { - throws(() => Temporal.TimeZone.from({ timeZone: 'local' }), RangeError); - throws(() => Temporal.TimeZone.from({ timeZone: { timeZone: 'Africa/Cairo' } }), RangeError); - }); - }); - describe('TimeZone.from(ISO string)', () => { - test('1994-11-05T08:15:30-05:00', '-05:00'); - test('1994-11-05T08:15:30-05:00[America/New_York]', 'America/New_York'); - test('1994-11-05T08:15:30-05[America/New_York]', 'America/New_York'); - test('1994-11-05T08:15:30\u221205:00', '-05:00'); - test('1994-11-05T08:15:30\u221205:00[America/New_York]', 'America/New_York'); - test('1994-11-05T08:15:30\u221205[America/New_York]', 'America/New_York'); - test('1994-11-05T13:15:30Z', 'UTC'); - function test(isoString, id) { - const tz = Temporal.TimeZone.from(isoString); - it(`TimeZone.from(${isoString}) is a time zone`, () => equal(typeof tz, 'object')); - it(`TimeZone.from(${isoString}) has ID ${id}`, () => equal(tz.id, id)); - } - it('offset out of range throws', () => { - throws(() => Temporal.TimeZone.from('1994-11-05T08:15:30+25:00'), RangeError); - throws(() => Temporal.TimeZone.from('1994-11-05T13:15:30-25:00'), RangeError); - }); - }); - describe('+01:00', () => { - const zone = new Temporal.TimeZone('+01:00'); - const inst = Temporal.Instant.fromEpochSeconds(Math.floor(Math.random() * 1e9)); - const dtm = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); - it(`${zone} has ID ${zone}`, () => equal(zone.id, `${zone}`)); - it(`${zone} has offset +01:00 in ns`, () => equal(zone.getOffsetNanosecondsFor(inst), 3600e9)); - it(`${zone} has offset +01:00`, () => equal(zone.getOffsetStringFor(inst), '+01:00')); - it(`(${zone}).getPlainDateTimeFor(${inst})`, () => - assert(zone.getPlainDateTimeFor(inst) instanceof Temporal.PlainDateTime)); - it(`(${zone}).getInstantFor(${dtm})`, () => assert(zone.getInstantFor(dtm) instanceof Temporal.Instant)); - it(`(${zone}).getNextTransition(${inst})`, () => equal(zone.getNextTransition(inst), null)); - it(`(${zone}).getPreviousTransition(${inst})`, () => equal(zone.getPreviousTransition(inst), null)); - it('wraps around to the next day', () => - equal(`${zone.getPlainDateTimeFor(Temporal.Instant.from('2020-02-06T23:59Z'))}`, '2020-02-07T00:59:00')); - }); - describe('UTC', () => { - const zone = new Temporal.TimeZone('UTC'); - const inst = Temporal.Instant.fromEpochSeconds(Math.floor(Math.random() * 1e9)); - const dtm = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); - it(`${zone} has ID ${zone}`, () => equal(zone.id, `${zone}`)); - it(`${zone} has offset +00:00 in ns`, () => equal(zone.getOffsetNanosecondsFor(inst), 0)); - it(`${zone} has offset +00:00`, () => equal(zone.getOffsetStringFor(inst), '+00:00')); - it(`(${zone}).getPlainDateTimeFor(${inst})`, () => - assert(zone.getPlainDateTimeFor(inst) instanceof Temporal.PlainDateTime)); - it(`(${zone}).getInstantFor(${dtm})`, () => assert(zone.getInstantFor(dtm) instanceof Temporal.Instant)); - it(`(${zone}).getNextTransition(${inst})`, () => equal(zone.getNextTransition(inst), null)); - it(`(${zone}).getPreviousTransition(${inst})`, () => equal(zone.getPreviousTransition(inst), null)); - }); - describe('America/Los_Angeles', () => { - const zone = new Temporal.TimeZone('America/Los_Angeles'); - const inst = new Temporal.Instant(0n); - const dtm = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); - it(`${zone} has ID ${zone}`, () => equal(zone.id, `${zone}`)); - it(`${zone} has offset -08:00 in ns`, () => equal(zone.getOffsetNanosecondsFor(inst), -8 * 3600e9)); - it(`${zone} has offset -08:00`, () => equal(zone.getOffsetStringFor(inst), '-08:00')); - it(`(${zone}).getPlainDateTimeFor(${inst})`, () => - assert(zone.getPlainDateTimeFor(inst) instanceof Temporal.PlainDateTime)); - it(`(${zone}).getInstantFor(${dtm})`, () => assert(zone.getInstantFor(dtm) instanceof Temporal.Instant)); - it(`(${zone}).getNextTransition() x 4 transitions`, () => { - for (let i = 0, txn = inst; i < 4; i++) { - const transition = zone.getNextTransition(txn); - assert(transition); - assert(!transition.equals(txn)); - txn = transition; - } - }); - it(`(${zone}).getPreviousTransition() x 4 transitions`, () => { - for (let i = 0, txn = inst; i < 4; i++) { - const transition = zone.getPreviousTransition(txn); - assert(transition); - assert(!transition.equals(txn)); - txn = transition; - } - }); - }); - const checkTime = (limitMsecs, func) => { - const now = Date.now(); - func(); - const msecs = Date.now() - now; - if (msecs > limitMsecs) assert(false, `Expected ${limitMsecs}ms or less, actual: ${msecs}ms`); - }; - describe('Far-future transitions (time zone currently has DST)', () => { - const zone = new Temporal.TimeZone('America/Los_Angeles'); - const inst = Temporal.Instant.from('+200000-01-01T00:00-08:00'); - it('next transition is valid', () => { - const nextTransition = zone.getNextTransition(inst, zone); - const zdtTransition = nextTransition.toZonedDateTimeISO(zone); - equal(zdtTransition.offset, '-07:00'); - equal(zdtTransition.month, 3); - equal(zdtTransition.subtract({ nanoseconds: 1 }).offset, '-08:00'); - }); - it('getNextTransition takes less than 800ms', () => { - checkTime(800, () => zone.getNextTransition(inst, zone)); - }); - it('previous transition is valid', () => { - const prevTransition = zone.getPreviousTransition(inst, zone); - const zdtTransition = prevTransition.toZonedDateTimeISO(zone); - equal(zdtTransition.offset, '-08:00'); - equal(zdtTransition.month, 11); - equal(zdtTransition.subtract({ nanoseconds: 1 }).offset, '-07:00'); - }); - it('getPreviousTransition takes less than 800ms', () => { - checkTime(800, () => zone.getPreviousTransition(inst, zone)); - }); - }); - describe('Far-future transitions (time zone has no DST now, but has past transitions)', () => { - const zone = new Temporal.TimeZone('Asia/Kolkata'); - const inst = Temporal.Instant.from('+200000-01-01T00:00+05:30'); - it('next transition is valid', () => { - const nextTransition = zone.getNextTransition(inst, zone); - equal(nextTransition, null); - }); - it('getNextTransition takes less than 800ms', () => { - checkTime(800, () => zone.getNextTransition(inst, zone)); - }); - it('previous transition is valid', () => { - const prevTransition = zone.getPreviousTransition(inst, zone); - const zdtTransition = prevTransition.toZonedDateTimeISO(zone); - equal(zdtTransition.offset, '+05:30'); - equal(prevTransition.toString(), '1945-10-14T17:30:00Z'); - equal(zdtTransition.subtract({ nanoseconds: 1 }).offset, '+06:30'); - }); - it('getPreviousTransition takes less than 800ms', () => { - checkTime(800, () => zone.getPreviousTransition(inst, zone)); - }); - }); - describe('Far-future transitions (time zone has never had any offset transitions)', () => { - const zone = new Temporal.TimeZone('Etc/GMT+8'); - const inst = Temporal.Instant.from('+200000-01-01T00:00-08:00'); - it('next transition is valid', () => { - const nextTransition = zone.getNextTransition(inst, zone); - equal(nextTransition, null); - }); - it('getNextTransition takes less than 800ms', () => { - checkTime(800, () => zone.getNextTransition(inst, zone)); - }); - it('previous transition is valid', () => { - const prevTransition = zone.getPreviousTransition(inst, zone); - equal(prevTransition, null); - }); - it('getPreviousTransition takes less than 800ms', () => { - checkTime(800, () => zone.getPreviousTransition(inst, zone)); - }); - }); - describe('Far-past transitions (time zone with some transitions)', () => { - const zone = new Temporal.TimeZone('America/Los_Angeles'); - const inst = Temporal.Instant.from('-200000-01-01T00:00-08:00'); - const zdt = inst.toZonedDateTimeISO(zone); - it('next transition is valid', () => { - const nextTransition = zone.getNextTransition(inst, zone); - const zdtTransition = nextTransition.toZonedDateTimeISO(zone); - equal(zdt.offset, '-07:52:58'); - equal(zdtTransition.toString(), '1883-11-18T12:00:00-08:00[America/Los_Angeles]'); - }); - it('getNextTransition takes less than 800ms', () => { - checkTime(800, () => zone.getNextTransition(inst, zone)); - }); - it('previous transition is valid', () => { - const prevTransition = zone.getPreviousTransition(inst, zone); - equal(prevTransition, null); - }); - it('getPreviousTransition takes less than 800ms', () => { - checkTime(800, () => zone.getPreviousTransition(inst, zone)); - }); - }); - describe('Far-past transitions (time zone has never had any offset transitions)', () => { - const zone = new Temporal.TimeZone('Etc/GMT+8'); - const inst = Temporal.Instant.from('-200000-01-01T00:00-08:00'); - it('next transition is valid', () => { - const nextTransition = zone.getNextTransition(inst, zone); - equal(nextTransition, null); - }); - it('getNextTransition takes less than 800ms', () => { - checkTime(800, () => zone.getNextTransition(inst, zone)); - }); - it('previous transition is valid', () => { - const prevTransition = zone.getPreviousTransition(inst, zone); - equal(prevTransition, null); - }); - it('getPreviousTransition takes less than 800ms', () => { - checkTime(800, () => zone.getPreviousTransition(inst, zone)); - }); - }); - describe('sub-minute offset', () => { - const zone = new Temporal.TimeZone('Europe/Amsterdam'); - const inst = Temporal.Instant.from('1900-01-01T12:00Z'); - const dtm = Temporal.PlainDateTime.from('1900-01-01T12:00'); - it(`${zone} has ID ${zone}`, () => equal(zone.id, `${zone}`)); - it(`${zone} has offset +00:19:32 in ns`, () => equal(zone.getOffsetNanosecondsFor(inst), 1172000000000)); - it(`${zone} has offset +00:19:32, does not truncate to HH:MM`, () => - equal(zone.getOffsetStringFor(inst), '+00:19:32')); - it(`(${zone}).getPlainDateTimeFor(${inst})`, () => - equal(`${zone.getPlainDateTimeFor(inst)}`, '1900-01-01T12:19:32')); - it(`(${zone}).getInstantFor(${dtm})`, () => equal(`${zone.getInstantFor(dtm)}`, '1900-01-01T11:40:28Z')); - it(`(${zone}).getNextTransition(${inst})`, () => equal(`${zone.getNextTransition(inst)}`, '1916-04-30T23:40:28Z')); - it(`(${zone}).getPreviousTransition(${inst})`, () => equal(zone.getPreviousTransition(inst), null)); - }); - describe('with DST change', () => { - it('clock moving forward', () => { - const zone = new Temporal.TimeZone('Europe/Berlin'); - const dtm = new Temporal.PlainDateTime(2019, 3, 31, 2, 45); - equal(`${zone.getInstantFor(dtm)}`, '2019-03-31T01:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'earlier' })}`, '2019-03-31T00:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'later' })}`, '2019-03-31T01:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'compatible' })}`, '2019-03-31T01:45:00Z'); - throws(() => zone.getInstantFor(dtm, { disambiguation: 'reject' }), RangeError); - }); - it('clock moving backward', () => { - const zone = new Temporal.TimeZone('America/Sao_Paulo'); - const dtm = new Temporal.PlainDateTime(2019, 2, 16, 23, 45); - equal(`${zone.getInstantFor(dtm)}`, '2019-02-17T01:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'earlier' })}`, '2019-02-17T01:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'later' })}`, '2019-02-17T02:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'compatible' })}`, '2019-02-17T01:45:00Z'); - throws(() => zone.getInstantFor(dtm, { disambiguation: 'reject' }), RangeError); - }); - }); - describe('Casting', () => { - const zone = Temporal.TimeZone.from('+03:30'); - it('getOffsetNanosecondsFor() casts its argument', () => { - equal(zone.getOffsetNanosecondsFor('2019-02-17T01:45Z'), 126e11); - }); - it('getOffsetNanosecondsFor() casts only from string', () => { - throws(() => zone.getOffsetNanosecondsFor(0n), RangeError); - throws(() => zone.getOffsetNanosecondsFor({}), RangeError); - }); - it('getOffsetStringFor() casts its argument', () => { - equal(zone.getOffsetStringFor('2019-02-17T01:45Z'), '+03:30'); - }); - it('getOffsetStringFor() casts only from string', () => { - throws(() => zone.getOffsetStringFor(0n), RangeError); - throws(() => zone.getOffsetStringFor({}), RangeError); - }); - it('getPlainDateTimeFor() casts its argument', () => { - equal(`${zone.getPlainDateTimeFor('2019-02-17T01:45Z')}`, '2019-02-17T05:15:00'); - }); - it('getPlainDateTimeFor() casts only from string', () => { - throws(() => zone.getPlainDateTimeFor(0n), RangeError); - throws(() => zone.getPlainDateTimeFor({}), RangeError); - }); - }); - describe('TimeZone.getInstantFor() works', () => { - it('recent date', () => { - const dt = Temporal.PlainDateTime.from('2019-10-29T10:46:38.271986102'); - const tz = Temporal.TimeZone.from('Europe/Amsterdam'); - equal(`${tz.getInstantFor(dt)}`, '2019-10-29T09:46:38.271986102Z'); - }); - it('year ≤ 99', () => { - const dt = Temporal.PlainDateTime.from('+000098-10-29T10:46:38.271986102'); - const tz = Temporal.TimeZone.from('+06:00'); - equal(`${tz.getInstantFor(dt)}`, '+000098-10-29T04:46:38.271986102Z'); - }); - it('year < 1', () => { - let dt = Temporal.PlainDateTime.from('+000000-10-29T10:46:38.271986102'); - const tz = Temporal.TimeZone.from('+06:00'); - equal(`${tz.getInstantFor(dt)}`, '+000000-10-29T04:46:38.271986102Z'); - dt = Temporal.PlainDateTime.from('-001000-10-29T10:46:38.271986102'); - equal(`${tz.getInstantFor(dt)}`, '-001000-10-29T04:46:38.271986102Z'); - }); - it('year 0 leap day', () => { - const dt = Temporal.PlainDateTime.from('+000000-02-29T00:00'); - const tz = Temporal.TimeZone.from('Europe/London'); - equal(`${tz.getInstantFor(dt)}`, '+000000-02-29T00:01:15Z'); - }); - it('outside of Instant range', () => { - const max = Temporal.PlainDateTime.from('+275760-09-13T23:59:59.999999999'); - - const offsetTz = Temporal.TimeZone.from('-01:00'); - throws(() => offsetTz.getInstantFor(max), RangeError); - - const namedTz = Temporal.TimeZone.from('America/Godthab'); - throws(() => namedTz.getInstantFor(max), RangeError); - }); - it('options may only be an object or undefined', () => { - const dt = Temporal.PlainDateTime.from('2019-10-29T10:46:38.271986102'); - const tz = Temporal.TimeZone.from('America/Sao_Paulo'); - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => tz.getInstantFor(dt, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${tz.getInstantFor(dt, options)}`, '2019-10-29T13:46:38.271986102Z') - ); - }); - it('casts argument', () => { - const tz = Temporal.TimeZone.from('Europe/Amsterdam'); - equal(`${tz.getInstantFor('2019-10-29T10:46:38.271986102')}`, '2019-10-29T09:46:38.271986102Z'); - equal( - `${tz.getInstantFor({ year: 2019, month: 10, day: 29, hour: 10, minute: 46, second: 38 })}`, - '2019-10-29T09:46:38Z' - ); - }); - it('object must contain at least the required properties', () => { - const tz = Temporal.TimeZone.from('Europe/Amsterdam'); - throws(() => tz.getInstantFor({ year: 2019 }), TypeError); - }); - }); - describe('getInstantFor disambiguation', () => { - const dtm = new Temporal.PlainDateTime(2019, 2, 16, 23, 45); - it('with constant offset', () => { - const zone = Temporal.TimeZone.from('+03:30'); - for (const disambiguation of [undefined, 'compatible', 'earlier', 'later', 'reject']) { - assert(zone.getInstantFor(dtm, { disambiguation }) instanceof Temporal.Instant); - } - }); - it('with daylight saving change - Fall', () => { - const zone = Temporal.TimeZone.from('America/Sao_Paulo'); - equal(`${zone.getInstantFor(dtm)}`, '2019-02-17T01:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'earlier' })}`, '2019-02-17T01:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'later' })}`, '2019-02-17T02:45:00Z'); - equal(`${zone.getInstantFor(dtm, { disambiguation: 'compatible' })}`, '2019-02-17T01:45:00Z'); - throws(() => zone.getInstantFor(dtm, { disambiguation: 'reject' }), RangeError); - }); - it('with daylight saving change - Spring', () => { - const dtmLA = new Temporal.PlainDateTime(2020, 3, 8, 2, 30); - const zone = Temporal.TimeZone.from('America/Los_Angeles'); - equal(`${zone.getInstantFor(dtmLA)}`, '2020-03-08T10:30:00Z'); - equal(`${zone.getInstantFor(dtmLA, { disambiguation: 'earlier' })}`, '2020-03-08T09:30:00Z'); - equal(`${zone.getInstantFor(dtmLA, { disambiguation: 'later' })}`, '2020-03-08T10:30:00Z'); - equal(`${zone.getInstantFor(dtmLA, { disambiguation: 'compatible' })}`, '2020-03-08T10:30:00Z'); - throws(() => zone.getInstantFor(dtmLA, { disambiguation: 'reject' }), RangeError); - }); - it('throws on bad disambiguation', () => { - const zone = Temporal.TimeZone.from('+03:30'); - ['', 'EARLIER', 'test', 3, null].forEach((disambiguation) => - throws(() => zone.getInstantFor(dtm, { disambiguation }), RangeError) - ); - }); - }); - describe('getPossibleInstantsFor', () => { - it('with constant offset', () => { - const zone = Temporal.TimeZone.from('+03:30'); - const dt = Temporal.PlainDateTime.from('2019-02-16T23:45'); - deepEqual( - zone.getPossibleInstantsFor(dt).map((a) => `${a}`), - ['2019-02-16T20:15:00Z'] - ); - }); - it('with clock moving forward', () => { - const zone = Temporal.TimeZone.from('Europe/Berlin'); - const dt = Temporal.PlainDateTime.from('2019-03-31T02:45'); - deepEqual(zone.getPossibleInstantsFor(dt), []); - }); - it('with clock moving backward', () => { - const zone = Temporal.TimeZone.from('America/Sao_Paulo'); - const dt = Temporal.PlainDateTime.from('2019-02-16T23:45'); - deepEqual( - zone.getPossibleInstantsFor(dt).map((a) => `${a}`), - ['2019-02-17T01:45:00Z', '2019-02-17T02:45:00Z'] - ); - }); - it('outside of Instant range', () => { - const max = Temporal.PlainDateTime.from('+275760-09-13T23:59:59.999999999'); - - const offsetTz = Temporal.TimeZone.from('-01:00'); - throws(() => offsetTz.getPossibleInstantsFor(max), RangeError); - - const namedTz = Temporal.TimeZone.from('America/Godthab'); - throws(() => namedTz.getPossibleInstantsFor(max), RangeError); - }); - it('casts argument', () => { - const tz = Temporal.TimeZone.from('+03:30'); - deepEqual( - tz - .getPossibleInstantsFor({ year: 2019, month: 2, day: 16, hour: 23, minute: 45, second: 30 }) - .map((a) => `${a}`), - ['2019-02-16T20:15:30Z'] - ); - deepEqual( - tz.getPossibleInstantsFor('2019-02-16T23:45:30').map((a) => `${a}`), - ['2019-02-16T20:15:30Z'] - ); - }); - it('object must contain at least the required properties', () => { - const tz = Temporal.TimeZone.from('Europe/Amsterdam'); - throws(() => tz.getPossibleInstantsFor({ year: 2019 }), TypeError); - }); - }); - describe('getNextTransition works', () => { - const nyc = Temporal.TimeZone.from('America/New_York'); - const noTransitionTZ = Temporal.TimeZone.from('Etc/GMT+10'); - - it('should not have bug #510', () => { - // See https://github.com/tc39/proposal-temporal/issues/510 for more. - const a1 = Temporal.Instant.from('2019-04-16T21:01Z'); - const a2 = Temporal.Instant.from('1800-01-01T00:00Z'); - - equal(nyc.getNextTransition(a1).toString(), '2019-11-03T06:00:00Z'); - equal(nyc.getNextTransition(a2).toString(), '1883-11-18T17:00:00Z'); - }); - it('should not return the same as its input if the input is a transition point', () => { - const inst = Temporal.Instant.from('2019-01-01T00:00Z'); - equal(`${nyc.getNextTransition(inst)}`, '2019-03-10T07:00:00Z'); - equal(`${nyc.getNextTransition(nyc.getNextTransition(inst))}`, '2019-11-03T06:00:00Z'); - }); - it('should work for timezones with no scheduled transitions in the near future', () => { - const start = Temporal.Instant.from('1945-10-15T13:00:00Z'); - equal(noTransitionTZ.getNextTransition(start), null); - }); - it('casts argument', () => { - equal(`${nyc.getNextTransition('2019-04-16T21:01Z')}`, '2019-11-03T06:00:00Z'); - }); - it('casts only from string', () => { - throws(() => nyc.getNextTransition(0n), RangeError); - throws(() => nyc.getNextTransition({}), RangeError); - }); - }); - - describe('getPreviousTransition works', () => { - const london = Temporal.TimeZone.from('Europe/London'); - it('should return first and last transition', () => { - const a1 = Temporal.Instant.from('2020-06-11T21:01Z'); - const a2 = Temporal.Instant.from('1848-01-01T00:00Z'); - - equal(london.getPreviousTransition(a1).toString(), '2020-03-29T01:00:00Z'); - equal(london.getPreviousTransition(a2).toString(), '1847-12-01T00:01:15Z'); - }); - it('should not return the same as its input if the input is a transition point', () => { - const inst = Temporal.Instant.from('2020-06-01T00:00Z'); - equal(`${london.getPreviousTransition(inst)}`, '2020-03-29T01:00:00Z'); - equal(`${london.getPreviousTransition(london.getPreviousTransition(inst))}`, '2019-10-27T01:00:00Z'); - }); - it('casts argument', () => { - equal(`${london.getPreviousTransition('2020-06-11T21:01Z')}`, '2020-03-29T01:00:00Z'); - }); - it('casts only from string', () => { - throws(() => london.getPreviousTransition(0n), RangeError); - throws(() => london.getPreviousTransition({}), RangeError); - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/tsconfig.json b/packages/temporal-polyfill/tests/tsconfig.json deleted file mode 100644 index 8488d426..00000000 --- a/packages/temporal-polyfill/tests/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.base", - "compilerOptions": { - "types": ["jest", "chai", "node"], - "paths": { - "temporal-polyfill/impl": ["../src/impl.build"] - } - } -} diff --git a/packages/temporal-polyfill/tests/userCalendar.js b/packages/temporal-polyfill/tests/userCalendar.js deleted file mode 100644 index 272f5ca1..00000000 --- a/packages/temporal-polyfill/tests/userCalendar.js +++ /dev/null @@ -1,524 +0,0 @@ - -// Copyright (C) 2020 Igalia, S.L. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; - -describe('Userland calendar', () => { - describe('Trivial subclass', () => { - // For the purposes of testing, a nonsensical calendar that uses 2-based - // month numbers, instead of 1-based - class TwoBasedCalendar extends Temporal.Calendar { - constructor() { - super('iso8601'); - } - toString() { - return 'two-based'; - } - dateFromFields(fields, options) { - let { year, month, monthCode, day } = fields; - if (month === undefined) month = +monthCode.slice(1); - return super.dateFromFields({ year, monthCode: `M${(month - 1).toString().padStart(2, '0')}`, day }, options); - } - yearMonthFromFields(fields, options) { - let { year, month, monthCode } = fields; - if (month === undefined) month = +monthCode.slice(1); - return super.yearMonthFromFields({ year, monthCode: `M${(month - 1).toString().padStart(2, '0')}` }, options); - } - monthDayFromFields(fields, options) { - let { month, monthCode, day } = fields; - if (month === undefined) month = +monthCode.slice(1); - return super.monthDayFromFields({ monthCode: `M${(month - 1).toString().padStart(2, '0')}`, day }, options); - } - month(date) { - return date.getISOFields().isoMonth + 1; - } - monthCode(date) { - return `M${this.month(date).toString().padStart(2, '0')}`; - } - } - - const obj = new TwoBasedCalendar(); - const date = Temporal.PlainDate.from({ year: 2020, month: 5, day: 5, calendar: obj }); - const dt = Temporal.PlainDateTime.from({ year: 2020, month: 5, day: 5, hour: 12, calendar: obj }); - const ym = Temporal.PlainYearMonth.from({ year: 2020, month: 5, calendar: obj }); - const md = Temporal.PlainMonthDay.from({ monthCode: 'M05', day: 5, calendar: obj }); - - it('is a calendar', () => equal(typeof obj, 'object')); - it('.id property', () => equal(obj.id, 'two-based')); - // FIXME: what should happen in Temporal.Calendar.from(obj)? - it('.id is not available in from()', () => { - throws(() => Temporal.Calendar.from('two-based'), RangeError); - throws(() => Temporal.Calendar.from('2020-06-05T09:34-07:00[America/Vancouver][u-ca=two-based]'), RangeError); - }); - it('Temporal.PlainDate.from()', () => equal(`${date}`, '2020-04-05[u-ca=two-based]')); - it('Temporal.PlainDate fields', () => { - equal(date.year, 2020); - equal(date.month, 5); - equal(date.day, 5); - }); - it('date.with()', () => { - const date2 = date.with({ month: 2 }); - equal(date2.month, 2); - }); - it('date.withCalendar()', () => { - const date2 = Temporal.PlainDate.from('2020-04-05'); - assert(date2.withCalendar(obj).equals(date)); - }); - it('Temporal.PlainDateTime.from()', () => equal(`${dt}`, '2020-04-05T12:00:00[u-ca=two-based]')); - it('Temporal.PlainDateTime fields', () => { - equal(dt.year, 2020); - equal(dt.month, 5); - equal(dt.day, 5); - equal(dt.hour, 12); - equal(dt.minute, 0); - equal(dt.second, 0); - equal(dt.millisecond, 0); - equal(dt.microsecond, 0); - equal(dt.nanosecond, 0); - }); - it('datetime.with()', () => { - const dt2 = dt.with({ month: 2 }); - equal(dt2.month, 2); - }); - it('datetime.withCalendar()', () => { - const dt2 = Temporal.PlainDateTime.from('2020-04-05T12:00'); - assert(dt2.withCalendar(obj).equals(dt)); - }); - it('Temporal.PlainYearMonth.from()', () => equal(`${ym}`, '2020-04-01[u-ca=two-based]')); - it('Temporal.PlainYearMonth fields', () => { - equal(dt.year, 2020); - equal(dt.month, 5); - }); - it('yearmonth.with()', () => { - const ym2 = ym.with({ month: 2 }); - equal(ym2.month, 2); - }); - it('Temporal.PlainMonthDay.from()', () => equal(`${md}`, '1972-04-05[u-ca=two-based]')); - it('Temporal.PlainMonthDay fields', () => { - equal(md.monthCode, 'M05'); - equal(md.day, 5); - }); - it('monthday.with()', () => { - const md2 = md.with({ monthCode: 'M02' }); - equal(md2.monthCode, 'M02'); - }); - it('timezone.getPlainDateTimeFor()', () => { - const tz = Temporal.TimeZone.from('UTC'); - const instant = Temporal.Instant.fromEpochSeconds(0); - const dt = tz.getPlainDateTimeFor(instant, obj); - equal(dt.calendar.id, obj.id); - }); - it('Temporal.Now.plainDateTime()', () => { - const nowDateTime = Temporal.Now.plainDateTime(obj, 'UTC'); - equal(nowDateTime.calendar.id, obj.id); - }); - it('Temporal.Now.plainDate()', () => { - const nowDate = Temporal.Now.plainDate(obj, 'UTC'); - equal(nowDate.calendar.id, obj.id); - }); - }); - describe('Trivial protocol implementation', () => { - // For the purposes of testing, a nonsensical calendar that has 10-month - // years, 10-day months, and the year zero is at the Unix epoch. - function decimalToISO(year, month, day, overflow = 'constrain') { - if (overflow === 'constrain') { - if (month < 1) month = 1; - if (month > 10) month = 10; - if (day < 1) day = 1; - if (day > 10) day = 10; - } else if (overflow === 'reject') { - if (month < 1 || month > 10 || day < 1 || day > 10) { - throw new RangeError('invalid value'); - } - } - const days = year * 100 + (month - 1) * 10 + (day - 1); - return new Temporal.PlainDate(1970, 1, 1, 'iso8601').add({ days }); - } - function isoToDecimal(date) { - let { isoYear, isoMonth, isoDay } = date.getISOFields(); - let isoDate = new Temporal.PlainDate(isoYear, isoMonth, isoDay); - let { days } = isoDate.since(new Temporal.PlainDate(1970, 1, 1), { - largestUnit: 'days' - }); - let year = Math.floor(days / 100); - days %= 100; - return { year, days }; - } - const obj = { - toString() { - return 'decimal'; - }, - dateFromFields(fields, options) { - const { overflow = 'constrain' } = options ? options : {}; - let { month, monthCode } = fields; - if (month === undefined) month = +monthCode.slice(1); - const isoDate = decimalToISO(fields.year, month, fields.day, 0, 0, 0, overflow); - return new Temporal.PlainDate(isoDate.year, isoDate.month, isoDate.day, this); - }, - yearMonthFromFields(fields, options) { - const { overflow = 'constrain' } = options ? options : {}; - let { month, monthCode } = fields; - if (month === undefined) month = +monthCode.slice(1); - const isoDate = decimalToISO(fields.year, month, 1, 0, 0, 0, overflow); - return new Temporal.PlainYearMonth(isoDate.year, isoDate.month, this, isoDate.day); - }, - monthDayFromFields(fields, options) { - const { overflow = 'constrain' } = options ? options : {}; - let { month, monthCode } = fields; - if (month === undefined) month = +monthCode.slice(1); - const isoDate = decimalToISO(0, month, fields.day, 0, 0, 0, overflow); - return new Temporal.PlainMonthDay(isoDate.month, isoDate.day, this, isoDate.year); - }, - year(date) { - return isoToDecimal(date).year; - }, - month(date) { - const { days } = isoToDecimal(date); - return Math.floor(days / 10) + 1; - }, - monthCode(date) { - return `M${this.month(date).toString().padStart(2, '0')}`; - }, - day(date) { - const { days } = isoToDecimal(date); - return (days % 10) + 1; - } - }; - - const date = Temporal.PlainDate.from({ year: 184, month: 2, day: 9, calendar: obj }); - const dt = Temporal.PlainDateTime.from({ year: 184, month: 2, day: 9, hour: 12, calendar: obj }); - const ym = Temporal.PlainYearMonth.from({ year: 184, month: 2, calendar: obj }); - const md = Temporal.PlainMonthDay.from({ monthCode: 'M02', day: 9, calendar: obj }); - - it('is a calendar', () => equal(typeof obj, 'object')); - // FIXME: what should happen in Temporal.Calendar.from(obj)? - it('.id is not available in from()', () => { - throws(() => Temporal.Calendar.from('decimal'), RangeError); - throws(() => Temporal.Calendar.from('2020-06-05T09:34-07:00[America/Vancouver][u-ca=decimal]'), RangeError); - }); - it('Temporal.PlainDate.from()', () => equal(`${date}`, '2020-06-05[u-ca=decimal]')); - it('Temporal.PlainDate fields', () => { - equal(date.year, 184); - equal(date.month, 2); - equal(date.day, 9); - }); - it('date.with()', () => { - const date2 = date.with({ year: 0 }); - equal(date2.year, 0); - }); - it('date.withCalendar()', () => { - const date2 = Temporal.PlainDate.from('2020-06-05T12:00'); - assert(date2.withCalendar(obj).equals(date)); - }); - it('Temporal.PlainDateTime.from()', () => equal(`${dt}`, '2020-06-05T12:00:00[u-ca=decimal]')); - it('Temporal.PlainDateTime fields', () => { - equal(dt.year, 184); - equal(dt.month, 2); - equal(dt.day, 9); - equal(dt.hour, 12); - equal(dt.minute, 0); - equal(dt.second, 0); - equal(dt.millisecond, 0); - equal(dt.microsecond, 0); - equal(dt.nanosecond, 0); - }); - it('datetime.with()', () => { - const dt2 = dt.with({ year: 0 }); - equal(dt2.year, 0); - }); - it('datetime.withCalendar()', () => { - const dt2 = Temporal.PlainDateTime.from('2020-06-05T12:00'); - assert(dt2.withCalendar(obj).equals(dt)); - }); - it('Temporal.PlainYearMonth.from()', () => equal(`${ym}`, '2020-05-28[u-ca=decimal]')); - it('Temporal.PlainYearMonth fields', () => { - equal(dt.year, 184); - equal(dt.month, 2); - }); - it('yearmonth.with()', () => { - const ym2 = ym.with({ year: 0 }); - equal(ym2.year, 0); - }); - it('Temporal.PlainMonthDay.from()', () => equal(`${md}`, '1970-01-19[u-ca=decimal]')); - it('Temporal.PlainMonthDay fields', () => { - equal(md.monthCode, 'M02'); - equal(md.day, 9); - }); - it('monthday.with()', () => { - const md2 = md.with({ monthCode: 'M01' }); - equal(md2.monthCode, 'M01'); - }); - it('timezone.getPlainDateTimeFor()', () => { - const tz = Temporal.TimeZone.from('UTC'); - const inst = Temporal.Instant.fromEpochSeconds(0); - const dt = tz.getPlainDateTimeFor(inst, obj); - equal(dt.calendar.id, obj.id); - }); - it('Temporal.Now.plainDateTime()', () => { - const nowDateTime = Temporal.Now.plainDateTime(obj, 'UTC'); - equal(nowDateTime.calendar.id, obj.id); - }); - it('Temporal.Now.plainDate()', () => { - const nowDate = Temporal.Now.plainDate(obj, 'UTC'); - equal(nowDate.calendar.id, obj.id); - }); - }); - describe('calendar with extra fields', () => { - // Contrived example of a calendar identical to the ISO calendar except that - // months are numbered 1, 2, 3, and each year has four seasons of 3 months - // numbered 1, 2, 3, 4. - class SeasonCalendar extends Temporal.Calendar { - constructor() { - super('iso8601'); - } - toString() { - return 'season'; - } - month(date) { - const { isoMonth } = date.getISOFields(); - return ((isoMonth - 1) % 3) + 1; - } - monthCode(date) { - return `M${this.month(date).toString().padStart(2, '0')}`; - } - season(date) { - const { isoMonth } = date.getISOFields(); - return Math.floor((isoMonth - 1) / 3) + 1; - } - _isoMonthCode(fields) { - const month = fields.month || +fields.monthCode.slice(1); - return `M${((fields.season - 1) * 3 + month).toString().padStart(2, '0')}`; - } - dateFromFields(fields, options) { - const monthCode = this._isoMonthCode(fields); - delete fields.month; - return super.dateFromFields({ ...fields, monthCode }, options); - } - yearMonthFromFields(fields, options) { - const monthCode = this._isoMonthCode(fields); - delete fields.month; - return super.yearMonthFromFields({ ...fields, monthCode }, options); - } - monthDayFromFields(fields, options) { - const monthCode = this._isoMonthCode(fields); - delete fields.month; - return super.monthDayFromFields({ ...fields, monthCode }, options); - } - fields(fields) { - fields = fields.slice(); - if (fields.includes('month') || fields.includes('monthCode')) fields.push('season'); - return fields; - } - } - const calendar = new SeasonCalendar(); - const datetime = new Temporal.PlainDateTime(2019, 9, 15, 0, 0, 0, 0, 0, 0, calendar); - const date = new Temporal.PlainDate(2019, 9, 15, calendar); - const yearmonth = new Temporal.PlainYearMonth(2019, 9, calendar); - const monthday = new Temporal.PlainMonthDay(9, 15, calendar); - const zoned = new Temporal.ZonedDateTime(1568505600_000_000_000n, 'UTC', calendar); - before(() => { - const propDesc = { - get() { - return this.calendar.season(this); - }, - configurable: true - }; - Object.defineProperty(Temporal.PlainDateTime.prototype, 'season', propDesc); - Object.defineProperty(Temporal.PlainDate.prototype, 'season', propDesc); - Object.defineProperty(Temporal.PlainYearMonth.prototype, 'season', propDesc); - Object.defineProperty(Temporal.PlainMonthDay.prototype, 'season', propDesc); - Object.defineProperty(Temporal.ZonedDateTime.prototype, 'season', propDesc); - }); - it('property getter works', () => { - equal(datetime.season, 3); - equal(datetime.month, 3); - equal(datetime.monthCode, 'M03'); - equal(date.season, 3); - equal(date.month, 3); - equal(date.monthCode, 'M03'); - equal(yearmonth.season, 3); - equal(yearmonth.month, 3); - equal(yearmonth.monthCode, 'M03'); - equal(monthday.season, 3); - equal(monthday.monthCode, 'M03'); - equal(zoned.season, 3); - equal(zoned.month, 3); - equal(zoned.monthCode, 'M03'); - }); - it('accepts season in from()', () => { - equal( - `${Temporal.PlainDateTime.from({ year: 2019, season: 3, month: 3, day: 15, calendar })}`, - '2019-09-15T00:00:00[u-ca=season]' - ); - equal( - `${Temporal.PlainDate.from({ year: 2019, season: 3, month: 3, day: 15, calendar })}`, - '2019-09-15[u-ca=season]' - ); - equal( - `${Temporal.PlainYearMonth.from({ year: 2019, season: 3, month: 3, calendar })}`, - '2019-09-01[u-ca=season]' - ); - equal( - `${Temporal.PlainMonthDay.from({ season: 3, monthCode: 'M03', day: 15, calendar })}`, - '1972-09-15[u-ca=season]' - ); - equal( - `${Temporal.ZonedDateTime.from({ year: 2019, season: 3, month: 3, day: 15, timeZone: 'UTC', calendar })}`, - '2019-09-15T00:00:00+00:00[UTC][u-ca=season]' - ); - }); - it('accepts season in with()', () => { - equal(`${datetime.with({ season: 2 })}`, '2019-06-15T00:00:00[u-ca=season]'); - equal(`${date.with({ season: 2 })}`, '2019-06-15[u-ca=season]'); - equal(`${yearmonth.with({ season: 2 })}`, '2019-06-01[u-ca=season]'); - equal(`${monthday.with({ season: 2 })}`, '1972-06-15[u-ca=season]'); - equal(`${zoned.with({ season: 2 })}`, '2019-06-15T00:00:00+00:00[UTC][u-ca=season]'); - }); - it('translates month correctly in with()', () => { - equal(`${datetime.with({ month: 2 })}`, '2019-08-15T00:00:00[u-ca=season]'); - equal(`${date.with({ month: 2 })}`, '2019-08-15[u-ca=season]'); - equal(`${yearmonth.with({ month: 2 })}`, '2019-08-01[u-ca=season]'); - equal(`${monthday.with({ monthCode: 'M02' })}`, '1972-08-15[u-ca=season]'); - equal(`${zoned.with({ month: 2 })}`, '2019-08-15T00:00:00+00:00[UTC][u-ca=season]'); - }); - after(() => { - delete Temporal.PlainDateTime.prototype.season; - delete Temporal.PlainDate.prototype.season; - delete Temporal.PlainYearMonth.prototype.season; - delete Temporal.PlainMonthDay.prototype.season; - delete Temporal.ZonedDateTime.prototype.season; - }); - }); - - describe('calendar with nontrivial mergeFields implementation', () => { - // Contrived example of a calendar identical to the ISO calendar except that - // you can specify years as a combination of `century` (the 21st century is - // the year 2001 through 2100) and `centuryYear` (1-100) - class CenturyCalendar extends Temporal.Calendar { - constructor() { - super('iso8601'); - } - toString() { - return 'century'; - } - century(date) { - const { isoYear } = date.getISOFields(); - return Math.ceil(isoYear / 100); - } - centuryYear(date) { - const { isoYear } = date.getISOFields(); - return isoYear % 100; - } - _validateFields(fields) { - const { year, century, centuryYear } = fields; - if ((century === undefined) !== (centuryYear === undefined)) { - throw new TypeError('pass either both or neither of century and centuryYear'); - } - if (year === undefined) return (century - 1) * 100 + centuryYear; - if (century !== undefined) { - let centuryCalculatedYear = (century - 1) * 100 + centuryYear; - if (year !== centuryCalculatedYear) { - throw new RangeError('year must agree with century/centuryYear if both given'); - } - } - return year; - } - dateFromFields(fields, options) { - const isoYear = this._validateFields(fields); - return super.dateFromFields({ ...fields, year: isoYear }, options); - } - yearMonthFromFields(fields, options) { - const isoYear = this._validateFields(fields); - return super.yearMonthFromFields({ ...fields, year: isoYear }, options); - } - monthDayFromFields(fields, options) { - const isoYear = this._validateFields(fields); - return super.monthDayFromFields({ ...fields, year: isoYear }, options); - } - fields(fields) { - fields = fields.slice(); - if (fields.includes('year')) fields.push('century', 'centuryYear'); - return fields; - } - mergeFields(fields, additionalFields) { - const { year, century, centuryYear, ...original } = fields; - const { year: newYear, century: newCentury, centuryYear: newCenturyYear } = additionalFields; - if (newYear === undefined) { - original.century = century; - original.centuryYear = centuryYear; - } - if (newCentury === undefined && newCenturyYear === undefined) { - original.year === year; - } - return { ...original, ...additionalFields }; - } - } - const calendar = new CenturyCalendar(); - const datetime = new Temporal.PlainDateTime(2019, 9, 15, 0, 0, 0, 0, 0, 0, calendar); - const date = new Temporal.PlainDate(2019, 9, 15, calendar); - const yearmonth = new Temporal.PlainYearMonth(2019, 9, calendar); - const zoned = new Temporal.ZonedDateTime(1568505600_000_000_000n, 'UTC', calendar); - before(() => { - const propDesc = { - century: { - get() { - return this.calendar.century(this); - }, - configurable: true - }, - centuryYear: { - get() { - return this.calendar.centuryYear(this); - }, - configurable: true - } - }; - Object.defineProperties(Temporal.PlainDateTime.prototype, propDesc); - Object.defineProperties(Temporal.PlainDate.prototype, propDesc); - Object.defineProperties(Temporal.PlainYearMonth.prototype, propDesc); - Object.defineProperties(Temporal.ZonedDateTime.prototype, propDesc); - }); - it('property getters work', () => { - equal(datetime.century, 21); - equal(datetime.centuryYear, 19); - equal(date.century, 21); - equal(date.centuryYear, 19); - equal(yearmonth.century, 21); - equal(yearmonth.centuryYear, 19); - equal(zoned.century, 21); - equal(zoned.centuryYear, 19); - }); - it('correctly resolves century in with()', () => { - equal(`${datetime.with({ century: 20 })}`, '1919-09-15T00:00:00[u-ca=century]'); - equal(`${date.with({ century: 20 })}`, '1919-09-15[u-ca=century]'); - equal(`${yearmonth.with({ century: 20 })}`, '1919-09-01[u-ca=century]'); - equal(`${zoned.with({ century: 20 })}`, '1919-09-15T00:00:00+00:00[UTC][u-ca=century]'); - }); - it('correctly resolves centuryYear in with()', () => { - equal(`${datetime.with({ centuryYear: 5 })}`, '2005-09-15T00:00:00[u-ca=century]'); - equal(`${date.with({ centuryYear: 5 })}`, '2005-09-15[u-ca=century]'); - equal(`${yearmonth.with({ centuryYear: 5 })}`, '2005-09-01[u-ca=century]'); - equal(`${zoned.with({ centuryYear: 5 })}`, '2005-09-15T00:00:00+00:00[UTC][u-ca=century]'); - }); - it('correctly resolves year in with()', () => { - equal(`${datetime.with({ year: 1974 })}`, '1974-09-15T00:00:00[u-ca=century]'); - equal(`${date.with({ year: 1974 })}`, '1974-09-15[u-ca=century]'); - equal(`${yearmonth.with({ year: 1974 })}`, '1974-09-01[u-ca=century]'); - equal(`${zoned.with({ year: 1974 })}`, '1974-09-15T00:00:00+00:00[UTC][u-ca=century]'); - }); - after(() => { - delete Temporal.PlainDateTime.prototype.century; - delete Temporal.PlainDateTime.prototype.centuryYear; - delete Temporal.PlainDate.prototype.century; - delete Temporal.PlainDate.prototype.centuryYear; - delete Temporal.PlainYearMonth.prototype.century; - delete Temporal.PlainYearMonth.prototype.centuryYear; - delete Temporal.ZonedDateTime.prototype.century; - delete Temporal.ZonedDateTime.prototype.centuryYear; - }); - }); -}); diff --git a/packages/temporal-polyfill/tests/userTimeZone.js b/packages/temporal-polyfill/tests/userTimeZone.js deleted file mode 100644 index b0503389..00000000 --- a/packages/temporal-polyfill/tests/userTimeZone.js +++ /dev/null @@ -1,208 +0,0 @@ - -// Copyright (C) 2020 Igalia, S.L. All rights reserved. -// This code is governed by the BSD license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; - -describe('Userland time zone', () => { - describe('Trivial subclass', () => { - class CustomUTCSubclass extends Temporal.TimeZone { - constructor() { - super('UTC'); - } - toString() { - return 'Etc/Custom/UTC_Subclass'; - } - getOffsetNanosecondsFor(/* instant */) { - return 0; - } - getPossibleInstantsFor(dateTime) { - const { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = dateTime; - const dayNum = MakeDay(year, month, day); - const time = MakeTime(hour, minute, second, millisecond, microsecond, nanosecond); - const epochNs = MakeDate(dayNum, time); - return [new Temporal.Instant(epochNs)]; - } - getNextTransition(/* instant */) { - return null; - } - getPreviousTransition(/* instant */) { - return null; - } - } - - const obj = new CustomUTCSubclass(); - const inst = Temporal.Instant.fromEpochNanoseconds(0n); - const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); - - it('is a time zone', () => equal(typeof obj, 'object')); - it('.id property', () => equal(obj.id, 'Etc/Custom/UTC_Subclass')); - // FIXME: what should happen in Temporal.TimeZone.from(obj)? - it('.id is not available in from()', () => { - throws(() => Temporal.TimeZone.from('Etc/Custom/UTC_Subclass'), RangeError); - throws(() => Temporal.TimeZone.from('2020-05-26T16:02:46.251163036+00:00[Etc/Custom/UTC_Subclass]'), RangeError); - }); - it('has offset string +00:00', () => equal(obj.getOffsetStringFor(inst), '+00:00')); - it('converts to DateTime', () => { - equal(`${obj.getPlainDateTimeFor(inst)}`, '1970-01-01T00:00:00'); - equal(`${obj.getPlainDateTimeFor(inst, 'gregory')}`, '1970-01-01T00:00:00[u-ca=gregory]'); - }); - it('converts to Instant', () => { - equal(`${obj.getInstantFor(dt)}`, '1976-11-18T15:23:30.123456789Z'); - }); - it('converts to string', () => equal(`${obj}`, obj.id)); - it('offset prints in instant.toString', () => equal(inst.toString({ timeZone: obj }), '1970-01-01T00:00:00+00:00')); - it('prints in zdt.toString', () => { - const zdt = new Temporal.ZonedDateTime(0n, obj); - equal(zdt.toString(), '1970-01-01T00:00:00+00:00[Etc/Custom/UTC_Subclass]'); - }); - it('has no next transitions', () => assert.equal(obj.getNextTransition(), null)); - it('has no previous transitions', () => assert.equal(obj.getPreviousTransition(), null)); - it('works in Temporal.Now', () => { - assert(Temporal.Now.plainDateTimeISO(obj) instanceof Temporal.PlainDateTime); - assert(Temporal.Now.plainDateTime('gregory', obj) instanceof Temporal.PlainDateTime); - assert(Temporal.Now.plainDateISO(obj) instanceof Temporal.PlainDate); - assert(Temporal.Now.plainDate('gregory', obj) instanceof Temporal.PlainDate); - assert(Temporal.Now.plainTimeISO(obj) instanceof Temporal.PlainTime); - }); - }); - describe('Trivial protocol implementation', () => { - const obj = { - getOffsetNanosecondsFor(/* instant */) { - return 0; - }, - getPossibleInstantsFor(dateTime) { - const { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond } = dateTime; - const dayNum = MakeDay(year, month, day); - const time = MakeTime(hour, minute, second, millisecond, microsecond, nanosecond); - const epochNs = MakeDate(dayNum, time); - return [new Temporal.Instant(epochNs)]; - }, - toString() { - return 'Etc/Custom/UTC_Protocol'; - } - }; - - const inst = Temporal.Instant.fromEpochNanoseconds(0n); - - it('converts to DateTime', () => { - equal(`${Temporal.TimeZone.prototype.getPlainDateTimeFor.call(obj, inst)}`, '1970-01-01T00:00:00'); - equal( - `${Temporal.TimeZone.prototype.getPlainDateTimeFor.call(obj, inst, 'gregory')}`, - '1970-01-01T00:00:00[u-ca=gregory]' - ); - }); - it('offset prints in instant.toString', () => equal(inst.toString({ timeZone: obj }), '1970-01-01T00:00:00+00:00')); - it('prints in zdt.toString', () => { - const zdt = new Temporal.ZonedDateTime(0n, obj); - equal(zdt.toString(), '1970-01-01T00:00:00+00:00[Etc/Custom/UTC_Protocol]'); - }); - it('works in Temporal.Now', () => { - assert(Temporal.Now.plainDateTimeISO(obj) instanceof Temporal.PlainDateTime); - assert(Temporal.Now.plainDateTime('gregory', obj) instanceof Temporal.PlainDateTime); - assert(Temporal.Now.plainDateISO(obj) instanceof Temporal.PlainDate); - assert(Temporal.Now.plainDate('gregory', obj) instanceof Temporal.PlainDate); - assert(Temporal.Now.plainTimeISO(obj) instanceof Temporal.PlainTime); - }); - }); - describe('sub-minute offset', () => { - class SubminuteTimeZone extends Temporal.TimeZone { - constructor() { - super('-00:00:01.111111111'); - } - toString() { - return 'Custom/Subminute'; - } - getOffsetNanosecondsFor() { - return -1111111111; - } - getPossibleInstantsFor(dateTime) { - const utc = Temporal.TimeZone.from('UTC'); - const instant = utc.getInstantFor(dateTime); - return [instant.add({ nanoseconds: 1111111111 })]; - } - getNextTransition() { - return null; - } - getPreviousTransition() { - return null; - } - } - - const obj = new SubminuteTimeZone(); - const inst = Temporal.Instant.fromEpochNanoseconds(0n); - const dt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789); - - it('is a time zone', () => equal(typeof obj, 'object')); - it('.id property', () => equal(obj.id, 'Custom/Subminute')); - it('.id is not available in from()', () => { - throws(() => Temporal.TimeZone.from('Custom/Subminute'), RangeError); - throws( - () => Temporal.TimeZone.from('2020-05-26T16:02:46.251163036-00:00:01.111111111[Custom/Subminute]'), - RangeError - ); - }); - it('has offset string -00:00:01.111111111', () => equal(obj.getOffsetStringFor(inst), '-00:00:01.111111111')); - it('converts to DateTime', () => { - equal(`${obj.getPlainDateTimeFor(inst)}`, '1969-12-31T23:59:58.888888889'); - equal(`${obj.getPlainDateTimeFor(inst, 'gregory')}`, '1969-12-31T23:59:58.888888889[u-ca=gregory]'); - }); - it('converts to Instant', () => { - equal(`${obj.getInstantFor(dt)}`, '1976-11-18T15:23:31.2345679Z'); - }); - it('converts to string', () => equal(`${obj}`, obj.id)); - it('offset prints with minute precision in instant.toString', () => - equal(inst.toString({ timeZone: obj }), '1969-12-31T23:59:58.888888889+00:00')); - it('offset prints with minute precision prints in zdt.toString', () => { - const zdt = new Temporal.ZonedDateTime(0n, obj); - equal(zdt.toString(), '1969-12-31T23:59:58.888888889+00:00[Custom/Subminute]'); - }); - it('has no next transitions', () => assert.equal(obj.getNextTransition(), null)); - it('has no previous transitions', () => assert.equal(obj.getPreviousTransition(), null)); - it('works in Temporal.Now', () => { - assert(Temporal.Now.plainDateTimeISO(obj) instanceof Temporal.PlainDateTime); - assert(Temporal.Now.plainDateTime('gregory', obj) instanceof Temporal.PlainDateTime); - assert(Temporal.Now.plainDateISO(obj) instanceof Temporal.PlainDate); - assert(Temporal.Now.plainDate('gregory', obj) instanceof Temporal.PlainDate); - assert(Temporal.Now.plainTimeISO(obj) instanceof Temporal.PlainTime); - }); - }); -}); - -const nsPerDay = 86400_000_000_000n; -const nsPerMillisecond = 1_000_000n; - -function Day(t) { - return t / nsPerDay; -} - -function MakeDate(day, time) { - return day * nsPerDay + time; -} - -function MakeDay(year, month, day) { - const m = month - 1; - const ym = year + Math.floor(m / 12); - const mn = m % 12; - const t = BigInt(Date.UTC(ym, mn, 1)) * nsPerMillisecond; - return Day(t) + BigInt(day) - 1n; -} - -function MakeTime(h, min, s, ms, µs, ns) { - const MinutesPerHour = 60n; - const SecondsPerMinute = 60n; - const nsPerSecond = 1_000_000_000n; - const nsPerMinute = nsPerSecond * SecondsPerMinute; - const nsPerHour = nsPerMinute * MinutesPerHour; - return ( - BigInt(h) * nsPerHour + - BigInt(min) * nsPerMinute + - BigInt(s) * nsPerSecond + - BigInt(ms) * nsPerMillisecond + - BigInt(µs) * 1000n + - BigInt(ns) - ); -} diff --git a/packages/temporal-polyfill/tests/zonedDateTime.js b/packages/temporal-polyfill/tests/zonedDateTime.js deleted file mode 100644 index 5ec18f97..00000000 --- a/packages/temporal-polyfill/tests/zonedDateTime.js +++ /dev/null @@ -1,2961 +0,0 @@ - -// Copyright (C) 2018-2019 Bloomberg LP. All rights reserved. -// This code is governed by the license found in the LICENSE file. - -import { assert } from 'chai'; -const { strictEqual: equal, notStrictEqual: notEqual, throws } = assert; - -import { Temporal } from 'temporal-polyfill/impl'; -const { ZonedDateTime } = Temporal; - -describe('ZonedDateTime', () => { - const tz = new Temporal.TimeZone('America/Los_Angeles'); - - describe('Structure', () => { - it('ZonedDateTime is a Function', () => { - equal(typeof ZonedDateTime, 'function'); - }); - it('ZonedDateTime has a prototype', () => { - assert(ZonedDateTime.prototype); - equal(typeof ZonedDateTime.prototype, 'object'); - }); - describe('ZonedDateTime.prototype', () => { - it('ZonedDateTime.prototype has calendar', () => { - assert('calendar' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has timeZone', () => { - assert('timeZone' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has year', () => { - assert('year' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has month', () => { - assert('month' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has monthCode', () => { - assert('monthCode' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has day', () => { - assert('day' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has hour', () => { - assert('hour' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has minute', () => { - assert('minute' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has second', () => { - assert('second' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has millisecond', () => { - assert('millisecond' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has microsecond', () => { - assert('microsecond' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has nanosecond', () => { - assert('nanosecond' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has epochSeconds', () => { - assert('epochSeconds' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has epochMilliseconds', () => { - assert('epochMilliseconds' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has epochMicroseconds', () => { - assert('epochMicroseconds' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has epochNanoseconds', () => { - assert('epochNanoseconds' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has dayOfWeek', () => { - assert('dayOfWeek' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has dayOfYear', () => { - assert('dayOfYear' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has weekOfYear', () => { - assert('weekOfYear' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has hoursInDay', () => { - assert('hoursInDay' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has daysInWeek', () => { - assert('daysInWeek' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has daysInMonth', () => { - assert('daysInMonth' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has daysInYear', () => { - assert('daysInYear' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has monthsInYear', () => { - assert('daysInWeek' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has inLeapYear', () => { - assert('daysInWeek' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has startOfDay', () => { - assert('daysInWeek' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype has offset', () => { - assert('daysInWeek' in ZonedDateTime.prototype); - }); - it('ZonedDateTime.prototype.with is a Function', () => { - equal(typeof ZonedDateTime.prototype.with, 'function'); - }); - it('ZonedDateTime.prototype.withTimeZone is a Function', () => { - equal(typeof ZonedDateTime.prototype.withTimeZone, 'function'); - }); - it('ZonedDateTime.prototype.withCalendar is a Function', () => { - equal(typeof ZonedDateTime.prototype.withCalendar, 'function'); - }); - it('ZonedDateTime.prototype.add is a Function', () => { - equal(typeof ZonedDateTime.prototype.add, 'function'); - }); - it('ZonedDateTime.prototype.subtract is a Function', () => { - equal(typeof ZonedDateTime.prototype.subtract, 'function'); - }); - it('ZonedDateTime.prototype.until is a Function', () => { - equal(typeof ZonedDateTime.prototype.until, 'function'); - }); - it('ZonedDateTime.prototype.since is a Function', () => { - equal(typeof ZonedDateTime.prototype.since, 'function'); - }); - it('ZonedDateTime.prototype.round is a Function', () => { - equal(typeof ZonedDateTime.prototype.round, 'function'); - }); - it('ZonedDateTime.prototype.equals is a Function', () => { - equal(typeof ZonedDateTime.prototype.equals, 'function'); - }); - it('ZonedDateTime.prototype.toString is a Function', () => { - equal(typeof ZonedDateTime.prototype.toString, 'function'); - }); - it('ZonedDateTime.prototype.toLocaleString is a Function', () => { - equal(typeof ZonedDateTime.prototype.toLocaleString, 'function'); - }); - it('ZonedDateTime.prototype.toJSON is a Function', () => { - equal(typeof ZonedDateTime.prototype.toJSON, 'function'); - }); - it('ZonedDateTime.prototype.valueOf is a Function', () => { - equal(typeof ZonedDateTime.prototype.valueOf, 'function'); - }); - it('ZonedDateTime.prototype.toInstant is a Function', () => { - equal(typeof ZonedDateTime.prototype.toInstant, 'function'); - }); - it('ZonedDateTime.prototype.toPlainDate is a Function', () => { - equal(typeof ZonedDateTime.prototype.toPlainDate, 'function'); - }); - it('ZonedDateTime.prototype.toPlainTime is a Function', () => { - equal(typeof ZonedDateTime.prototype.toPlainTime, 'function'); - }); - it('ZonedDateTime.prototype.toPlainDateTime is a Function', () => { - equal(typeof ZonedDateTime.prototype.toPlainDateTime, 'function'); - }); - it('ZonedDateTime.prototype.toPlainYearMonth is a Function', () => { - equal(typeof ZonedDateTime.prototype.toPlainYearMonth, 'function'); - }); - it('ZonedDateTime.prototype.toPlainMonthDay is a Function', () => { - equal(typeof ZonedDateTime.prototype.toPlainMonthDay, 'function'); - }); - it('ZonedDateTime.prototype.getISOFields is a Function', () => { - equal(typeof ZonedDateTime.prototype.getISOFields, 'function'); - }); - }); - it('ZonedDateTime.from is a Function', () => { - equal(typeof ZonedDateTime.from, 'function'); - }); - it('ZonedDateTime.compare is a Function', () => { - equal(typeof ZonedDateTime.compare, 'function'); - }); - }); - - describe('Construction and properties', () => { - const epochMillis = Date.UTC(1976, 10, 18, 15, 23, 30, 123); - const epochNanos = BigInt(epochMillis) * BigInt(1e6) + BigInt(456789); - it('works', () => { - const zdt = new ZonedDateTime(epochNanos, tz); - assert(zdt); - equal(typeof zdt, 'object'); - equal(zdt.toInstant().epochSeconds, Math.floor(Date.UTC(1976, 10, 18, 15, 23, 30, 123) / 1e3), 'epochSeconds'); - equal(zdt.toInstant().epochMilliseconds, Date.UTC(1976, 10, 18, 15, 23, 30, 123), 'epochMilliseconds'); - }); - it('Temporal.ZonedDateTime.from(zonedDateTime) is not the same object)', () => { - const zdt = new ZonedDateTime(epochNanos, tz); - notEqual(ZonedDateTime.from(zdt), zdt); - }); - - describe('ZonedDateTime for (1976, 11, 18, 15, 23, 30, 123, 456, 789)', () => { - const zdt = new ZonedDateTime(epochNanos, new Temporal.TimeZone('UTC')); - it('can be constructed', () => { - assert(zdt); - equal(typeof zdt, 'object'); - }); - it('zdt.year is 1976', () => equal(zdt.year, 1976)); - it('zdt.month is 11', () => equal(zdt.month, 11)); - it('zdt.monthCode is "M11"', () => equal(zdt.monthCode, 'M11')); - it('zdt.day is 18', () => equal(zdt.day, 18)); - it('zdt.hour is 15', () => equal(zdt.hour, 15)); - it('zdt.minute is 23', () => equal(zdt.minute, 23)); - it('zdt.second is 30', () => equal(zdt.second, 30)); - it('zdt.millisecond is 123', () => equal(zdt.millisecond, 123)); - it('zdt.microsecond is 456', () => equal(zdt.microsecond, 456)); - it('zdt.nanosecond is 789', () => equal(zdt.nanosecond, 789)); - it('zdt.epochSeconds is 217178610', () => equal(zdt.epochSeconds, 217178610)); - it('zdt.epochMilliseconds is 217178610123', () => equal(zdt.epochMilliseconds, 217178610123)); - it('zdt.epochMicroseconds is 217178610123456n', () => equal(zdt.epochMicroseconds, 217178610123456n)); - it('zdt.epochNanoseconds is 217178610123456789n', () => equal(zdt.epochNanoseconds, 217178610123456789n)); - it('zdt.dayOfWeek is 4', () => equal(zdt.dayOfWeek, 4)); - it('zdt.dayOfYear is 323', () => equal(zdt.dayOfYear, 323)); - it('zdt.weekOfYear is 47', () => equal(zdt.weekOfYear, 47)); - it('zdt.daysInWeek is 7', () => equal(zdt.daysInWeek, 7)); - it('zdt.daysInMonth is 30', () => equal(zdt.daysInMonth, 30)); - it('zdt.daysInYear is 366', () => equal(zdt.daysInYear, 366)); - it('zdt.monthsInYear is 12', () => equal(zdt.monthsInYear, 12)); - it('zdt.inLeapYear is true', () => equal(zdt.inLeapYear, true)); - it('zdt.offset is +00:00', () => equal(zdt.offset, '+00:00')); - it('zdt.offsetNanoseconds is 0', () => equal(zdt.offsetNanoseconds, 0)); - it('string output is 1976-11-18T15:23:30.123456789+00:00[UTC]', () => - equal(`${zdt}`, '1976-11-18T15:23:30.123456789+00:00[UTC]')); - }); - describe('ZonedDateTime with non-UTC time zone and non-ISO calendar', () => { - const zdt = new ZonedDateTime( - epochNanos, - Temporal.TimeZone.from('Europe/Vienna'), - Temporal.Calendar.from('gregory') - ); - it('can be constructed', () => { - assert(zdt); - equal(typeof zdt, 'object'); - }); - it('zdt.era is ce', () => equal(zdt.era, 'ce')); - it('zdt.year is 1976', () => equal(zdt.year, 1976)); - it('zdt.month is 11', () => equal(zdt.month, 11)); - it('zdt.monthCode is "M11"', () => equal(zdt.monthCode, 'M11')); - it('zdt.day is 18', () => equal(zdt.day, 18)); - it('zdt.hour is 16', () => equal(zdt.hour, 16)); - it('zdt.minute is 23', () => equal(zdt.minute, 23)); - it('zdt.second is 30', () => equal(zdt.second, 30)); - it('zdt.millisecond is 123', () => equal(zdt.millisecond, 123)); - it('zdt.microsecond is 456', () => equal(zdt.microsecond, 456)); - it('zdt.nanosecond is 789', () => equal(zdt.nanosecond, 789)); - it('zdt.epochSeconds is 217178610', () => equal(zdt.epochSeconds, 217178610)); - it('zdt.epochMilliseconds is 217178610123', () => equal(zdt.epochMilliseconds, 217178610123)); - it('zdt.epochMicroseconds is 217178610123456n', () => equal(zdt.epochMicroseconds, 217178610123456n)); - it('zdt.epochNanoseconds is 217178610123456789n', () => equal(zdt.epochNanoseconds, 217178610123456789n)); - it('zdt.dayOfWeek is 4', () => equal(zdt.dayOfWeek, 4)); - it('zdt.dayOfYear is 323', () => equal(zdt.dayOfYear, 323)); - it('zdt.weekOfYear is 47', () => equal(zdt.weekOfYear, 47)); - it('zdt.daysInWeek is 7', () => equal(zdt.daysInWeek, 7)); - it('zdt.daysInMonth is 30', () => equal(zdt.daysInMonth, 30)); - it('zdt.daysInYear is 366', () => equal(zdt.daysInYear, 366)); - it('zdt.monthsInYear is 12', () => equal(zdt.monthsInYear, 12)); - it('zdt.inLeapYear is true', () => equal(zdt.inLeapYear, true)); - it('zdt.offset is +01:00', () => equal(zdt.offset, '+01:00')); - it('zdt.offsetNanoseconds is 3600e9', () => equal(zdt.offsetNanoseconds, 3600e9)); - it('string output is 1976-11-18T16:23:30.123456789+01:00[Europe/Vienna][u-ca=gregory]', () => - equal(`${zdt}`, '1976-11-18T16:23:30.123456789+01:00[Europe/Vienna][u-ca=gregory]')); - }); - - it('casts time zone', () => { - const zdt = new ZonedDateTime(epochNanos, 'Asia/Seoul'); - equal(typeof zdt.timeZone, 'object'); - assert(zdt.timeZone instanceof Temporal.TimeZone); - equal(zdt.timeZone.id, 'Asia/Seoul'); - }); - it('defaults to ISO calendar', () => { - const zdt = new ZonedDateTime(epochNanos, tz); - equal(typeof zdt.calendar, 'object'); - assert(zdt.calendar instanceof Temporal.Calendar); - equal(zdt.calendar.id, 'iso8601'); - }); - it('casts calendar', () => { - const zdt = new ZonedDateTime(epochNanos, Temporal.TimeZone.from('Asia/Tokyo'), 'japanese'); - equal(typeof zdt.calendar, 'object'); - assert(zdt.calendar instanceof Temporal.Calendar); - equal(zdt.calendar.id, 'japanese'); - }); - }); - - describe('string parsing', () => { - it('parses with an IANA zone', () => { - const zdt = ZonedDateTime.from('2020-03-08T01:00-08:00[America/Los_Angeles]'); - equal(zdt.toString(), '2020-03-08T01:00:00-08:00[America/Los_Angeles]'); - }); - it('parses with an IANA zone but no offset', () => { - const zdt = ZonedDateTime.from('2020-03-08T01:00[America/Los_Angeles]'); - equal(zdt.toString(), '2020-03-08T01:00:00-08:00[America/Los_Angeles]'); - }); - it('parses with an IANA zone but no offset (with disambiguation)', () => { - const zdt = ZonedDateTime.from('2020-03-08T02:30[America/Los_Angeles]', { disambiguation: 'earlier' }); - equal(zdt.toString(), '2020-03-08T01:30:00-08:00[America/Los_Angeles]'); - }); - it('parses with an offset in brackets', () => { - const zdt = ZonedDateTime.from('2020-03-08T01:00-08:00[-08:00]'); - equal(zdt.toString(), '2020-03-08T01:00:00-08:00[-08:00]'); - }); - it('throws if no brackets', () => { - throws(() => ZonedDateTime.from('2020-03-08T01:00-08:00'), RangeError); - throws(() => ZonedDateTime.from('2020-03-08T01:00Z'), RangeError); - }); - it('"Z" means preserve the exact time in the given IANA time zone', () => { - const zdt = ZonedDateTime.from('2020-03-08T09:00:00Z[America/Los_Angeles]'); - equal(zdt.toString(), '2020-03-08T01:00:00-08:00[America/Los_Angeles]'); - }); - it('ZonedDateTime.from(ISO string leap second) is constrained', () => { - equal( - `${ZonedDateTime.from('2016-12-31T23:59:60-08:00[America/Vancouver]')}`, - '2016-12-31T23:59:59-08:00[America/Vancouver]' - ); - }); - it('variant time separators', () => { - ['1976-11-18t15:23-08:00[America/Los_Angeles]', '1976-11-18 15:23-08:00[America/Los_Angeles]'].forEach((input) => - equal(`${ZonedDateTime.from(input)}`, '1976-11-18T15:23:00-08:00[America/Los_Angeles]') - ); - }); - it('any number of decimal places', () => { - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.1-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.1-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.12-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.12-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.123-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.123-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.1234-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.1234-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.12345-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.12345-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.123456-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.123456-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.1234567-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.1234567-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.12345678-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.12345678-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.123456789-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.123456789-08:00[America/Los_Angeles]' - ); - }); - it('variant decimal separator', () => { - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30,12-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.12-08:00[America/Los_Angeles]' - ); - }); - it('variant minus sign', () => { - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30.12\u221208:00[America/Los_Angeles]')}`, - '1976-11-18T15:23:30.12-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('\u2212009999-11-18T15:23:30.12+00:00[UTC]')}`, - '-009999-11-18T15:23:30.12+00:00[UTC]' - ); - }); - it('mixture of basic and extended format', () => { - [ - '1976-11-18T152330.1-08:00[America/Los_Angeles]', - '19761118T15:23:30.1-08:00[America/Los_Angeles]', - '1976-11-18T15:23:30.1-0800[America/Los_Angeles]', - '1976-11-18T152330.1-0800[America/Los_Angeles]', - '19761118T15:23:30.1-0800[America/Los_Angeles]', - '19761118T152330.1-08:00[America/Los_Angeles]', - '19761118T152330.1-0800[America/Los_Angeles]', - '+001976-11-18T152330.1-08:00[America/Los_Angeles]', - '+0019761118T15:23:30.1-08:00[America/Los_Angeles]', - '+001976-11-18T15:23:30.1-0800[America/Los_Angeles]', - '+001976-11-18T152330.1-0800[America/Los_Angeles]', - '+0019761118T15:23:30.1-0800[America/Los_Angeles]', - '+0019761118T152330.1-08:00[America/Los_Angeles]', - '+0019761118T152330.1-0800[America/Los_Angeles]' - ].forEach((input) => equal(`${ZonedDateTime.from(input)}`, '1976-11-18T15:23:30.1-08:00[America/Los_Angeles]')); - }); - it('optional parts', () => { - equal( - `${ZonedDateTime.from('1976-11-18T15:23:30-08[America/Los_Angeles]')}`, - '1976-11-18T15:23:30-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from('1976-11-18T15-08:00[America/Los_Angeles]')}`, - '1976-11-18T15:00:00-08:00[America/Los_Angeles]' - ); - equal(`${ZonedDateTime.from('2020-01-01[Asia/Tokyo]')}`, '2020-01-01T00:00:00+09:00[Asia/Tokyo]'); - }); - it('no junk at end of string', () => - throws(() => ZonedDateTime.from('1976-11-18T15:23:30.123456789-08:00[America/Los_Angeles]junk'), RangeError)); - it('constrain has no effect on invalid ISO string', () => { - throws(() => ZonedDateTime.from('2020-13-34T24:60[America/Los_Angeles]', { overflow: 'constrain' }), RangeError); - }); - describe('Offset option', () => { - it("{ offset: 'reject' } throws if offset does not match offset time zone", () => { - throws(() => ZonedDateTime.from('2020-03-08T01:00-04:00[-08:00]'), RangeError); - throws(() => ZonedDateTime.from('2020-03-08T01:00-04:00[-08:00]', { offset: 'reject' }), RangeError); - }); - it("{ offset: 'reject' } throws if offset does not match IANA time zone", () => { - throws(() => ZonedDateTime.from('2020-03-08T01:00-04:00[America/Chicago]'), RangeError); - throws(() => ZonedDateTime.from('2020-03-08T01:00-04:00[America/Chicago]', { offset: 'reject' }), RangeError); - }); - it("{ offset: 'prefer' } if offset matches time zone (first 1:30 when DST ends)", () => { - const zdt = ZonedDateTime.from('2020-11-01T01:30-07:00[America/Los_Angeles]', { offset: 'prefer' }); - equal(zdt.toString(), '2020-11-01T01:30:00-07:00[America/Los_Angeles]'); - }); - it("{ offset: 'prefer' } if offset matches time zone (second 1:30 when DST ends)", () => { - const zdt = ZonedDateTime.from('2020-11-01T01:30-08:00[America/Los_Angeles]', { offset: 'prefer' }); - equal(zdt.toString(), '2020-11-01T01:30:00-08:00[America/Los_Angeles]'); - }); - it("{ offset: 'prefer' } if offset does not match time zone", () => { - const zdt = ZonedDateTime.from('2020-11-01T04:00-07:00[America/Los_Angeles]', { offset: 'prefer' }); - equal(zdt.toString(), '2020-11-01T04:00:00-08:00[America/Los_Angeles]'); - }); - it("{ offset: 'ignore' } uses time zone only", () => { - const zdt = ZonedDateTime.from('2020-11-01T04:00-12:00[America/Los_Angeles]', { offset: 'ignore' }); - equal(zdt.toString(), '2020-11-01T04:00:00-08:00[America/Los_Angeles]'); - }); - it("{ offset: 'use' } uses offset only", () => { - const zdt = ZonedDateTime.from('2020-11-01T04:00-07:00[America/Los_Angeles]', { offset: 'use' }); - equal(zdt.toString(), '2020-11-01T03:00:00-08:00[America/Los_Angeles]'); - }); - it('throw when bad offset', () => { - ['', 'PREFER', 'balance', 3, null].forEach((offset) => { - throws(() => ZonedDateTime.from('2020-11-01T04:00-07:00[America/Los_Angeles]', { offset }), RangeError); - }); - }); - }); - describe('Disambiguation option', () => { - it('plain datetime with multiple instants - Fall DST in Brazil', () => { - const str = '2019-02-16T23:45[America/Sao_Paulo]'; - equal(`${ZonedDateTime.from(str)}`, '2019-02-16T23:45:00-02:00[America/Sao_Paulo]'); - equal( - `${ZonedDateTime.from(str, { disambiguation: 'compatible' })}`, - '2019-02-16T23:45:00-02:00[America/Sao_Paulo]' - ); - equal( - `${ZonedDateTime.from(str, { disambiguation: 'earlier' })}`, - '2019-02-16T23:45:00-02:00[America/Sao_Paulo]' - ); - equal( - `${ZonedDateTime.from(str, { disambiguation: 'later' })}`, - '2019-02-16T23:45:00-03:00[America/Sao_Paulo]' - ); - throws(() => ZonedDateTime.from(str, { disambiguation: 'reject' }), RangeError); - }); - it('plain datetime with multiple instants - Spring DST in Los Angeles', () => { - const str = '2020-03-08T02:30[America/Los_Angeles]'; - equal(`${ZonedDateTime.from(str)}`, '2020-03-08T03:30:00-07:00[America/Los_Angeles]'); - equal( - `${ZonedDateTime.from(str, { disambiguation: 'compatible' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(str, { disambiguation: 'earlier' })}`, - '2020-03-08T01:30:00-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(str, { disambiguation: 'later' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - throws(() => ZonedDateTime.from(str, { disambiguation: 'reject' }), RangeError); - }); - it('uses disambiguation if offset is ignored', () => { - const str = '2020-03-08T02:30[America/Los_Angeles]'; - const offset = 'ignore'; - equal(`${ZonedDateTime.from(str, { offset })}`, '2020-03-08T03:30:00-07:00[America/Los_Angeles]'); - equal( - `${ZonedDateTime.from(str, { offset, disambiguation: 'compatible' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(str, { offset, disambiguation: 'earlier' })}`, - '2020-03-08T01:30:00-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(str, { offset, disambiguation: 'later' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - throws(() => ZonedDateTime.from(str, { offset, disambiguation: 'reject' }), RangeError); - }); - it('uses disambiguation if offset is wrong and option is prefer', () => { - const str = '2020-03-08T02:30-23:59[America/Los_Angeles]'; - const offset = 'prefer'; - equal(`${ZonedDateTime.from(str, { offset })}`, '2020-03-08T03:30:00-07:00[America/Los_Angeles]'); - equal( - `${ZonedDateTime.from(str, { offset, disambiguation: 'compatible' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(str, { offset, disambiguation: 'earlier' })}`, - '2020-03-08T01:30:00-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(str, { offset, disambiguation: 'later' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - throws(() => ZonedDateTime.from(str, { offset, disambiguation: 'reject' }), RangeError); - }); - it('throw when bad disambiguation', () => { - ['', 'EARLIER', 'balance', 3, null].forEach((disambiguation) => { - throws(() => ZonedDateTime.from('2020-11-01T04:00[America/Los_Angeles]', { disambiguation }), RangeError); - }); - }); - }); - }); - describe('property bags', () => { - const lagos = Temporal.TimeZone.from('Africa/Lagos'); - it('can be constructed with monthCode and without month', () => { - equal( - `${ZonedDateTime.from({ year: 1976, monthCode: 'M11', day: 18, timeZone: lagos })}`, - '1976-11-18T00:00:00+01:00[Africa/Lagos]' - ); - }); - it('can be constructed with month and without monthCode', () => { - equal( - `${ZonedDateTime.from({ year: 1976, month: 11, day: 18, timeZone: lagos })}`, - '1976-11-18T00:00:00+01:00[Africa/Lagos]' - ); - }); - it('month and monthCode must agree', () => { - throws( - () => ZonedDateTime.from({ year: 1976, month: 11, monthCode: 'M12', day: 18, timeZone: lagos }), - RangeError - ); - }); - it('ZonedDateTime.from({}) throws', () => throws(() => ZonedDateTime.from({}), TypeError)); - it('ZonedDateTime.from(required prop undefined) throws', () => - throws( - () => ZonedDateTime.from({ year: 1976, month: undefined, monthCode: undefined, day: 18, timeZone: lagos }), - TypeError - )); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => ZonedDateTime.from({ year: 1976, month: 11, day: 18, timeZone: lagos }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal( - `${ZonedDateTime.from({ year: 1976, month: 11, day: 18, timeZone: lagos }, options)}`, - '1976-11-18T00:00:00+01:00[Africa/Lagos]' - ) - ); - }); - it('object must contain at least the required correctly-spelled properties', () => { - throws(() => ZonedDateTime.from({ years: 1976, months: 11, days: 18, timeZone: lagos }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal( - `${ZonedDateTime.from({ year: 1976, month: 11, day: 18, timeZone: lagos, hours: 12 })}`, - '1976-11-18T00:00:00+01:00[Africa/Lagos]' - ); - }); - it('casts timeZone property', () => { - equal( - `${ZonedDateTime.from({ year: 1976, month: 11, day: 18, timeZone: 'Africa/Lagos' })}`, - '1976-11-18T00:00:00+01:00[Africa/Lagos]' - ); - equal( - `${ZonedDateTime.from({ year: 1976, month: 11, day: 18, timeZone: -1030 })}`, - '1976-11-18T00:00:00-10:30[-10:30]' - ); - }); - it('casts offset property', () => { - const zdt = ZonedDateTime.from({ - year: 1976, - month: 11, - day: 18, - offset: -1030, - timeZone: Temporal.TimeZone.from('-10:30') - }); - equal(`${zdt}`, '1976-11-18T00:00:00-10:30[-10:30]'); - }); - it('throws with invalid offset', () => { - const offsets = ['use', 'prefer', 'ignore', 'reject']; - offsets.forEach((offset) => { - throws(() => { - Temporal.ZonedDateTime.from( - { - year: 2021, - month: 11, - day: 26, - offset: '+099:00', - timeZone: 'Europe/London' - }, - { offset } - ); - }, RangeError); - }); - }); - describe('Overflow option', () => { - const bad = { year: 2019, month: 1, day: 32, timeZone: lagos }; - it('reject', () => throws(() => ZonedDateTime.from(bad, { overflow: 'reject' }), RangeError)); - it('constrain', () => { - equal(`${ZonedDateTime.from(bad)}`, '2019-01-31T00:00:00+01:00[Africa/Lagos]'); - equal(`${ZonedDateTime.from(bad, { overflow: 'constrain' })}`, '2019-01-31T00:00:00+01:00[Africa/Lagos]'); - }); - it('throw when bad overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => { - throws(() => ZonedDateTime.from({ year: 2019, month: 1, day: 1, timeZone: lagos }, { overflow }), RangeError); - }); - }); - const leap = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60, timeZone: lagos }; - it('reject leap second', () => throws(() => ZonedDateTime.from(leap, { overflow: 'reject' }), RangeError)); - it('constrain leap second', () => - equal(`${ZonedDateTime.from(leap)}`, '2016-12-31T23:59:59+01:00[Africa/Lagos]')); - }); - describe('Offset option', () => { - it("{ offset: 'reject' } throws if offset does not match offset time zone", () => { - const obj = { year: 2020, month: 3, day: 8, hour: 1, offset: '-04:00', timeZone: '-08:00' }; - throws(() => ZonedDateTime.from(obj), RangeError); - throws(() => ZonedDateTime.from(obj, { offset: 'reject' }), RangeError); - }); - it("{ offset: 'reject' } throws if offset does not match IANA time zone", () => { - const obj = { year: 2020, month: 3, day: 8, hour: 1, offset: '-04:00', timeZone: 'America/Chicago' }; - throws(() => ZonedDateTime.from(obj), RangeError); - throws(() => ZonedDateTime.from(obj, { offset: 'reject' }), RangeError); - }); - const cali = Temporal.TimeZone.from('America/Los_Angeles'); - const date = { year: 2020, month: 11, day: 1, timeZone: cali }; - it("{ offset: 'prefer' } if offset matches time zone (first 1:30 when DST ends)", () => { - const obj = { ...date, hour: 1, minute: 30, offset: '-07:00' }; - equal(`${ZonedDateTime.from(obj, { offset: 'prefer' })}`, '2020-11-01T01:30:00-07:00[America/Los_Angeles]'); - }); - it("{ offset: 'prefer' } if offset matches time zone (second 1:30 when DST ends)", () => { - const obj = { ...date, hour: 1, minute: 30, offset: '-08:00' }; - equal(`${ZonedDateTime.from(obj, { offset: 'prefer' })}`, '2020-11-01T01:30:00-08:00[America/Los_Angeles]'); - }); - it("{ offset: 'prefer' } if offset does not match time zone", () => { - const obj = { ...date, hour: 4, offset: '-07:00' }; - equal(`${ZonedDateTime.from(obj, { offset: 'prefer' })}`, '2020-11-01T04:00:00-08:00[America/Los_Angeles]'); - }); - it("{ offset: 'ignore' } uses time zone only", () => { - const obj = { ...date, hour: 4, offset: '-12:00' }; - equal(`${ZonedDateTime.from(obj, { offset: 'ignore' })}`, '2020-11-01T04:00:00-08:00[America/Los_Angeles]'); - }); - it("{ offset: 'use' } uses offset only", () => { - const obj = { ...date, hour: 4, offset: '-07:00' }; - equal(`${ZonedDateTime.from(obj, { offset: 'use' })}`, '2020-11-01T03:00:00-08:00[America/Los_Angeles]'); - }); - it('throw when bad offset', () => { - ['', 'PREFER', 'balance', 3, null].forEach((offset) => { - throws(() => ZonedDateTime.from({ year: 2019, month: 1, day: 1, timeZone: lagos }, { offset }), RangeError); - }); - }); - }); - describe('Disambiguation option', () => { - it('plain datetime with multiple instants - Fall DST in Brazil', () => { - const brazil = Temporal.TimeZone.from('America/Sao_Paulo'); - const obj = { year: 2019, month: 2, day: 16, hour: 23, minute: 45, timeZone: brazil }; - equal(`${ZonedDateTime.from(obj)}`, '2019-02-16T23:45:00-02:00[America/Sao_Paulo]'); - equal( - `${ZonedDateTime.from(obj, { disambiguation: 'compatible' })}`, - '2019-02-16T23:45:00-02:00[America/Sao_Paulo]' - ); - equal( - `${ZonedDateTime.from(obj, { disambiguation: 'earlier' })}`, - '2019-02-16T23:45:00-02:00[America/Sao_Paulo]' - ); - equal( - `${ZonedDateTime.from(obj, { disambiguation: 'later' })}`, - '2019-02-16T23:45:00-03:00[America/Sao_Paulo]' - ); - throws(() => ZonedDateTime.from(obj, { disambiguation: 'reject' }), RangeError); - }); - it('plain datetime with multiple instants - Spring DST in Los Angeles', () => { - const cali = Temporal.TimeZone.from('America/Los_Angeles'); - const obj = { year: 2020, month: 3, day: 8, hour: 2, minute: 30, timeZone: cali }; - equal(`${ZonedDateTime.from(obj)}`, '2020-03-08T03:30:00-07:00[America/Los_Angeles]'); - equal( - `${ZonedDateTime.from(obj, { disambiguation: 'compatible' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(obj, { disambiguation: 'earlier' })}`, - '2020-03-08T01:30:00-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(obj, { disambiguation: 'later' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - throws(() => ZonedDateTime.from(obj, { disambiguation: 'reject' }), RangeError); - }); - it('uses disambiguation if offset is ignored', () => { - const cali = Temporal.TimeZone.from('America/Los_Angeles'); - const obj = { year: 2020, month: 3, day: 8, hour: 2, minute: 30, timeZone: cali }; - const offset = 'ignore'; - equal(`${ZonedDateTime.from(obj, { offset })}`, '2020-03-08T03:30:00-07:00[America/Los_Angeles]'); - equal( - `${ZonedDateTime.from(obj, { offset, disambiguation: 'compatible' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(obj, { offset, disambiguation: 'earlier' })}`, - '2020-03-08T01:30:00-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(obj, { offset, disambiguation: 'later' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - throws(() => ZonedDateTime.from(obj, { disambiguation: 'reject' }), RangeError); - }); - it('uses disambiguation if offset is wrong and option is prefer', () => { - const cali = Temporal.TimeZone.from('America/Los_Angeles'); - const obj = { year: 2020, month: 3, day: 8, hour: 2, minute: 30, offset: '-23:59', timeZone: cali }; - const offset = 'prefer'; - equal(`${ZonedDateTime.from(obj, { offset })}`, '2020-03-08T03:30:00-07:00[America/Los_Angeles]'); - equal( - `${ZonedDateTime.from(obj, { offset, disambiguation: 'compatible' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(obj, { offset, disambiguation: 'earlier' })}`, - '2020-03-08T01:30:00-08:00[America/Los_Angeles]' - ); - equal( - `${ZonedDateTime.from(obj, { offset, disambiguation: 'later' })}`, - '2020-03-08T03:30:00-07:00[America/Los_Angeles]' - ); - throws(() => ZonedDateTime.from(obj, { offset, disambiguation: 'reject' }), RangeError); - }); - it('throw when bad disambiguation', () => { - ['', 'EARLIER', 'balance', 3, null].forEach((disambiguation) => { - throws(() => ZonedDateTime.from('2020-11-01T04:00[America/Los_Angeles]', { disambiguation }), RangeError); - }); - }); - }); - describe('sub-minute time zone offsets', () => { - ['use', 'ignore', 'prefer', 'reject'].forEach((offset) => { - it(`accepts the exact offset string (offset=${offset})`, () => { - const zdt1 = ZonedDateTime.from('1971-01-01T12:00-00:44:30[Africa/Monrovia]', { offset }); - equal(`${zdt1}`, '1971-01-01T12:00:00-00:45[Africa/Monrovia]'); - equal(zdt1.offset, '-00:44:30'); - - const zdt2 = ZonedDateTime.from('1921-01-01T12:00+00:19:32[Europe/Amsterdam]', { offset }); - equal(`${zdt2}`, '1921-01-01T12:00:00+00:20[Europe/Amsterdam]'); - equal(zdt2.offset, '+00:19:32'); - }); - }); - it('prioritizes the offset string with HH:MM precision when offset=use', () => { - const zdt1 = ZonedDateTime.from('1971-01-01T12:00-00:45[Africa/Monrovia]', { offset: 'use' }); - equal(`${zdt1}`, '1971-01-01T12:00:30-00:45[Africa/Monrovia]'); - equal(zdt1.offset, '-00:44:30'); - - const zdt2 = ZonedDateTime.from('1921-01-01T12:00+00:20[Europe/Amsterdam]', { offset: 'use' }); - equal(`${zdt2}`, '1921-01-01T11:59:32+00:20[Europe/Amsterdam]'); - equal(zdt2.offset, '+00:19:32'); - }); - ['ignore', 'prefer', 'reject'].forEach((offset) => { - it(`accepts the offset string with HH:MM precision (offset=${offset})`, () => { - const zdt1 = ZonedDateTime.from('1971-01-01T12:00-00:45[Africa/Monrovia]', { offset }); - equal(`${zdt1}`, '1971-01-01T12:00:00-00:45[Africa/Monrovia]'); - equal(zdt1.offset, '-00:44:30'); - - const zdt2 = ZonedDateTime.from('1921-01-01T12:00+00:20[Europe/Amsterdam]', { offset }); - equal(`${zdt2}`, '1921-01-01T12:00:00+00:20[Europe/Amsterdam]'); - equal(zdt2.offset, '+00:19:32'); - }); - }); - it('does not do fuzzy matching on HH:MM offset string passed in a property bag in from()', () => { - const properties = { year: 1971, month: 1, day: 1, hour: 12, offset: '-00:45', timeZone: 'Africa/Monrovia' }; - const zdt1 = ZonedDateTime.from(properties, { offset: 'use' }); - equal(`${zdt1}`, '1971-01-01T12:00:30-00:45[Africa/Monrovia]'); - - const zdt2 = ZonedDateTime.from(properties, { offset: 'ignore' }); - equal(`${zdt2}`, '1971-01-01T12:00:00-00:45[Africa/Monrovia]'); - - const zdt3 = ZonedDateTime.from(properties, { offset: 'prefer' }); - equal(`${zdt3}`, '1971-01-01T12:00:00-00:45[Africa/Monrovia]'); - - throws(() => ZonedDateTime.from(properties, { offset: 'reject' }), RangeError); - }); - it('does not do fuzzy matching on HH:MM offset string passed in a property bag in with()', () => { - const zdt = ZonedDateTime.from({ year: 1971, month: 1, day: 1, hour: 12, timeZone: 'Africa/Monrovia' }); - - const zdt1 = zdt.with({ month: 2, offset: '-00:45' }, { offset: 'use' }); - equal(`${zdt1}`, '1971-02-01T12:00:30-00:45[Africa/Monrovia]'); - - const zdt2 = zdt.with({ month: 2, offset: '-00:45' }, { offset: 'ignore' }); - equal(`${zdt2}`, '1971-02-01T12:00:00-00:45[Africa/Monrovia]'); - - const zdt3 = zdt.with({ month: 2, offset: '-00:45' }, { offset: 'prefer' }); - equal(`${zdt3}`, '1971-02-01T12:00:00-00:45[Africa/Monrovia]'); - - throws(() => zdt.with({ month: 2, offset: '-00:45' }, { offset: 'reject' }), RangeError); - }); - it('does not truncate offset property to minutes', () => { - const zdt = ZonedDateTime.from({ year: 1971, month: 1, day: 1, hour: 12, timeZone: 'Africa/Monrovia' }); - equal(zdt.offset, '-00:44:30'); - }); - }); - }); - - describe('ZonedDateTime.with()', () => { - const zdt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789).toZonedDateTime('UTC'); - it('zdt.with({ year: 2019 } works', () => { - equal(`${zdt.with({ year: 2019 })}`, '2019-11-18T15:23:30.123456789+00:00[UTC]'); - }); - it('zdt.with({ month: 5 } works', () => { - equal(`${zdt.with({ month: 5 })}`, '1976-05-18T15:23:30.123456789+00:00[UTC]'); - }); - it('zdt.with({ monthCode: "M05" }) works', () => { - equal(`${zdt.with({ monthCode: 'M05' })}`, '1976-05-18T15:23:30.123456789+00:00[UTC]'); - }); - it('month and monthCode must agree', () => { - throws(() => zdt.with({ month: 5, monthCode: 'M06' }), RangeError); - }); - it('zdt.with({ day: 5 } works', () => { - equal(`${zdt.with({ day: 5 })}`, '1976-11-05T15:23:30.123456789+00:00[UTC]'); - }); - it('zdt.with({ hour: 5 } works', () => { - equal(`${zdt.with({ hour: 5 })}`, '1976-11-18T05:23:30.123456789+00:00[UTC]'); - }); - it('zdt.with({ minute: 5 } works', () => { - equal(`${zdt.with({ minute: 5 })}`, '1976-11-18T15:05:30.123456789+00:00[UTC]'); - }); - it('zdt.with({ second: 5 } works', () => { - equal(`${zdt.with({ second: 5 })}`, '1976-11-18T15:23:05.123456789+00:00[UTC]'); - }); - it('zdt.with({ millisecond: 5 } works', () => { - equal(`${zdt.with({ millisecond: 5 })}`, '1976-11-18T15:23:30.005456789+00:00[UTC]'); - }); - it('zdt.with({ microsecond: 5 } works', () => { - equal(`${zdt.with({ microsecond: 5 })}`, '1976-11-18T15:23:30.123005789+00:00[UTC]'); - }); - it('zdt.with({ nanosecond: 5 } works', () => { - equal(`${zdt.with({ nanosecond: 5 })}`, '1976-11-18T15:23:30.123456005+00:00[UTC]'); - }); - it('zdt.with({ month: 5, second: 15 } works', () => { - equal(`${zdt.with({ month: 5, second: 15 })}`, '1976-05-18T15:23:15.123456789+00:00[UTC]'); - }); - describe('Overflow', () => { - it('constrain', () => { - const overflow = 'constrain'; - equal(`${zdt.with({ month: 29 }, { overflow })}`, '1976-12-18T15:23:30.123456789+00:00[UTC]'); - equal(`${zdt.with({ day: 31 }, { overflow })}`, '1976-11-30T15:23:30.123456789+00:00[UTC]'); - equal(`${zdt.with({ hour: 29 }, { overflow })}`, '1976-11-18T23:23:30.123456789+00:00[UTC]'); - equal(`${zdt.with({ nanosecond: 9000 }, { overflow })}`, '1976-11-18T15:23:30.123456999+00:00[UTC]'); - }); - it('reject', () => { - const overflow = 'reject'; - throws(() => zdt.with({ month: 29 }, { overflow }), RangeError); - throws(() => zdt.with({ day: 31 }, { overflow }), RangeError); - throws(() => zdt.with({ hour: 29 }, { overflow }), RangeError); - throws(() => zdt.with({ nanosecond: 9000 }, { overflow }), RangeError); - }); - it('constrain is the default', () => { - equal(`${zdt.with({ month: 29 })}`, `${zdt.with({ month: 29 }, { overflow: 'constrain' })}`); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => zdt.with({ day: 5 }, { overflow }), RangeError) - ); - }); - }); - const dstStartDay = ZonedDateTime.from('2019-03-10T12:00:01-02:30[America/St_Johns]'); - const dstEndDay = ZonedDateTime.from('2019-11-03T12:00:01-03:30[America/St_Johns]'); - const oneThirty = { hour: 1, minute: 30 }; - const twoThirty = { hour: 2, minute: 30 }; - describe('Disambiguation option', () => { - const offset = 'ignore'; - it('compatible, skipped wall time', () => { - equal( - `${dstStartDay.with(twoThirty, { offset, disambiguation: 'compatible' })}`, - '2019-03-10T03:30:01-02:30[America/St_Johns]' - ); - }); - it('earlier, skipped wall time', () => { - equal( - `${dstStartDay.with(twoThirty, { offset, disambiguation: 'earlier' })}`, - '2019-03-10T01:30:01-03:30[America/St_Johns]' - ); - }); - it('later, skipped wall time', () => { - equal( - `${dstStartDay.with(twoThirty, { offset, disambiguation: 'later' })}`, - '2019-03-10T03:30:01-02:30[America/St_Johns]' - ); - }); - it('compatible, repeated wall time', () => { - equal( - `${dstEndDay.with(oneThirty, { offset, disambiguation: 'compatible' })}`, - '2019-11-03T01:30:01-02:30[America/St_Johns]' - ); - }); - it('earlier, repeated wall time', () => { - equal( - `${dstEndDay.with(oneThirty, { offset, disambiguation: 'earlier' })}`, - '2019-11-03T01:30:01-02:30[America/St_Johns]' - ); - }); - it('later, repeated wall time', () => { - equal( - `${dstEndDay.with(oneThirty, { offset, disambiguation: 'later' })}`, - '2019-11-03T01:30:01-03:30[America/St_Johns]' - ); - }); - it('reject', () => { - throws(() => dstStartDay.with(twoThirty, { offset, disambiguation: 'reject' }), RangeError); - throws(() => dstEndDay.with(oneThirty, { offset, disambiguation: 'reject' }), RangeError); - }); - it('compatible is the default', () => { - equal( - `${dstStartDay.with(twoThirty, { offset })}`, - `${dstStartDay.with(twoThirty, { offset, disambiguation: 'compatible' })}` - ); - equal( - `${dstEndDay.with(twoThirty, { offset })}`, - `${dstEndDay.with(twoThirty, { offset, disambiguation: 'compatible' })}` - ); - }); - it('invalid disambiguation', () => { - ['', 'EARLIER', 'balance', 3, null].forEach((disambiguation) => - throws(() => zdt.with({ day: 5 }, { disambiguation }), RangeError) - ); - }); - }); - describe('Offset option', () => { - const bogus = { ...twoThirty, offset: '+23:59' }; - it('use, with bogus offset, changes to the exact time with the offset', () => { - const preserveExact = dstStartDay.with(bogus, { offset: 'use' }); - equal(`${preserveExact}`, '2019-03-08T23:01:01-03:30[America/St_Johns]'); - equal(preserveExact.epochNanoseconds, Temporal.Instant.from('2019-03-10T02:30:01+23:59').epochNanoseconds); - }); - it('ignore, with bogus offset, defers to disambiguation option', () => { - const offset = 'ignore'; - equal( - `${dstStartDay.with(bogus, { offset, disambiguation: 'earlier' })}`, - '2019-03-10T01:30:01-03:30[America/St_Johns]' - ); - equal( - `${dstStartDay.with(bogus, { offset, disambiguation: 'later' })}`, - '2019-03-10T03:30:01-02:30[America/St_Johns]' - ); - }); - it('prefer, with bogus offset, defers to disambiguation option', () => { - const offset = 'prefer'; - equal( - `${dstStartDay.with(bogus, { offset, disambiguation: 'earlier' })}`, - '2019-03-10T01:30:01-03:30[America/St_Johns]' - ); - equal( - `${dstStartDay.with(bogus, { offset, disambiguation: 'later' })}`, - '2019-03-10T03:30:01-02:30[America/St_Johns]' - ); - }); - it('reject, with bogus offset, throws', () => { - throws(() => dstStartDay.with({ ...twoThirty, offset: '+23:59' }, { offset: 'reject' }), RangeError); - }); - const doubleTime = ZonedDateTime.from('2019-11-03T01:30:01-03:30[America/St_Johns]'); - it('use changes to the exact time with the offset', () => { - const preserveExact = doubleTime.with({ offset: '-02:30' }, { offset: 'use' }); - equal(preserveExact.offset, '-02:30'); - equal(preserveExact.epochNanoseconds, Temporal.Instant.from('2019-11-03T01:30:01-02:30').epochNanoseconds); - }); - it('ignore defers to disambiguation option', () => { - const offset = 'ignore'; - equal(doubleTime.with({ offset: '-02:30' }, { offset, disambiguation: 'earlier' }).offset, '-02:30'); - equal(doubleTime.with({ offset: '-02:30' }, { offset, disambiguation: 'later' }).offset, '-03:30'); - }); - it('prefer adjusts offset of repeated clock time', () => { - equal(doubleTime.with({ offset: '-02:30' }, { offset: 'prefer' }).offset, '-02:30'); - }); - it('reject adjusts offset of repeated clock time', () => { - equal(doubleTime.with({ offset: '-02:30' }, { offset: 'reject' }).offset, '-02:30'); - }); - it('use does not cause the offset to change when adjusting repeated clock time', () => { - equal(doubleTime.with({ minute: 31 }, { offset: 'use' }).offset, '-03:30'); - }); - it('ignore may cause the offset to change when adjusting repeated clock time', () => { - equal(doubleTime.with({ minute: 31 }, { offset: 'ignore' }).offset, '-02:30'); - }); - it('prefer does not cause the offset to change when adjusting repeated clock time', () => { - equal(doubleTime.with({ minute: 31 }, { offset: 'prefer' }).offset, '-03:30'); - }); - it('reject does not cause the offset to change when adjusting repeated clock time', () => { - equal(doubleTime.with({ minute: 31 }, { offset: 'reject' }).offset, '-03:30'); - }); - it('prefer is the default', () => { - equal(`${dstStartDay.with(twoThirty)}`, `${dstStartDay.with(twoThirty, { offset: 'prefer' })}`); - equal(`${dstEndDay.with(twoThirty)}`, `${dstEndDay.with(twoThirty, { offset: 'prefer' })}`); - equal(`${doubleTime.with({ minute: 31 })}`, `${doubleTime.with({ minute: 31 }, { offset: 'prefer' })}`); - }); - it('invalid offset', () => { - ['', 'PREFER', 'balance', 3, null].forEach((offset) => - throws(() => zdt.with({ day: 5 }, { offset }), RangeError) - ); - }); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => zdt.with({ day: 5 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${zdt.with({ day: 5 }, options)}`, '1976-11-05T15:23:30.123456789+00:00[UTC]') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => zdt.with({}), TypeError); - throws(() => zdt.with({ months: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${zdt.with({ month: 12, days: 15 })}`, '1976-12-18T15:23:30.123456789+00:00[UTC]'); - }); - it('throws if timeZone is included', () => { - throws(() => zdt.with({ month: 2, timeZone: 'Asia/Ulaanbaatar' }), TypeError); - }); - it('throws if given a Temporal object with a time zone', () => { - throws(() => zdt.with(dstStartDay), TypeError); - }); - it('throws if calendarName is included', () => { - throws(() => zdt.with({ month: 2, calendar: 'japanese' }), TypeError); - }); - it('throws if given a Temporal object with a calendar', () => { - throws(() => zdt.with(Temporal.PlainDateTime.from('1976-11-18T12:00')), TypeError); - throws(() => zdt.with(Temporal.PlainDate.from('1976-11-18')), TypeError); - throws(() => zdt.with(Temporal.PlainTime.from('12:00')), TypeError); - throws(() => zdt.with(Temporal.PlainYearMonth.from('1976-11')), TypeError); - throws(() => zdt.with(Temporal.PlainMonthDay.from('11-18')), TypeError); - }); - it('throws if given a string', () => { - throws(() => zdt.with('1976-11-18T12:00+00:00[UTC]'), TypeError); - throws(() => zdt.with('1976-11-18'), TypeError); - throws(() => zdt.with('12:00'), TypeError); - throws(() => zdt.with('invalid'), TypeError); - }); - it('throws with invalid offset', () => { - const offsets = ['use', 'prefer', 'ignore', 'reject']; - offsets.forEach((offset) => { - throws(() => { - Temporal.ZonedDateTime.from('2022-11-26[Europe/London]').with({ offset: '+088:00' }, { offset }); - }, RangeError); - }); - }); - }); - - describe('.withPlainTime manipulation', () => { - const zdt = Temporal.ZonedDateTime.from('2015-12-07T03:24:30.000003500[America/Los_Angeles]'); - it('withPlainTime({ hour: 10 }) works', () => { - equal(`${zdt.withPlainTime({ hour: 10 })}`, '2015-12-07T10:00:00-08:00[America/Los_Angeles]'); - }); - it('withPlainTime(time) works', () => { - const time = Temporal.PlainTime.from('11:22'); - equal(`${zdt.withPlainTime(time)}`, '2015-12-07T11:22:00-08:00[America/Los_Angeles]'); - }); - it("withPlainTime('12:34') works", () => { - equal(`${zdt.withPlainTime('12:34')}`, '2015-12-07T12:34:00-08:00[America/Los_Angeles]'); - }); - it('withPlainTime() defaults to midnight', () => { - equal(`${zdt.withPlainTime()}`, '2015-12-07T00:00:00-08:00[America/Los_Angeles]'); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => zdt.withPlainTime({}), TypeError); - throws(() => zdt.withPlainTime({ minutes: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${zdt.withPlainTime({ hour: 10, seconds: 55 })}`, '2015-12-07T10:00:00-08:00[America/Los_Angeles]'); - }); - }); - describe('.withPlainDate manipulation', () => { - const zdt = Temporal.ZonedDateTime.from('1995-12-07T03:24:30[America/Los_Angeles]'); - it('withPlainDate({ year: 2000, month: 6, day: 1 }) works', () => { - equal(`${zdt.withPlainDate({ year: 2000, month: 6, day: 1 })}`, '2000-06-01T03:24:30-07:00[America/Los_Angeles]'); - }); - it('withPlainDate(plainDate) works', () => { - const date = Temporal.PlainDate.from('2020-01-23'); - equal(`${zdt.withPlainDate(date)}`, '2020-01-23T03:24:30-08:00[America/Los_Angeles]'); - }); - it("withPlainDate('2018-09-15') works", () => { - equal(`${zdt.withPlainDate('2018-09-15')}`, '2018-09-15T03:24:30-07:00[America/Los_Angeles]'); - }); - it('result contains a non-ISO calendar if present in the input', () => { - equal( - `${zdt.withCalendar('japanese').withPlainDate('2008-09-06')}`, - '2008-09-06T03:24:30-07:00[America/Los_Angeles][u-ca=japanese]' - ); - }); - it('calendar is unchanged if input has ISO calendar', () => { - equal( - `${zdt.withPlainDate('2008-09-06[u-ca=japanese]')}`, - '2008-09-06T03:24:30-07:00[America/Los_Angeles][u-ca=japanese]' - ); - }); - it('throws if both `this` and `other` have a non-ISO calendar', () => { - throws( - () => zdt.withCalendar('gregory').withPlainDate('2008-09-06-07:00[America/Los_Angeles][u-ca=japanese]'), - RangeError - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => zdt.withPlainDate({}), TypeError); - throws(() => zdt.withPlainDate({ months: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal( - `${zdt.withPlainDate({ year: 2000, month: 6, day: 1, months: 123 })}`, - '2000-06-01T03:24:30-07:00[America/Los_Angeles]' - ); - }); - }); - - describe('ZonedDateTime.withTimeZone()', () => { - const instant = Temporal.Instant.from('2019-11-18T15:23:30.123456789-08:00[America/Los_Angeles]'); - const zdt = instant.toZonedDateTimeISO('UTC'); - it('zonedDateTime.withTimeZone(America/Los_Angeles) works', () => { - equal(`${zdt.withTimeZone(tz)}`, '2019-11-18T15:23:30.123456789-08:00[America/Los_Angeles]'); - }); - it('casts its argument', () => { - equal(`${zdt.withTimeZone('America/Los_Angeles')}`, '2019-11-18T15:23:30.123456789-08:00[America/Los_Angeles]'); - }); - it('keeps instant and calendar the same', () => { - const zdt = ZonedDateTime.from('2019-11-18T15:23:30.123456789+01:00[Europe/Madrid][u-ca=gregory]'); - const zdt2 = zdt.withTimeZone('America/Vancouver'); - equal(zdt.epochNanoseconds, zdt2.epochNanoseconds); - equal(zdt2.calendar.id, 'gregory'); - equal(zdt2.timeZone.id, 'America/Vancouver'); - notEqual(`${zdt.toPlainDateTime()}`, `${zdt2.toPlainDateTime()}`); - }); - }); - describe('ZonedDateTime.withCalendar()', () => { - const zdt = ZonedDateTime.from('2019-11-18T15:23:30.123456789-08:00[America/Los_Angeles]'); - it('zonedDateTime.withCalendar(japanese) works', () => { - const cal = Temporal.Calendar.from('japanese'); - equal(`${zdt.withCalendar(cal)}`, '2019-11-18T15:23:30.123456789-08:00[America/Los_Angeles][u-ca=japanese]'); - }); - it('casts its argument', () => { - equal( - `${zdt.withCalendar('japanese')}`, - '2019-11-18T15:23:30.123456789-08:00[America/Los_Angeles][u-ca=japanese]' - ); - }); - it('keeps instant and time zone the same', () => { - const zdt = ZonedDateTime.from('2019-11-18T15:23:30.123456789+01:00[Europe/Madrid][u-ca=gregory]'); - const zdt2 = zdt.withCalendar('japanese'); - equal(zdt.epochNanoseconds, zdt2.epochNanoseconds); - equal(zdt2.calendar.id, 'japanese'); - equal(zdt2.timeZone.id, 'Europe/Madrid'); - }); - }); - - describe('Reversibility of differences', () => { - const earlier = ZonedDateTime.from('1976-11-18T15:23:30.123456789-03:00[America/Santiago]'); - const later = ZonedDateTime.from('2019-10-29T10:46:38.271986102-03:00[America/Santiago]'); - // The interchangeability of since() and until() holds for time units only - ['hours', 'minutes', 'seconds'].forEach((largestUnit) => { - const diff = later.since(earlier, { largestUnit }); - it(`earlier.since(later, ${largestUnit}) == later.since(earlier, ${largestUnit}).negated()`, () => - equal(`${earlier.since(later, { largestUnit })}`, `${diff.negated()}`)); - it(`earlier.until(later, ${largestUnit}) == later.since(earlier, ${largestUnit})`, () => - equal(`${earlier.until(later, { largestUnit })}`, `${diff}`)); - it(`${largestUnit} difference symmetrical with regard to negative durations`, () => { - assert(earlier.subtract(diff.negated()).equals(later)); - assert(later.add(diff.negated()).equals(earlier)); - }); - }); - // For all units, add() undoes until() and subtract() undoes since() - ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'].forEach((largestUnit) => { - const diff1 = earlier.until(later, { largestUnit }); - const diff2 = later.since(earlier, { largestUnit }); - it(`earlier.add(${diff1}) == later`, () => assert(earlier.add(diff1).equals(later))); - it(`later.subtract(${diff2}) == earlier`, () => assert(later.subtract(diff2).equals(earlier))); - }); - }); - describe('date/time maths: hours overflow', () => { - it('subtract result', () => { - const later = ZonedDateTime.from('2019-10-29T10:46:38.271986102-03:00[America/Santiago]'); - const earlier = later.subtract({ hours: 12 }); - equal(`${earlier}`, '2019-10-28T22:46:38.271986102-03:00[America/Santiago]'); - }); - it('add result', () => { - const earlier = ZonedDateTime.from('2020-05-31T23:12:38.271986102-04:00[America/Santiago]'); - const later = earlier.add({ hours: 2 }); - equal(`${later}`, '2020-06-01T01:12:38.271986102-04:00[America/Santiago]'); - }); - it('symmetrical with regard to negative durations', () => { - equal( - `${ZonedDateTime.from('2019-10-29T10:46:38.271986102-03:00[America/Santiago]').add({ hours: -12 })}`, - '2019-10-28T22:46:38.271986102-03:00[America/Santiago]' - ); - equal( - `${ZonedDateTime.from('2020-05-31T23:12:38.271986102-04:00[America/Santiago]').subtract({ hours: -2 })}`, - '2020-06-01T01:12:38.271986102-04:00[America/Santiago]' - ); - }); - }); - describe('ZonedDateTime.add()', () => { - const zdt = ZonedDateTime.from('1969-12-25T12:23:45.678901234+00:00[UTC]'); - describe('cross epoch in ms', () => { - const one = zdt.subtract({ hours: 240, nanoseconds: 800 }); - const two = zdt.add({ hours: 240, nanoseconds: 800 }); - const three = two.subtract({ hours: 480, nanoseconds: 1600 }); - const four = one.add({ hours: 480, nanoseconds: 1600 }); - it(`(${zdt}).subtract({ hours: 240, nanoseconds: 800 }) = ${one}`, () => - equal(`${one}`, '1969-12-15T12:23:45.678900434+00:00[UTC]')); - it(`(${zdt}).add({ hours: 240, nanoseconds: 800 }) = ${two}`, () => - equal(`${two}`, '1970-01-04T12:23:45.678902034+00:00[UTC]')); - it(`(${two}).subtract({ hours: 480, nanoseconds: 1600 }) = ${one}`, () => assert(three.equals(one))); - it(`(${one}).add({ hours: 480, nanoseconds: 1600 }) = ${two}`, () => assert(four.equals(two))); - }); - it('zdt.add(durationObj)', () => { - const later = zdt.add(Temporal.Duration.from('PT240H0.000000800S')); - equal(`${later}`, '1970-01-04T12:23:45.678902034+00:00[UTC]'); - }); - it('casts argument', () => { - equal(`${zdt.add('PT240H0.000000800S')}`, '1970-01-04T12:23:45.678902034+00:00[UTC]'); - }); - const jan31 = ZonedDateTime.from('2020-01-31T15:00-08:00[America/Vancouver]'); - it('constrain when ambiguous result', () => { - equal(`${jan31.add({ months: 1 })}`, '2020-02-29T15:00:00-08:00[America/Vancouver]'); - equal(`${jan31.add({ months: 1 }, { overflow: 'constrain' })}`, '2020-02-29T15:00:00-08:00[America/Vancouver]'); - }); - it('symmetrical with regard to negative durations in the time part', () => { - equal(`${jan31.add({ minutes: -30 })}`, '2020-01-31T14:30:00-08:00[America/Vancouver]'); - equal(`${jan31.add({ seconds: -30 })}`, '2020-01-31T14:59:30-08:00[America/Vancouver]'); - }); - it('throw when ambiguous result with reject', () => { - throws(() => jan31.add({ months: 1 }, { overflow: 'reject' }), RangeError); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => zdt.add({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => zdt.add({ hours: 1, minutes: -30 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => zdt.add({ years: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${zdt.add({ years: 1 }, options)}`, '1970-12-25T12:23:45.678901234+00:00[UTC]') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => zdt.add({}), TypeError); - throws(() => zdt.add({ hour: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${zdt.add({ hour: 1, minutes: 1 })}`, '1969-12-25T12:24:45.678901234+00:00[UTC]'); - }); - }); - describe('ZonedDateTime.subtract()', () => { - const zdt = ZonedDateTime.from('1969-12-25T12:23:45.678901234+00:00[UTC]'); - it('inst.subtract(durationObj)', () => { - const earlier = zdt.subtract(Temporal.Duration.from('PT240H0.000000800S')); - equal(`${earlier}`, '1969-12-15T12:23:45.678900434+00:00[UTC]'); - }); - it('casts argument', () => { - equal(`${zdt.subtract('PT240H0.000000800S')}`, '1969-12-15T12:23:45.678900434+00:00[UTC]'); - }); - const mar31 = ZonedDateTime.from('2020-03-31T15:00-07:00[America/Vancouver]'); - it('constrain when ambiguous result', () => { - equal(`${mar31.subtract({ months: 1 })}`, '2020-02-29T15:00:00-08:00[America/Vancouver]'); - equal( - `${mar31.subtract({ months: 1 }, { overflow: 'constrain' })}`, - '2020-02-29T15:00:00-08:00[America/Vancouver]' - ); - }); - it('symmetrical with regard to negative durations in the time part', () => { - equal(`${mar31.subtract({ minutes: -30 })}`, '2020-03-31T15:30:00-07:00[America/Vancouver]'); - equal(`${mar31.subtract({ seconds: -30 })}`, '2020-03-31T15:00:30-07:00[America/Vancouver]'); - }); - it('throw when ambiguous result with reject', () => { - throws(() => mar31.subtract({ months: 1 }, { overflow: 'reject' }), RangeError); - }); - it('invalid overflow', () => { - ['', 'CONSTRAIN', 'balance', 3, null].forEach((overflow) => - throws(() => zdt.subtract({ months: 1 }, { overflow }), RangeError) - ); - }); - it('mixed positive and negative values always throw', () => { - ['constrain', 'reject'].forEach((overflow) => - throws(() => zdt.add({ hours: 1, minutes: -30 }, { overflow }), RangeError) - ); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => zdt.subtract({ years: 1 }, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(`${zdt.subtract({ years: 1 }, options)}`, '1968-12-25T12:23:45.678901234+00:00[UTC]') - ); - }); - it('object must contain at least one correctly-spelled property', () => { - throws(() => zdt.subtract({}), TypeError); - throws(() => zdt.subtract({ hour: 12 }), TypeError); - }); - it('incorrectly-spelled properties are ignored', () => { - equal(`${zdt.subtract({ hour: 1, minutes: 1 })}`, '1969-12-25T12:22:45.678901234+00:00[UTC]'); - }); - }); - - describe('ZonedDateTime.until()', () => { - const zdt = ZonedDateTime.from('1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'); - it('zdt.until(later) === later.since(zdt) with default options', () => { - const later = ZonedDateTime.from({ year: 2016, month: 3, day: 3, hour: 18, timeZone: 'Europe/Vienna' }); - equal(`${zdt.until(later)}`, `${later.since(zdt)}`); - }); - it('casts argument', () => { - equal( - `${zdt.until({ year: 2019, month: 10, day: 29, hour: 10, timeZone: 'Europe/Vienna' })}`, - 'PT376434H36M29.876543211S' - ); - equal(`${zdt.until('2019-10-29T10:46:38.271986102+01:00[Europe/Vienna]')}`, 'PT376435H23M8.148529313S'); - }); - const feb20 = ZonedDateTime.from('2020-02-01T00:00+01:00[Europe/Vienna]'); - const feb21 = ZonedDateTime.from('2021-02-01T00:00+01:00[Europe/Vienna]'); - it('defaults to returning hours', () => { - equal(`${feb20.until(feb21)}`, 'PT8784H'); - equal(`${feb20.until(feb21, { largestUnit: 'auto' })}`, 'PT8784H'); - equal(`${feb20.until(feb21, { largestUnit: 'hours' })}`, 'PT8784H'); - equal( - `${feb20.until(ZonedDateTime.from('2021-02-01T00:00:00.000000001+01:00[Europe/Vienna]'))}`, - 'PT8784H0.000000001S' - ); - equal( - `${ZonedDateTime.from('2020-02-01T00:00:00.000000001+01:00[Europe/Vienna]').until(feb21)}`, - 'PT8783H59M59.999999999S' - ); - }); - it('can return lower or higher units', () => { - equal(`${feb20.until(feb21, { largestUnit: 'years' })}`, 'P1Y'); - equal(`${feb20.until(feb21, { largestUnit: 'months' })}`, 'P12M'); - equal(`${feb20.until(feb21, { largestUnit: 'weeks' })}`, 'P52W2D'); - equal(`${feb20.until(feb21, { largestUnit: 'days' })}`, 'P366D'); - equal(`${feb20.until(feb21, { largestUnit: 'minutes' })}`, 'PT527040M'); - equal(`${feb20.until(feb21, { largestUnit: 'seconds' })}`, 'PT31622400S'); - }); - it('can return subseconds', () => { - const later = feb20.add({ days: 1, milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = feb20.until(later, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 86400250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = feb20.until(later, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 86400250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = feb20.until(later, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 86400250250250); - }); - it('does not include higher units than necessary', () => { - const lastFeb20 = ZonedDateTime.from('2020-02-29T00:00+01:00[Europe/Vienna]'); - const lastJan21 = ZonedDateTime.from('2021-01-31T00:00+01:00[Europe/Vienna]'); - equal(`${lastFeb20.until(lastJan21)}`, 'PT8088H'); - equal(`${lastFeb20.until(lastJan21, { largestUnit: 'months' })}`, 'P11M2D'); - equal(`${lastFeb20.until(lastJan21, { largestUnit: 'years' })}`, 'P11M2D'); - }); - it('weeks and months are mutually exclusive', () => { - const laterDateTime = zdt.add({ days: 42, hours: 3 }); - const weeksDifference = zdt.until(laterDateTime, { largestUnit: 'weeks' }); - notEqual(weeksDifference.weeks, 0); - equal(weeksDifference.months, 0); - const monthsDifference = zdt.until(laterDateTime, { largestUnit: 'months' }); - equal(monthsDifference.weeks, 0); - notEqual(monthsDifference.months, 0); - }); - it('no two different calendars', () => { - const zdt1 = new ZonedDateTime(0n, 'UTC'); - const zdt2 = new ZonedDateTime(0n, 'UTC', Temporal.Calendar.from('japanese')); - throws(() => zdt1.until(zdt2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb20.until(feb21, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb20.until(feb21, options)}`, 'PT8784H')); - }); - const earlier = ZonedDateTime.from('2019-01-08T09:22:36.123456789+01:00[Europe/Vienna]'); - const later = ZonedDateTime.from('2021-09-07T14:39:40.987654321+02:00[Europe/Vienna]'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'nonsense'].forEach((smallestUnit) => { - throws(() => earlier.until(later, { smallestUnit }), RangeError); - }); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = [ - 'years', - 'months', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ]; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => earlier.until(later, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than hours', () => { - equal(`${earlier.until(later, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P3Y'); - equal(`${earlier.until(later, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P32M'); - equal(`${earlier.until(later, { smallestUnit: 'weeks', roundingMode: 'halfExpand' })}`, 'P139W'); - equal(`${earlier.until(later, { smallestUnit: 'days', roundingMode: 'halfExpand' })}`, 'P973D'); - }); - it('throws on invalid roundingMode', () => { - throws(() => earlier.until(later, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P32M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'PT23356H'], - ['minutes', 'PT23356H17M'], - ['seconds', 'PT23356H17M5S'], - ['milliseconds', 'PT23356H17M4.864S'], - ['microseconds', 'PT23356H17M4.864198S'], - ['nanoseconds', 'PT23356H17M4.864197532S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P32M', '-P31M'], - ['weeks', 'P140W', '-P139W'], - ['days', 'P974D', '-P973D'], - ['hours', 'PT23357H', '-PT23356H'], - ['minutes', 'PT23356H18M', '-PT23356H17M'], - ['seconds', 'PT23356H17M5S', '-PT23356H17M4S'], - ['milliseconds', 'PT23356H17M4.865S', '-PT23356H17M4.864S'], - ['microseconds', 'PT23356H17M4.864198S', '-PT23356H17M4.864197S'], - ['nanoseconds', 'PT23356H17M4.864197532S', '-PT23356H17M4.864197532S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P31M', '-P32M'], - ['weeks', 'P139W', '-P140W'], - ['days', 'P973D', '-P974D'], - ['hours', 'PT23356H', '-PT23357H'], - ['minutes', 'PT23356H17M', '-PT23356H18M'], - ['seconds', 'PT23356H17M4S', '-PT23356H17M5S'], - ['milliseconds', 'PT23356H17M4.864S', '-PT23356H17M4.865S'], - ['microseconds', 'PT23356H17M4.864197S', '-PT23356H17M4.864198S'], - ['nanoseconds', 'PT23356H17M4.864197532S', '-PT23356H17M4.864197532S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P31M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'PT23356H'], - ['minutes', 'PT23356H17M'], - ['seconds', 'PT23356H17M4S'], - ['milliseconds', 'PT23356H17M4.864S'], - ['microseconds', 'PT23356H17M4.864197S'], - ['nanoseconds', 'PT23356H17M4.864197532S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${earlier.until(later, { smallestUnit, roundingMode })}`, expected); - equal(`${later.until(earlier, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${earlier.until(later, { smallestUnit: 'minutes' })}`, 'PT23356H17M'); - equal(`${earlier.until(later, { smallestUnit: 'seconds' })}`, 'PT23356H17M4S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 3, roundingMode: 'halfExpand' })}`, - 'PT23355H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 30, roundingMode: 'halfExpand' })}`, - 'PT23356H30M' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 15, roundingMode: 'halfExpand' })}`, - 'PT23356H17M' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT23356H17M4.86S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT23356H17M4.8642S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT23356H17M4.86419753S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { smallestUnit: 'hours', roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(earlier.until(later, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 29 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => earlier.until(later, { smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'milliseconds', roundingIncrement: 1000 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'microseconds', roundingIncrement: 1000 }), RangeError); - throws(() => earlier.until(later, { smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), RangeError); - }); - it('accepts singular units', () => { - equal(`${earlier.until(later, { largestUnit: 'year' })}`, `${earlier.until(later, { largestUnit: 'years' })}`); - equal(`${earlier.until(later, { smallestUnit: 'year' })}`, `${earlier.until(later, { smallestUnit: 'years' })}`); - equal(`${earlier.until(later, { largestUnit: 'month' })}`, `${earlier.until(later, { largestUnit: 'months' })}`); - equal( - `${earlier.until(later, { smallestUnit: 'month' })}`, - `${earlier.until(later, { smallestUnit: 'months' })}` - ); - equal(`${earlier.until(later, { largestUnit: 'day' })}`, `${earlier.until(later, { largestUnit: 'days' })}`); - equal(`${earlier.until(later, { smallestUnit: 'day' })}`, `${earlier.until(later, { smallestUnit: 'days' })}`); - equal(`${earlier.until(later, { largestUnit: 'hour' })}`, `${earlier.until(later, { largestUnit: 'hours' })}`); - equal(`${earlier.until(later, { smallestUnit: 'hour' })}`, `${earlier.until(later, { smallestUnit: 'hours' })}`); - equal( - `${earlier.until(later, { largestUnit: 'minute' })}`, - `${earlier.until(later, { largestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'minute' })}`, - `${earlier.until(later, { smallestUnit: 'minutes' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'second' })}`, - `${earlier.until(later, { largestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'second' })}`, - `${earlier.until(later, { smallestUnit: 'seconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'millisecond' })}`, - `${earlier.until(later, { largestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'millisecond' })}`, - `${earlier.until(later, { smallestUnit: 'milliseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'microsecond' })}`, - `${earlier.until(later, { largestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'microsecond' })}`, - `${earlier.until(later, { smallestUnit: 'microseconds' })}` - ); - equal( - `${earlier.until(later, { largestUnit: 'nanosecond' })}`, - `${earlier.until(later, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${earlier.until(later, { smallestUnit: 'nanosecond' })}`, - `${earlier.until(later, { smallestUnit: 'nanoseconds' })}` - ); - }); - it('rounds relative to the receiver', () => { - const dt1 = ZonedDateTime.from('2019-01-01T00:00+00:00[UTC]'); - const dt2 = ZonedDateTime.from('2020-07-02T00:00+00:00[UTC]'); - equal(`${dt1.until(dt2, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P2Y'); - equal(`${dt2.until(dt1, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, '-P1Y'); - }); - it('throws with invalid offset', () => { - throws(() => { - const zdt = ZonedDateTime.from('2019-01-01T00:00+00:00[UTC]'); - zdt.until({ - year: 2021, - month: 11, - day: 26, - offset: '+099:00', - timeZone: 'Europe/London' - }); - }, RangeError); - }); - }); - describe('ZonedDateTime.since()', () => { - const zdt = ZonedDateTime.from('1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'); - it('zdt.since(earlier) === earlier.until(zdt) with default options', () => { - const earlier = ZonedDateTime.from({ year: 1966, month: 3, day: 3, hour: 18, timeZone: 'Europe/Vienna' }); - equal(`${zdt.since(earlier)}`, `${earlier.until(zdt)}`); - }); - it('casts argument', () => { - equal( - `${zdt.since({ year: 2019, month: 10, day: 29, hour: 10, timeZone: 'Europe/Vienna' })}`, - '-PT376434H36M29.876543211S' - ); - equal(`${zdt.since('2019-10-29T10:46:38.271986102+01:00[Europe/Vienna]')}`, '-PT376435H23M8.148529313S'); - }); - const feb20 = ZonedDateTime.from('2020-02-01T00:00+01:00[Europe/Vienna]'); - const feb21 = ZonedDateTime.from('2021-02-01T00:00+01:00[Europe/Vienna]'); - it('defaults to returning hours', () => { - equal(`${feb21.since(feb20)}`, 'PT8784H'); - equal(`${feb21.since(feb20, { largestUnit: 'auto' })}`, 'PT8784H'); - equal(`${feb21.since(feb20, { largestUnit: 'hours' })}`, 'PT8784H'); - equal( - `${ZonedDateTime.from('2021-02-01T00:00:00.000000001+01:00[Europe/Vienna]').since(feb20)}`, - 'PT8784H0.000000001S' - ); - equal( - `${feb21.since(ZonedDateTime.from('2020-02-01T00:00:00.000000001+01:00[Europe/Vienna]'))}`, - 'PT8783H59M59.999999999S' - ); - }); - it('can return lower or higher units', () => { - equal(`${feb21.since(feb20, { largestUnit: 'years' })}`, 'P1Y'); - equal(`${feb21.since(feb20, { largestUnit: 'months' })}`, 'P12M'); - equal(`${feb21.since(feb20, { largestUnit: 'weeks' })}`, 'P52W2D'); - equal(`${feb21.since(feb20, { largestUnit: 'days' })}`, 'P366D'); - equal(`${feb21.since(feb20, { largestUnit: 'minutes' })}`, 'PT527040M'); - equal(`${feb21.since(feb20, { largestUnit: 'seconds' })}`, 'PT31622400S'); - }); - it('can return subseconds', () => { - const later = feb20.add({ days: 1, milliseconds: 250, microseconds: 250, nanoseconds: 250 }); - - const msDiff = later.since(feb20, { largestUnit: 'milliseconds' }); - equal(msDiff.seconds, 0); - equal(msDiff.milliseconds, 86400250); - equal(msDiff.microseconds, 250); - equal(msDiff.nanoseconds, 250); - - const µsDiff = later.since(feb20, { largestUnit: 'microseconds' }); - equal(µsDiff.milliseconds, 0); - equal(µsDiff.microseconds, 86400250250); - equal(µsDiff.nanoseconds, 250); - - const nsDiff = later.since(feb20, { largestUnit: 'nanoseconds' }); - equal(nsDiff.microseconds, 0); - equal(nsDiff.nanoseconds, 86400250250250); - }); - it('does not include higher units than necessary', () => { - const lastFeb20 = ZonedDateTime.from('2020-02-29T00:00+01:00[Europe/Vienna]'); - const lastFeb21 = ZonedDateTime.from('2021-02-28T00:00+01:00[Europe/Vienna]'); - equal(`${lastFeb21.since(lastFeb20)}`, 'PT8760H'); - equal(`${lastFeb21.since(lastFeb20, { largestUnit: 'months' })}`, 'P11M28D'); - equal(`${lastFeb21.since(lastFeb20, { largestUnit: 'years' })}`, 'P11M28D'); - }); - it('weeks and months are mutually exclusive', () => { - const laterDateTime = zdt.add({ days: 42, hours: 3 }); - const weeksDifference = laterDateTime.since(zdt, { largestUnit: 'weeks' }); - notEqual(weeksDifference.weeks, 0); - equal(weeksDifference.months, 0); - const monthsDifference = laterDateTime.since(zdt, { largestUnit: 'months' }); - equal(monthsDifference.weeks, 0); - notEqual(monthsDifference.months, 0); - }); - it('no two different calendars', () => { - const zdt1 = new ZonedDateTime(0n, 'UTC'); - const zdt2 = new ZonedDateTime(0n, 'UTC', Temporal.Calendar.from('japanese')); - throws(() => zdt1.since(zdt2), RangeError); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => feb21.since(feb20, badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => equal(`${feb21.since(feb20, options)}`, 'PT8784H')); - }); - const earlier = ZonedDateTime.from('2019-01-08T09:22:36.123456789+01:00[Europe/Vienna]'); - const later = ZonedDateTime.from('2021-09-07T14:39:40.987654321+02:00[Europe/Vienna]'); - it('throws on disallowed or invalid smallestUnit', () => { - ['era', 'nonsense'].forEach((smallestUnit) => { - throws(() => later.since(earlier, { smallestUnit }), RangeError); - }); - }); - it('throws if smallestUnit is larger than largestUnit', () => { - const units = [ - 'years', - 'months', - 'weeks', - 'days', - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ]; - for (let largestIdx = 1; largestIdx < units.length; largestIdx++) { - for (let smallestIdx = 0; smallestIdx < largestIdx; smallestIdx++) { - const largestUnit = units[largestIdx]; - const smallestUnit = units[smallestIdx]; - throws(() => later.since(earlier, { largestUnit, smallestUnit }), RangeError); - } - } - }); - it('assumes a different default for largestUnit if smallestUnit is larger than days', () => { - equal(`${later.since(earlier, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P3Y'); - equal(`${later.since(earlier, { smallestUnit: 'months', roundingMode: 'halfExpand' })}`, 'P32M'); - equal(`${later.since(earlier, { smallestUnit: 'weeks', roundingMode: 'halfExpand' })}`, 'P139W'); - }); - it('throws on invalid roundingMode', () => { - throws(() => later.since(earlier, { roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['years', 'P3Y'], - ['months', 'P32M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'PT23356H'], - ['minutes', 'PT23356H17M'], - ['seconds', 'PT23356H17M5S'], - ['milliseconds', 'PT23356H17M4.864S'], - ['microseconds', 'PT23356H17M4.864198S'], - ['nanoseconds', 'PT23356H17M4.864197532S'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - const roundingMode = 'halfExpand'; - it(`rounds to nearest ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - const incrementOneCeil = [ - ['years', 'P3Y', '-P2Y'], - ['months', 'P32M', '-P31M'], - ['weeks', 'P140W', '-P139W'], - ['days', 'P974D', '-P973D'], - ['hours', 'PT23357H', '-PT23356H'], - ['minutes', 'PT23356H18M', '-PT23356H17M'], - ['seconds', 'PT23356H17M5S', '-PT23356H17M4S'], - ['milliseconds', 'PT23356H17M4.865S', '-PT23356H17M4.864S'], - ['microseconds', 'PT23356H17M4.864198S', '-PT23356H17M4.864197S'], - ['nanoseconds', 'PT23356H17M4.864197532S', '-PT23356H17M4.864197532S'] - ]; - incrementOneCeil.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'ceil'; - it(`rounds up to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneFloor = [ - ['years', 'P2Y', '-P3Y'], - ['months', 'P31M', '-P32M'], - ['weeks', 'P139W', '-P140W'], - ['days', 'P973D', '-P974D'], - ['hours', 'PT23356H', '-PT23357H'], - ['minutes', 'PT23356H17M', '-PT23356H18M'], - ['seconds', 'PT23356H17M4S', '-PT23356H17M5S'], - ['milliseconds', 'PT23356H17M4.864S', '-PT23356H17M4.865S'], - ['microseconds', 'PT23356H17M4.864197S', '-PT23356H17M4.864198S'], - ['nanoseconds', 'PT23356H17M4.864197532S', '-PT23356H17M4.864197532S'] - ]; - incrementOneFloor.forEach(([smallestUnit, expectedPositive, expectedNegative]) => { - const roundingMode = 'floor'; - it(`rounds down to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expectedPositive); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, expectedNegative); - }); - }); - const incrementOneTrunc = [ - ['years', 'P2Y'], - ['months', 'P31M'], - ['weeks', 'P139W'], - ['days', 'P973D'], - ['hours', 'PT23356H'], - ['minutes', 'PT23356H17M'], - ['seconds', 'PT23356H17M4S'], - ['milliseconds', 'PT23356H17M4.864S'], - ['microseconds', 'PT23356H17M4.864197S'], - ['nanoseconds', 'PT23356H17M4.864197532S'] - ]; - incrementOneTrunc.forEach(([smallestUnit, expected]) => { - const roundingMode = 'trunc'; - it(`truncates to ${smallestUnit}`, () => { - equal(`${later.since(earlier, { smallestUnit, roundingMode })}`, expected); - equal(`${earlier.since(later, { smallestUnit, roundingMode })}`, `-${expected}`); - }); - }); - it('trunc is the default', () => { - equal(`${later.since(earlier, { smallestUnit: 'minutes' })}`, 'PT23356H17M'); - equal(`${later.since(earlier, { smallestUnit: 'seconds' })}`, 'PT23356H17M4S'); - }); - it('rounds to an increment of hours', () => { - equal( - `${later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 3, roundingMode: 'halfExpand' })}`, - 'PT23355H' - ); - }); - it('rounds to an increment of minutes', () => { - equal( - `${later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 30, roundingMode: 'halfExpand' })}`, - 'PT23356H30M' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 15, roundingMode: 'halfExpand' })}`, - 'PT23356H17M' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT23356H17M4.86S' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT23356H17M4.8642S' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 10, roundingMode: 'halfExpand' })}`, - 'PT23356H17M4.86419753S' - ); - }); - it('valid hour increments divide into 24', () => { - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - const options = { smallestUnit: 'hours', roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - ['minutes', 'seconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - ['milliseconds', 'microseconds', 'nanoseconds'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - const options = { smallestUnit, roundingIncrement }; - assert(later.since(earlier, options) instanceof Temporal.Duration); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 11 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 29 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => later.since(earlier, { smallestUnit: 'hours', roundingIncrement: 24 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'minutes', roundingIncrement: 60 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'seconds', roundingIncrement: 60 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'milliseconds', roundingIncrement: 1000 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'microseconds', roundingIncrement: 1000 }), RangeError); - throws(() => later.since(earlier, { smallestUnit: 'nanoseconds', roundingIncrement: 1000 }), RangeError); - }); - it('accepts singular units', () => { - equal(`${later.since(earlier, { largestUnit: 'year' })}`, `${later.since(earlier, { largestUnit: 'years' })}`); - equal(`${later.since(earlier, { smallestUnit: 'year' })}`, `${later.since(earlier, { smallestUnit: 'years' })}`); - equal(`${later.since(earlier, { largestUnit: 'month' })}`, `${later.since(earlier, { largestUnit: 'months' })}`); - equal( - `${later.since(earlier, { smallestUnit: 'month' })}`, - `${later.since(earlier, { smallestUnit: 'months' })}` - ); - equal(`${later.since(earlier, { largestUnit: 'day' })}`, `${later.since(earlier, { largestUnit: 'days' })}`); - equal(`${later.since(earlier, { smallestUnit: 'day' })}`, `${later.since(earlier, { smallestUnit: 'days' })}`); - equal(`${later.since(earlier, { largestUnit: 'hour' })}`, `${later.since(earlier, { largestUnit: 'hours' })}`); - equal(`${later.since(earlier, { smallestUnit: 'hour' })}`, `${later.since(earlier, { smallestUnit: 'hours' })}`); - equal( - `${later.since(earlier, { largestUnit: 'minute' })}`, - `${later.since(earlier, { largestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'minute' })}`, - `${later.since(earlier, { smallestUnit: 'minutes' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'second' })}`, - `${later.since(earlier, { largestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'second' })}`, - `${later.since(earlier, { smallestUnit: 'seconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'millisecond' })}`, - `${later.since(earlier, { largestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'millisecond' })}`, - `${later.since(earlier, { smallestUnit: 'milliseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'microsecond' })}`, - `${later.since(earlier, { largestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'microsecond' })}`, - `${later.since(earlier, { smallestUnit: 'microseconds' })}` - ); - equal( - `${later.since(earlier, { largestUnit: 'nanosecond' })}`, - `${later.since(earlier, { largestUnit: 'nanoseconds' })}` - ); - equal( - `${later.since(earlier, { smallestUnit: 'nanosecond' })}`, - `${later.since(earlier, { smallestUnit: 'nanoseconds' })}` - ); - }); - it('rounds relative to the receiver', () => { - const dt1 = ZonedDateTime.from('2019-01-01T00:00+00:00[UTC]'); - const dt2 = ZonedDateTime.from('2020-07-02T00:00+00:00[UTC]'); - equal(`${dt2.since(dt1, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, 'P1Y'); - equal(`${dt1.since(dt2, { smallestUnit: 'years', roundingMode: 'halfExpand' })}`, '-P2Y'); - }); - it('throws with invalid offset', () => { - throws(() => { - const zdt = ZonedDateTime.from('2019-01-01T00:00+00:00[UTC]'); - zdt.since({ - year: 2021, - month: 11, - day: 26, - offset: '+099:00', - timeZone: 'Europe/London' - }); - }, RangeError); - }); - }); - - describe('ZonedDateTime.round()', () => { - const zdt = ZonedDateTime.from('1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'); - it('throws without parameter', () => { - throws(() => zdt.round(), TypeError); - }); - it('throws without required smallestUnit parameter', () => { - throws(() => zdt.round({}), RangeError); - throws(() => zdt.round({ roundingIncrement: 1, roundingMode: 'ceil' }), RangeError); - }); - it('throws on disallowed or invalid smallestUnit (object param)', () => { - ['era', 'year', 'month', 'week', 'years', 'months', 'weeks', 'nonsense'].forEach((smallestUnit) => { - throws(() => zdt.round({ smallestUnit }), RangeError); - }); - }); - it('throws on disallowed or invalid smallestUnit (string param)', () => { - ['era', 'year', 'month', 'week', 'years', 'months', 'weeks', 'nonsense'].forEach((smallestUnit) => { - throws(() => zdt.round(smallestUnit), RangeError); - }); - }); - it('throws on invalid roundingMode', () => { - throws(() => zdt.round({ smallestUnit: 'second', roundingMode: 'cile' }), RangeError); - }); - const incrementOneNearest = [ - ['day', '1976-11-19T00:00:00+01:00[Europe/Vienna]'], - ['hour', '1976-11-18T15:00:00+01:00[Europe/Vienna]'], - ['minute', '1976-11-18T15:24:00+01:00[Europe/Vienna]'], - ['second', '1976-11-18T15:23:30+01:00[Europe/Vienna]'], - ['millisecond', '1976-11-18T15:23:30.123+01:00[Europe/Vienna]'], - ['microsecond', '1976-11-18T15:23:30.123457+01:00[Europe/Vienna]'], - ['nanosecond', '1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'] - ]; - incrementOneNearest.forEach(([smallestUnit, expected]) => { - it(`rounds to nearest ${smallestUnit}`, () => - equal(`${zdt.round({ smallestUnit, roundingMode: 'halfExpand' })}`, expected)); - }); - const incrementOneCeil = [ - ['day', '1976-11-19T00:00:00+01:00[Europe/Vienna]'], - ['hour', '1976-11-18T16:00:00+01:00[Europe/Vienna]'], - ['minute', '1976-11-18T15:24:00+01:00[Europe/Vienna]'], - ['second', '1976-11-18T15:23:31+01:00[Europe/Vienna]'], - ['millisecond', '1976-11-18T15:23:30.124+01:00[Europe/Vienna]'], - ['microsecond', '1976-11-18T15:23:30.123457+01:00[Europe/Vienna]'], - ['nanosecond', '1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'] - ]; - incrementOneCeil.forEach(([smallestUnit, expected]) => { - it(`rounds up to ${smallestUnit}`, () => equal(`${zdt.round({ smallestUnit, roundingMode: 'ceil' })}`, expected)); - }); - const incrementOneFloor = [ - ['day', '1976-11-18T00:00:00+01:00[Europe/Vienna]'], - ['hour', '1976-11-18T15:00:00+01:00[Europe/Vienna]'], - ['minute', '1976-11-18T15:23:00+01:00[Europe/Vienna]'], - ['second', '1976-11-18T15:23:30+01:00[Europe/Vienna]'], - ['millisecond', '1976-11-18T15:23:30.123+01:00[Europe/Vienna]'], - ['microsecond', '1976-11-18T15:23:30.123456+01:00[Europe/Vienna]'], - ['nanosecond', '1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'] - ]; - incrementOneFloor.forEach(([smallestUnit, expected]) => { - it(`rounds down to ${smallestUnit}`, () => - equal(`${zdt.round({ smallestUnit, roundingMode: 'floor' })}`, expected)); - it(`truncates to ${smallestUnit}`, () => - equal(`${zdt.round({ smallestUnit, roundingMode: 'trunc' })}`, expected)); - }); - it('halfExpand is the default', () => { - equal(`${zdt.round({ smallestUnit: 'minute' })}`, '1976-11-18T15:24:00+01:00[Europe/Vienna]'); - equal(`${zdt.round({ smallestUnit: 'second' })}`, '1976-11-18T15:23:30+01:00[Europe/Vienna]'); - }); - it('rounding down is towards the Big Bang, not towards the epoch', () => { - const zdt2 = ZonedDateTime.from('1969-12-15T12:00:00.5+00:00[UTC]'); - const smallestUnit = 'second'; - equal(`${zdt2.round({ smallestUnit, roundingMode: 'ceil' })}`, '1969-12-15T12:00:01+00:00[UTC]'); - equal(`${zdt2.round({ smallestUnit, roundingMode: 'floor' })}`, '1969-12-15T12:00:00+00:00[UTC]'); - equal(`${zdt2.round({ smallestUnit, roundingMode: 'trunc' })}`, '1969-12-15T12:00:00+00:00[UTC]'); - equal(`${zdt2.round({ smallestUnit, roundingMode: 'halfExpand' })}`, '1969-12-15T12:00:01+00:00[UTC]'); - }); - it('rounding down is towards the Big Bang, not towards 1 BCE', () => { - const zdt3 = ZonedDateTime.from('-000099-12-15T12:00:00.5+00:00[UTC]'); - const smallestUnit = 'second'; - equal(`${zdt3.round({ smallestUnit, roundingMode: 'ceil' })}`, '-000099-12-15T12:00:01+00:00[UTC]'); - equal(`${zdt3.round({ smallestUnit, roundingMode: 'floor' })}`, '-000099-12-15T12:00:00+00:00[UTC]'); - equal(`${zdt3.round({ smallestUnit, roundingMode: 'trunc' })}`, '-000099-12-15T12:00:00+00:00[UTC]'); - equal(`${zdt3.round({ smallestUnit, roundingMode: 'halfExpand' })}`, '-000099-12-15T12:00:01+00:00[UTC]'); - }); - it('rounds to an increment of hours', () => { - equal(`${zdt.round({ smallestUnit: 'hour', roundingIncrement: 4 })}`, '1976-11-18T16:00:00+01:00[Europe/Vienna]'); - }); - it('rounds to an increment of minutes', () => { - equal( - `${zdt.round({ smallestUnit: 'minute', roundingIncrement: 15 })}`, - '1976-11-18T15:30:00+01:00[Europe/Vienna]' - ); - }); - it('rounds to an increment of seconds', () => { - equal( - `${zdt.round({ smallestUnit: 'second', roundingIncrement: 30 })}`, - '1976-11-18T15:23:30+01:00[Europe/Vienna]' - ); - }); - it('rounds to an increment of milliseconds', () => { - equal( - `${zdt.round({ smallestUnit: 'millisecond', roundingIncrement: 10 })}`, - '1976-11-18T15:23:30.12+01:00[Europe/Vienna]' - ); - }); - it('rounds to an increment of microseconds', () => { - equal( - `${zdt.round({ smallestUnit: 'microsecond', roundingIncrement: 10 })}`, - '1976-11-18T15:23:30.12346+01:00[Europe/Vienna]' - ); - }); - it('rounds to an increment of nanoseconds', () => { - equal( - `${zdt.round({ smallestUnit: 'nanosecond', roundingIncrement: 10 })}`, - '1976-11-18T15:23:30.12345679+01:00[Europe/Vienna]' - ); - }); - it('1 day is a valid increment', () => { - equal(`${zdt.round({ smallestUnit: 'day', roundingIncrement: 1 })}`, '1976-11-19T00:00:00+01:00[Europe/Vienna]'); - }); - it('valid hour increments divide into 24', () => { - const smallestUnit = 'hour'; - [1, 2, 3, 4, 6, 8, 12].forEach((roundingIncrement) => { - assert(zdt.round({ smallestUnit, roundingIncrement }) instanceof ZonedDateTime); - }); - }); - ['minute', 'second'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 60`, () => { - [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30].forEach((roundingIncrement) => { - assert(zdt.round({ smallestUnit, roundingIncrement }) instanceof ZonedDateTime); - }); - }); - }); - ['millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - it(`valid ${smallestUnit} increments divide into 1000`, () => { - [1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500].forEach((roundingIncrement) => { - assert(zdt.round({ smallestUnit, roundingIncrement }) instanceof ZonedDateTime); - }); - }); - }); - it('throws on increments that do not divide evenly into the next highest', () => { - throws(() => zdt.round({ smallestUnit: 'day', roundingIncrement: 29 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'hour', roundingIncrement: 29 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'minute', roundingIncrement: 29 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'second', roundingIncrement: 29 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'millisecond', roundingIncrement: 29 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'microsecond', roundingIncrement: 29 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'nanosecond', roundingIncrement: 29 }), RangeError); - }); - it('throws on increments that are equal to the next highest', () => { - throws(() => zdt.round({ smallestUnit: 'hour', roundingIncrement: 24 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'minute', roundingIncrement: 60 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'second', roundingIncrement: 60 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'millisecond', roundingIncrement: 1000 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'microsecond', roundingIncrement: 1000 }), RangeError); - throws(() => zdt.round({ smallestUnit: 'nanosecond', roundingIncrement: 1000 }), RangeError); - }); - const bal = ZonedDateTime.from('1976-11-18T23:59:59.999999999+01:00[Europe/Vienna]'); - ['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond'].forEach((smallestUnit) => { - it(`balances to next ${smallestUnit}`, () => { - equal(`${bal.round({ smallestUnit })}`, '1976-11-19T00:00:00+01:00[Europe/Vienna]'); - }); - }); - it('accepts plural units', () => { - ['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(zdt.round({ smallestUnit }).equals(zdt.round({ smallestUnit: `${smallestUnit}s` }))); - }); - }); - it('accepts string parameter as shortcut for {smallestUnit}', () => { - ['day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'].forEach((smallestUnit) => { - assert(zdt.round(smallestUnit).equals(zdt.round({ smallestUnit }))); - }); - }); - it('rounds correctly to a 25-hour day', () => { - const roundTo = { smallestUnit: 'day' }; - const roundMeDown = ZonedDateTime.from('2020-11-01T12:29:59-08:00[America/Vancouver]'); - equal(`${roundMeDown.round(roundTo)}`, '2020-11-01T00:00:00-07:00[America/Vancouver]'); - const roundMeUp = ZonedDateTime.from('2020-11-01T12:30:01-08:00[America/Vancouver]'); - equal(`${roundMeUp.round(roundTo)}`, '2020-11-02T00:00:00-08:00[America/Vancouver]'); - }); - it('rounds correctly to a 23-hour day', () => { - const roundTo = { smallestUnit: 'day' }; - const roundMeDown = ZonedDateTime.from('2020-03-08T11:29:59-07:00[America/Vancouver]'); - equal(`${roundMeDown.round(roundTo)}`, '2020-03-08T00:00:00-08:00[America/Vancouver]'); - const roundMeUp = ZonedDateTime.from('2020-03-08T11:30:01-07:00[America/Vancouver]'); - equal(`${roundMeUp.round(roundTo)}`, '2020-03-09T00:00:00-07:00[America/Vancouver]'); - }); - it('rounding up to a nonexistent wall-clock time', () => { - const almostSkipped = ZonedDateTime.from('2018-11-03T23:59:59.999999999-03:00[America/Sao_Paulo]'); - const rounded = almostSkipped.round({ smallestUnit: 'microsecond', roundingMode: 'halfExpand' }); - equal(`${rounded}`, '2018-11-04T01:00:00-02:00[America/Sao_Paulo]'); - equal(rounded.epochNanoseconds - almostSkipped.epochNanoseconds, 1n); - }); - }); - - describe('ZonedDateTime.equals()', () => { - const tz = Temporal.TimeZone.from('America/New_York'); - const cal = Temporal.Calendar.from('gregory'); - const zdt = new ZonedDateTime(0n, tz, cal); - it('constructed from equivalent parameters are equal', () => { - const zdt2 = ZonedDateTime.from('1969-12-31T19:00-05:00[America/New_York][u-ca=gregory]'); - assert(zdt.equals(zdt2)); - assert(zdt2.equals(zdt)); - }); - it('different instant not equal', () => { - const zdt2 = new ZonedDateTime(1n, tz, cal); - assert(!zdt.equals(zdt2)); - }); - it('different time zone not equal', () => { - const zdt2 = new ZonedDateTime(0n, 'America/Chicago', cal); - assert(!zdt.equals(zdt2)); - }); - it('different calendar not equal', () => { - const zdt2 = new ZonedDateTime(0n, tz, 'iso8601'); - assert(!zdt.equals(zdt2)); - }); - it('casts its argument', () => { - assert(zdt.equals('1969-12-31T19:00-05:00[America/New_York][u-ca=gregory]')); - assert( - zdt.equals({ - year: 1969, - month: 12, - day: 31, - hour: 19, - timeZone: 'America/New_York', - calendar: 'gregory' - }) - ); - }); - it('at least the required properties must be present', () => { - assert(!zdt.equals({ year: 1969, month: 12, day: 31, timeZone: 'America/New_York' })); - throws(() => zdt.equals({ month: 12, day: 31, timeZone: 'America/New_York' }), TypeError); - throws(() => zdt.equals({ year: 1969, day: 31, timeZone: 'America/New_York' }), TypeError); - throws(() => zdt.equals({ year: 1969, month: 12, timeZone: 'America/New_York' }), TypeError); - throws(() => zdt.equals({ year: 1969, month: 12, day: 31 }), TypeError); - throws( - () => zdt.equals({ years: 1969, months: 12, days: 31, timeZone: 'America/New_York', calendarName: 'gregory' }), - TypeError - ); - }); - it('throws with invalid offset', () => { - throws(() => { - zdt.equals({ - year: 2021, - month: 11, - day: 26, - offset: '+099:00', - timeZone: 'Europe/London' - }); - }, RangeError); - }); - }); - describe('ZonedDateTime.toString()', () => { - const zdt1 = ZonedDateTime.from('1976-11-18T15:23+01:00[Europe/Vienna]'); - const zdt2 = ZonedDateTime.from('1976-11-18T15:23:30+01:00[Europe/Vienna]'); - const zdt3 = ZonedDateTime.from('1976-11-18T15:23:30.1234+01:00[Europe/Vienna]'); - it('default is to emit seconds and drop trailing zeros after the decimal', () => { - equal(zdt1.toString(), '1976-11-18T15:23:00+01:00[Europe/Vienna]'); - equal(zdt2.toString(), '1976-11-18T15:23:30+01:00[Europe/Vienna]'); - equal(zdt3.toString(), '1976-11-18T15:23:30.1234+01:00[Europe/Vienna]'); - }); - it('shows only non-ISO calendar if calendarName = auto', () => { - equal(zdt1.toString({ calendarName: 'auto' }), '1976-11-18T15:23:00+01:00[Europe/Vienna]'); - equal( - zdt1.withCalendar('gregory').toString({ calendarName: 'auto' }), - '1976-11-18T15:23:00+01:00[Europe/Vienna][u-ca=gregory]' - ); - }); - it('shows ISO calendar if calendarName = always', () => { - equal(zdt1.toString({ calendarName: 'always' }), '1976-11-18T15:23:00+01:00[Europe/Vienna][u-ca=iso8601]'); - }); - it('omits non-ISO calendar if calendarName = never', () => { - equal( - zdt1.withCalendar('gregory').toString({ calendarName: 'never' }), - '1976-11-18T15:23:00+01:00[Europe/Vienna]' - ); - }); - it('default is calendar = auto', () => { - equal(zdt1.toString(), '1976-11-18T15:23:00+01:00[Europe/Vienna]'); - equal(zdt1.withCalendar('gregory').toString(), '1976-11-18T15:23:00+01:00[Europe/Vienna][u-ca=gregory]'); - }); - it('throws on invalid calendar', () => { - ['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => { - throws(() => zdt1.toString({ calendarName }), RangeError); - }); - }); - it('shows time zone if timeZoneName = auto', () => { - equal(zdt1.toString({ timeZoneName: 'auto' }), '1976-11-18T15:23:00+01:00[Europe/Vienna]'); - }); - it('omits time zone if timeZoneName = never', () => { - equal(zdt1.toString({ timeZoneName: 'never' }), '1976-11-18T15:23:00+01:00'); - }); - it('shows offset if offset = auto', () => { - equal(zdt1.toString({ offset: 'auto' }), '1976-11-18T15:23:00+01:00[Europe/Vienna]'); - }); - it('omits offset if offset = never', () => { - equal(zdt1.toString({ offset: 'never' }), '1976-11-18T15:23:00[Europe/Vienna]'); - }); - it('combinations of calendar, time zone, and offset', () => { - const zdt = zdt1.withCalendar('gregory'); - equal(zdt.toString({ timeZoneName: 'never', calendarName: 'never' }), '1976-11-18T15:23:00+01:00'); - equal(zdt.toString({ offset: 'never', calendarName: 'never' }), '1976-11-18T15:23:00[Europe/Vienna]'); - equal(zdt.toString({ offset: 'never', timeZoneName: 'never' }), '1976-11-18T15:23:00[u-ca=gregory]'); - equal(zdt.toString({ offset: 'never', timeZoneName: 'never', calendarName: 'never' }), '1976-11-18T15:23:00'); - }); - it('truncates to minute', () => { - [zdt1, zdt2, zdt3].forEach((zdt) => - equal(zdt.toString({ smallestUnit: 'minute' }), '1976-11-18T15:23+01:00[Europe/Vienna]') - ); - }); - it('other smallestUnits are aliases for fractional digits', () => { - equal(zdt3.toString({ smallestUnit: 'second' }), zdt3.toString({ fractionalSecondDigits: 0 })); - equal(zdt3.toString({ smallestUnit: 'millisecond' }), zdt3.toString({ fractionalSecondDigits: 3 })); - equal(zdt3.toString({ smallestUnit: 'microsecond' }), zdt3.toString({ fractionalSecondDigits: 6 })); - equal(zdt3.toString({ smallestUnit: 'nanosecond' }), zdt3.toString({ fractionalSecondDigits: 9 })); - }); - it('throws on invalid or disallowed smallestUnit', () => { - ['era', 'year', 'month', 'day', 'hour', 'nonsense'].forEach((smallestUnit) => - throws(() => zdt1.toString({ smallestUnit }), RangeError) - ); - }); - it('accepts plural units', () => { - equal(zdt3.toString({ smallestUnit: 'minutes' }), zdt3.toString({ smallestUnit: 'minute' })); - equal(zdt3.toString({ smallestUnit: 'seconds' }), zdt3.toString({ smallestUnit: 'second' })); - equal(zdt3.toString({ smallestUnit: 'milliseconds' }), zdt3.toString({ smallestUnit: 'millisecond' })); - equal(zdt3.toString({ smallestUnit: 'microseconds' }), zdt3.toString({ smallestUnit: 'microsecond' })); - equal(zdt3.toString({ smallestUnit: 'nanoseconds' }), zdt3.toString({ smallestUnit: 'nanosecond' })); - }); - it('truncates or pads to 2 places', () => { - const options = { fractionalSecondDigits: 2 }; - equal(zdt1.toString(options), '1976-11-18T15:23:00.00+01:00[Europe/Vienna]'); - equal(zdt2.toString(options), '1976-11-18T15:23:30.00+01:00[Europe/Vienna]'); - equal(zdt3.toString(options), '1976-11-18T15:23:30.12+01:00[Europe/Vienna]'); - }); - it('pads to 7 places', () => { - const options = { fractionalSecondDigits: 7 }; - equal(zdt1.toString(options), '1976-11-18T15:23:00.0000000+01:00[Europe/Vienna]'); - equal(zdt2.toString(options), '1976-11-18T15:23:30.0000000+01:00[Europe/Vienna]'); - equal(zdt3.toString(options), '1976-11-18T15:23:30.1234000+01:00[Europe/Vienna]'); - }); - it('auto is the default', () => { - [zdt1, zdt2, zdt3].forEach((zdt) => equal(zdt.toString({ fractionalSecondDigits: 'auto' }), zdt.toString())); - }); - it('throws on out of range or invalid fractionalSecondDigits', () => { - [-1, 10, Infinity, NaN, 'not-auto'].forEach((fractionalSecondDigits) => - throws(() => zdt1.toString({ fractionalSecondDigits }), RangeError) - ); - }); - it('accepts and truncates fractional fractionalSecondDigits', () => { - equal(zdt3.toString({ fractionalSecondDigits: 5.5 }), '1976-11-18T15:23:30.12340+01:00[Europe/Vienna]'); - }); - it('smallestUnit overrides fractionalSecondDigits', () => { - equal( - zdt3.toString({ smallestUnit: 'minute', fractionalSecondDigits: 9 }), - '1976-11-18T15:23+01:00[Europe/Vienna]' - ); - }); - it('throws on invalid roundingMode', () => { - throws(() => zdt1.toString({ roundingMode: 'cile' }), RangeError); - }); - it('rounds to nearest', () => { - equal( - zdt2.toString({ smallestUnit: 'minute', roundingMode: 'halfExpand' }), - '1976-11-18T15:24+01:00[Europe/Vienna]' - ); - equal( - zdt3.toString({ fractionalSecondDigits: 3, roundingMode: 'halfExpand' }), - '1976-11-18T15:23:30.123+01:00[Europe/Vienna]' - ); - }); - it('rounds up', () => { - equal(zdt2.toString({ smallestUnit: 'minute', roundingMode: 'ceil' }), '1976-11-18T15:24+01:00[Europe/Vienna]'); - equal( - zdt3.toString({ fractionalSecondDigits: 3, roundingMode: 'ceil' }), - '1976-11-18T15:23:30.124+01:00[Europe/Vienna]' - ); - }); - it('rounds down', () => { - ['floor', 'trunc'].forEach((roundingMode) => { - equal(zdt2.toString({ smallestUnit: 'minute', roundingMode }), '1976-11-18T15:23+01:00[Europe/Vienna]'); - equal( - zdt3.toString({ fractionalSecondDigits: 3, roundingMode }), - '1976-11-18T15:23:30.123+01:00[Europe/Vienna]' - ); - }); - }); - it('rounding down is towards the Big Bang, not towards 1 BCE', () => { - const zdt4 = ZonedDateTime.from('-000099-12-15T12:00:00.5+00:00[UTC]'); - equal(zdt4.toString({ smallestUnit: 'second', roundingMode: 'floor' }), '-000099-12-15T12:00:00+00:00[UTC]'); - }); - it('rounding can affect all units', () => { - const zdt5 = ZonedDateTime.from('1999-12-31T23:59:59.999999999+01:00[Europe/Berlin]'); - equal( - zdt5.toString({ fractionalSecondDigits: 8, roundingMode: 'halfExpand' }), - '2000-01-01T00:00:00.00000000+01:00[Europe/Berlin]' - ); - }); - it('rounding up to a nonexistent wall-clock time', () => { - const zdt5 = ZonedDateTime.from('2018-11-03T23:59:59.999999999-03:00[America/Sao_Paulo]'); - const roundedString = zdt5.toString({ fractionalSecondDigits: 8, roundingMode: 'halfExpand' }); - equal(roundedString, '2018-11-04T01:00:00.00000000-02:00[America/Sao_Paulo]'); - const zdt6 = ZonedDateTime.from(roundedString); - equal(zdt6.epochNanoseconds - zdt5.epochNanoseconds, 1n); - }); - it('options may only be an object or undefined', () => { - [null, 1, 'hello', true, Symbol('foo'), 1n].forEach((badOptions) => - throws(() => zdt1.toString(badOptions), TypeError) - ); - [{}, () => {}, undefined].forEach((options) => - equal(zdt1.toString(options), '1976-11-18T15:23:00+01:00[Europe/Vienna]') - ); - }); - }); - describe('ZonedDateTime.toJSON()', () => { - it('does the default toString', () => { - const zdt1 = ZonedDateTime.from('1976-11-18T15:23+01:00[Europe/Vienna]'); - const zdt2 = ZonedDateTime.from('1976-11-18T15:23:30+01:00[Europe/Vienna]'); - const zdt3 = ZonedDateTime.from('1976-11-18T15:23:30.1234+01:00[Europe/Vienna]'); - equal(zdt1.toJSON(), '1976-11-18T15:23:00+01:00[Europe/Vienna]'); - equal(zdt2.toJSON(), '1976-11-18T15:23:30+01:00[Europe/Vienna]'); - equal(zdt3.toJSON(), '1976-11-18T15:23:30.1234+01:00[Europe/Vienna]'); - }); - }); - describe("Comparison operators don't work", () => { - const zdt1 = ZonedDateTime.from('1963-02-13T09:36:29.123456789+01:00[Europe/Vienna]'); - const zdt1again = ZonedDateTime.from('1963-02-13T09:36:29.123456789+01:00[Europe/Vienna]'); - const zdt2 = ZonedDateTime.from('1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'); - it('=== is object equality', () => equal(zdt1, zdt1)); - it('!== is object equality', () => notEqual(zdt1, zdt1again)); - it('<', () => throws(() => zdt1 < zdt2)); - it('>', () => throws(() => zdt1 > zdt2)); - it('<=', () => throws(() => zdt1 <= zdt2)); - it('>=', () => throws(() => zdt1 >= zdt2)); - }); - - describe('ZonedDateTime.toInstant()', () => { - it('recent date', () => { - const zdt = ZonedDateTime.from('2019-10-29T10:46:38.271986102+01:00[Europe/Amsterdam]'); - equal(`${zdt.toInstant()}`, '2019-10-29T09:46:38.271986102Z'); - }); - it('year ≤ 99', () => { - const zdt = ZonedDateTime.from('+000098-10-29T10:46:38.271986102+00:00[UTC]'); - equal(`${zdt.toInstant()}`, '+000098-10-29T10:46:38.271986102Z'); - }); - it('year < 1', () => { - let zdt = ZonedDateTime.from('+000000-10-29T10:46:38.271986102+00:00[UTC]'); - equal(`${zdt.toInstant()}`, '+000000-10-29T10:46:38.271986102Z'); - zdt = ZonedDateTime.from('-001000-10-29T10:46:38.271986102+00:00[UTC]'); - equal(`${zdt.toInstant()}`, '-001000-10-29T10:46:38.271986102Z'); - }); - it('year 0 leap day', () => { - const zdt = ZonedDateTime.from('+000000-02-29T00:00-00:01:15[Europe/London]'); - equal(`${zdt.toInstant()}`, '+000000-02-29T00:01:15Z'); - }); - }); - describe('ZonedDateTime.toPlainDate()', () => { - it('works', () => { - const zdt = Temporal.Instant.from('2019-10-29T09:46:38.271986102Z').toZonedDateTimeISO(tz); - equal(`${zdt.toPlainDate()}`, '2019-10-29'); - }); - it('preserves the calendar', () => { - const zdt = Temporal.Instant.from('2019-10-29T09:46:38.271986102Z').toZonedDateTime({ - timeZone: tz, - calendar: 'gregory' - }); - equal(zdt.toPlainDate().calendar.id, 'gregory'); - }); - }); - describe('ZonedDateTime.toPlainTime()', () => { - it('works', () => { - const zdt = Temporal.Instant.from('2019-10-29T09:46:38.271986102Z').toZonedDateTimeISO(tz); - equal(`${zdt.toPlainTime()}`, '02:46:38.271986102'); - }); - }); - describe('ZonedDateTime.toPlainYearMonth()', () => { - it('works', () => { - const zdt = Temporal.Instant.from('2019-10-29T09:46:38.271986102Z').toZonedDateTimeISO(tz); - equal(`${zdt.toPlainYearMonth()}`, '2019-10'); - }); - it('preserves the calendar', () => { - const zdt = Temporal.Instant.from('2019-10-29T09:46:38.271986102Z').toZonedDateTime({ - timeZone: tz, - calendar: 'gregory' - }); - equal(zdt.toPlainYearMonth().calendar.id, 'gregory'); - }); - }); - describe('ZonedDateTime.toPlainMonthDay()', () => { - it('works', () => { - const zdt = Temporal.Instant.from('2019-10-29T09:46:38.271986102Z').toZonedDateTimeISO(tz); - equal(`${zdt.toPlainMonthDay()}`, '10-29'); - }); - it('preserves the calendar', () => { - const zdt = Temporal.Instant.from('2019-10-29T09:46:38.271986102Z').toZonedDateTime({ - timeZone: tz, - calendar: 'gregory' - }); - equal(zdt.toPlainMonthDay().calendar.id, 'gregory'); - }); - }); - - describe('ZonedDateTime.getISOFields()', () => { - const zdt1 = ZonedDateTime.from('1976-11-18T15:23:30.123456789+08:00[Asia/Shanghai]'); - const fields = zdt1.getISOFields(); - it('fields', () => { - equal(fields.isoYear, 1976); - equal(fields.isoMonth, 11); - equal(fields.isoDay, 18); - equal(fields.isoHour, 15); - equal(fields.isoMinute, 23); - equal(fields.isoSecond, 30); - equal(fields.isoMillisecond, 123); - equal(fields.isoMicrosecond, 456); - equal(fields.isoNanosecond, 789); - equal(fields.offset, '+08:00'); - equal(fields.timeZone.id, 'Asia/Shanghai'); - equal(fields.calendar.id, 'iso8601'); - }); - it('enumerable', () => { - const fields2 = { ...fields }; - equal(fields2.isoYear, 1976); - equal(fields2.isoMonth, 11); - equal(fields2.isoDay, 18); - equal(fields2.isoHour, 15); - equal(fields2.isoMinute, 23); - equal(fields2.isoSecond, 30); - equal(fields2.isoMillisecond, 123); - equal(fields2.isoMicrosecond, 456); - equal(fields2.isoNanosecond, 789); - equal(fields2.offset, '+08:00'); - equal(fields2.timeZone, fields.timeZone); - equal(fields2.calendar, fields.calendar); - }); - }); - - const hourBeforeDstStart = new Temporal.PlainDateTime(2020, 3, 8, 1).toZonedDateTime(tz); - const dayBeforeDstStart = new Temporal.PlainDateTime(2020, 3, 7, 2, 30).toZonedDateTime(tz); - describe('properties around DST', () => { - it('hoursInDay works with DST start', () => { - equal(hourBeforeDstStart.hoursInDay, 23); - }); - it('hoursInDay works with non-DST days', () => { - equal(dayBeforeDstStart.hoursInDay, 24); - }); - it('hoursInDay works with DST end', () => { - const dstEnd = ZonedDateTime.from('2020-11-01T01:00-08:00[America/Los_Angeles]'); - equal(dstEnd.hoursInDay, 25); - }); - it('hoursInDay works with non-hour DST change', () => { - const zdt1 = ZonedDateTime.from('2020-10-04T12:00[Australia/Lord_Howe]'); - equal(zdt1.hoursInDay, 23.5); - const zdt2 = ZonedDateTime.from('2020-04-05T12:00[Australia/Lord_Howe]'); - equal(zdt2.hoursInDay, 24.5); - }); - it('hoursInDay works with non-half-hour DST change', () => { - const zdt = ZonedDateTime.from('1933-01-01T12:00[Asia/Singapore]'); - // eslint-disable-next-line @typescript-eslint/no-loss-of-precision,no-loss-of-precision - assert(Math.abs(zdt.hoursInDay - 23.6666666666666666) < Number.EPSILON); - }); - it('hoursInDay works when day starts at 1:00 due to DST start at midnight', () => { - const zdt = ZonedDateTime.from('2015-10-18T12:00:00-02:00[America/Sao_Paulo]'); - equal(zdt.hoursInDay, 23); - }); - it('startOfDay works', () => { - const start = dayBeforeDstStart.startOfDay(); - equal(`${start.toPlainDate()}`, `${dayBeforeDstStart.toPlainDate()}`); - equal(`${start.toPlainTime()}`, '00:00:00'); - }); - it('startOfDay works when day starts at 1:00 due to DST start at midnight', () => { - const zdt = ZonedDateTime.from('2015-10-18T12:00:00-02:00[America/Sao_Paulo]'); - equal(`${zdt.startOfDay().toPlainTime()}`, '01:00:00'); - }); - - const dayAfterSamoaDateLineChange = ZonedDateTime.from('2011-12-31T22:00+14:00[Pacific/Apia]'); - const dayBeforeSamoaDateLineChange = ZonedDateTime.from('2011-12-29T22:00-10:00[Pacific/Apia]'); - it('startOfDay works after Samoa date line change', () => { - const start = dayAfterSamoaDateLineChange.startOfDay(); - equal(`${start.toPlainTime()}`, '00:00:00'); - }); - it('hoursInDay works after Samoa date line change', () => { - equal(dayAfterSamoaDateLineChange.hoursInDay, 24); - }); - it('hoursInDay works before Samoa date line change', () => { - equal(dayBeforeSamoaDateLineChange.hoursInDay, 24); - }); - }); - - describe('math around DST', () => { - it('add 1 hour to get to DST start', () => { - const added = hourBeforeDstStart.add({ hours: 1 }); - equal(added.hour, 3); - const diff = hourBeforeDstStart.until(added, { largestUnit: 'hours' }); - equal(`${diff}`, 'PT1H'); - equal(`${diff}`, `${added.since(hourBeforeDstStart, { largestUnit: 'hours' })}`); - const undo = added.subtract(diff); - equal(`${undo}`, `${hourBeforeDstStart}`); - }); - - it('add 2 hours to get to DST start +1', () => { - const added = hourBeforeDstStart.add({ hours: 2 }); - equal(added.hour, 4); - const diff = hourBeforeDstStart.until(added, { largestUnit: 'hours' }); - equal(`${diff}`, 'PT2H'); - equal(`${diff}`, `${added.since(hourBeforeDstStart, { largestUnit: 'hours' })}`); - const undo = added.subtract(diff); - equal(`${undo}`, `${hourBeforeDstStart}`); - }); - - it('add 1.5 hours to get to 0.5 hours after DST start', () => { - const added = hourBeforeDstStart.add({ hours: 1, minutes: 30 }); - equal(added.hour, 3); - equal(added.minute, 30); - const diff = hourBeforeDstStart.until(added, { largestUnit: 'hours' }); - equal(`${diff}`, 'PT1H30M'); - equal(`${diff}`, `${added.since(hourBeforeDstStart, { largestUnit: 'hours' })}`); - const undo = added.subtract(diff); - equal(`${undo}`, `${hourBeforeDstStart}`); - }); - - it('Samoa date line change (add): 10:00PM 29 Dec 2011 -> 11:00PM 31 Dec 2011', () => { - const timeZone = Temporal.TimeZone.from('Pacific/Apia'); - const dayBeforeSamoaDateLineChangeAbs = timeZone.getInstantFor(new Temporal.PlainDateTime(2011, 12, 29, 22)); - const start = dayBeforeSamoaDateLineChangeAbs.toZonedDateTimeISO(timeZone); - const added = start.add({ days: 1, hours: 1 }); - equal(added.day, 31); - equal(added.hour, 23); - equal(added.minute, 0); - const diff = start.until(added, { largestUnit: 'days' }); - equal(`${diff}`, 'P2DT1H'); - const undo = added.subtract(diff); - equal(`${undo}`, `${start}`); - }); - - it('Samoa date line change (subtract): 11:00PM 31 Dec 2011 -> 10:00PM 29 Dec 2011', () => { - const timeZone = Temporal.TimeZone.from('Pacific/Apia'); - const dayAfterSamoaDateLineChangeAbs = timeZone.getInstantFor(new Temporal.PlainDateTime(2011, 12, 31, 23)); - const start = dayAfterSamoaDateLineChangeAbs.toZonedDateTimeISO(timeZone); - const skipped = start.subtract({ days: 1, hours: 1 }); - equal(skipped.day, 31); - equal(skipped.hour, 22); - equal(skipped.minute, 0); - const end = start.subtract({ days: 2, hours: 1 }); - equal(end.day, 29); - equal(end.hour, 22); - equal(end.minute, 0); - const diff = end.since(start, { largestUnit: 'days' }); - equal(`${diff}`, '-P2DT1H'); - const undo = start.add(diff); - equal(`${undo}`, `${end}`); - }); - - it('3:30 day before DST start -> 3:30 day of DST start', () => { - const start = dayBeforeDstStart.add({ hours: 1 }); // 3:30AM - const added = start.add({ days: 1 }); - equal(added.day, 8); - equal(added.hour, 3); - equal(added.minute, 30); - const diff = start.until(added, { largestUnit: 'days' }); - equal(`${diff}`, 'P1D'); - const undo = added.subtract(diff); - equal(`${undo}`, `${start}`); - }); - - it('2:30 day before DST start -> 3:30 day of DST start', () => { - const added = dayBeforeDstStart.add({ days: 1 }); - equal(added.day, 8); - equal(added.hour, 3); - equal(added.minute, 30); - const diff = dayBeforeDstStart.until(added, { largestUnit: 'days' }); - equal(`${diff}`, 'P1D'); - const undo = dayBeforeDstStart.add(diff); - equal(`${undo}`, `${added}`); - }); - - it('1:30 day DST starts -> 4:30 day DST starts', () => { - const start = dayBeforeDstStart.add({ hours: 23 }); // 1:30AM - const added = start.add({ hours: 2 }); - equal(added.day, 8); - equal(added.hour, 4); - equal(added.minute, 30); - const diff = start.until(added, { largestUnit: 'days' }); - equal(`${diff}`, 'PT2H'); - const undo = added.subtract(diff); - equal(`${undo}`, `${start}`); - }); - - it('2:00 day before DST starts -> 3:00 day DST starts', () => { - const start = hourBeforeDstStart.subtract({ days: 1 }).add({ hours: 1 }); // 2:00AM - const added = start.add({ days: 1 }); - equal(added.day, 8); - equal(added.hour, 3); - equal(added.minute, 0); - const diff = start.until(added, { largestUnit: 'days' }); - equal(`${diff}`, 'P1D'); - const undo = start.add(diff); - equal(`${undo}`, `${added}`); - }); - - it('1:00AM day DST starts -> (add 24 hours) -> 2:00AM day after DST starts', () => { - const start = hourBeforeDstStart; // 1:00AM - const added = start.add({ hours: 24 }); - equal(added.day, 9); - equal(added.hour, 2); - equal(added.minute, 0); - const diff = start.until(added, { largestUnit: 'days' }); - equal(`${diff}`, 'P1DT1H'); - const undo = added.subtract(diff); - equal(`${undo}`, `${start}`); - }); - - it('12:00AM day DST starts -> (add 24 hours) -> 1:00AM day after DST starts', () => { - const start = hourBeforeDstStart.subtract({ hours: 1 }); // 1:00AM - const added = start.add({ hours: 24 }); - equal(added.day, 9); - equal(added.hour, 1); - equal(added.minute, 0); - const diff = start.until(added, { largestUnit: 'days' }); - equal(`${diff}`, 'P1DT1H'); - const undo = added.subtract(diff); - equal(`${undo}`, `${start}`); - }); - - it('Difference can return day length > 24 hours', () => { - const start = ZonedDateTime.from('2020-10-30T01:45-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-11-02T01:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { largestUnit: 'days' }); - equal(`${diff}`, 'P2DT24H30M'); - const undo = start.add(diff); - equal(`${undo}`, `${end}`); - }); - - it('Difference rounding (nearest day) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { smallestUnit: 'days', roundingMode: 'halfExpand' }); - equal(`${diff}`, '-P3D'); - }); - - it('Difference rounding (ceil day) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { smallestUnit: 'days', roundingMode: 'ceil' }); - equal(`${diff}`, '-P2D'); - }); - - it('Difference rounding (trunc day) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { smallestUnit: 'days', roundingMode: 'trunc' }); - equal(`${diff}`, '-P2D'); - }); - - it('Difference rounding (floor day) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { smallestUnit: 'days', roundingMode: 'floor' }); - equal(`${diff}`, '-P3D'); - }); - - it('Difference rounding (nearest hour) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { largestUnit: 'days', smallestUnit: 'hours', roundingMode: 'halfExpand' }); - equal(`${diff}`, '-P2DT12H'); - }); - - it('Difference rounding (ceil hour) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { largestUnit: 'days', smallestUnit: 'hours', roundingMode: 'ceil' }); - equal(`${diff}`, '-P2DT12H'); - }); - - it('Difference rounding (trunc hour) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { largestUnit: 'days', smallestUnit: 'hours', roundingMode: 'trunc' }); - equal(`${diff}`, '-P2DT12H'); - }); - - it('Difference rounding (floor hour) is DST-aware', () => { - const start = ZonedDateTime.from('2020-03-10T02:30-07:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-07T14:15-08:00[America/Los_Angeles]'); - const diff = start.until(end, { largestUnit: 'days', smallestUnit: 'hours', roundingMode: 'floor' }); - equal(`${diff}`, '-P2DT13H'); - }); - - it('Difference when date portion ends inside a DST-skipped period', () => { - const start = ZonedDateTime.from('2020-03-07T02:30-08:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-03-08T03:15-07:00[America/Los_Angeles]'); - const diff = start.until(end, { largestUnit: 'days' }); - equal(`${diff}`, 'PT23H45M'); - }); - - it("Difference when date portion ends inside day skipped by Samoa's 24hr 2011 transition", () => { - const end = ZonedDateTime.from('2011-12-31T05:00+14:00[Pacific/Apia]'); - const start = ZonedDateTime.from('2011-12-28T10:00-10:00[Pacific/Apia]'); - const diff = start.until(end, { largestUnit: 'days' }); - equal(`${diff}`, 'P1DT19H'); - }); - - it('Rounding up to hours causes one more day of overflow (positive)', () => { - const start = ZonedDateTime.from('2020-01-01T00:00-08:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-01-03T23:59-08:00[America/Los_Angeles]'); - const diff = start.until(end, { largestUnit: 'days', smallestUnit: 'hours', roundingMode: 'halfExpand' }); - equal(`${diff}`, 'P3D'); - }); - - it('Rounding up to hours causes one more day of overflow (negative)', () => { - const start = ZonedDateTime.from('2020-01-01T00:00-08:00[America/Los_Angeles]'); - const end = ZonedDateTime.from('2020-01-03T23:59-08:00[America/Los_Angeles]'); - const diff = end.until(start, { largestUnit: 'days', smallestUnit: 'hours', roundingMode: 'halfExpand' }); - equal(`${diff}`, '-P3D'); - }); - - it('addition and difference work near DST start', () => { - // Test the difference between different distances near DST start - const stepsPerHour = 2; - const minutesPerStep = 60 / stepsPerHour; - const hoursUntilEnd = 26; - const startHourRange = 3; - for (let i = 0; i < startHourRange * stepsPerHour; i++) { - const start = hourBeforeDstStart.add({ minutes: minutesPerStep * i }); - for (let j = 0; j < hoursUntilEnd * stepsPerHour; j++) { - const end = start.add({ minutes: j * minutesPerStep }); - const diff = start.until(end, { largestUnit: 'days' }); - const expectedMinutes = minutesPerStep * (j % stepsPerHour); - equal(diff.minutes, expectedMinutes); - const diff60 = Math.floor(j / stepsPerHour); - if (i >= stepsPerHour) { - // DST transition already happened - const expectedDays = diff60 < 24 ? 0 : diff60 < 48 ? 1 : 2; - const expectedHours = diff60 < 24 ? diff60 : diff60 < 48 ? diff60 - 24 : diff60 - 48; - equal(diff.hours, expectedHours); - equal(diff.days, expectedDays); - } else { - // DST transition hasn't happened yet - const expectedDays = diff60 < 23 ? 0 : diff60 < 47 ? 1 : 2; - const expectedHours = diff60 < 23 ? diff60 : diff60 < 47 ? diff60 - 23 : diff60 - 47; - equal(diff.hours, expectedHours); - equal(diff.days, expectedDays); - } - } - } - }); - }); - - describe('math order of operations and options', () => { - const breakoutUnits = (op, zdt, d, options) => - zdt[op]({ years: d.years }, options) - [op]({ months: d.months }, options) - [op]({ weeks: d.weeks }, options) - [op]({ days: d.days }, options) - [op]( - { - hours: d.hours, - minutes: d.minutes, - seconds: d.seconds, - milliseconds: d.milliseconds, - microseconds: d.microseconds, - nanoseconds: d.nanoseconds - }, - - options - ); - - it('order of operations: add / none', () => { - const zdt = ZonedDateTime.from('2020-01-31T00:00-08:00[America/Los_Angeles]'); - const d = Temporal.Duration.from({ months: 1, days: 1 }); - const options = undefined; - const result = zdt.add(d, options); - equal(result.toString(), '2020-03-01T00:00:00-08:00[America/Los_Angeles]'); - equal(breakoutUnits('add', zdt, d, options).toString(), result.toString()); - }); - it('order of operations: add / constrain', () => { - const zdt = ZonedDateTime.from('2020-01-31T00:00-08:00[America/Los_Angeles]'); - const d = Temporal.Duration.from({ months: 1, days: 1 }); - const options = { overflow: 'constrain' }; - const result = zdt.add(d, options); - equal(result.toString(), '2020-03-01T00:00:00-08:00[America/Los_Angeles]'); - equal(breakoutUnits('add', zdt, d, options).toString(), result.toString()); - }); - it('order of operations: add / reject', () => { - const zdt = ZonedDateTime.from('2020-01-31T00:00-08:00[America/Los_Angeles]'); - const d = Temporal.Duration.from({ months: 1, days: 1 }); - const options = { overflow: 'reject' }; - throws(() => zdt.add(d, options), RangeError); - }); - it('order of operations: subtract / none', () => { - const zdt = ZonedDateTime.from('2020-03-31T00:00-07:00[America/Los_Angeles]'); - const d = Temporal.Duration.from({ months: 1, days: 1 }); - const options = undefined; - const result = zdt.subtract(d, options); - equal(result.toString(), '2020-02-28T00:00:00-08:00[America/Los_Angeles]'); - equal(breakoutUnits('subtract', zdt, d, options).toString(), result.toString()); - }); - it('order of operations: subtract / constrain', () => { - const zdt = ZonedDateTime.from('2020-03-31T00:00-07:00[America/Los_Angeles]'); - const d = Temporal.Duration.from({ months: 1, days: 1 }); - const options = { overflow: 'constrain' }; - const result = zdt.subtract(d, options); - equal(result.toString(), '2020-02-28T00:00:00-08:00[America/Los_Angeles]'); - equal(breakoutUnits('subtract', zdt, d, options).toString(), result.toString()); - }); - it('order of operations: subtract / reject', () => { - const zdt = ZonedDateTime.from('2020-03-31T00:00-07:00[America/Los_Angeles]'); - const d = Temporal.Duration.from({ months: 1, days: 1 }); - const options = { overflow: 'reject' }; - throws(() => zdt.subtract(d, options), RangeError); - }); - }); - - describe('ZonedDateTime.compare()', () => { - const zdt1 = ZonedDateTime.from('1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]'); - const zdt2 = ZonedDateTime.from('2019-10-29T10:46:38.271986102+01:00[Europe/Vienna]'); - it('equal', () => equal(ZonedDateTime.compare(zdt1, zdt1), 0)); - it('smaller/larger', () => equal(ZonedDateTime.compare(zdt1, zdt2), -1)); - it('larger/smaller', () => equal(ZonedDateTime.compare(zdt2, zdt1), 1)); - it('casts first argument', () => { - equal(ZonedDateTime.compare({ year: 1976, month: 11, day: 18, hour: 15, timeZone: 'Europe/Vienna' }, zdt2), -1); - equal(ZonedDateTime.compare('1976-11-18T15:23:30.123456789+01:00[Europe/Vienna]', zdt2), -1); - }); - it('casts second argument', () => { - equal(ZonedDateTime.compare(zdt1, { year: 2019, month: 10, day: 29, hour: 10, timeZone: 'Europe/Vienna' }), -1); - equal(ZonedDateTime.compare(zdt1, '2019-10-29T10:46:38.271986102+01:00[Europe/Vienna]'), -1); - }); - it('object must contain at least the required properties', () => { - equal(ZonedDateTime.compare({ year: 1976, month: 11, day: 18, timeZone: 'Europe/Vienna' }, zdt2), -1); - throws(() => ZonedDateTime.compare({ month: 11, day: 18, timeZone: 'Europe/Vienna' }, zdt2), TypeError); - throws(() => ZonedDateTime.compare({ year: 1976, day: 18, timeZone: 'Europe/Vienna' }, zdt2), TypeError); - throws(() => ZonedDateTime.compare({ year: 1976, month: 11, timeZone: 'Europe/Vienna' }, zdt2), TypeError); - throws(() => ZonedDateTime.compare({ year: 1976, month: 11, day: 18 }, zdt2), TypeError); - throws( - () => ZonedDateTime.compare({ years: 1976, months: 11, days: 19, hours: 15, timeZone: 'Europe/Vienna' }, zdt2), - TypeError - ); - equal(ZonedDateTime.compare(zdt1, { year: 2019, month: 10, day: 29, timeZone: 'Europe/Vienna' }), -1); - throws(() => ZonedDateTime.compare(zdt1, { month: 10, day: 29, timeZone: 'Europe/Vienna' }), TypeError); - throws(() => ZonedDateTime.compare(zdt1, { year: 2019, day: 29, timeZone: 'Europe/Vienna' }), TypeError); - throws(() => ZonedDateTime.compare(zdt1, { year: 2019, month: 10, timeZone: 'Europe/Vienna' }), TypeError); - throws(() => ZonedDateTime.compare(zdt1, { year: 2019, month: 10, day: 29 }), TypeError); - throws( - () => ZonedDateTime.compare(zdt1, { years: 2019, months: 10, days: 29, hours: 10, timeZone: 'Europe/Vienna' }), - TypeError - ); - }); - it('disregards time zone IDs if exact times are equal', () => { - equal(ZonedDateTime.compare(zdt1, zdt1.withTimeZone('Asia/Kolkata')), 0); - }); - it('disregards calendar IDs if exact times and time zones are equal', () => { - equal(ZonedDateTime.compare(zdt1, zdt1.withCalendar('japanese')), 0); - }); - it('compares exact time, not clock time', () => { - const clockBefore = ZonedDateTime.from('1999-12-31T23:30-08:00[America/Vancouver]'); - const clockAfter = ZonedDateTime.from('2000-01-01T01:30-04:00[America/Halifax]'); - equal(ZonedDateTime.compare(clockBefore, clockAfter), 1); - equal(Temporal.PlainDateTime.compare(clockBefore.toPlainDateTime(), clockAfter.toPlainDateTime()), -1); - }); - it('throws with invalid offset', () => { - throws(() => { - Temporal.ZonedDateTime.compare(zdt1, { - year: 2021, - month: 11, - day: 26, - offset: '+099:00', - timeZone: 'Europe/London' - }); - }, RangeError); - }); - }); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dc6d8ba4..3711a741 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,21 +13,9 @@ importers: .: devDependencies: - '@babel/core': - specifier: ^7.14.6 - version: 7.21.0 - '@babel/preset-env': - specifier: ^7.14.5 - version: 7.20.2(@babel/core@7.21.0) - '@babel/preset-typescript': - specifier: ^7.15.0 - version: 7.21.0(@babel/core@7.21.0) '@rollup/plugin-node-resolve': specifier: ^13.3.0 version: 13.3.0(rollup@2.79.1) - '@types/jest': - specifier: ^26.0.23 - version: 26.0.24 '@typescript-eslint/eslint-plugin': specifier: ^4.22.1 version: 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6) @@ -58,9 +46,6 @@ importers: eslint-plugin-promise: specifier: ^5.1.0 version: 5.2.0(eslint@7.32.0) - jest: - specifier: ^27.0.4 - version: 27.5.1 rollup: specifier: ^2.55.1 version: 2.79.1 @@ -83,12 +68,6 @@ importers: specifier: workspace:* version: link:../temporal-spec devDependencies: - '@types/jest': - specifier: ^26.0.23 - version: 26.0.24 - jest: - specifier: ^27.0.4 - version: 27.5.1 locale-data: specifier: workspace:* version: link:../locale-data @@ -102,12 +81,6 @@ importers: specifier: workspace:* version: link:../temporal-spec devDependencies: - '@types/jest': - specifier: ^26.0.23 - version: 26.0.24 - jest: - specifier: ^27.0.4 - version: 27.5.1 temporal-polyfill: specifier: workspace:* version: link:../temporal-polyfill @@ -126,24 +99,12 @@ importers: packages/locale-textinfo: devDependencies: - '@types/jest': - specifier: ^26.0.23 - version: 26.0.24 - jest: - specifier: ^27.0.4 - version: 27.5.1 locale-data: specifier: workspace:* version: link:../locale-data packages/locale-weekinfo: devDependencies: - '@types/jest': - specifier: ^26.0.23 - version: 26.0.24 - jest: - specifier: ^27.0.4 - version: 27.5.1 locale-data: specifier: workspace:* version: link:../locale-data @@ -157,33 +118,18 @@ importers: '@js-temporal/temporal-test262-runner': specifier: ^0.9.0 version: 0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza) - '@types/chai': - specifier: ^4.2.22 - version: 4.3.4 - '@types/jest': - specifier: ^26.0.24 - version: 26.0.24 '@types/node': specifier: ^16.9.1 version: 16.18.14 ansi-colors: specifier: ^4.1.3 version: 4.1.3 - chai: - specifier: ^4.3.4 - version: 4.3.7 concurrently: specifier: ^7.6.0 version: 7.6.0 eslint: specifier: ^7.25.0 version: 7.32.0 - jest: - specifier: ^27.0.6 - version: 27.5.1 - jest-date-mock: - specifier: ^1.0.8 - version: 1.0.8 js-yaml: specifier: ^4.1.0 version: 4.1.0 @@ -207,14 +153,6 @@ importers: packages: - /@ampproject/remapping@2.2.0: - resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.17 - dev: true - /@babel/code-frame@7.12.11: resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} dependencies: @@ -228,4093 +166,1561 @@ packages: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data@7.21.0: - resolution: {integrity: sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.21.0: - resolution: {integrity: sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.21.1 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) - '@babel/helper-module-transforms': 7.21.2 - '@babel/helpers': 7.21.0 - '@babel/parser': 7.21.2 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.2 - '@babel/types': 7.21.2 - convert-source-map: 1.9.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.21.1: - resolution: {integrity: sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==} + /@babel/helper-validator-identifier@7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 - jsesc: 2.5.2 dev: true - /@babel/helper-annotate-as-pure@7.18.6: - resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} + /@babel/highlight@7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.2 + '@babel/helper-validator-identifier': 7.19.1 + chalk: 2.4.2 + js-tokens: 4.0.0 dev: true - /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: - resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-explode-assignable-expression': 7.18.6 - '@babel/types': 7.21.2 + /@esbuild/android-arm64@0.18.17: + resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true dev: true + optional: true - /@babel/helper-compilation-targets@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.21.0 - '@babel/core': 7.21.0 - '@babel/helper-validator-option': 7.21.0 - browserslist: 4.21.5 - lru-cache: 5.1.1 - semver: 6.3.0 + /@esbuild/android-arm@0.18.17: + resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true dev: true + optional: true - /@babel/helper-create-class-features-plugin@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-member-expression-to-functions': 7.21.0 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/helper-split-export-declaration': 7.18.6 - transitivePeerDependencies: - - supports-color + /@esbuild/android-x64@0.18.17: + resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true dev: true + optional: true - /@babel/helper-create-regexp-features-plugin@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-annotate-as-pure': 7.18.6 - regexpu-core: 5.3.1 + /@esbuild/darwin-arm64@0.18.17: + resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true dev: true + optional: true - /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.21.0): - resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} - peerDependencies: - '@babel/core': ^7.4.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - debug: 4.3.4 - lodash.debounce: 4.0.8 - resolve: 1.22.1 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color + /@esbuild/darwin-x64@0.18.17: + resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true dev: true + optional: true - /@babel/helper-environment-visitor@7.18.9: - resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} - engines: {node: '>=6.9.0'} + /@esbuild/freebsd-arm64@0.18.17: + resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true dev: true + optional: true - /@babel/helper-explode-assignable-expression@7.18.6: - resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/freebsd-x64@0.18.17: + resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true dev: true + optional: true - /@babel/helper-function-name@7.21.0: - resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.20.7 - '@babel/types': 7.21.2 + /@esbuild/linux-arm64@0.18.17: + resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-hoist-variables@7.18.6: - resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/linux-arm@0.18.17: + resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-member-expression-to-functions@7.21.0: - resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/linux-ia32@0.18.17: + resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-module-imports@7.18.6: - resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/linux-loong64@0.18.17: + resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-module-transforms@7.21.2: - resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.20.2 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.2 - '@babel/types': 7.21.2 - transitivePeerDependencies: - - supports-color + /@esbuild/linux-mips64el@0.18.17: + resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-optimise-call-expression@7.18.6: - resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/linux-ppc64@0.18.17: + resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-plugin-utils@7.20.2: - resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} - engines: {node: '>=6.9.0'} + /@esbuild/linux-riscv64@0.18.17: + resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.21.0): - resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-wrap-function': 7.20.5 - '@babel/types': 7.21.2 - transitivePeerDependencies: - - supports-color + /@esbuild/linux-s390x@0.18.17: + resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-replace-supers@7.20.7: - resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-member-expression-to-functions': 7.21.0 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.2 - '@babel/types': 7.21.2 - transitivePeerDependencies: - - supports-color + /@esbuild/linux-x64@0.18.17: + resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true dev: true + optional: true - /@babel/helper-simple-access@7.20.2: - resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/netbsd-x64@0.18.17: + resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true dev: true + optional: true - /@babel/helper-skip-transparent-expression-wrappers@7.20.0: - resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/openbsd-x64@0.18.17: + resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true dev: true + optional: true - /@babel/helper-split-export-declaration@7.18.6: - resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.2 + /@esbuild/sunos-x64@0.18.17: + resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true dev: true + optional: true - /@babel/helper-string-parser@7.19.4: - resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} - engines: {node: '>=6.9.0'} + /@esbuild/win32-arm64@0.18.17: + resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true dev: true + optional: true - /@babel/helper-validator-identifier@7.19.1: - resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} - engines: {node: '>=6.9.0'} + /@esbuild/win32-ia32@0.18.17: + resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true dev: true + optional: true - /@babel/helper-validator-option@7.21.0: - resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} - engines: {node: '>=6.9.0'} + /@esbuild/win32-x64@0.18.17: + resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true dev: true + optional: true - /@babel/helper-wrap-function@7.20.5: - resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==} - engines: {node: '>=6.9.0'} + /@eslint/eslintrc@0.4.3: + resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} + engines: {node: ^10.12.0 || >=12.0.0} dependencies: - '@babel/helper-function-name': 7.21.0 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.2 - '@babel/types': 7.21.2 + ajv: 6.12.6 + debug: 4.3.4 + espree: 7.3.1 + globals: 13.20.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + js-yaml: 3.14.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color dev: true - /@babel/helpers@7.21.0: - resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.2 - '@babel/types': 7.21.2 - transitivePeerDependencies: + /@humanwhocodes/config-array@0.5.0: + resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: - supports-color dev: true - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.19.1 - chalk: 2.4.2 - js-tokens: 4.0.0 + /@humanwhocodes/object-schema@1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@babel/parser@7.21.2: - resolution: {integrity: sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==} + /@jridgewell/gen-mapping@0.3.2: + resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} engines: {node: '>=6.0.0'} - hasBin: true dependencies: - '@babel/types': 7.21.2 + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping': 0.3.17 dev: true - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /@jridgewell/resolve-uri@3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.13.0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.0) + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} dev: true - /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@jridgewell/source-map@0.3.2: + resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.0) - transitivePeerDependencies: - - supports-color + '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.17 dev: true - /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - transitivePeerDependencies: - - supports-color + /@jridgewell/sourcemap-codec@1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} dev: true - /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.12.0 + /@jridgewell/trace-mapping@0.3.17: + resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.21.0) - transitivePeerDependencies: - - supports-color + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@js-temporal/temporal-test262-runner@0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza): + resolution: {integrity: sha512-+DbfZ6oyuFyHbfe77HOuYEPfIkSNlYvFfS7hA+o9n1MxTqjdTN1xxQ0IOkGloVblIsl5Ceu1yzG4RNVzZHWL9Q==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.21.0) + ansi-colors: 4.1.3 + js-yaml: 4.1.0 + progress: 2.0.3 + tiny-glob: 0.2.9 dev: true + patched: true - /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.21.0): - resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.21.0) + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 dev: true - /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.0) + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} dev: true - /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.0) + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 dev: true - /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} - engines: {node: '>=6.9.0'} + /@rollup/plugin-node-resolve@13.3.0(rollup@2.79.1): + resolution: {integrity: sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==} + engines: {node: '>= 10.0.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + rollup: ^2.42.0 dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.0) + '@rollup/pluginutils': 3.1.0(rollup@2.79.1) + '@types/resolve': 1.17.1 + deepmerge: 4.3.0 + is-builtin-module: 3.2.1 + is-module: 1.0.0 + resolve: 1.22.1 + rollup: 2.79.1 dev: true - /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} - engines: {node: '>=6.9.0'} + /@rollup/pluginutils@3.1.0(rollup@2.79.1): + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + rollup: ^1.20.0||^2.0.0 dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.0) + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 2.79.1 dev: true - /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@rollup/pluginutils@4.2.1: + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} dependencies: - '@babel/compat-data': 7.21.0 - '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-transform-parameters': 7.20.7(@babel/core@7.21.0) + estree-walker: 2.0.2 + picomatch: 2.3.1 dev: true - /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.0) + /@types/estree@0.0.39: + resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: true - /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.0) + /@types/json-schema@7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true - /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - transitivePeerDependencies: - - supports-color + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.0) - transitivePeerDependencies: - - supports-color + /@types/node@16.18.14: + resolution: {integrity: sha512-wvzClDGQXOCVNU4APPopC2KtMYukaF1MN/W3xAmslx22Z4/IF1/izDMekuyoUlwfnDHYCIZGaj7jMwnJKBTxKw==} dev: true - /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} - engines: {node: '>=4'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 + /@types/node@18.14.5: + resolution: {integrity: sha512-CRT4tMK/DHYhw1fcCEBwME9CSaZNclxfzVMe7GsO6ULSwsttbj70wSiX6rZdIjGblu93sTJxLdhNIT85KKI7Qw==} dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.21.0): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@types/resolve@1.17.1: + resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + '@types/node': 18.14.5 dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + /@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6): + resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==} + engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: - '@babel/core': ^7.0.0-0 + '@typescript-eslint/parser': ^4.0.0 + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + '@typescript-eslint/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.1.6) + '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) + '@typescript-eslint/scope-manager': 4.33.0 + debug: 4.3.4 + eslint: 7.32.0 + functional-red-black-tree: 1.0.1 + ignore: 5.2.4 + regexpp: 3.2.0 + semver: 7.3.8 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.21.0): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + /@typescript-eslint/experimental-utils@4.33.0(eslint@7.32.0)(typescript@5.1.6): + resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==} + engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: - '@babel/core': ^7.0.0-0 + eslint: '*' dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + '@types/json-schema': 7.0.11 + '@typescript-eslint/scope-manager': 4.33.0 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.6) + eslint: 7.32.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0(eslint@7.32.0) + transitivePeerDependencies: + - supports-color + - typescript dev: true - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.21.0): - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} - engines: {node: '>=6.9.0'} + /@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.1.6): + resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==} + engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: - '@babel/core': ^7.0.0-0 + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + '@typescript-eslint/scope-manager': 4.33.0 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.6) + debug: 4.3.4 + eslint: 7.32.0 + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@typescript-eslint/scope-manager@4.33.0: + resolution: {integrity: sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/visitor-keys': 4.33.0 dev: true - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /@typescript-eslint/types@4.33.0: + resolution: {integrity: sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dev: true - /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.21.0): - resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} - engines: {node: '>=6.9.0'} + /@typescript-eslint/typescript-estree@4.33.0(typescript@5.1.6): + resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} + engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: - '@babel/core': ^7.0.0-0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + '@typescript-eslint/types': 4.33.0 + '@typescript-eslint/visitor-keys': 4.33.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.21.0): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 + /@typescript-eslint/visitor-keys@4.33.0: + resolution: {integrity: sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + '@typescript-eslint/types': 4.33.0 + eslint-visitor-keys: 2.1.0 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + /acorn-jsx@5.3.2(acorn@7.4.1): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: - '@babel/core': ^7.0.0-0 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + acorn: 7.4.1 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.21.0): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /acorn@8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.21.0): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - dev: true + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.21.0): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + color-convert: 1.9.3 dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.21.0): - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - dev: true + color-convert: 2.0.1 - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.21.0): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + sprintf-js: 1.0.3 dev: true - /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.21.0): - resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /@babel/plugin-transform-arrow-functions@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /array-includes@3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + engines: {node: '>= 0.4'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + get-intrinsic: 1.2.0 + is-string: 1.0.7 dev: true - /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.0) - transitivePeerDependencies: - - supports-color + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} dev: true - /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /array.prototype.flat@1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + engines: {node: '>= 0.4'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + es-shim-unscopables: 1.0.0 dev: true - /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /array.prototype.flatmap@1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + engines: {node: '>= 0.4'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + es-shim-unscopables: 1.0.0 dev: true - /@babel/plugin-transform-classes@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-split-export-declaration': 7.18.6 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + /astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} dev: true - /@babel/plugin-transform-computed-properties@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/template': 7.20.7 + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} dev: true - /@babel/plugin-transform-destructuring@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 + balanced-match: 1.0.2 + concat-map: 0.0.1 dev: true - /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.21.0): - resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + balanced-match: 1.0.2 dev: true - /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9 - '@babel/helper-plugin-utils': 7.20.2 + fill-range: 7.0.1 dev: true - /@babel/plugin-transform-for-of@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true - /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.21.0): - resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) - '@babel/helper-function-name': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} dev: true - /@babel/plugin-transform-literals@7.18.9(@babel/core@7.21.0): - resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + function-bind: 1.1.1 + get-intrinsic: 1.2.0 dev: true - /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} dev: true - /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.21.0): - resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-module-transforms': 7.21.2 - '@babel/helper-plugin-utils': 7.20.2 - transitivePeerDependencies: - - supports-color + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 dev: true - /@babel/plugin-transform-modules-commonjs@7.21.2(@babel/core@7.21.0): - resolution: {integrity: sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-module-transforms': 7.21.2 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-simple-access': 7.20.2 - transitivePeerDependencies: - - supports-color + ansi-styles: 4.3.0 + supports-color: 7.2.0 dev: true - /@babel/plugin-transform-modules-systemjs@7.20.11(@babel/core@7.21.0): - resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-module-transforms': 7.21.2 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-identifier': 7.19.1 - transitivePeerDependencies: - - supports-color - dev: true + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 - /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-module-transforms': 7.21.2 - '@babel/helper-plugin-utils': 7.20.2 - transitivePeerDependencies: - - supports-color + color-name: 1.1.3 dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.20.5(@babel/core@7.21.0): - resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - dev: true + color-name: 1.1.4 - /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} dev: true - /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-replace-supers': 7.20.7 - transitivePeerDependencies: - - supports-color - dev: true + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - /@babel/plugin-transform-parameters@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true - /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /concat-map@0.0.1: + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true - /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.21.0): - resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /concurrently@7.6.0: + resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==} + engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} + hasBin: true dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - regenerator-transform: 0.15.1 + chalk: 4.1.2 + date-fns: 2.29.3 + lodash: 4.17.21 + rxjs: 7.8.0 + shell-quote: 1.8.0 + spawn-command: 0.0.2-1 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.1 dev: true - /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 dev: true - /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + /date-fns@2.29.3: + resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} + engines: {node: '>=0.11'} dev: true - /@babel/plugin-transform-spread@7.20.7(@babel/core@7.21.0): - resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} - engines: {node: '>=6.9.0'} + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: - '@babel/core': ^7.0.0-0 + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + ms: 2.1.3 dev: true - /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} - engines: {node: '>=6.9.0'} + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 + ms: 2.1.2 dev: true - /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.21.0): - resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - dev: true - - /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.21.0): - resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - dev: true - - /@babel/plugin-transform-typescript@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-xo///XTPp3mDzTtrqXoBlK9eiAYW3wv9JXglcn/u1bi60RW11dEUxIgA8cbnDhutS1zacjMRmAwxE0gMklLnZg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.21.0) - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.21.0): - resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - dev: true - - /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.21.0): - resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - dev: true - - /@babel/preset-env@7.20.2(@babel/core@7.21.0): - resolution: {integrity: sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.21.0 - '@babel/core': 7.21.0 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.0) - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-proposal-class-static-block': 7.21.0(@babel/core@7.21.0) - '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.21.0) - '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.0) - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0(@babel/core@7.21.0) - '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.21.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.21.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.21.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.21.0) - '@babel/plugin-transform-arrow-functions': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-block-scoping': 7.21.0(@babel/core@7.21.0) - '@babel/plugin-transform-classes': 7.21.0(@babel/core@7.21.0) - '@babel/plugin-transform-computed-properties': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-transform-destructuring': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.21.0) - '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-for-of': 7.21.0(@babel/core@7.21.0) - '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.21.0) - '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.21.0) - '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.21.0) - '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.21.0) - '@babel/plugin-transform-modules-systemjs': 7.20.11(@babel/core@7.21.0) - '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5(@babel/core@7.21.0) - '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-parameters': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-regenerator': 7.20.5(@babel/core@7.21.0) - '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.21.0) - '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.21.0) - '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.21.0) - '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.21.0) - '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.21.0) - '@babel/preset-modules': 0.1.5(@babel/core@7.21.0) - '@babel/types': 7.21.2 - babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.21.0) - babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.21.0) - babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.21.0) - core-js-compat: 3.29.0 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/preset-modules@0.1.5(@babel/core@7.21.0): - resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.0) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.0) - '@babel/types': 7.21.2 - esutils: 2.0.3 - dev: true - - /@babel/preset-typescript@7.21.0(@babel/core@7.21.0): - resolution: {integrity: sha512-myc9mpoVA5m1rF8K8DgLEatOYFDpwC+RkMkjZ0Du6uI62YvDe8uxIEYVs/VCdSJ097nlALiU/yBC7//3nI+hNg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-transform-typescript': 7.21.0(@babel/core@7.21.0) - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/regjsgen@0.8.0: - resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - dev: true - - /@babel/runtime@7.21.0: - resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.11 - dev: true - - /@babel/template@7.20.7: - resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.21.2 - '@babel/types': 7.21.2 - dev: true - - /@babel/traverse@7.21.2: - resolution: {integrity: sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.21.1 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.21.2 - '@babel/types': 7.21.2 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.21.2: - resolution: {integrity: sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - - /@esbuild/android-arm64@0.18.17: - resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.18.17: - resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.18.17: - resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.18.17: - resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.18.17: - resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.18.17: - resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.18.17: - resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.18.17: - resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.18.17: - resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.18.17: - resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.18.17: - resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.18.17: - resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.18.17: - resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.18.17: - resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.18.17: - resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.18.17: - resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.18.17: - resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.18.17: - resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.18.17: - resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.18.17: - resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.18.17: - resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.18.17: - resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@eslint/eslintrc@0.4.3: - resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 7.3.1 - globals: 13.20.0 - ignore: 4.0.6 - import-fresh: 3.3.0 - js-yaml: 3.14.1 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/config-array@0.5.0: - resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true - - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - dev: true - - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true - - /@jest/console@27.5.1: - resolution: {integrity: sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - chalk: 4.1.2 - jest-message-util: 27.5.1 - jest-util: 27.5.1 - slash: 3.0.0 - dev: true - - /@jest/core@27.5.1: - resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/console': 27.5.1 - '@jest/reporters': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.8.1 - exit: 0.1.2 - graceful-fs: 4.2.10 - jest-changed-files: 27.5.1 - jest-config: 27.5.1 - jest-haste-map: 27.5.1 - jest-message-util: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-resolve-dependencies: 27.5.1 - jest-runner: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - jest-watcher: 27.5.1 - micromatch: 4.0.5 - rimraf: 3.0.2 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate - dev: true - - /@jest/environment@27.5.1: - resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/fake-timers': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - jest-mock: 27.5.1 - dev: true - - /@jest/fake-timers@27.5.1: - resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@sinonjs/fake-timers': 8.1.0 - '@types/node': 18.14.5 - jest-message-util: 27.5.1 - jest-mock: 27.5.1 - jest-util: 27.5.1 - dev: true - - /@jest/globals@27.5.1: - resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/environment': 27.5.1 - '@jest/types': 27.5.1 - expect: 27.5.1 - dev: true - - /@jest/reporters@27.5.1: - resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - chalk: 4.1.2 - collect-v8-coverage: 1.0.1 - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.10 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-instrument: 5.2.1 - istanbul-lib-report: 3.0.0 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 - jest-haste-map: 27.5.1 - jest-resolve: 27.5.1 - jest-util: 27.5.1 - jest-worker: 27.5.1 - slash: 3.0.0 - source-map: 0.6.1 - string-length: 4.0.2 - terminal-link: 2.1.1 - v8-to-istanbul: 8.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/source-map@27.5.1: - resolution: {integrity: sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - callsites: 3.1.0 - graceful-fs: 4.2.10 - source-map: 0.6.1 - dev: true - - /@jest/test-result@27.5.1: - resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/console': 27.5.1 - '@jest/types': 27.5.1 - '@types/istanbul-lib-coverage': 2.0.4 - collect-v8-coverage: 1.0.1 - dev: true - - /@jest/test-sequencer@27.5.1: - resolution: {integrity: sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/test-result': 27.5.1 - graceful-fs: 4.2.10 - jest-haste-map: 27.5.1 - jest-runtime: 27.5.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/transform@27.5.1: - resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@babel/core': 7.21.0 - '@jest/types': 27.5.1 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 1.9.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.10 - jest-haste-map: 27.5.1 - jest-regex-util: 27.5.1 - jest-util: 27.5.1 - micromatch: 4.0.5 - pirates: 4.0.5 - slash: 3.0.0 - source-map: 0.6.1 - write-file-atomic: 3.0.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/types@26.6.2: - resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} - engines: {node: '>= 10.14.2'} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 18.14.5 - '@types/yargs': 15.0.15 - chalk: 4.1.2 - dev: true - - /@jest/types@27.5.1: - resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 18.14.5 - '@types/yargs': 16.0.5 - chalk: 4.1.2 - dev: true - - /@jridgewell/gen-mapping@0.1.1: - resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - - /@jridgewell/gen-mapping@0.3.2: - resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.17 - dev: true - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/source-map@0.3.2: - resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} - dependencies: - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 - dev: true - - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true - - /@jridgewell/trace-mapping@0.3.17: - resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - - /@js-temporal/temporal-test262-runner@0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza): - resolution: {integrity: sha512-+DbfZ6oyuFyHbfe77HOuYEPfIkSNlYvFfS7hA+o9n1MxTqjdTN1xxQ0IOkGloVblIsl5Ceu1yzG4RNVzZHWL9Q==} - dependencies: - ansi-colors: 4.1.3 - js-yaml: 4.1.0 - progress: 2.0.3 - tiny-glob: 0.2.9 - dev: true - patched: true - - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 - dev: true - - /@rollup/plugin-node-resolve@13.3.0(rollup@2.79.1): - resolution: {integrity: sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==} - engines: {node: '>= 10.0.0'} - peerDependencies: - rollup: ^2.42.0 - dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) - '@types/resolve': 1.17.1 - deepmerge: 4.3.0 - is-builtin-module: 3.2.1 - is-module: 1.0.0 - resolve: 1.22.1 - rollup: 2.79.1 - dev: true - - /@rollup/pluginutils@3.1.0(rollup@2.79.1): - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.1 - rollup: 2.79.1 - dev: true - - /@rollup/pluginutils@4.2.1: - resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} - engines: {node: '>= 8.0.0'} - dependencies: - estree-walker: 2.0.2 - picomatch: 2.3.1 - dev: true - - /@sinonjs/commons@1.8.6: - resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} - dependencies: - type-detect: 4.0.8 - dev: true - - /@sinonjs/fake-timers@8.1.0: - resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} - dependencies: - '@sinonjs/commons': 1.8.6 - dev: true - - /@tootallnate/once@1.1.2: - resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} - engines: {node: '>= 6'} - dev: true - - /@types/babel__core@7.20.0: - resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==} - dependencies: - '@babel/parser': 7.21.2 - '@babel/types': 7.21.2 - '@types/babel__generator': 7.6.4 - '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.18.3 - dev: true - - /@types/babel__generator@7.6.4: - resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} - dependencies: - '@babel/types': 7.21.2 - dev: true - - /@types/babel__template@7.4.1: - resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} - dependencies: - '@babel/parser': 7.21.2 - '@babel/types': 7.21.2 - dev: true - - /@types/babel__traverse@7.18.3: - resolution: {integrity: sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==} - dependencies: - '@babel/types': 7.21.2 - dev: true - - /@types/chai@4.3.4: - resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} - dev: true - - /@types/estree@0.0.39: - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - dev: true - - /@types/graceful-fs@4.1.6: - resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} - dependencies: - '@types/node': 18.14.5 - dev: true - - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} - dev: true - - /@types/istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - dev: true - - /@types/istanbul-reports@3.0.1: - resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} - dependencies: - '@types/istanbul-lib-report': 3.0.0 - dev: true - - /@types/jest@26.0.24: - resolution: {integrity: sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==} - dependencies: - jest-diff: 26.6.2 - pretty-format: 26.6.2 - dev: true - - /@types/json-schema@7.0.11: - resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} - dev: true - - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true - - /@types/node@16.18.14: - resolution: {integrity: sha512-wvzClDGQXOCVNU4APPopC2KtMYukaF1MN/W3xAmslx22Z4/IF1/izDMekuyoUlwfnDHYCIZGaj7jMwnJKBTxKw==} - dev: true - - /@types/node@18.14.5: - resolution: {integrity: sha512-CRT4tMK/DHYhw1fcCEBwME9CSaZNclxfzVMe7GsO6ULSwsttbj70wSiX6rZdIjGblu93sTJxLdhNIT85KKI7Qw==} - dev: true - - /@types/prettier@2.7.2: - resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} - dev: true - - /@types/resolve@1.17.1: - resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} - dependencies: - '@types/node': 18.14.5 - dev: true - - /@types/stack-utils@2.0.1: - resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} - dev: true - - /@types/yargs-parser@21.0.0: - resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} - dev: true - - /@types/yargs@15.0.15: - resolution: {integrity: sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==} - dependencies: - '@types/yargs-parser': 21.0.0 - dev: true - - /@types/yargs@16.0.5: - resolution: {integrity: sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==} - dependencies: - '@types/yargs-parser': 21.0.0 - dev: true - - /@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6): - resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - '@typescript-eslint/parser': ^4.0.0 - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.1.6) - '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) - '@typescript-eslint/scope-manager': 4.33.0 - debug: 4.3.4 - eslint: 7.32.0 - functional-red-black-tree: 1.0.1 - ignore: 5.2.4 - regexpp: 3.2.0 - semver: 7.3.8 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/experimental-utils@4.33.0(eslint@7.32.0)(typescript@5.1.6): - resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: '*' - dependencies: - '@types/json-schema': 7.0.11 - '@typescript-eslint/scope-manager': 4.33.0 - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.6) - eslint: 7.32.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@7.32.0) - transitivePeerDependencies: - - supports-color - - typescript - dev: true - - /@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.1.6): - resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 4.33.0 - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.1.6) - debug: 4.3.4 - eslint: 7.32.0 - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/scope-manager@4.33.0: - resolution: {integrity: sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==} - engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} - dependencies: - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/visitor-keys': 4.33.0 - dev: true - - /@typescript-eslint/types@4.33.0: - resolution: {integrity: sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==} - engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} - dev: true - - /@typescript-eslint/typescript-estree@4.33.0(typescript@5.1.6): - resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/visitor-keys': 4.33.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.8 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/visitor-keys@4.33.0: - resolution: {integrity: sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==} - engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} - dependencies: - '@typescript-eslint/types': 4.33.0 - eslint-visitor-keys: 2.1.0 - dev: true - - /abab@2.0.6: - resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} - dev: true - - /acorn-globals@6.0.0: - resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==} - dependencies: - acorn: 7.4.1 - acorn-walk: 7.2.0 - dev: true - - /acorn-jsx@5.3.2(acorn@7.4.1): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 7.4.1 - dev: true - - /acorn-walk@7.2.0: - resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn@7.4.1: - resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /acorn@8.8.2: - resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: true - - /ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: true - - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.21.3 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true - - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.1 - get-intrinsic: 1.2.0 - is-string: 1.0.7 - dev: true - - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true - - /array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.1 - es-shim-unscopables: 1.0.0 - dev: true - - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.1 - es-shim-unscopables: 1.0.0 - dev: true - - /assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - dev: true - - /astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - dev: true - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: true - - /available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} - engines: {node: '>= 0.4'} - dev: true - - /babel-jest@27.5.1(@babel/core@7.21.0): - resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - dependencies: - '@babel/core': 7.21.0 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/babel__core': 7.20.0 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1(@babel/core@7.21.0) - chalk: 4.1.2 - graceful-fs: 4.2.10 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - dependencies: - '@babel/helper-plugin-utils': 7.20.2 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-jest-hoist@27.5.1: - resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@babel/template': 7.20.7 - '@babel/types': 7.21.2 - '@types/babel__core': 7.20.0 - '@types/babel__traverse': 7.18.3 - dev: true - - /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.21.0): - resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.21.0 - '@babel/core': 7.21.0 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.0) - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.21.0): - resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.0) - core-js-compat: 3.29.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.21.0): - resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.21.0 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.0) - transitivePeerDependencies: - - supports-color - dev: true - - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.21.0): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.21.0 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.0) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.21.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.21.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.21.0) - dev: true - - /babel-preset-jest@27.5.1(@babel/core@7.21.0): - resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.21.0 - babel-plugin-jest-hoist: 27.5.1 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.21.0) - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - dev: true - - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /browser-process-hrtime@1.0.0: - resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} - dev: true - - /browserslist@4.21.5: - resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001460 - electron-to-chromium: 1.4.319 - node-releases: 2.0.10 - update-browserslist-db: 1.0.10(browserslist@4.21.5) - dev: true - - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - dependencies: - node-int64: 0.4.0 - dev: true - - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - - /builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - dev: true - - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.0 - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - dev: true - - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true - - /caniuse-lite@1.0.30001460: - resolution: {integrity: sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==} - dev: true - - /chai@4.3.7: - resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} - engines: {node: '>=4'} - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.2 - deep-eql: 4.1.3 - get-func-name: 2.0.0 - loupe: 2.3.6 - pathval: 1.1.1 - type-detect: 4.0.8 - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true - - /check-error@1.0.2: - resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} - dev: true - - /ci-info@3.8.0: - resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} - engines: {node: '>=8'} - dev: true - - /cjs-module-lexer@1.2.2: - resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} - dev: true - - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true - - /collect-v8-coverage@1.0.1: - resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - /colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: true - - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} - dev: true - - /concurrently@7.6.0: - resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==} - engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} - hasBin: true - dependencies: - chalk: 4.1.2 - date-fns: 2.29.3 - lodash: 4.17.21 - rxjs: 7.8.0 - shell-quote: 1.8.0 - spawn-command: 0.0.2-1 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.1 - dev: true - - /convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - dev: true - - /core-js-compat@3.29.0: - resolution: {integrity: sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ==} - dependencies: - browserslist: 4.21.5 - dev: true - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /cssom@0.3.8: - resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} - dev: true - - /cssom@0.4.4: - resolution: {integrity: sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==} - dev: true - - /cssstyle@2.3.0: - resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} - engines: {node: '>=8'} - dependencies: - cssom: 0.3.8 - dev: true - - /data-urls@2.0.0: - resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} - engines: {node: '>=10'} - dependencies: - abab: 2.0.6 - whatwg-mimetype: 2.3.0 - whatwg-url: 8.7.0 - dev: true - - /date-fns@2.29.3: - resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} - engines: {node: '>=0.11'} - dev: true - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /decimal.js@10.4.3: - resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} - dev: true - - /dedent@0.7.0: - resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} - dev: true - - /deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} - engines: {node: '>=6'} - dependencies: - type-detect: 4.0.8 - dev: true - - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /deepmerge@4.3.0: - resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==} - engines: {node: '>=0.10.0'} - - /define-properties@1.2.0: - resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} - engines: {node: '>= 0.4'} - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: true - - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true - - /diff-sequences@26.6.2: - resolution: {integrity: sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==} - engines: {node: '>= 10.14.2'} - dev: true - - /diff-sequences@27.5.1: - resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true - - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - - /doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /domexception@2.0.1: - resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} - engines: {node: '>=8'} - dependencies: - webidl-conversions: 5.0.0 - dev: true - - /electron-to-chromium@1.4.319: - resolution: {integrity: sha512-WeoI6NwZUgteKB+Wmn692S35QycwwNxwgTomNnoCJ79znBAjtBi6C/cIW62JkXmpJRX5rKNYSLDBdAM8l5fH0w==} - dev: true - - /emittery@0.8.1: - resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} - engines: {node: '>=10'} - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - /enquirer@2.3.6: - resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} - engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.3 - dev: true - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: true - - /es-abstract@1.21.1: - resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - es-set-tostringtag: 2.0.1 - es-to-primitive: 1.2.1 - function-bind: 1.1.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.2.0 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 - is-callable: 1.2.7 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-typed-array: 1.1.10 - is-weakref: 1.0.2 - object-inspect: 1.12.3 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.4.3 - safe-regex-test: 1.0.0 - string.prototype.trimend: 1.0.6 - string.prototype.trimstart: 1.0.6 - typed-array-length: 1.0.4 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.9 - dev: true - - /es-module-lexer@0.9.3: - resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} - dev: true - - /es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.0 - has: 1.0.3 - has-tostringtag: 1.0.0 - dev: true - - /es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - dependencies: - has: 1.0.3 - dev: true - - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - dev: true - - /esbuild@0.18.17: - resolution: {integrity: sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.18.17 - '@esbuild/android-arm64': 0.18.17 - '@esbuild/android-x64': 0.18.17 - '@esbuild/darwin-arm64': 0.18.17 - '@esbuild/darwin-x64': 0.18.17 - '@esbuild/freebsd-arm64': 0.18.17 - '@esbuild/freebsd-x64': 0.18.17 - '@esbuild/linux-arm': 0.18.17 - '@esbuild/linux-arm64': 0.18.17 - '@esbuild/linux-ia32': 0.18.17 - '@esbuild/linux-loong64': 0.18.17 - '@esbuild/linux-mips64el': 0.18.17 - '@esbuild/linux-ppc64': 0.18.17 - '@esbuild/linux-riscv64': 0.18.17 - '@esbuild/linux-s390x': 0.18.17 - '@esbuild/linux-x64': 0.18.17 - '@esbuild/netbsd-x64': 0.18.17 - '@esbuild/openbsd-x64': 0.18.17 - '@esbuild/sunos-x64': 0.18.17 - '@esbuild/win32-arm64': 0.18.17 - '@esbuild/win32-ia32': 0.18.17 - '@esbuild/win32-x64': 0.18.17 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /escodegen@2.0.0: - resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} - engines: {node: '>=6.0'} - hasBin: true - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 - optionator: 0.8.3 - optionalDependencies: - source-map: 0.6.1 - dev: true - - /eslint-config-standard@16.0.3(eslint-plugin-import@2.27.5)(eslint-plugin-node@11.1.0)(eslint-plugin-promise@5.2.0)(eslint@7.32.0): - resolution: {integrity: sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==} - peerDependencies: - eslint: ^7.12.1 - eslint-plugin-import: ^2.22.1 - eslint-plugin-node: ^11.1.0 - eslint-plugin-promise: ^4.2.1 || ^5.0.0 - dependencies: - eslint: 7.32.0 - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@4.33.0)(eslint@7.32.0) - eslint-plugin-node: 11.1.0(eslint@7.32.0) - eslint-plugin-promise: 5.2.0(eslint@7.32.0) - dev: true - - /eslint-import-resolver-node@0.3.7: - resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} - dependencies: - debug: 3.2.7 - is-core-module: 2.11.0 - resolve: 1.22.1 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.7.4(@typescript-eslint/parser@4.33.0)(eslint-import-resolver-node@0.3.7)(eslint@7.32.0): - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) - debug: 3.2.7 - eslint: 7.32.0 - eslint-import-resolver-node: 0.3.7 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-es@3.0.1(eslint@7.32.0): - resolution: {integrity: sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==} - engines: {node: '>=8.10.0'} - peerDependencies: - eslint: '>=4.19.1' - dependencies: - eslint: 7.32.0 - eslint-utils: 2.1.0 - regexpp: 3.2.0 - dev: true - - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@4.33.0)(eslint@7.32.0): - resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 7.32.0 - eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@4.33.0)(eslint-import-resolver-node@0.3.7)(eslint@7.32.0) - has: 1.0.3 - is-core-module: 2.11.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.1.6 - resolve: 1.22.1 - semver: 6.3.0 - tsconfig-paths: 3.14.2 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - - /eslint-plugin-node@11.1.0(eslint@7.32.0): - resolution: {integrity: sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==} - engines: {node: '>=8.10.0'} - peerDependencies: - eslint: '>=5.16.0' - dependencies: - eslint: 7.32.0 - eslint-plugin-es: 3.0.1(eslint@7.32.0) - eslint-utils: 2.1.0 - ignore: 5.2.4 - minimatch: 3.1.2 - resolve: 1.22.1 - semver: 6.3.0 - dev: true - - /eslint-plugin-promise@5.2.0(eslint@7.32.0): - resolution: {integrity: sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: ^7.0.0 - dependencies: - eslint: 7.32.0 - dev: true - - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - dev: true - - /eslint-utils@2.1.0: - resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} - engines: {node: '>=6'} - dependencies: - eslint-visitor-keys: 1.3.0 - dev: true - - /eslint-utils@3.0.0(eslint@7.32.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 7.32.0 - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys@1.3.0: - resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} - engines: {node: '>=4'} - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true - - /eslint@7.32.0: - resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==} - engines: {node: ^10.12.0 || >=12.0.0} - hasBin: true - dependencies: - '@babel/code-frame': 7.12.11 - '@eslint/eslintrc': 0.4.3 - '@humanwhocodes/config-array': 0.5.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - enquirer: 2.3.6 - escape-string-regexp: 4.0.0 - eslint-scope: 5.1.1 - eslint-utils: 2.1.0 - eslint-visitor-keys: 2.1.0 - espree: 7.3.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 - glob-parent: 5.1.2 - globals: 13.20.0 - ignore: 4.0.6 - import-fresh: 3.3.0 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - js-yaml: 3.14.1 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.1 - progress: 2.0.3 - regexpp: 3.2.0 - semver: 7.3.8 - strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 - table: 6.8.1 - text-table: 0.2.0 - v8-compile-cache: 2.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /espree@7.3.1: - resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - acorn: 7.4.1 - acorn-jsx: 5.3.2(acorn@7.4.1) - eslint-visitor-keys: 1.3.0 - dev: true - - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true - - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true - - /estree-walker@1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - dev: true - - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true - - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - dev: true - - /expect@27.5.1: - resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - jest-get-type: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - dev: true - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-glob@3.2.12: - resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} - dependencies: - reusify: 1.0.4 + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - dependencies: - bser: 2.1.1 - dev: true + /deepmerge@4.3.0: + resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==} + engines: {node: '>=0.10.0'} - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + /define-properties@1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} dependencies: - flat-cache: 3.0.4 + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} dependencies: - to-regex-range: 5.0.1 + path-type: 4.0.0 dev: true - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 + esutils: 2.0.3 dev: true - /flat-cache@3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} dependencies: - flatted: 3.2.7 - rimraf: 3.0.2 - dev: true - - /flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + esutils: 2.0.3 dev: true - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - dependencies: - is-callable: 1.2.7 - dev: true + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - /form-data@3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} - engines: {node: '>= 6'} + /enquirer@2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + ansi-colors: 4.1.3 dev: true - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + /es-abstract@1.21.1: + resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} engines: {node: '>= 0.4'} dependencies: + available-typed-arrays: 1.0.5 call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.1 - functions-have-names: 1.2.3 - dev: true - - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - /get-func-name@2.0.0: - resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} - dev: true - - /get-intrinsic@1.2.0: - resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} - dependencies: + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 function-bind: 1.1.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.2.0 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 has-symbols: 1.0.3 + internal-slot: 1.0.5 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.10 + is-weakref: 1.0.2 + object-inspect: 1.12.3 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + safe-regex-test: 1.0.0 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.9 dev: true - /get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} + /es-module-lexer@0.9.3: + resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} dev: true - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + /es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 get-intrinsic: 1.2.0 + has: 1.0.3 + has-tostringtag: 1.0.0 dev: true - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + /es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: - is-glob: 4.0.3 + has: 1.0.3 dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 dev: true - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} + /esbuild@0.18.17: + resolution: {integrity: sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.17 + '@esbuild/android-arm64': 0.18.17 + '@esbuild/android-x64': 0.18.17 + '@esbuild/darwin-arm64': 0.18.17 + '@esbuild/darwin-x64': 0.18.17 + '@esbuild/freebsd-arm64': 0.18.17 + '@esbuild/freebsd-x64': 0.18.17 + '@esbuild/linux-arm': 0.18.17 + '@esbuild/linux-arm64': 0.18.17 + '@esbuild/linux-ia32': 0.18.17 + '@esbuild/linux-loong64': 0.18.17 + '@esbuild/linux-mips64el': 0.18.17 + '@esbuild/linux-ppc64': 0.18.17 + '@esbuild/linux-riscv64': 0.18.17 + '@esbuild/linux-s390x': 0.18.17 + '@esbuild/linux-x64': 0.18.17 + '@esbuild/netbsd-x64': 0.18.17 + '@esbuild/openbsd-x64': 0.18.17 + '@esbuild/sunos-x64': 0.18.17 + '@esbuild/win32-arm64': 0.18.17 + '@esbuild/win32-ia32': 0.18.17 + '@esbuild/win32-x64': 0.18.17 dev: true - /globals@13.20.0: - resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} dev: true - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-standard@16.0.3(eslint-plugin-import@2.27.5)(eslint-plugin-node@11.1.0)(eslint-plugin-promise@5.2.0)(eslint@7.32.0): + resolution: {integrity: sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==} + peerDependencies: + eslint: ^7.12.1 + eslint-plugin-import: ^2.22.1 + eslint-plugin-node: ^11.1.0 + eslint-plugin-promise: ^4.2.1 || ^5.0.0 dependencies: - define-properties: 1.2.0 + eslint: 7.32.0 + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@4.33.0)(eslint@7.32.0) + eslint-plugin-node: 11.1.0(eslint@7.32.0) + eslint-plugin-promise: 5.2.0(eslint@7.32.0) dev: true - /globalyzer@0.1.0: - resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + /eslint-import-resolver-node@0.3.7: + resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + dependencies: + debug: 3.2.7 + is-core-module: 2.11.0 + resolve: 1.22.1 + transitivePeerDependencies: + - supports-color dev: true - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + /eslint-module-utils@2.7.4(@typescript-eslint/parser@4.33.0)(eslint-import-resolver-node@0.3.7)(eslint@7.32.0): + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.2.12 - ignore: 5.2.4 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - - /globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) + debug: 3.2.7 + eslint: 7.32.0 + eslint-import-resolver-node: 0.3.7 + transitivePeerDependencies: + - supports-color dev: true - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + /eslint-plugin-es@3.0.1(eslint@7.32.0): + resolution: {integrity: sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=4.19.1' dependencies: - get-intrinsic: 1.2.0 - dev: true - - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - dev: true - - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + eslint: 7.32.0 + eslint-utils: 2.1.0 + regexpp: 3.2.0 dev: true - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@4.33.0)(eslint@7.32.0): + resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.1.6) + array-includes: 3.1.6 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 7.32.0 + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.7.4(@typescript-eslint/parser@4.33.0)(eslint-import-resolver-node@0.3.7)(eslint@7.32.0) + has: 1.0.3 + is-core-module: 2.11.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.6 + resolve: 1.22.1 + semver: 6.3.0 + tsconfig-paths: 3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color dev: true - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + /eslint-plugin-node@11.1.0(eslint@7.32.0): + resolution: {integrity: sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=5.16.0' dependencies: - get-intrinsic: 1.2.0 + eslint: 7.32.0 + eslint-plugin-es: 3.0.1(eslint@7.32.0) + eslint-utils: 2.1.0 + ignore: 5.2.4 + minimatch: 3.1.2 + resolve: 1.22.1 + semver: 6.3.0 dev: true - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} + /eslint-plugin-promise@5.2.0(eslint@7.32.0): + resolution: {integrity: sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: ^7.0.0 + dependencies: + eslint: 7.32.0 dev: true - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 dev: true - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} + /eslint-utils@2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} dependencies: - has-symbols: 1.0.3 + eslint-visitor-keys: 1.3.0 dev: true - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} + /eslint-utils@3.0.0(eslint@7.32.0): + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' dependencies: - function-bind: 1.1.1 + eslint: 7.32.0 + eslint-visitor-keys: 2.1.0 dev: true - /html-encoding-sniffer@2.0.1: - resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} - engines: {node: '>=10'} - dependencies: - whatwg-encoding: 1.0.5 + /eslint-visitor-keys@1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} dev: true - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + /eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} dev: true - /http-proxy-agent@4.0.1: - resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} - engines: {node: '>= 6'} + /eslint@7.32.0: + resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==} + engines: {node: ^10.12.0 || >=12.0.0} + hasBin: true dependencies: - '@tootallnate/once': 1.1.2 - agent-base: 6.0.2 + '@babel/code-frame': 7.12.11 + '@eslint/eslintrc': 0.4.3 + '@humanwhocodes/config-array': 0.5.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 debug: 4.3.4 + doctrine: 3.0.0 + enquirer: 2.3.6 + escape-string-regexp: 4.0.0 + eslint-scope: 5.1.1 + eslint-utils: 2.1.0 + eslint-visitor-keys: 2.1.0 + espree: 7.3.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 5.1.2 + globals: 13.20.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 3.14.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + progress: 2.0.3 + regexpp: 3.2.0 + semver: 7.3.8 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + table: 6.8.1 + text-table: 0.2.0 + v8-compile-cache: 2.3.0 transitivePeerDependencies: - supports-color dev: true - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} + /espree@7.3.1: + resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} + engines: {node: ^10.12.0 || >=12.0.0} dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color + acorn: 7.4.1 + acorn-jsx: 5.3.2(acorn@7.4.1) + eslint-visitor-keys: 1.3.0 dev: true - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true dev: true - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} dependencies: - safer-buffer: 2.1.2 + estraverse: 5.3.0 dev: true - /ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 dev: true - /ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} dev: true - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} dev: true - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 + /estree-walker@1.0.1: + resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} - engines: {node: '>= 0.4'} + /fast-glob@3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} dependencies: - get-intrinsic: 1.2.0 - has: 1.0.3 - side-channel: 1.0.4 + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 dev: true - /is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.0 - is-typed-array: 1.1.10 + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: - has-bigints: 1.0.2 + reusify: 1.0.4 dev: true - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 + flat-cache: 3.0.4 dev: true - /is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} dependencies: - builtin-modules: 3.3.0 - dev: true - - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} + to-regex-range: 5.0.1 dev: true - /is-core-module@2.11.0: - resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + /flat-cache@3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} dependencies: - has: 1.0.3 + flatted: 3.2.7 + rimraf: 3.0.2 dev: true - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 + /flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 dev: true - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true dev: true + optional: true - /is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + /function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.21.1 + functions-have-names: 1.2.3 dev: true - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 + /functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true - /is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + /get-intrinsic@1.2.0: + resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 dev: true - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - has-tostringtag: 1.0.0 + get-intrinsic: 1.2.0 dev: true - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} dependencies: - call-bind: 1.0.2 + is-glob: 4.0.3 dev: true - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 dev: true - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} + /globals@13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + engines: {node: '>=8'} dependencies: - has-tostringtag: 1.0.0 + type-fest: 0.20.2 dev: true - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} dependencies: - has-symbols: 1.0.3 + define-properties: 1.2.0 dev: true - /is-typed-array@1.1.10: - resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} - engines: {node: '>= 0.4'} + /globalyzer@0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 dev: true - /is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + /globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - call-bind: 1.0.2 + get-intrinsic: 1.2.0 dev: true - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true - /istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} - engines: {node: '>=8'} + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} dev: true - /istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dependencies: - '@babel/core': 7.21.0 - '@babel/parser': 7.21.2 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color dev: true - /istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} + /has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 3.1.0 - supports-color: 7.2.0 + get-intrinsic: 1.2.0 dev: true - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - dependencies: - debug: 4.3.4 - istanbul-lib-coverage: 3.2.0 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} dev: true - /istanbul-reports@3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} - engines: {node: '>=8'} - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.0 + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} dev: true - /jest-changed-files@27.5.1: - resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} dependencies: - '@jest/types': 27.5.1 - execa: 5.1.1 - throat: 6.0.2 + has-symbols: 1.0.3 dev: true - /jest-circus@27.5.1: - resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} dependencies: - '@jest/environment': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - chalk: 4.1.2 - co: 4.6.0 - dedent: 0.7.0 - expect: 27.5.1 - is-generator-fn: 2.1.0 - jest-each: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - pretty-format: 27.5.1 - slash: 3.0.0 - stack-utils: 2.0.6 - throat: 6.0.2 - transitivePeerDependencies: - - supports-color + function-bind: 1.1.1 dev: true - /jest-cli@27.5.1: - resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.10 - import-local: 3.1.0 - jest-config: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - prompts: 2.4.2 - yargs: 16.2.0 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate + /ignore@4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} + engines: {node: '>= 4'} dev: true - /jest-config@27.5.1: - resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - peerDependencies: - ts-node: '>=9.0.0' - peerDependenciesMeta: - ts-node: - optional: true - dependencies: - '@babel/core': 7.21.0 - '@jest/test-sequencer': 27.5.1 - '@jest/types': 27.5.1 - babel-jest: 27.5.1(@babel/core@7.21.0) - chalk: 4.1.2 - ci-info: 3.8.0 - deepmerge: 4.3.0 - glob: 7.2.3 - graceful-fs: 4.2.10 - jest-circus: 27.5.1 - jest-environment-jsdom: 27.5.1 - jest-environment-node: 27.5.1 - jest-get-type: 27.5.1 - jest-jasmine2: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-runner: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 27.5.1 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - utf-8-validate + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 dev: true - /jest-date-mock@1.0.8: - resolution: {integrity: sha512-0Lyp+z9xvuNmLbK+5N6FOhSiBeux05Lp5bbveFBmYo40Aggl2wwxFoIrZ+rOWC8nDNcLeBoDd2miQdEDSf3iQw==} + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} dev: true - /jest-diff@26.6.2: - resolution: {integrity: sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==} - engines: {node: '>= 10.14.2'} + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: - chalk: 4.1.2 - diff-sequences: 26.6.2 - jest-get-type: 26.3.0 - pretty-format: 26.6.2 + once: 1.4.0 + wrappy: 1.0.2 dev: true - /jest-diff@27.5.1: - resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 27.5.1 - jest-get-type: 27.5.1 - pretty-format: 27.5.1 + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true - /jest-docblock@27.5.1: - resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + engines: {node: '>= 0.4'} dependencies: - detect-newline: 3.1.0 + get-intrinsic: 1.2.0 + has: 1.0.3 + side-channel: 1.0.4 dev: true - /jest-each@27.5.1: - resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: - '@jest/types': 27.5.1 - chalk: 4.1.2 - jest-get-type: 27.5.1 - jest-util: 27.5.1 - pretty-format: 27.5.1 + call-bind: 1.0.2 + get-intrinsic: 1.2.0 + is-typed-array: 1.1.10 dev: true - /jest-environment-jsdom@27.5.1: - resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: - '@jest/environment': 27.5.1 - '@jest/fake-timers': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - jest-mock: 27.5.1 - jest-util: 27.5.1 - jsdom: 16.7.0 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - utf-8-validate + has-bigints: 1.0.2 dev: true - /jest-environment-node@27.5.1: - resolution: {integrity: sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} dependencies: - '@jest/environment': 27.5.1 - '@jest/fake-timers': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - jest-mock: 27.5.1 - jest-util: 27.5.1 + call-bind: 1.0.2 + has-tostringtag: 1.0.0 dev: true - /jest-get-type@26.3.0: - resolution: {integrity: sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==} - engines: {node: '>= 10.14.2'} + /is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 dev: true - /jest-get-type@27.5.1: - resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} dev: true - /jest-haste-map@27.5.1: - resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-core-module@2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} dependencies: - '@jest/types': 27.5.1 - '@types/graceful-fs': 4.1.6 - '@types/node': 18.14.5 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.10 - jest-regex-util: 27.5.1 - jest-serializer: 27.5.1 - jest-util: 27.5.1 - jest-worker: 27.5.1 - micromatch: 4.0.5 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.2 + has: 1.0.3 dev: true - /jest-jasmine2@27.5.1: - resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} dependencies: - '@jest/environment': 27.5.1 - '@jest/source-map': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - chalk: 4.1.2 - co: 4.6.0 - expect: 27.5.1 - is-generator-fn: 2.1.0 - jest-each: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - pretty-format: 27.5.1 - throat: 6.0.2 - transitivePeerDependencies: - - supports-color + has-tostringtag: 1.0.0 dev: true - /jest-leak-detector@27.5.1: - resolution: {integrity: sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - jest-get-type: 27.5.1 - pretty-format: 27.5.1 + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} dev: true - /jest-matcher-utils@27.5.1: - resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 27.5.1 - jest-get-type: 27.5.1 - pretty-format: 27.5.1 - dev: true + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} - /jest-message-util@27.5.1: - resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@jest/types': 27.5.1 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.10 - micromatch: 4.0.5 - pretty-format: 27.5.1 - slash: 3.0.0 - stack-utils: 2.0.6 + is-extglob: 2.1.1 dev: true - /jest-mock@27.5.1: - resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - '@types/node': 18.14.5 + /is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: true - /jest-pnp-resolver@1.2.3(jest-resolve@27.5.1): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: - jest-resolve: 27.5.1 + /is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} dev: true - /jest-regex-util@27.5.1: - resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 dev: true - /jest-resolve-dependencies@27.5.1: - resolution: {integrity: sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/types': 27.5.1 - jest-regex-util: 27.5.1 - jest-snapshot: 27.5.1 - transitivePeerDependencies: - - supports-color + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} dev: true - /jest-resolve@27.5.1: - resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} dependencies: - '@jest/types': 27.5.1 - chalk: 4.1.2 - graceful-fs: 4.2.10 - jest-haste-map: 27.5.1 - jest-pnp-resolver: 1.2.3(jest-resolve@27.5.1) - jest-util: 27.5.1 - jest-validate: 27.5.1 - resolve: 1.22.1 - resolve.exports: 1.1.1 - slash: 3.0.0 + call-bind: 1.0.2 + has-tostringtag: 1.0.0 dev: true - /jest-runner@27.5.1: - resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: - '@jest/console': 27.5.1 - '@jest/environment': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - chalk: 4.1.2 - emittery: 0.8.1 - graceful-fs: 4.2.10 - jest-docblock: 27.5.1 - jest-environment-jsdom: 27.5.1 - jest-environment-node: 27.5.1 - jest-haste-map: 27.5.1 - jest-leak-detector: 27.5.1 - jest-message-util: 27.5.1 - jest-resolve: 27.5.1 - jest-runtime: 27.5.1 - jest-util: 27.5.1 - jest-worker: 27.5.1 - source-map-support: 0.5.21 - throat: 6.0.2 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - utf-8-validate + call-bind: 1.0.2 dev: true - /jest-runtime@27.5.1: - resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} dependencies: - '@jest/environment': 27.5.1 - '@jest/fake-timers': 27.5.1 - '@jest/globals': 27.5.1 - '@jest/source-map': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - chalk: 4.1.2 - cjs-module-lexer: 1.2.2 - collect-v8-coverage: 1.0.1 - execa: 5.1.1 - glob: 7.2.3 - graceful-fs: 4.2.10 - jest-haste-map: 27.5.1 - jest-message-util: 27.5.1 - jest-mock: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - slash: 3.0.0 - strip-bom: 4.0.0 - transitivePeerDependencies: - - supports-color + has-tostringtag: 1.0.0 dev: true - /jest-serializer@27.5.1: - resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} dependencies: - '@types/node': 18.14.5 - graceful-fs: 4.2.10 - dev: true - - /jest-snapshot@27.5.1: - resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@babel/core': 7.21.0 - '@babel/generator': 7.21.1 - '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.21.0) - '@babel/traverse': 7.21.2 - '@babel/types': 7.21.2 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 - '@types/babel__traverse': 7.18.3 - '@types/prettier': 2.7.2 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.21.0) - chalk: 4.1.2 - expect: 27.5.1 - graceful-fs: 4.2.10 - jest-diff: 27.5.1 - jest-get-type: 27.5.1 - jest-haste-map: 27.5.1 - jest-matcher-utils: 27.5.1 - jest-message-util: 27.5.1 - jest-util: 27.5.1 - natural-compare: 1.4.0 - pretty-format: 27.5.1 - semver: 7.3.8 - transitivePeerDependencies: - - supports-color + has-symbols: 1.0.3 dev: true - /jest-util@27.5.1: - resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-typed-array@1.1.10: + resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} + engines: {node: '>= 0.4'} dependencies: - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - chalk: 4.1.2 - ci-info: 3.8.0 - graceful-fs: 4.2.10 - picomatch: 2.3.1 + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 dev: true - /jest-validate@27.5.1: - resolution: {integrity: sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - '@jest/types': 27.5.1 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 27.5.1 - leven: 3.1.0 - pretty-format: 27.5.1 + call-bind: 1.0.2 dev: true - /jest-watcher@27.5.1: - resolution: {integrity: sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - '@types/node': 18.14.5 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - jest-util: 27.5.1 - string-length: 4.0.2 + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true /jest-worker@26.6.2: @@ -4326,36 +1732,6 @@ packages: supports-color: 7.2.0 dev: true - /jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - dependencies: - '@types/node': 18.14.5 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - - /jest@27.5.1: - resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 27.5.1 - import-local: 3.1.0 - jest-cli: 27.5.1 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate - dev: true - /joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -4380,63 +1756,6 @@ packages: argparse: 2.0.1 dev: true - /jsdom@16.7.0: - resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==} - engines: {node: '>=10'} - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - dependencies: - abab: 2.0.6 - acorn: 8.8.2 - acorn-globals: 6.0.0 - cssom: 0.4.4 - cssstyle: 2.3.0 - data-urls: 2.0.0 - decimal.js: 10.4.3 - domexception: 2.0.1 - escodegen: 2.0.0 - form-data: 3.0.1 - html-encoding-sniffer: 2.0.1 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.2 - parse5: 6.0.1 - saxes: 5.0.1 - symbol-tree: 3.2.4 - tough-cookie: 4.1.2 - w3c-hr-time: 1.0.2 - w3c-xmlserializer: 2.0.0 - webidl-conversions: 6.1.0 - whatwg-encoding: 1.0.5 - whatwg-mimetype: 2.3.0 - whatwg-url: 8.7.0 - ws: 7.5.9 - xml-name-validator: 3.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /jsesc@0.5.0: - resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} - hasBin: true - dev: true - - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true - /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true @@ -4456,34 +1775,10 @@ packages: minimist: 1.2.8 dev: true - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} dev: true - /kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true - - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true - - /levn@0.3.0: - resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - dev: true - /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -4492,21 +1787,6 @@ packages: type-check: 0.4.0 dev: true - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true - - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - dev: true - - /lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - dev: true - /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -4519,18 +1799,6 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - /loupe@2.3.6: - resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} - dependencies: - get-func-name: 2.0.0 - dev: true - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -4544,19 +1812,6 @@ packages: sourcemap-codec: 1.4.8 dev: true - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - dependencies: - semver: 6.3.0 - dev: true - - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - dependencies: - tmpl: 1.0.5 - dev: true - /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true @@ -4574,23 +1829,6 @@ packages: picomatch: 2.3.1 dev: true - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: true - - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: true - - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true - /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -4612,36 +1850,12 @@ packages: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true - - /node-releases@2.0.10: - resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} - dev: true - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /nwsapi@2.2.2: - resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true /object-inspect@1.12.3: @@ -4678,25 +1892,6 @@ packages: wrappy: 1.0.2 dev: true - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - dev: true - - /optionator@0.8.3: - resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} - engines: {node: '>= 0.8.0'} - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.3.0 - prelude-ls: 1.1.2 - type-check: 0.3.2 - word-wrap: 1.2.3 - dev: true - /optionator@0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} engines: {node: '>= 0.8.0'} @@ -4709,25 +1904,6 @@ packages: word-wrap: 1.2.3 dev: true - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - dependencies: - p-try: 2.2.0 - dev: true - - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - dependencies: - p-limit: 2.3.0 - dev: true - - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - dev: true - /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4735,25 +1911,6 @@ packages: callsites: 3.1.0 dev: true - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.18.6 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - dev: true - - /parse5@6.0.1: - resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - dev: true - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true - /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -4773,86 +1930,26 @@ packages: engines: {node: '>=8'} dev: true - /pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - dev: true - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true - /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} dev: true - /pirates@4.0.5: - resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} - engines: {node: '>= 6'} - dev: true - - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - dev: true - - /prelude-ls@1.1.2: - resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} - engines: {node: '>= 0.8.0'} - dev: true - /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} dev: true - /pretty-format@26.6.2: - resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} - engines: {node: '>= 10'} - dependencies: - '@jest/types': 26.6.2 - ansi-regex: 5.0.1 - ansi-styles: 4.3.0 - react-is: 17.0.2 - dev: true - - /pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - dev: true - /progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} dev: true - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - dev: true - - /psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - dev: true - /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} dev: true - /querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - dev: true - /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -4863,31 +1960,6 @@ packages: safe-buffer: 5.2.1 dev: true - /react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - dev: true - - /regenerate-unicode-properties@10.1.0: - resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} - engines: {node: '>=4'} - dependencies: - regenerate: 1.4.2 - dev: true - - /regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - dev: true - - /regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - dev: true - - /regenerator-transform@0.15.1: - resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} - dependencies: - '@babel/runtime': 7.21.0 - dev: true - /regexp.prototype.flags@1.4.3: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} engines: {node: '>= 0.4'} @@ -4902,25 +1974,6 @@ packages: engines: {node: '>=8'} dev: true - /regexpu-core@5.3.1: - resolution: {integrity: sha512-nCOzW2V/X15XpLsK2rlgdwrysrBq+AauCn+omItIz4R1pIcmeot5zvjdmOBRLzEH/CkC6IxMJVmxDe3QcMuNVQ==} - engines: {node: '>=4'} - dependencies: - '@babel/regjsgen': 0.8.0 - regenerate: 1.4.2 - regenerate-unicode-properties: 10.1.0 - regjsparser: 0.9.1 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.1.0 - dev: true - - /regjsparser@0.9.1: - resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} - hasBin: true - dependencies: - jsesc: 0.5.0 - dev: true - /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4930,32 +1983,11 @@ packages: engines: {node: '>=0.10.0'} dev: true - /requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - dev: true - - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - dependencies: - resolve-from: 5.0.0 - dev: true - /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} dev: true - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true - - /resolve.exports@1.1.1: - resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} - engines: {node: '>=10'} - dev: true - /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true @@ -5054,17 +2086,6 @@ packages: is-regex: 1.1.4 dev: true - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true - - /saxes@5.0.1: - resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} - engines: {node: '>=10'} - dependencies: - xmlchars: 2.2.0 - dev: true - /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true @@ -5108,14 +2129,6 @@ packages: object-inspect: 1.12.3 dev: true - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true - - /sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true - /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -5142,11 +2155,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} - dev: true - /sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead @@ -5160,21 +2168,6 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true - /stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - dev: true - /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -5210,16 +2203,6 @@ packages: engines: {node: '>=4'} dev: true - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true - - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -5246,23 +2229,11 @@ packages: has-flag: 4.0.0 dev: true - /supports-hyperlinks@2.3.0: - resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} dev: true - /symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - dev: true - /table@6.8.1: resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} engines: {node: '>=10.0.0'} @@ -5274,14 +2245,6 @@ packages: strip-ansi: 6.0.1 dev: true - /terminal-link@2.1.1: - resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} - engines: {node: '>=8'} - dependencies: - ansi-escapes: 4.3.2 - supports-hyperlinks: 2.3.0 - dev: true - /terser@5.16.5: resolution: {integrity: sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==} engines: {node: '>=10'} @@ -5293,23 +2256,10 @@ packages: source-map-support: 0.5.21 dev: true - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true - /throat@6.0.2: - resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} - dev: true - /tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} dependencies: @@ -5317,15 +2267,6 @@ packages: globrex: 0.1.2 dev: true - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true - - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true - /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -5333,23 +2274,6 @@ packages: is-number: 7.0.0 dev: true - /tough-cookie@4.1.2: - resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} - engines: {node: '>=6'} - dependencies: - psl: 1.9.0 - punycode: 2.3.0 - universalify: 0.2.0 - url-parse: 1.5.10 - dev: true - - /tr46@2.1.0: - resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==} - engines: {node: '>=8'} - dependencies: - punycode: 2.3.0 - dev: true - /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -5382,13 +2306,6 @@ packages: typescript: 5.1.6 dev: true - /type-check@0.3.2: - resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.1.2 - dev: true - /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -5396,21 +2313,11 @@ packages: prelude-ls: 1.2.1 dev: true - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true - /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} dev: true - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true - /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: @@ -5419,12 +2326,6 @@ packages: is-typed-array: 1.1.10 dev: true - /typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - dependencies: - is-typedarray: 1.0.0 - dev: true - /typescript@5.1.6: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} @@ -5440,120 +2341,16 @@ packages: which-boxed-primitive: 1.0.2 dev: true - /unicode-canonical-property-names-ecmascript@2.0.0: - resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} - engines: {node: '>=4'} - dev: true - - /unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.0 - unicode-property-aliases-ecmascript: 2.1.0 - dev: true - - /unicode-match-property-value-ecmascript@2.1.0: - resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} - engines: {node: '>=4'} - dev: true - - /unicode-property-aliases-ecmascript@2.1.0: - resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} - engines: {node: '>=4'} - dev: true - - /universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - dev: true - - /update-browserslist-db@1.0.10(browserslist@4.21.5): - resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.21.5 - escalade: 3.1.1 - picocolors: 1.0.0 - dev: true - /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 dev: true - /url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - dev: true - /v8-compile-cache@2.3.0: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true - /v8-to-istanbul@8.1.1: - resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==} - engines: {node: '>=10.12.0'} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.9.0 - source-map: 0.7.4 - dev: true - - /w3c-hr-time@1.0.2: - resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} - deprecated: Use your platform's native performance.now() and performance.timeOrigin. - dependencies: - browser-process-hrtime: 1.0.0 - dev: true - - /w3c-xmlserializer@2.0.0: - resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==} - engines: {node: '>=10'} - dependencies: - xml-name-validator: 3.0.0 - dev: true - - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - dependencies: - makeerror: 1.0.12 - dev: true - - /webidl-conversions@5.0.0: - resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} - engines: {node: '>=8'} - dev: true - - /webidl-conversions@6.1.0: - resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==} - engines: {node: '>=10.4'} - dev: true - - /whatwg-encoding@1.0.5: - resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} - dependencies: - iconv-lite: 0.4.24 - dev: true - - /whatwg-mimetype@2.3.0: - resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} - dev: true - - /whatwg-url@8.7.0: - resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==} - engines: {node: '>=10'} - dependencies: - lodash: 4.17.21 - tr46: 2.1.0 - webidl-conversions: 6.1.0 - dev: true - /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -5601,70 +2398,18 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /write-file-atomic@3.0.3: - resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - dependencies: - imurmurhash: 0.1.4 - is-typedarray: 1.0.0 - signal-exit: 3.0.7 - typedarray-to-buffer: 3.1.5 - dev: true - - /ws@7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true - - /xml-name-validator@3.0.0: - resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} - dev: true - - /xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - dev: true - /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true - /yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - dev: true - /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - dev: true - /yargs@17.7.1: resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} engines: {node: '>=12'} From cea6befccab4a5b66c8d4ad8d406e838b5dd6d3d Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 11:03:50 -0400 Subject: [PATCH 214/805] thin out scripts --- .../scripts/config/pkgBundle.cjs | 5 - .../scripts/lib/pkgAnalyze.cjs | 120 ----------------- .../scripts/lib/pkgBundle.cjs | 123 ------------------ .../scripts/lib/pkgTypes.cjs | 94 ------------- .../temporal-polyfill/scripts/pkgClean.cjs | 28 ---- .../scripts/{pkgSize.cjs => size.cjs} | 0 .../{misc => scripts/test-config}/LICENSE.txt | 0 .../{misc => scripts/test-config}/NOTES.txt | 0 .../expected-failures-before-node16.txt | 0 .../expected-failures-before-node18.txt | 0 .../test-config}/expected-failures-es5.txt | 0 .../test-config}/expected-failures-opt.txt | 0 .../expected-failures-todo-migrated-code.txt | 0 .../test-config}/expected-failures.txt | 0 .../scripts/{runtest262.js => test.js} | 0 .../{scripts/config => }/terser.json | 0 16 files changed, 370 deletions(-) delete mode 100644 packages/temporal-polyfill/scripts/config/pkgBundle.cjs delete mode 100644 packages/temporal-polyfill/scripts/lib/pkgAnalyze.cjs delete mode 100644 packages/temporal-polyfill/scripts/lib/pkgBundle.cjs delete mode 100644 packages/temporal-polyfill/scripts/lib/pkgTypes.cjs delete mode 100644 packages/temporal-polyfill/scripts/pkgClean.cjs rename packages/temporal-polyfill/scripts/{pkgSize.cjs => size.cjs} (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/LICENSE.txt (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/NOTES.txt (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/expected-failures-before-node16.txt (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/expected-failures-before-node18.txt (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/expected-failures-es5.txt (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/expected-failures-opt.txt (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/expected-failures-todo-migrated-code.txt (100%) rename packages/temporal-polyfill/{misc => scripts/test-config}/expected-failures.txt (100%) rename packages/temporal-polyfill/scripts/{runtest262.js => test.js} (100%) rename packages/temporal-polyfill/{scripts/config => }/terser.json (100%) diff --git a/packages/temporal-polyfill/scripts/config/pkgBundle.cjs b/packages/temporal-polyfill/scripts/config/pkgBundle.cjs deleted file mode 100644 index 529f3eb8..00000000 --- a/packages/temporal-polyfill/scripts/config/pkgBundle.cjs +++ /dev/null @@ -1,5 +0,0 @@ -const { buildPkgBundleConfigs } = require('../lib/pkgBundle.cjs') - -module.exports = async(commandLineArgs) => { - return buildPkgBundleConfigs(process.cwd(), commandLineArgs) -} diff --git a/packages/temporal-polyfill/scripts/lib/pkgAnalyze.cjs b/packages/temporal-polyfill/scripts/lib/pkgAnalyze.cjs deleted file mode 100644 index 8b6b80a9..00000000 --- a/packages/temporal-polyfill/scripts/lib/pkgAnalyze.cjs +++ /dev/null @@ -1,120 +0,0 @@ -const path = require('path') -const fs = require('fs/promises') -const minimatch = require('minimatch') - -module.exports = { - getPkgConfig, - analyzePkgConfig, -} - -async function getPkgConfig(dir) { - const rawData = await fs.readFile(path.join(dir, 'package.json')) - return JSON.parse(rawData) -} - -function analyzePkgConfig(pkgConfig) { - const pkgName = pkgConfig.name - - if (pkgConfig.type !== 'module') { - throw new Error(`[${pkgName}] Must specify "type":"module"`) - } - ['main', 'module', 'types'].forEach((prop) => { - if (!pkgConfig[prop]) { - throw new Error(`[${pkgName}] Must specify "${prop}"`) - } - }) - - const exportsHash = normalizeExportsHash(pkgConfig.exports || {}) - const defaultExport = exportsHash['.'] - - if (typeof defaultExport !== 'object' || !defaultExport) { - throw new Error(`[${pkgName}] Must specify default "." export`) - } - if (defaultExport.import !== pkgConfig.module) { - throw new Error(`[${pkgName}] default export must be consistent with pkg.module`) - } - if (defaultExport.require !== pkgConfig.main) { - throw new Error(`[${pkgName}] default export must be consistent with pkg.main`) - } - - const sideEffectsArray = Array.isArray(pkgConfig.sideEffects) ? pkgConfig.sideEffects : [] - const entryPoints = [] - const entryPointTypes = [] - const globalEntryPoints = [] - - for (const exportId in exportsHash) { - const exportPaths = exportsHash[exportId] - const importPath = exportPaths.import || '' - const requirePath = exportPaths.require || '' - const importPathNoExt = importPath.replace(/\.mjs$/, '') - const requirePathNoExt = requirePath.replace(/\.cjs$/, '') - - if (importPathNoExt !== requirePathNoExt) { - throw new Error(`[${pkgName}] Inconsistent "import" and "require"`) - } - - const match = importPathNoExt.match(/\.\/dist\/(.*)$/) - if (match) { - const entryPoint = './src/' + match[1] + '.ts' - entryPoints.push(entryPoint) - entryPointTypes.push(importPathNoExt + '.d.ts') - - for (const sideEffectsGlob of sideEffectsArray) { - if (minimatch(importPath, sideEffectsGlob)) { - globalEntryPoints.push(entryPoint) - break - } - } - } - } - - // is there building? check the package.json's "files" array - if (entryPoints.length) { - const fileGlobs = pkgConfig.files || [] - const hasTypesHackFiles = fileGlobs.includes('/*.d.ts') - const hasMultExports = Object.keys(exportsHash).length > 1 - - ;['/dist', '/src'].forEach((glob) => { - if (!fileGlobs.includes(glob)) { - throw new Error(`Must include "${glob}" in "files" array`) - } - }) - - if (hasTypesHackFiles !== hasMultExports) { - throw new Error( - (hasMultExports ? 'Must have' : 'Must NOT have') + - '"/*.d.ts" included in the "files" array', - ) - } - } - - return { - entryPoints, // in src - entryPointTypes, // in dist - globalEntryPoints, - dependencyNames: Object.keys(pkgConfig.dependencies || {}), - } -} - -/* -The package.json "exports" hash can take two forms: -1. { require, import } -2. { ".": { require, import } } -Normalize to the 2nd -*/ -function normalizeExportsHash(obj) { - let hasPaths = false - - for (const key in obj) { - if (key.match(/^\./)) { - hasPaths = true - break - } - } - - if (hasPaths) { - return obj - } - - return { '.': obj } -} diff --git a/packages/temporal-polyfill/scripts/lib/pkgBundle.cjs b/packages/temporal-polyfill/scripts/lib/pkgBundle.cjs deleted file mode 100644 index d7c916b1..00000000 --- a/packages/temporal-polyfill/scripts/lib/pkgBundle.cjs +++ /dev/null @@ -1,123 +0,0 @@ -const path = require('path') -const fs = require('fs/promises') -const { analyzePkgConfig, getPkgConfig } = require('../lib/pkgAnalyze.cjs') -const resolve = require('@rollup/plugin-node-resolve').default -const esbuild = require('rollup-plugin-esbuild').default -const { terser } = require('rollup-plugin-terser') -const dts = require('rollup-plugin-dts').default -const { createTypeInputHash, typePreparing } = require('../lib/pkgTypes.cjs') -const terserConfig = require('../config/terser.json') - -const noMin = Boolean(process.env.NO_MIN) - -module.exports = { - buildPkgBundleConfigs, -} - -const watchOptions = { - buildDelay: 100, - clearScreen: false, // don't clear tsc's concurrent output (see preserveWatchOutput) -} - -async function buildPkgBundleConfigs(pkgDir, commandLineArgs) { - const { watch } = commandLineArgs - const pkgConfig = await getPkgConfig(pkgDir) - const pkgAnalysis = analyzePkgConfig(pkgConfig) - const { entryPoints, entryPointTypes, globalEntryPoints, dependencyNames } = pkgAnalysis - - const configs = globalEntryPoints.map((globalEntryPoint) => ({ - input: path.join(pkgDir, globalEntryPoint.replace('/src/', '/dist/.tsc/').replace(/\.ts$/, '.js')), - external: dependencyNames, - output: buildGlobalOutputConfig(pkgDir), - watch: watchOptions, - plugins: buildPlugins(watch), - })) - - /* - if (entryPoints.length) { - configs.push({ - input: entryPoints.map((f) => path.join(pkgDir, f)), - external: dependencyNames, - output: [ - buildOutputConfig(pkgDir, 'es', '.mjs', true), - buildOutputConfig(pkgDir, 'cjs', '.cjs', true), - ], - watch: watchOptions, - plugins: buildPlugins(watch), - }) - } - */ - - /* - if (entryPointTypes.length && !watch) { - configs.push({ - input: createTypeInputHash(entryPointTypes.map((f) => path.join(pkgDir, f))), - external: dependencyNames, - output: buildOutputConfig(pkgDir, 'es', '.d.ts', false), - plugins: [dts(), typePreparing(pkgDir)], - }) - } - */ - - return configs -} - -// Output config -// ------------------------------------------------------------------------------------------------- - -function buildOutputConfig(pkgDir, format, extension, sourcemap) { - return { - format, - dir: path.join(pkgDir, 'dist'), - entryFileNames: '[name]' + extension, - chunkFileNames: 'common-[hash]' + extension, - sourcemap, - sourcemapExcludeSources: true, - } -} - -function buildGlobalOutputConfig(pkgDir) { - return { - format: 'iife', - dir: path.join(pkgDir, 'dist'), - // no code splitting - sourcemap: true, - sourcemapExcludeSources: true, - } -} - -// Rollup plugins -// ------------------------------------------------------------------------------------------------- - -function buildPlugins(watch) { - return [ - resolve({ - extensions: ['.js', /* '.ts' */], - }), - // esbuild({ - // // TODO: this is a bad technique because it has the potential to inject multiple - // // helper-functions in the same output. Luckily it doesn't for this target. - // target: 'es2018', - // }), - // tsFileOverriding('.build.ts'), - !watch && !noMin && terser(terserConfig), - ] -} - -// a Rollup plugin -function tsFileOverriding(forcedExtension) { - return { - async load(id) { - const match = id.match(/^(.*)\.ts$/) - if (match) { - const altPath = match[1] + forcedExtension - try { - const contents = await fs.readFile(altPath, 'utf8') - this.addWatchFile(altPath) // watch the alt file - return contents - } catch (err) {} - } - return null - }, - } -} diff --git a/packages/temporal-polyfill/scripts/lib/pkgTypes.cjs b/packages/temporal-polyfill/scripts/lib/pkgTypes.cjs deleted file mode 100644 index d111c8ff..00000000 --- a/packages/temporal-polyfill/scripts/lib/pkgTypes.cjs +++ /dev/null @@ -1,94 +0,0 @@ -const path = require('path') -const fs = require('fs/promises') - -module.exports = { - typePreparing, - cleanTypeScriptCache, - cleanRootTypesHack, - createTypeInputHash, -} - -// a Rollup plugin -function typePreparing(pkgDir) { - return { - // before writing .d.ts files - generateBundle: async(options, bundle) => { - const rootPaths = Object.keys(bundle) - - return Promise.all([ - cleanDistTypes(pkgDir), - cleanRootTypesHack(pkgDir).then(() => { - writeRootTypesHack(pkgDir, rootPaths) - }), - ]) - }, - } -} - -async function cleanDistTypes(pkgDir) { - await cleanTypeScriptCache(pkgDir) // invalid now that we're deleting .d.ts files - - const distDir = path.join(pkgDir, 'dist') - const filenames = await fs.readdir(distDir) - - for (const filename of filenames) { - const filePath = path.join(distDir, filename) - const stat = await fs.lstat(filePath) - - if ( - stat.isDirectory() || - filename.match(/\.d\.ts$/) || - filename.match(/\.d\.ts\.map$/) - ) { - await fs.rm(filePath, { recursive: true, force: true }) - } - } -} - -async function cleanTypeScriptCache(pkgDir) { - await fs.rm( - path.join(pkgDir, 'tsconfig.tsbuildinfo'), - { recursive: true, force: true }, - ) -} - -/* -HACK to overcome export maps not working in TypeScript -https://github.com/microsoft/TypeScript/issues/33079 -Writes .d.ts files in root of package, referencing ./dist/* -*/ -async function writeRootTypesHack(pkgDir, rootPaths) { - for (const rootPath of rootPaths) { - const moduleName = rootPath.replace(/\.d\.ts$/, '') - if (moduleName !== 'index') { // no need. always specified in package.json "types" - await fs.writeFile( - path.join(pkgDir, rootPath), - `export * from './dist/${moduleName}'\n`, // does not support default exports - ) - } - } -} - -async function cleanRootTypesHack(pkgDir) { - const filenames = await fs.readdir(pkgDir) - - for (const filename of filenames) { - const filePath = path.join(pkgDir, filename) - - if (filename.match(/\.d\.ts$/)) { - await fs.rm(filePath, { recursive: true, force: true }) - } - } -} - -/* -Rollup gets confused with deriving module names from filename extensions for .d.ts. -Make a hash the explicitly names modules -*/ -function createTypeInputHash(inputArray) { - return inputArray.reduce((accum, inputPath) => { - const moduleName = path.basename(inputPath).replace(/\.d\.ts$/, '') - accum[moduleName] = inputPath - return accum - }, {}) -} diff --git a/packages/temporal-polyfill/scripts/pkgClean.cjs b/packages/temporal-polyfill/scripts/pkgClean.cjs deleted file mode 100644 index 771062fa..00000000 --- a/packages/temporal-polyfill/scripts/pkgClean.cjs +++ /dev/null @@ -1,28 +0,0 @@ -const path = require('path') -const fs = require('fs/promises') -const { getPkgConfig, analyzePkgConfig } = require('./lib/pkgAnalyze.cjs') -const { cleanTypeScriptCache, cleanRootTypesHack } = require('./lib/pkgTypes.cjs') - -async function clean() { - const pkgDir = process.cwd() - const pkgConfig = await getPkgConfig(pkgDir) - const pkgAnalysis = analyzePkgConfig(pkgConfig) - const promises = [] - - promises.push( - fs.rm( - path.join(pkgDir, 'dist'), - { recursive: true, force: true }, - ), - ) - - // has generated types? - if (pkgAnalysis.entryPointTypes.length) { - promises.push(cleanTypeScriptCache(pkgDir)) - promises.push(cleanRootTypesHack(pkgDir)) - } - - return Promise.all(promises) -} - -clean() diff --git a/packages/temporal-polyfill/scripts/pkgSize.cjs b/packages/temporal-polyfill/scripts/size.cjs similarity index 100% rename from packages/temporal-polyfill/scripts/pkgSize.cjs rename to packages/temporal-polyfill/scripts/size.cjs diff --git a/packages/temporal-polyfill/misc/LICENSE.txt b/packages/temporal-polyfill/scripts/test-config/LICENSE.txt similarity index 100% rename from packages/temporal-polyfill/misc/LICENSE.txt rename to packages/temporal-polyfill/scripts/test-config/LICENSE.txt diff --git a/packages/temporal-polyfill/misc/NOTES.txt b/packages/temporal-polyfill/scripts/test-config/NOTES.txt similarity index 100% rename from packages/temporal-polyfill/misc/NOTES.txt rename to packages/temporal-polyfill/scripts/test-config/NOTES.txt diff --git a/packages/temporal-polyfill/misc/expected-failures-before-node16.txt b/packages/temporal-polyfill/scripts/test-config/expected-failures-before-node16.txt similarity index 100% rename from packages/temporal-polyfill/misc/expected-failures-before-node16.txt rename to packages/temporal-polyfill/scripts/test-config/expected-failures-before-node16.txt diff --git a/packages/temporal-polyfill/misc/expected-failures-before-node18.txt b/packages/temporal-polyfill/scripts/test-config/expected-failures-before-node18.txt similarity index 100% rename from packages/temporal-polyfill/misc/expected-failures-before-node18.txt rename to packages/temporal-polyfill/scripts/test-config/expected-failures-before-node18.txt diff --git a/packages/temporal-polyfill/misc/expected-failures-es5.txt b/packages/temporal-polyfill/scripts/test-config/expected-failures-es5.txt similarity index 100% rename from packages/temporal-polyfill/misc/expected-failures-es5.txt rename to packages/temporal-polyfill/scripts/test-config/expected-failures-es5.txt diff --git a/packages/temporal-polyfill/misc/expected-failures-opt.txt b/packages/temporal-polyfill/scripts/test-config/expected-failures-opt.txt similarity index 100% rename from packages/temporal-polyfill/misc/expected-failures-opt.txt rename to packages/temporal-polyfill/scripts/test-config/expected-failures-opt.txt diff --git a/packages/temporal-polyfill/misc/expected-failures-todo-migrated-code.txt b/packages/temporal-polyfill/scripts/test-config/expected-failures-todo-migrated-code.txt similarity index 100% rename from packages/temporal-polyfill/misc/expected-failures-todo-migrated-code.txt rename to packages/temporal-polyfill/scripts/test-config/expected-failures-todo-migrated-code.txt diff --git a/packages/temporal-polyfill/misc/expected-failures.txt b/packages/temporal-polyfill/scripts/test-config/expected-failures.txt similarity index 100% rename from packages/temporal-polyfill/misc/expected-failures.txt rename to packages/temporal-polyfill/scripts/test-config/expected-failures.txt diff --git a/packages/temporal-polyfill/scripts/runtest262.js b/packages/temporal-polyfill/scripts/test.js similarity index 100% rename from packages/temporal-polyfill/scripts/runtest262.js rename to packages/temporal-polyfill/scripts/test.js diff --git a/packages/temporal-polyfill/scripts/config/terser.json b/packages/temporal-polyfill/terser.json similarity index 100% rename from packages/temporal-polyfill/scripts/config/terser.json rename to packages/temporal-polyfill/terser.json From a88618521b9fa6588054027dc43dfeb196cbaf99 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 11:19:37 -0400 Subject: [PATCH 215/805] clean up scripts --- package.json | 15 +- .../locale-data/scripts/localesScrape.cjs | 2 + packages/temporal-polyfill/package.json | 31 +- packages/temporal-polyfill/scripts/bundle.js | 1 + packages/temporal-polyfill/scripts/meta.js | 1 + packages/temporal-polyfill/scripts/size.cjs | 2 + packages/temporal-polyfill/scripts/test.js | 2 + pnpm-lock.yaml | 519 +----------------- 8 files changed, 43 insertions(+), 530 deletions(-) mode change 100644 => 100755 packages/locale-data/scripts/localesScrape.cjs create mode 100755 packages/temporal-polyfill/scripts/bundle.js create mode 100755 packages/temporal-polyfill/scripts/meta.js mode change 100644 => 100755 packages/temporal-polyfill/scripts/size.cjs mode change 100644 => 100755 packages/temporal-polyfill/scripts/test.js diff --git a/package.json b/package.json index 3faf41fc..c37334d6 100644 --- a/package.json +++ b/package.json @@ -22,32 +22,19 @@ "preinstall": "npx only-allow pnpm", "ci": "pnpm run clean && pnpm run lint && pnpm run build && pnpm run test", "build": "cd ./packages/temporal-polyfill && pnpm run build", - "build:dev": "cd ./packages/temporal-polyfill && pnpm run build:dev", - "watch": "cd ./packages/temporal-polyfill && pnpm run watch", "test": "cd ./packages/temporal-polyfill && pnpm run test", - "test262": "cd ./packages/temporal-polyfill && pnpm run test262", "lint": "cd ./packages/temporal-polyfill && pnpm run lint", - "size": "cd ./packages/temporal-polyfill && pnpm run size", - "clean": "cd ./packages/temporal-polyfill && pnpm run clean", - "locales-scrape": "node ./scripts/localesScrape.cjs", - "locales-compile": "echo 'TODO: recursively execute locales-compile'" + "clean": "cd ./packages/temporal-polyfill && pnpm run clean" }, "devDependencies": { - "@rollup/plugin-node-resolve": "^13.3.0", "@typescript-eslint/eslint-plugin": "^4.22.1", "@typescript-eslint/parser": "^4.22.1", - "colors": "^1.4.0", - "esbuild": "^0.18.17", "eslint": "^7.25.0", "eslint-config-standard": "^16.0.3", "eslint-import-resolver-node": "^0.3.6", "eslint-plugin-import": "^2.24.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", - "rollup": "^2.55.1", - "rollup-plugin-dts": "^3.0.2", - "rollup-plugin-esbuild": "^4.9.1", - "rollup-plugin-terser": "^7.0.2", "typescript": "^5.1.6" }, "pnpm": { diff --git a/packages/locale-data/scripts/localesScrape.cjs b/packages/locale-data/scripts/localesScrape.cjs old mode 100644 new mode 100755 index 49985ba4..95818bfc --- a/packages/locale-data/scripts/localesScrape.cjs +++ b/packages/locale-data/scripts/localesScrape.cjs @@ -1,3 +1,5 @@ +#!/usr/bin/env node + const { existsSync, readdirSync } = require('fs') const { readFile, writeFile } = require('fs/promises') const { resolve } = require('path') diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 983428aa..869d30cb 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -22,17 +22,17 @@ "directory": "packages/temporal-polyfill" }, "scripts": { - "build": "pnpm run types && pnpm run bundle", - "build:dev": "pnpm run types && NO_MIN=1 pnpm run bundle", - "watch": "concurrently npm:types:watch npm:bundle:watch", - "types": "tsc --build", - "types:watch": "tsc --build --preserveWatchOutput --watch", - "bundle": "rollup -c ../../scripts/config/pkgBundle.cjs", - "bundle:watch": "rollup -c ../../scripts/config/pkgBundle.cjs --watch", - "test262": "node ./runtest262.js", + "build": "pnpm run tsc && pnpm run bundle", + "tsc": "tsc --build", + "tsc:clean": "rm -rf dist/.tsc dist/tsconfig.tsbuildinfo", + "bundle": "./scripts/bundle.js", + "bundle:clean": "rm -rf dist/*.js dist/*.cjs dist/*.map", + "meta": "./scripts/meta.js", + "meta:clean": "rm -rf dist/package.json", + "test": "./test.js", "lint": "eslint .", - "size": "node ../../scripts/pkgSize.cjs", - "clean": "node ../../scripts/pkgClean.cjs" + "size": "./scripts/size.cjs", + "clean": "pnpm run tsc:clean && pnpm run bundle:clean && pnpm run meta:clean" }, "type": "module", "types": "./dist/index.d.ts", @@ -67,16 +67,13 @@ "temporal-spec": "~0.1.0" }, "devDependencies": { - "@types/node": "^16.9.1", "@js-temporal/temporal-test262-runner": "^0.9.0", - "ansi-colors": "^4.1.3", - "concurrently": "^7.6.0", + "@rollup/plugin-node-resolve": "^13.3.0", + "@types/node": "^16.9.1", + "colors": "^1.4.0", "eslint": "^7.25.0", - "js-yaml": "^4.1.0", - "minimatch": "^5.0.1", - "progress": "^2.0.3", "rollup": "^2.55.1", - "tiny-glob": "^0.2.9", + "rollup-plugin-dts": "^3.0.2", "typescript": "^5.1.6" } } diff --git a/packages/temporal-polyfill/scripts/bundle.js b/packages/temporal-polyfill/scripts/bundle.js new file mode 100755 index 00000000..908ba841 --- /dev/null +++ b/packages/temporal-polyfill/scripts/bundle.js @@ -0,0 +1 @@ +#!/usr/bin/env node diff --git a/packages/temporal-polyfill/scripts/meta.js b/packages/temporal-polyfill/scripts/meta.js new file mode 100755 index 00000000..908ba841 --- /dev/null +++ b/packages/temporal-polyfill/scripts/meta.js @@ -0,0 +1 @@ +#!/usr/bin/env node diff --git a/packages/temporal-polyfill/scripts/size.cjs b/packages/temporal-polyfill/scripts/size.cjs old mode 100644 new mode 100755 index db1a21f5..135cd91f --- a/packages/temporal-polyfill/scripts/size.cjs +++ b/packages/temporal-polyfill/scripts/size.cjs @@ -1,3 +1,5 @@ +#!/usr/bin/env node + const path = require('path') const fs = require('fs/promises') const { promisify } = require('util') diff --git a/packages/temporal-polyfill/scripts/test.js b/packages/temporal-polyfill/scripts/test.js old mode 100644 new mode 100755 index a78facdc..9314fbb1 --- a/packages/temporal-polyfill/scripts/test.js +++ b/packages/temporal-polyfill/scripts/test.js @@ -1,3 +1,5 @@ +#!/usr/bin/env node + import runTest262 from '@js-temporal/temporal-test262-runner' const testGlobs = process.argv.slice(2) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3711a741..a0841a32 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,21 +13,12 @@ importers: .: devDependencies: - '@rollup/plugin-node-resolve': - specifier: ^13.3.0 - version: 13.3.0(rollup@2.79.1) '@typescript-eslint/eslint-plugin': specifier: ^4.22.1 version: 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6) '@typescript-eslint/parser': specifier: ^4.22.1 version: 4.33.0(eslint@7.32.0)(typescript@5.1.6) - colors: - specifier: ^1.4.0 - version: 1.4.0 - esbuild: - specifier: ^0.18.17 - version: 0.18.17 eslint: specifier: ^7.25.0 version: 7.32.0 @@ -46,18 +37,6 @@ importers: eslint-plugin-promise: specifier: ^5.1.0 version: 5.2.0(eslint@7.32.0) - rollup: - specifier: ^2.55.1 - version: 2.79.1 - rollup-plugin-dts: - specifier: ^3.0.2 - version: 3.0.2(rollup@2.79.1)(typescript@5.1.6) - rollup-plugin-esbuild: - specifier: ^4.9.1 - version: 4.10.3(esbuild@0.18.17)(rollup@2.79.1) - rollup-plugin-terser: - specifier: ^7.0.2 - version: 7.0.2(rollup@2.79.1) typescript: specifier: ^5.1.6 version: 5.1.6 @@ -118,33 +97,24 @@ importers: '@js-temporal/temporal-test262-runner': specifier: ^0.9.0 version: 0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza) + '@rollup/plugin-node-resolve': + specifier: ^13.3.0 + version: 13.3.0(rollup@2.79.1) '@types/node': specifier: ^16.9.1 version: 16.18.14 - ansi-colors: - specifier: ^4.1.3 - version: 4.1.3 - concurrently: - specifier: ^7.6.0 - version: 7.6.0 + colors: + specifier: ^1.4.0 + version: 1.4.0 eslint: specifier: ^7.25.0 version: 7.32.0 - js-yaml: - specifier: ^4.1.0 - version: 4.1.0 - minimatch: - specifier: ^5.0.1 - version: 5.1.6 - progress: - specifier: ^2.0.3 - version: 2.0.3 rollup: specifier: ^2.55.1 version: 2.79.1 - tiny-glob: - specifier: ^0.2.9 - version: 0.2.9 + rollup-plugin-dts: + specifier: ^3.0.2 + version: 3.0.2(rollup@2.79.1)(typescript@5.1.6) typescript: specifier: ^5.1.6 version: 5.1.6 @@ -162,9 +132,11 @@ packages: /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} + requiresBuild: true dependencies: '@babel/highlight': 7.18.6 dev: true + optional: true /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} @@ -180,204 +152,6 @@ packages: js-tokens: 4.0.0 dev: true - /@esbuild/android-arm64@0.18.17: - resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.18.17: - resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.18.17: - resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.18.17: - resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.18.17: - resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.18.17: - resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.18.17: - resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.18.17: - resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.18.17: - resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.18.17: - resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.18.17: - resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.18.17: - resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.18.17: - resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.18.17: - resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.18.17: - resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.18.17: - resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.18.17: - resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.18.17: - resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.18.17: - resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.18.17: - resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.18.17: - resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.18.17: - resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@eslint/eslintrc@0.4.3: resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} engines: {node: ^10.12.0 || >=12.0.0} @@ -410,43 +184,6 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@jridgewell/gen-mapping@0.3.2: - resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.17 - dev: true - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/source-map@0.3.2: - resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} - dependencies: - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 - dev: true - - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true - - /@jridgewell/trace-mapping@0.3.17: - resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - /@js-temporal/temporal-test262-runner@0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza): resolution: {integrity: sha512-+DbfZ6oyuFyHbfe77HOuYEPfIkSNlYvFfS7hA+o9n1MxTqjdTN1xxQ0IOkGloVblIsl5Ceu1yzG4RNVzZHWL9Q==} dependencies: @@ -505,14 +242,6 @@ packages: rollup: 2.79.1 dev: true - /@rollup/pluginutils@4.2.1: - resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} - engines: {node: '>= 8.0.0'} - dependencies: - estree-walker: 2.0.2 - picomatch: 2.3.1 - dev: true - /@types/estree@0.0.39: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: true @@ -529,14 +258,10 @@ packages: resolution: {integrity: sha512-wvzClDGQXOCVNU4APPopC2KtMYukaF1MN/W3xAmslx22Z4/IF1/izDMekuyoUlwfnDHYCIZGaj7jMwnJKBTxKw==} dev: true - /@types/node@18.14.5: - resolution: {integrity: sha512-CRT4tMK/DHYhw1fcCEBwME9CSaZNclxfzVMe7GsO6ULSwsttbj70wSiX6rZdIjGblu93sTJxLdhNIT85KKI7Qw==} - dev: true - /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 18.14.5 + '@types/node': 16.18.14 dev: true /@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6): @@ -659,12 +384,6 @@ packages: hasBin: true dev: true - /acorn@8.8.2: - resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -772,12 +491,6 @@ packages: concat-map: 0.0.1 dev: true - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - dev: true - /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -785,10 +498,6 @@ packages: fill-range: 7.0.1 dev: true - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -830,6 +539,7 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + dev: false /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -854,30 +564,10 @@ packages: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true - /concat-map@0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true - /concurrently@7.6.0: - resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==} - engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} - hasBin: true - dependencies: - chalk: 4.1.2 - date-fns: 2.29.3 - lodash: 4.17.21 - rxjs: 7.8.0 - shell-quote: 1.8.0 - spawn-command: 0.0.2-1 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.1 - dev: true - /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -887,11 +577,6 @@ packages: which: 2.0.2 dev: true - /date-fns@2.29.3: - resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} - engines: {node: '>=0.11'} - dev: true - /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -1001,10 +686,6 @@ packages: which-typed-array: 1.1.9 dev: true - /es-module-lexer@0.9.3: - resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} - dev: true - /es-set-tostringtag@2.0.1: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} engines: {node: '>= 0.4'} @@ -1029,39 +710,10 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild@0.18.17: - resolution: {integrity: sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.18.17 - '@esbuild/android-arm64': 0.18.17 - '@esbuild/android-x64': 0.18.17 - '@esbuild/darwin-arm64': 0.18.17 - '@esbuild/darwin-x64': 0.18.17 - '@esbuild/freebsd-arm64': 0.18.17 - '@esbuild/freebsd-x64': 0.18.17 - '@esbuild/linux-arm': 0.18.17 - '@esbuild/linux-arm64': 0.18.17 - '@esbuild/linux-ia32': 0.18.17 - '@esbuild/linux-loong64': 0.18.17 - '@esbuild/linux-mips64el': 0.18.17 - '@esbuild/linux-ppc64': 0.18.17 - '@esbuild/linux-riscv64': 0.18.17 - '@esbuild/linux-s390x': 0.18.17 - '@esbuild/linux-x64': 0.18.17 - '@esbuild/netbsd-x64': 0.18.17 - '@esbuild/openbsd-x64': 0.18.17 - '@esbuild/sunos-x64': 0.18.17 - '@esbuild/win32-arm64': 0.18.17 - '@esbuild/win32-ia32': 0.18.17 - '@esbuild/win32-x64': 0.18.17 - dev: true - /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + dev: false /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -1321,10 +973,6 @@ packages: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} dev: true - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true - /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -1428,6 +1076,7 @@ packages: /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + dev: false /get-intrinsic@1.2.0: resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} @@ -1723,20 +1372,6 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true - /jest-worker@26.6.2: - resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} - engines: {node: '>= 10.13.0'} - dependencies: - '@types/node': 18.14.5 - merge-stream: 2.0.0 - supports-color: 7.2.0 - dev: true - - /joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - dev: true - /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -1775,10 +1410,6 @@ packages: minimist: 1.2.8 dev: true - /jsonc-parser@3.2.0: - resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: true - /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -1795,10 +1426,6 @@ packages: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} dev: true - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: true - /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -1812,10 +1439,6 @@ packages: sourcemap-codec: 1.4.8 dev: true - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1835,13 +1458,6 @@ packages: brace-expansion: 1.1.11 dev: true - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true @@ -1954,12 +1570,6 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - dependencies: - safe-buffer: 5.2.1 - dev: true - /regexp.prototype.flags@1.4.3: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} engines: {node: '>= 0.4'} @@ -1977,6 +1587,7 @@ packages: /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + dev: false /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} @@ -2023,37 +1634,6 @@ packages: '@babel/code-frame': 7.18.6 dev: true - /rollup-plugin-esbuild@4.10.3(esbuild@0.18.17)(rollup@2.79.1): - resolution: {integrity: sha512-RILwUCgnCL5vo8vyZ/ZpwcqRuE5KmLizEv6BujBQfgXFZ6ggcS0FiYvQN+gsTJfWCMaU37l0Fosh4eEufyO97Q==} - engines: {node: '>=12'} - peerDependencies: - esbuild: '>=0.10.1' - rollup: ^1.20.0 || ^2.0.0 - dependencies: - '@rollup/pluginutils': 4.2.1 - debug: 4.3.4 - es-module-lexer: 0.9.3 - esbuild: 0.18.17 - joycon: 3.1.1 - jsonc-parser: 3.2.0 - rollup: 2.79.1 - transitivePeerDependencies: - - supports-color - dev: true - - /rollup-plugin-terser@7.0.2(rollup@2.79.1): - resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} - deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser - peerDependencies: - rollup: ^2.0.0 - dependencies: - '@babel/code-frame': 7.18.6 - jest-worker: 26.6.2 - rollup: 2.79.1 - serialize-javascript: 4.0.0 - terser: 5.16.5 - dev: true - /rollup@2.79.1: resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} engines: {node: '>=10.0.0'} @@ -2068,16 +1648,6 @@ packages: queue-microtask: 1.2.3 dev: true - /rxjs@7.8.0: - resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} - dependencies: - tslib: 2.5.0 - dev: true - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: @@ -2099,12 +1669,6 @@ packages: lru-cache: 6.0.0 dev: true - /serialize-javascript@4.0.0: - resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} - dependencies: - randombytes: 2.1.0 - dev: true - /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2117,10 +1681,6 @@ packages: engines: {node: '>=8'} dev: true - /shell-quote@1.8.0: - resolution: {integrity: sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==} - dev: true - /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: @@ -2143,27 +1703,11 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true - /sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead dev: true - /spawn-command@0.0.2-1: - resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==} - dev: true - /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -2222,13 +1766,6 @@ packages: has-flag: 4.0.0 dev: true - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -2245,17 +1782,6 @@ packages: strip-ansi: 6.0.1 dev: true - /terser@5.16.5: - resolution: {integrity: sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==} - engines: {node: '>=10'} - hasBin: true - dependencies: - '@jridgewell/source-map': 0.3.2 - acorn: 8.8.2 - commander: 2.20.3 - source-map-support: 0.5.21 - dev: true - /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -2274,11 +1800,6 @@ packages: is-number: 7.0.0 dev: true - /tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - dev: true - /tsconfig-paths@3.14.2: resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} dependencies: @@ -2292,10 +1813,6 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /tslib@2.5.0: - resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} - dev: true - /tsutils@3.21.0(typescript@5.1.6): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -2393,6 +1910,7 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: false /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -2401,6 +1919,7 @@ packages: /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + dev: false /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -2409,6 +1928,7 @@ packages: /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + dev: false /yargs@17.7.1: resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} @@ -2421,3 +1941,4 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 + dev: false From 0eccdc96008bfffff024321f62fa6dd6af43ee50 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 11:28:30 -0400 Subject: [PATCH 216/805] new gitignore --- .gitignore | 11 ++--------- packages/temporal-polyfill/dist/.npmignore | 2 ++ 2 files changed, 4 insertions(+), 9 deletions(-) create mode 100644 packages/temporal-polyfill/dist/.npmignore diff --git a/.gitignore b/.gitignore index 3dfe42cc..172245cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,4 @@ - node_modules -/coverage -tsconfig.tsbuildinfo -dist - -# see pkgExportsFix -/packages/*/*.d.ts -# hack -!/packages/temporal-spec/*.d.ts +packages/*/dist/* +!packages/*/dist/.npmignore diff --git a/packages/temporal-polyfill/dist/.npmignore b/packages/temporal-polyfill/dist/.npmignore new file mode 100644 index 00000000..e8e373a5 --- /dev/null +++ b/packages/temporal-polyfill/dist/.npmignore @@ -0,0 +1,2 @@ +.tsc +tsconfig.tsbuildinfo From 61da2810054f48be6f9d1b3042cad14d56cb95aa Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 12:35:11 -0400 Subject: [PATCH 217/805] start types --- .gitignore | 4 +- packages/temporal-polyfill/package.json | 42 ++++++-------------- packages/temporal-polyfill/scripts/bundle.js | 2 + packages/temporal-polyfill/tsconfig.json | 1 + tsconfig.base.json | 10 +---- 5 files changed, 20 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 172245cb..181493d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules -packages/*/dist/* -!packages/*/dist/.npmignore +/packages/*/dist/* +/!packages/*/dist/.npmignore diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 869d30cb..988a7ef1 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -22,47 +22,31 @@ "directory": "packages/temporal-polyfill" }, "scripts": { - "build": "pnpm run tsc && pnpm run bundle", + "build": "pnpm run tsc && pnpm run type-overrides && pnpm run bundle", "tsc": "tsc --build", "tsc:clean": "rm -rf dist/.tsc dist/tsconfig.tsbuildinfo", + "type-overrides": "cp src/type-overrides/*.d.ts dist", "bundle": "./scripts/bundle.js", - "bundle:clean": "rm -rf dist/*.js dist/*.cjs dist/*.map", + "bundle:clean": "rm -rf dist/*.js dist/*.cjs dist/*.map dist/*.d.ts", "meta": "./scripts/meta.js", "meta:clean": "rm -rf dist/package.json", - "test": "./test.js", + "test": "./scripts/test.js", "lint": "eslint .", "size": "./scripts/size.cjs", "clean": "pnpm run tsc:clean && pnpm run bundle:clean && pnpm run meta:clean" }, "type": "module", - "types": "./dist/index.d.ts", - "main": "./dist/index.cjs", - "module": "./dist/index.mjs", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.cjs", - "import": "./dist/index.mjs" - }, - "./impl": { - "types": "./dist/impl.d.ts", - "require": "./dist/impl.cjs", - "import": "./dist/impl.mjs" - }, - "./global": { - "types": "./dist/global.d.ts", - "require": "./dist/global.cjs", - "import": "./dist/global.mjs" + "buildConfig": { + "exports": { + ".": {}, + "./impl": {}, + "./global": { "iife": true } } }, - "sideEffects": [ - "./dist/global.*" - ], - "files": [ - "/src", - "/dist", - "/*.d.ts" - ], + "publishConfig": { + "directory": "./dist", + "linkDirectory": true + }, "dependencies": { "temporal-spec": "~0.1.0" }, diff --git a/packages/temporal-polyfill/scripts/bundle.js b/packages/temporal-polyfill/scripts/bundle.js index 908ba841..d9d1f741 100755 --- a/packages/temporal-polyfill/scripts/bundle.js +++ b/packages/temporal-polyfill/scripts/bundle.js @@ -1 +1,3 @@ #!/usr/bin/env node + +console.log('TODO: bundle') diff --git a/packages/temporal-polyfill/tsconfig.json b/packages/temporal-polyfill/tsconfig.json index ccd8e3cd..c39d4496 100644 --- a/packages/temporal-polyfill/tsconfig.json +++ b/packages/temporal-polyfill/tsconfig.json @@ -15,6 +15,7 @@ "src/**/*" ], "exclude": [ + "src/type-overrides/**", "src/old/**/*" ] } diff --git a/tsconfig.base.json b/tsconfig.base.json index 3e3b9141..3efab1a5 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -6,15 +6,9 @@ "lib": ["ES2020"], "moduleResolution": "Node", "composite": true, - "allowJs": true, - "isolatedModules": false, - "emitDeclarationOnly": false, - "esModuleInterop": true, - "importHelpers": true, - "resolveJsonModule": true, "declaration": true, "declarationMap": true, - "skipLibCheck": false, - "checkJs": false + "importHelpers": true, + "resolveJsonModule": true } } From 22a57cdfbefcaecef8267a7128fabfbbac6bbca3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 12:43:44 -0400 Subject: [PATCH 218/805] new stuff --- packages/temporal-polyfill/package.json | 4 +- .../src/type-overrides/global.d.ts | 1 + .../src/type-overrides/impl.d.ts | 1 + .../src/type-overrides/index.d.ts | 1 + pnpm-lock.yaml | 113 ++---------------- 5 files changed, 13 insertions(+), 107 deletions(-) create mode 100644 packages/temporal-polyfill/src/type-overrides/global.d.ts create mode 100644 packages/temporal-polyfill/src/type-overrides/impl.d.ts create mode 100644 packages/temporal-polyfill/src/type-overrides/index.d.ts diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 988a7ef1..1062a9e7 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -52,12 +52,10 @@ }, "devDependencies": { "@js-temporal/temporal-test262-runner": "^0.9.0", - "@rollup/plugin-node-resolve": "^13.3.0", "@types/node": "^16.9.1", "colors": "^1.4.0", "eslint": "^7.25.0", - "rollup": "^2.55.1", - "rollup-plugin-dts": "^3.0.2", + "rollup": "^3.27.2", "typescript": "^5.1.6" } } diff --git a/packages/temporal-polyfill/src/type-overrides/global.d.ts b/packages/temporal-polyfill/src/type-overrides/global.d.ts new file mode 100644 index 00000000..4a889e48 --- /dev/null +++ b/packages/temporal-polyfill/src/type-overrides/global.d.ts @@ -0,0 +1 @@ +export * from 'temporal-spec/global' diff --git a/packages/temporal-polyfill/src/type-overrides/impl.d.ts b/packages/temporal-polyfill/src/type-overrides/impl.d.ts new file mode 100644 index 00000000..8746380b --- /dev/null +++ b/packages/temporal-polyfill/src/type-overrides/impl.d.ts @@ -0,0 +1 @@ +export * from 'temporal-spec' diff --git a/packages/temporal-polyfill/src/type-overrides/index.d.ts b/packages/temporal-polyfill/src/type-overrides/index.d.ts new file mode 100644 index 00000000..8746380b --- /dev/null +++ b/packages/temporal-polyfill/src/type-overrides/index.d.ts @@ -0,0 +1 @@ +export * from 'temporal-spec' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0841a32..ffce4f30 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,7 +52,7 @@ importers: version: link:../locale-data temporal-polyfill: specifier: workspace:* - version: link:../temporal-polyfill + version: link:../temporal-polyfill/dist packages/durationformat-polyfill: dependencies: @@ -62,7 +62,7 @@ importers: devDependencies: temporal-polyfill: specifier: workspace:* - version: link:../temporal-polyfill + version: link:../temporal-polyfill/dist packages/locale-data: dependencies: @@ -97,9 +97,6 @@ importers: '@js-temporal/temporal-test262-runner': specifier: ^0.9.0 version: 0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza) - '@rollup/plugin-node-resolve': - specifier: ^13.3.0 - version: 13.3.0(rollup@2.79.1) '@types/node': specifier: ^16.9.1 version: 16.18.14 @@ -110,14 +107,12 @@ importers: specifier: ^7.25.0 version: 7.32.0 rollup: - specifier: ^2.55.1 - version: 2.79.1 - rollup-plugin-dts: - specifier: ^3.0.2 - version: 3.0.2(rollup@2.79.1)(typescript@5.1.6) + specifier: ^3.27.2 + version: 3.27.2 typescript: specifier: ^5.1.6 version: 5.1.6 + publishDirectory: ./dist packages/temporal-spec: {} @@ -129,15 +124,6 @@ packages: '@babel/highlight': 7.18.6 dev: true - /@babel/code-frame@7.18.6: - resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} - engines: {node: '>=6.9.0'} - requiresBuild: true - dependencies: - '@babel/highlight': 7.18.6 - dev: true - optional: true - /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} @@ -215,37 +201,6 @@ packages: fastq: 1.15.0 dev: true - /@rollup/plugin-node-resolve@13.3.0(rollup@2.79.1): - resolution: {integrity: sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==} - engines: {node: '>= 10.0.0'} - peerDependencies: - rollup: ^2.42.0 - dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.1) - '@types/resolve': 1.17.1 - deepmerge: 4.3.0 - is-builtin-module: 3.2.1 - is-module: 1.0.0 - resolve: 1.22.1 - rollup: 2.79.1 - dev: true - - /@rollup/pluginutils@3.1.0(rollup@2.79.1): - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.1 - rollup: 2.79.1 - dev: true - - /@types/estree@0.0.39: - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - dev: true - /@types/json-schema@7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true @@ -258,12 +213,6 @@ packages: resolution: {integrity: sha512-wvzClDGQXOCVNU4APPopC2KtMYukaF1MN/W3xAmslx22Z4/IF1/izDMekuyoUlwfnDHYCIZGaj7jMwnJKBTxKw==} dev: true - /@types/resolve@1.17.1: - resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} - dependencies: - '@types/node': 16.18.14 - dev: true - /@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.1.6): resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -498,11 +447,6 @@ packages: fill-range: 7.0.1 dev: true - /builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - dev: true - /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -607,6 +551,7 @@ packages: /deepmerge@4.3.0: resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==} engines: {node: '>=0.10.0'} + dev: false /define-properties@1.2.0: resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} @@ -969,10 +914,6 @@ packages: engines: {node: '>=4.0'} dev: true - /estree-walker@1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - dev: true - /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -1261,13 +1202,6 @@ packages: has-tostringtag: 1.0.0 dev: true - /is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} - dependencies: - builtin-modules: 3.3.0 - dev: true - /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -1302,10 +1236,6 @@ packages: is-extglob: 2.1.1 dev: true - /is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - dev: true - /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -1433,12 +1363,6 @@ packages: yallist: 4.0.0 dev: true - /magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - dependencies: - sourcemap-codec: 1.4.8 - dev: true - /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1620,23 +1544,9 @@ packages: glob: 7.2.3 dev: true - /rollup-plugin-dts@3.0.2(rollup@2.79.1)(typescript@5.1.6): - resolution: {integrity: sha512-hswlsdWu/x7k5pXzaLP6OvKRKcx8Bzprksz9i9mUe72zvt8LvqAb/AZpzs6FkLgmyRaN8B6rUQOVtzA3yEt9Yw==} - engines: {node: '>=v12.22.1'} - peerDependencies: - rollup: ^2.48.0 - typescript: ^4.2.4 - dependencies: - magic-string: 0.25.9 - rollup: 2.79.1 - typescript: 5.1.6 - optionalDependencies: - '@babel/code-frame': 7.18.6 - dev: true - - /rollup@2.79.1: - resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} - engines: {node: '>=10.0.0'} + /rollup@3.27.2: + resolution: {integrity: sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: fsevents: 2.3.2 @@ -1703,11 +1613,6 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true - /sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - dev: true - /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true From e3f17b4c5f246038d285e696a3ca864216c5fca0 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 13:30:08 -0400 Subject: [PATCH 219/805] actual bundling --- packages/temporal-polyfill/scripts/bundle.js | 85 +++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/scripts/bundle.js b/packages/temporal-polyfill/scripts/bundle.js index d9d1f741..af25e9d4 100755 --- a/packages/temporal-polyfill/scripts/bundle.js +++ b/packages/temporal-polyfill/scripts/bundle.js @@ -1,3 +1,86 @@ #!/usr/bin/env node -console.log('TODO: bundle') +import { join as joinPaths, dirname } from 'path' +import { readFile } from 'fs/promises' +import { rollup } from 'rollup' + +const extensions = { + esm: '.esm.js', + cjs: '.cjs', + iife: '.js', +} + +writeBundles( + joinPaths(dirname(process.argv[1]), '..') +) + +async function writeBundles(pkgDir) { + const pkgJsonPath = joinPaths(pkgDir, 'package.json') + const pkgJson = JSON.parse(await readFile(pkgJsonPath)) + const exportsMap = pkgJson.buildConfig.exports + const moduleInputs = {} + const iifeConfigs = [] + + for (const exportPath in exportsMap) { + const exportConfig = exportsMap[exportPath] + const shortName = exportPath === '.' ? 'index' : exportPath.replace(/^\.\//, '') + const inputPath = joinPaths(pkgDir, 'dist', '.tsc', shortName + '.js') + + moduleInputs[shortName] = inputPath + + if (exportConfig.iife) { + iifeConfigs.push({ + input: inputPath, + onwarn, + output: { + format: 'iife', + file: joinPaths('dist', shortName + extensions.iife), + } + }) + } + } + + const configs = [ + { + input: moduleInputs, + onwarn, + output: [ + { + format: 'cjs', + dir: 'dist', + entryFileNames: '[name]' + extensions.cjs, + chunkFileNames: 'chunk-[hash]' + extensions.cjs, + }, + { + format: 'es', + dir: 'dist', + entryFileNames: '[name]' + extensions.esm, + chunkFileNames: 'chunk-[hash]' + extensions.esm, + } + ] + }, + ...iifeConfigs, + ] + + await Promise.all( + configs.map(async (config) => { + const bundle = await rollup(config) + + return Promise.all( + arrayify(config.output).map((outputConfig) => { + return bundle.write(outputConfig) + }) + ) + }) + ) +} + +function onwarn(warning) { + if (warning.code !== 'CIRCULAR_DEPENDENCY') { + console.error(warning.toString()) + } +} + +function arrayify(input) { + return Array.isArray(input) ? input : (input == null ? [] : [input]) +} From 4d78aa0b3d20c41bea12450ed6dd64e9f935e238 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 14:01:55 -0400 Subject: [PATCH 220/805] minify --- packages/temporal-polyfill/package.json | 4 +- pnpm-lock.yaml | 77 +++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 1062a9e7..817b38d8 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -22,12 +22,13 @@ "directory": "packages/temporal-polyfill" }, "scripts": { - "build": "pnpm run tsc && pnpm run type-overrides && pnpm run bundle", + "build": "pnpm run tsc && pnpm run type-overrides && pnpm run bundle && pnpm run minify", "tsc": "tsc --build", "tsc:clean": "rm -rf dist/.tsc dist/tsconfig.tsbuildinfo", "type-overrides": "cp src/type-overrides/*.d.ts dist", "bundle": "./scripts/bundle.js", "bundle:clean": "rm -rf dist/*.js dist/*.cjs dist/*.map dist/*.d.ts", + "minify": "terser --config-file terser.json -o dist/global.min.js -- dist/global.js", "meta": "./scripts/meta.js", "meta:clean": "rm -rf dist/package.json", "test": "./scripts/test.js", @@ -56,6 +57,7 @@ "colors": "^1.4.0", "eslint": "^7.25.0", "rollup": "^3.27.2", + "terser": "^5.19.2", "typescript": "^5.1.6" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ffce4f30..de9a6094 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -109,6 +109,9 @@ importers: rollup: specifier: ^3.27.2 version: 3.27.2 + terser: + specifier: ^5.19.2 + version: 5.19.2 typescript: specifier: ^5.1.6 version: 5.1.6 @@ -170,6 +173,43 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.19 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/source-map@0.3.5: + resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.19 + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /@js-temporal/temporal-test262-runner@0.9.0(patch_hash=a5sbr7rbe6j2wt5ajt2xelhpza): resolution: {integrity: sha512-+DbfZ6oyuFyHbfe77HOuYEPfIkSNlYvFfS7hA+o9n1MxTqjdTN1xxQ0IOkGloVblIsl5Ceu1yzG4RNVzZHWL9Q==} dependencies: @@ -333,6 +373,12 @@ packages: hasBin: true dev: true + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -447,6 +493,10 @@ packages: fill-range: 7.0.1 dev: true + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -508,6 +558,10 @@ packages: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true @@ -1613,6 +1667,18 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -1687,6 +1753,17 @@ packages: strip-ansi: 6.0.1 dev: true + /terser@5.19.2: + resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.5 + acorn: 8.10.0 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true From 5f04ba5899926c4e62a5989712906e6a2bcc47fa Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 14:19:55 -0400 Subject: [PATCH 221/805] writing package.json --- packages/temporal-polyfill/package.json | 8 ++-- packages/temporal-polyfill/scripts/bundle.js | 7 +-- packages/temporal-polyfill/scripts/meta.js | 1 - .../temporal-polyfill/scripts/pkg-json.js | 43 +++++++++++++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) delete mode 100755 packages/temporal-polyfill/scripts/meta.js create mode 100755 packages/temporal-polyfill/scripts/pkg-json.js diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 817b38d8..3b87fd83 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -22,19 +22,19 @@ "directory": "packages/temporal-polyfill" }, "scripts": { - "build": "pnpm run tsc && pnpm run type-overrides && pnpm run bundle && pnpm run minify", + "build": "pnpm run pkg-json && pnpm run tsc && pnpm run type-overrides && pnpm run bundle && pnpm run minify", "tsc": "tsc --build", "tsc:clean": "rm -rf dist/.tsc dist/tsconfig.tsbuildinfo", "type-overrides": "cp src/type-overrides/*.d.ts dist", "bundle": "./scripts/bundle.js", "bundle:clean": "rm -rf dist/*.js dist/*.cjs dist/*.map dist/*.d.ts", "minify": "terser --config-file terser.json -o dist/global.min.js -- dist/global.js", - "meta": "./scripts/meta.js", - "meta:clean": "rm -rf dist/package.json", + "pkg-json": "./scripts/pkg-json.js", + "pkg-json:clean": "rm -rf dist/package.json", "test": "./scripts/test.js", "lint": "eslint .", "size": "./scripts/size.cjs", - "clean": "pnpm run tsc:clean && pnpm run bundle:clean && pnpm run meta:clean" + "clean": "pnpm run tsc:clean && pnpm run bundle:clean && pnpm run pkg-json:clean" }, "type": "module", "buildConfig": { diff --git a/packages/temporal-polyfill/scripts/bundle.js b/packages/temporal-polyfill/scripts/bundle.js index af25e9d4..4f114f57 100755 --- a/packages/temporal-polyfill/scripts/bundle.js +++ b/packages/temporal-polyfill/scripts/bundle.js @@ -4,6 +4,7 @@ import { join as joinPaths, dirname } from 'path' import { readFile } from 'fs/promises' import { rollup } from 'rollup' +// TODO: make DRY with pkg-json.js const extensions = { esm: '.esm.js', cjs: '.cjs', @@ -17,12 +18,12 @@ writeBundles( async function writeBundles(pkgDir) { const pkgJsonPath = joinPaths(pkgDir, 'package.json') const pkgJson = JSON.parse(await readFile(pkgJsonPath)) - const exportsMap = pkgJson.buildConfig.exports + const exportMap = pkgJson.buildConfig.exports const moduleInputs = {} const iifeConfigs = [] - for (const exportPath in exportsMap) { - const exportConfig = exportsMap[exportPath] + for (const exportPath in exportMap) { + const exportConfig = exportMap[exportPath] const shortName = exportPath === '.' ? 'index' : exportPath.replace(/^\.\//, '') const inputPath = joinPaths(pkgDir, 'dist', '.tsc', shortName + '.js') diff --git a/packages/temporal-polyfill/scripts/meta.js b/packages/temporal-polyfill/scripts/meta.js deleted file mode 100755 index 908ba841..00000000 --- a/packages/temporal-polyfill/scripts/meta.js +++ /dev/null @@ -1 +0,0 @@ -#!/usr/bin/env node diff --git a/packages/temporal-polyfill/scripts/pkg-json.js b/packages/temporal-polyfill/scripts/pkg-json.js new file mode 100755 index 00000000..c5ff9a10 --- /dev/null +++ b/packages/temporal-polyfill/scripts/pkg-json.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node + +import { join as joinPaths, dirname } from 'path' +import { readFile, writeFile } from 'fs/promises' + +writePkgJson( + joinPaths(dirname(process.argv[1]), '..') +) + +async function writePkgJson(pkgDir) { + const srcPkgJsonPath = joinPaths(pkgDir, 'package.json') + const distPkgJsonPath = joinPaths(pkgDir, 'dist', 'package.json') + + const srcPkgJson = JSON.parse(await readFile(srcPkgJsonPath)) + const distPkgJson = { ...srcPkgJson } + + const srcExportMap = srcPkgJson.buildConfig.exports + const distExportMap = {} + + for (const exportPath in srcExportMap) { + const shortName = exportPath === '.' ? './index' : exportPath + + // TODO: make DRY with bundle.js + distExportMap[exportPath] = { + types: shortName + '.d.ts', + require: shortName + '.cjs', + import: shortName + '.esm.js', + } + } + + distPkgJson.types = distExportMap['.'].types + distPkgJson.main = distExportMap['.'].require + distPkgJson.module = distExportMap['.'].import + distPkgJson.unpkg = distPkgJson.jsdelivr = './global.min.js' + distPkgJson.exports = distExportMap + + delete distPkgJson.scripts + delete distPkgJson.buildConfig + delete distPkgJson.publishConfig + delete distPkgJson.devDependencies + + await writeFile(distPkgJsonPath, JSON.stringify(distPkgJson, undefined, 2)) +} From 6bdbe677c9578a79351180f08c6e8b44f99a69f2 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 14:28:46 -0400 Subject: [PATCH 222/805] revamp size script --- packages/temporal-polyfill/package.json | 3 +- packages/temporal-polyfill/scripts/size.cjs | 47 --------------------- packages/temporal-polyfill/scripts/size.js | 38 +++++++++++++++++ 3 files changed, 39 insertions(+), 49 deletions(-) delete mode 100755 packages/temporal-polyfill/scripts/size.cjs create mode 100755 packages/temporal-polyfill/scripts/size.js diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 3b87fd83..7ec967c5 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -33,7 +33,7 @@ "pkg-json:clean": "rm -rf dist/package.json", "test": "./scripts/test.js", "lint": "eslint .", - "size": "./scripts/size.cjs", + "size": "./scripts/size.js", "clean": "pnpm run tsc:clean && pnpm run bundle:clean && pnpm run pkg-json:clean" }, "type": "module", @@ -54,7 +54,6 @@ "devDependencies": { "@js-temporal/temporal-test262-runner": "^0.9.0", "@types/node": "^16.9.1", - "colors": "^1.4.0", "eslint": "^7.25.0", "rollup": "^3.27.2", "terser": "^5.19.2", diff --git a/packages/temporal-polyfill/scripts/size.cjs b/packages/temporal-polyfill/scripts/size.cjs deleted file mode 100755 index 135cd91f..00000000 --- a/packages/temporal-polyfill/scripts/size.cjs +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env node - -const path = require('path') -const fs = require('fs/promises') -const { promisify } = require('util') -const exec = promisify(require('child_process').exec) - -require('colors') -printPkgSize(process.cwd()) - -async function printPkgSize(pkgDir) { - const distDir = path.join(pkgDir, 'dist') - let filenames - let bytes = 0 - - try { - filenames = await fs.readdir(distDir) - } catch (ex) { - // some projects aren't buildable and don't have a dist directory - process.exit(0) - } - - for (const filename of filenames) { - if ( - // !filename.match(/\.map$/) && - // !filename.match(/\.cjs$/) - filename.match(/\.js$/) - ) { - const filePath = path.join(distDir, filename) - console.log(filename) - const { stdout } = await exec(`gzip -c -r ${filePath} | wc -c`) - const fileBytes = parseInt(stdout.trim()) - bytes = Math.max(bytes, fileBytes) - } - } - - console.log( - path.basename(pkgDir) + ':', - bytes - ? (bytes / 1024).toFixed(3).green + ' kb' - : 'Empty or nonexistent file'.red, - ) - - if (!bytes) { - process.exit(1) - } -} diff --git a/packages/temporal-polyfill/scripts/size.js b/packages/temporal-polyfill/scripts/size.js new file mode 100755 index 00000000..c32c76d7 --- /dev/null +++ b/packages/temporal-polyfill/scripts/size.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +import { join as joinPaths, dirname } from 'path' +import { readdir } from 'fs/promises' +import { exec as execCb } from 'child_process' +import { promisify } from 'util' + +const exec = promisify(execCb) + +printSizes( + joinPaths(dirname(process.argv[1]), '..') +) + +async function printSizes(pkgDir) { + const distDir = joinPaths(pkgDir, 'dist') + let filenames + + try { + filenames = await readdir(distDir) + } catch (ex) { + process.exit(0) + } + + for (const filename of filenames) { + if (filename.match(/\.min\.js$/)) { + const filePath = joinPaths(distDir, filename) + const { stdout } = await exec(`gzip -c -r ${filePath} | wc -c`) + const bytes = parseInt(stdout.trim()) + + console.log( + ' ' + filename + ':', + (bytes / 1024).toFixed(3) + ' kb' + ) + } + } + + console.log() +} From 621976ba35cc1fe9a7f0619b84a429f9c2e828f3 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 8 Aug 2023 14:31:38 -0400 Subject: [PATCH 223/805] move global file --- test.html => packages/temporal-polyfill/test.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test.html => packages/temporal-polyfill/test.html (82%) diff --git a/test.html b/packages/temporal-polyfill/test.html similarity index 82% rename from test.html rename to packages/temporal-polyfill/test.html index 430354ea..33a96868 100644 --- a/test.html +++ b/packages/temporal-polyfill/test.html @@ -2,7 +2,7 @@ - + + ``` -[Temporal]: https://github.com/tc39/proposal-temporal -[BigInt]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt -[JSBI-why]: https://github.com/GoogleChromeLabs/jsbi#why +## Comparison with `@js-temporal/polyfill` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Package + temporal-polyfill + + @js-temporal/polyfill +
Repo + + github.com/fullcalendar/temporal-polyfill + + + + github.com/js-temporal/temporal-polyfill + +
CreatorsFullCalendar lead dev arshawChampions of the Temporal proposal
Minified+gzip size ✝20.0 kB43.2 kB (+116%)
Minified-only size ✝58.7 kB206.0 kB (+251%)
Spec compliance + Strict compliance for common API.
+ Functional compliance for custom-implemented Calendar/TimeZone,
+ though internal calling order may differ (more info). +
+ Strict compliance for entire API. +
Spec date + Nov 2023 (latest) + + May 2023 +
BigInt ApproachInternally avoids BigInt operations altogetherInternally relies on JSBI
Global usage in ESM/CJS + + import 'temporal-polyfill/global'; // ESM
+ require('temporal-polyfill/global'); // CJS +
+
Not currently possible
Global usage directly in browser + + <script>
+   Temporal.Now.zonedDateTimeISO()
+ </script> +
+
+ + <script>
+   temporal.Temporal.Now.zonedDateTimeISO()
+ </script> +
+
+ +✝ Compares [global.min.js](https://cdn.jsdelivr.net/npm/temporal-polyfill@0.2.0/global.min.js) with [index.esm.js](https://cdn.jsdelivr.net/npm/@js-temporal/polyfill@0.4.4/dist/index.esm.js), which are similarly transpiled. + + +## Spec Compliance + +All calendar systems (ex: `chinese`, `persian`) and time zones are supported. + +Compliance with the latest version of the Temporal spec (Nov 2023) is near-perfect with the following intentional deviations: + +- `Duration::toString` does not display units greater than `Number.MAX_SAFE_INTEGER` according to spec. Precision is chosen differently. +- *Custom implementations* of Calendars and TimeZones are queried differently. Only affects those subclassing built-in classes, which is extremely rare. See the CALLING entries in the [test-ignore file](https://github.com/fullcalendar/temporal/blob/main/packages/temporal-polyfill/scripts/test-config/expected-failures.txt). +- There are believed to be 3 bugs in the Temporal spec itself, one of which [has been filed](https://github.com/tc39/proposal-temporal/issues/2742). See SPEC-BUG entries in the [test-ignore file](https://github.com/fullcalendar/temporal/blob/main/packages/temporal-polyfill/scripts/test-config/expected-failures.txt). +- Canonicalization of time zone IDs is simplified, leveraging the built-in `Intl` API. +- `Intl.DateTimeFormat` has not been polyfilled to accept number-offset values for the `timeZone` option. +- Method descriptors and `Function::length` are not strictly compliant due to ES-related space-saving techniques. + +The [Official ECMAScript Conformance Test Suite](https://github.com/tc39/test262) has: + +- 6811 *total* Temporal-related test files +- 6138 *passed* by `temporal-polyfill` +- 495 *ignored* due to superficial method descriptor compliance +- 178 *ignored* due to other aforementioned intentional deviations + + +## Browser Support + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Minimum required browsers: +
Chrome 60
(Jul 2017)
Firefox 55
(Aug 2017)
Safari 11.1
(Mar 2018)
Safari iOS 11.3
(Mar 2018)
Edge 79
(Jan 2020)
Node.js 14
(Apr 2020)
+ If you transpile, you can support older browsers down to: +
Chrome 57
(Mar 2017)
Firefox 52
(Mar 2017)
Safari 10
(Sep 2016)
Safari iOS 10
(Sep 2016)
Edge 15
(Apr 2017)
Node.js 14
(Apr 2020)
+ + + + +## BigInt Considerations + +This polyfill works fine in environments that do not support [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). + +However, to use methods that accept/emit them, your browser [must support BigInt](https://caniuse.com/bigint). + +Here's how to sidestep this browser compatibility issue: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
❌ Avoid microseconds/nanoseconds✅ Use milliseconds instead
instant.epochMicrosecondsinstant.epochMilliseconds
instant.epochNanosecondsinstant.epochMilliseconds
Temporal.Instant.fromEpochMicroseconds(micro)Temporal.Instant.fromEpochMilliseconds(milli)
Temporal.Instant.fromEpochNanoseconds(nano)Temporal.Instant.fromEpochMilliseconds(milli)
new Temporal.Instant(nano)Temporal.Instant.fromEpochMilliseconds(milli)
zonedDateTime.epochMicrosecondszonedDateTime.epochMilliseconds
zonedDateTime.epochNanosecondszonedDateTime.epochMilliseconds
+ + new Temporal.ZonedDateTime(nano, tz, cal) + + + + Temporal.Instant.fromEpochMilliseconds(milli)
+   .toZonedDateTimeISO() // or toZonedDateTime +
+
+ + +## Tree-shakeable API + +🚧 Coming Soon + +For library authors and other devs who are hyper-concerned about bundle size, `temporal-polyfill` will be providing an alternate API designed for tree-shaking. + +```js +import * as ZonedDateTime from 'temporal-polyfill/fns/zoneddatetime' + +const zdt = ZonedDateTime.from({ year: 2024, month: 1, day: 1 }) +const s = ZonedDateTime.toString(zdt) // not how you normally call a method! +``` diff --git a/packages/temporal-polyfill/package.json b/packages/temporal-polyfill/package.json index 42182bb3..22b10942 100644 --- a/packages/temporal-polyfill/package.json +++ b/packages/temporal-polyfill/package.json @@ -1,8 +1,8 @@ { "name": "temporal-polyfill", - "version": "0.1.1", + "version": "0.2.0", "title": "Temporal Polyfill", - "description": "A spec-compliant Temporal JavaScript polyfill in 16kb", + "description": "A lightweight polyfill for Temporal, successor to the JavaScript Date object", "author": { "name": "Adam Shaw", "email": "arshaw@users.noreply.github.com", @@ -18,7 +18,7 @@ "copyright": "2022 Adam Shaw", "repository": { "type": "git", - "url": "https://github.com/fullcalendar/temporal.git", + "url": "https://github.com/fullcalendar/temporal-polyfill.git", "directory": "packages/temporal-polyfill" }, "scripts": { @@ -36,7 +36,7 @@ "test": "./scripts/test.js", "lint": "eslint .", "clean": "pnpm run tsc:clean && pnpm run bundle:clean && pnpm run pkg-json:clean", - "size": "gzip-size --include-original --raw dist/global.min.js && pnpm export-size ./dist" + "size": "gzip-size --include-original dist/global.min.js && pnpm export-size ./dist" }, "type": "module", "buildConfig": { @@ -53,7 +53,7 @@ "linkDirectory": true }, "dependencies": { - "temporal-spec": "~0.1.0" + "temporal-spec": "~0.2.0" }, "devDependencies": { "@js-temporal/temporal-test262-runner": "workspace:*", diff --git a/packages/temporal-spec/package.json b/packages/temporal-spec/package.json index cedfe132..3a862286 100644 --- a/packages/temporal-spec/package.json +++ b/packages/temporal-spec/package.json @@ -1,6 +1,6 @@ { "name": "temporal-spec", - "version": "0.1.0", + "version": "0.2.0", "title": "TypeScript types for Temporal", "author": { "name": "Adam Shaw", @@ -10,7 +10,7 @@ "license": "ISC", "repository": { "type": "git", - "url": "https://github.com/fullcalendar/temporal.git", + "url": "https://github.com/fullcalendar/temporal-polyfill.git", "directory": "packages/temporal-spec" }, "type": "module", From 89a40709dcc4c1d2991f12a8f3039c51150ee90e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 7 Jan 2024 04:21:30 -0500 Subject: [PATCH 799/805] tweaks to README --- packages/temporal-polyfill/README.md | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/temporal-polyfill/README.md b/packages/temporal-polyfill/README.md index 8fc6e2fb..d7302ef6 100644 --- a/packages/temporal-polyfill/README.md +++ b/packages/temporal-polyfill/README.md @@ -22,7 +22,7 @@ Only 20.0 kB, with near-perfect [spec compliance](#spec-compliance). npm install temporal-polyfill ``` -**Import as an ES module** without side effects: +Import as an ES module without side effects: ```js import { Temporal } from 'temporal-polyfill' @@ -30,7 +30,7 @@ import { Temporal } from 'temporal-polyfill' console.log(Temporal.Now.zonedDateTimeISO().toString()) ``` -Or, **import globally:** +Or, import globally: ```js import 'temporal-polyfill/global' @@ -116,28 +116,22 @@ Use a ` + +``` -## Repo Dev Commands -``` -pnpm build -pnpm watch -pnpm test --watch -pnpm test --coverage -pnpm lint -pnpm size -``` +## Comparison with `@js-temporal/polyfill` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Package + temporal-polyfill + + @js-temporal/polyfill +
Repo + + github.com/fullcalendar/temporal-polyfill + + + + github.com/js-temporal/temporal-polyfill + +
CreatorsFullCalendar lead dev arshawChampions of the Temporal proposal
Minified+gzip size ✝20.0 kB43.2 kB (+116%)
Minified-only size ✝58.7 kB206.0 kB (+251%)
Spec compliance + Strict compliance for common API.
+ Functional compliance for custom-implemented Calendar/TimeZone,
+ though internal calling order may differ (more info). +
+ Strict compliance for entire API. +
Spec date + Nov 2023 (latest) + + May 2023 +
BigInt ApproachInternally avoids BigInt operations altogetherInternally relies on JSBI
Global usage in ESM/CJS +
import 'temporal-polyfill/global'; // ESM
+require('temporal-polyfill/global'); // CJS
+
Not currently possible
Global usage directly in browser +
<script>
+  Temporal.Now.zonedDateTimeISO()
+</script>
+
+
<script>
+  temporal.Temporal.Now.zonedDateTimeISO()
+</script>
+
+ +✝ Compares [global.min.js](https://cdn.jsdelivr.net/npm/temporal-polyfill@0.2.0/global.min.js) with [index.esm.js](https://cdn.jsdelivr.net/npm/@js-temporal/polyfill@0.4.4/dist/index.esm.js), which are similarly transpiled. + + +## Spec Compliance + +All calendar systems (ex: `chinese`, `persian`) and time zones are supported. + +Compliance with the latest version of the Temporal spec (Nov 2023) is near-perfect with the following intentional deviations: + +- `Duration::toString` does not display units greater than `Number.MAX_SAFE_INTEGER` according to spec. Precision is chosen differently. +- *Custom implementations* of Calendars and TimeZones are queried differently. Only affects those subclassing built-in classes, which is extremely rare. See the CALLING entries in the [test-ignore file](https://github.com/fullcalendar/temporal/blob/main/packages/temporal-polyfill/scripts/test-config/expected-failures.txt). +- There are believed to be 3 bugs in the Temporal spec itself, one of which [has been filed](https://github.com/tc39/proposal-temporal/issues/2742). See SPEC-BUG entries in the [test-ignore file](https://github.com/fullcalendar/temporal/blob/main/packages/temporal-polyfill/scripts/test-config/expected-failures.txt). +- Canonicalization of time zone IDs is simplified, leveraging the built-in `Intl` API. +- `Intl.DateTimeFormat` has not been polyfilled to accept number-offset values for the `timeZone` option. +- Method descriptors and `Function::length` are not strictly compliant due to ES-related space-saving techniques. + +The [Official ECMAScript Conformance Test Suite](https://github.com/tc39/test262) has: + +- 6811 *total* Temporal-related test files +- 6138 *passed* by `temporal-polyfill` +- 495 *ignored* due to superficial method descriptor compliance +- 178 *ignored* due to other aforementioned intentional deviations + +## Browser Support -[Temporal]: https://github.com/tc39/proposal-temporal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Minimum required browsers: +
Chrome 60
(Jul 2017)
Firefox 55
(Aug 2017)
Safari 11.1
(Mar 2018)
Safari iOS 11.3
(Mar 2018)
Edge 79
(Jan 2020)
Node.js 14
(Apr 2020)
+ If you transpile, you can support older browsers down to: +
Chrome 57
(Mar 2017)
Firefox 52
(Mar 2017)
Safari 10
(Sep 2016)
Safari iOS 10
(Sep 2016)
Edge 15
(Apr 2017)
Node.js 14
(Apr 2020)
+ + + + +## BigInt Considerations + +This polyfill works fine in environments that do not support [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). + +However, to use methods that accept/emit them, your browser [must support BigInt](https://caniuse.com/bigint). + +Here's how to sidestep this browser compatibility issue: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
❌ Avoid microseconds/nanoseconds✅ Use milliseconds instead
instant.epochMicrosecondsinstant.epochMilliseconds
instant.epochNanosecondsinstant.epochMilliseconds
Temporal.Instant.fromEpochMicroseconds(micro)Temporal.Instant.fromEpochMilliseconds(milli)
Temporal.Instant.fromEpochNanoseconds(nano)Temporal.Instant.fromEpochMilliseconds(milli)
new Temporal.Instant(nano)Temporal.Instant.fromEpochMilliseconds(milli)
zonedDateTime.epochMicrosecondszonedDateTime.epochMilliseconds
zonedDateTime.epochNanosecondszonedDateTime.epochMilliseconds
+ + new Temporal.ZonedDateTime(nano, tz, cal) + + + + Temporal.Instant.fromEpochMilliseconds(milli)
+   .toZonedDateTimeISO() // or toZonedDateTime +
+
+ + +## Tree-shakeable API + +🚧 Coming Soon + +For library authors and other devs who are hyper-concerned about bundle size, `temporal-polyfill` will be providing an alternate API designed for tree-shaking. + +```js +import * as ZonedDateTime from 'temporal-polyfill/fns/zoneddatetime' + +const zdt = ZonedDateTime.from({ year: 2024, month: 1, day: 1 }) +const s = ZonedDateTime.toString(zdt) // not how you normally call a method! +``` diff --git a/packages/temporal-polyfill/README.md b/packages/temporal-polyfill/README.md deleted file mode 100644 index d7302ef6..00000000 --- a/packages/temporal-polyfill/README.md +++ /dev/null @@ -1,292 +0,0 @@ - -# temporal-polyfill - -A lightweight polyfill for [Temporal](https://tc39.es/proposal-temporal/docs/), successor to the JavaScript `Date` object. - -Only 20.0 kB, with near-perfect [spec compliance](#spec-compliance). - - -## Table of Contents - -- [Installation](#installation) -- [Comparison with `@js-temporal/polyfill`](#comparison-with-js-temporalpolyfill) -- [Spec Compliance](#spec-compliance) -- [Browser Support](#browser-support) -- [BigInt Considerations](#bigint-considerations) -- [Tree-shakeable API](#tree-shakeable-api) (coming soon) - - -## Installation - -``` -npm install temporal-polyfill -``` - -Import as an ES module without side effects: - -```js -import { Temporal } from 'temporal-polyfill' - -console.log(Temporal.Now.zonedDateTimeISO().toString()) -``` - -Or, import globally: - -```js -import 'temporal-polyfill/global' - -console.log(Temporal.Now.zonedDateTimeISO().toString()) -``` - -Use a ` - -``` - - -## Comparison with `@js-temporal/polyfill` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Package - temporal-polyfill - - @js-temporal/polyfill -
Repo - - github.com/fullcalendar/temporal-polyfill - - - - github.com/js-temporal/temporal-polyfill - -
CreatorsFullCalendar lead dev arshawChampions of the Temporal proposal
Minified+gzip size ✝20.0 kB43.2 kB (+116%)
Minified-only size ✝58.7 kB206.0 kB (+251%)
Spec compliance - Strict compliance for common API.
- Functional compliance for custom-implemented Calendar/TimeZone,
- though internal calling order may differ (more info). -
- Strict compliance for entire API. -
Spec date - Nov 2023 (latest) - - May 2023 -
BigInt ApproachInternally avoids BigInt operations altogetherInternally relies on JSBI
Global usage in ESM/CJS -
import 'temporal-polyfill/global'; // ESM
-require('temporal-polyfill/global'); // CJS
-
Not currently possible
Global usage directly in browser -
<script>
-  Temporal.Now.zonedDateTimeISO()
-</script>
-
-
<script>
-  temporal.Temporal.Now.zonedDateTimeISO()
-</script>
-
- -✝ Compares [global.min.js](https://cdn.jsdelivr.net/npm/temporal-polyfill@0.2.0/global.min.js) with [index.esm.js](https://cdn.jsdelivr.net/npm/@js-temporal/polyfill@0.4.4/dist/index.esm.js), which are similarly transpiled. - - -## Spec Compliance - -All calendar systems (ex: `chinese`, `persian`) and time zones are supported. - -Compliance with the latest version of the Temporal spec (Nov 2023) is near-perfect with the following intentional deviations: - -- `Duration::toString` does not display units greater than `Number.MAX_SAFE_INTEGER` according to spec. Precision is chosen differently. -- *Custom implementations* of Calendars and TimeZones are queried differently. Only affects those subclassing built-in classes, which is extremely rare. See the CALLING entries in the [test-ignore file](https://github.com/fullcalendar/temporal/blob/main/packages/temporal-polyfill/scripts/test-config/expected-failures.txt). -- There are believed to be 3 bugs in the Temporal spec itself, one of which [has been filed](https://github.com/tc39/proposal-temporal/issues/2742). See SPEC-BUG entries in the [test-ignore file](https://github.com/fullcalendar/temporal/blob/main/packages/temporal-polyfill/scripts/test-config/expected-failures.txt). -- Canonicalization of time zone IDs is simplified, leveraging the built-in `Intl` API. -- `Intl.DateTimeFormat` has not been polyfilled to accept number-offset values for the `timeZone` option. -- Method descriptors and `Function::length` are not strictly compliant due to ES-related space-saving techniques. - -The [Official ECMAScript Conformance Test Suite](https://github.com/tc39/test262) has: - -- 6811 *total* Temporal-related test files -- 6138 *passed* by `temporal-polyfill` -- 495 *ignored* due to superficial method descriptor compliance -- 178 *ignored* due to other aforementioned intentional deviations - - -## Browser Support - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Minimum required browsers: -
Chrome 60
(Jul 2017)
Firefox 55
(Aug 2017)
Safari 11.1
(Mar 2018)
Safari iOS 11.3
(Mar 2018)
Edge 79
(Jan 2020)
Node.js 14
(Apr 2020)
- If you transpile, you can support older browsers down to: -
Chrome 57
(Mar 2017)
Firefox 52
(Mar 2017)
Safari 10
(Sep 2016)
Safari iOS 10
(Sep 2016)
Edge 15
(Apr 2017)
Node.js 14
(Apr 2020)
- - - - -## BigInt Considerations - -This polyfill works fine in environments that do not support [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). - -However, to use methods that accept/emit them, your browser [must support BigInt](https://caniuse.com/bigint). - -Here's how to sidestep this browser compatibility issue: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
❌ Avoid microseconds/nanoseconds✅ Use milliseconds instead
instant.epochMicrosecondsinstant.epochMilliseconds
instant.epochNanosecondsinstant.epochMilliseconds
Temporal.Instant.fromEpochMicroseconds(micro)Temporal.Instant.fromEpochMilliseconds(milli)
Temporal.Instant.fromEpochNanoseconds(nano)Temporal.Instant.fromEpochMilliseconds(milli)
new Temporal.Instant(nano)Temporal.Instant.fromEpochMilliseconds(milli)
zonedDateTime.epochMicrosecondszonedDateTime.epochMilliseconds
zonedDateTime.epochNanosecondszonedDateTime.epochMilliseconds
- - new Temporal.ZonedDateTime(nano, tz, cal) - - - - Temporal.Instant.fromEpochMilliseconds(milli)
-   .toZonedDateTimeISO() // or toZonedDateTime -
-
- - -## Tree-shakeable API - -🚧 Coming Soon - -For library authors and other devs who are hyper-concerned about bundle size, `temporal-polyfill` will be providing an alternate API designed for tree-shaking. - -```js -import * as ZonedDateTime from 'temporal-polyfill/fns/zoneddatetime' - -const zdt = ZonedDateTime.from({ year: 2024, month: 1, day: 1 }) -const s = ZonedDateTime.toString(zdt) // not how you normally call a method! -``` From e94f47a2ad27b4e438038eb180ac2e444c269a0f Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 7 Jan 2024 04:23:12 -0500 Subject: [PATCH 801/805] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e1bee42..144fd987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ most notably changes to "user-visible operations". - In NPM directory, all files are now top-level as opposed to within `dist/`. Thus, the [jsDelivr URL](https://cdn.jsdelivr.net/npm/temporal-polyfill@0.2.0/global.min.js) has changed. - Fixed bugs: #9, #12, #13, #21 - Improved README content, including comparison with @js-temporal (#22) +- Renamed github repo to fullcalendar/temporal-polyfill v0.1.1 (2023-02-15) From b3175027481b7ffa6702bf855cebc418f4af0d55 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sun, 7 Jan 2024 04:30:18 -0500 Subject: [PATCH 802/805] readme rendering tweaks --- README.md | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index d7302ef6..fddb7dbc 100644 --- a/README.md +++ b/README.md @@ -116,22 +116,18 @@ Use a `