diff --git a/src/custom-calendars/nepaliCalendar.ts b/src/custom-calendars/nepaliCalendar.ts index 92d5ac0..fa65533 100644 --- a/src/custom-calendars/nepaliCalendar.ts +++ b/src/custom-calendars/nepaliCalendar.ts @@ -64,12 +64,18 @@ class NepaliCalendar extends Temporal.Calendar { * * A custom implementation of these methods is used to convert the calendar-space arguments to the ISO calendar. */ - dateFromFields(fields: CalendarYMD): Temporal.PlainDate { - const { year, day, month } = _nepaliToIso({ - year: fields.year, - month: fields.month, - day: fields.day, - }) + dateFromFields( + fields: CalendarYMD, + options: Temporal.AssignmentOptions + ): Temporal.PlainDate { + const { year, day, month } = _nepaliToIso( + { + year: fields.year, + month: fields.month, + day: fields.day, + }, + options + ) return new Temporal.PlainDate(year, month, day, this) } yearMonthFromFields(fields: CalendarYMD): Temporal.PlainYearMonth { @@ -96,7 +102,10 @@ const lastSupportedNepaliYear = Number( supportedNepaliYears[supportedNepaliYears.length - 1] ) -const _nepaliToIso = (fields: { day: number; year: number; month: number }) => { +const _nepaliToIso = ( + fields: { day: number; year: number; month: number }, + { overflow }: Temporal.AssignmentOptions = {} +) => { let { year: nepaliYear } = fields if ( @@ -109,6 +118,15 @@ const _nepaliToIso = (fields: { day: number; year: number; month: number }) => { } const { month: nepaliMonth, day: nepaliDay = 1 } = fields + if ( + overflow === 'reject' && + (nepaliMonth < 1 || + nepaliMonth > 12 || + nepaliDay > NEPALI_CALENDAR_DATA[nepaliYear][nepaliMonth]) + ) { + throw new Error('Invalid date in Nepali calendar') + } + let gregorianDayOfYear = 0 let monthCounter = nepaliMonth diff --git a/src/utils/validate-date-string.ts b/src/utils/validate-date-string.ts index 084a060..8105192 100644 --- a/src/utils/validate-date-string.ts +++ b/src/utils/validate-date-string.ts @@ -3,53 +3,7 @@ import { Temporal } from '@js-temporal/polyfill' import { dhis2CalendarsMap } from '../constants/dhis2CalendarsMap' import type { SupportedCalendar } from '../types' import { extractDatePartsFromDateString } from './extract-date-parts-from-date-string' -import { getCustomCalendarIfExists } from './helpers' - -type ValidateNepaliDateFn = ( - year: number, - month: number, - day: number -) => ValidationResult - -const validateNepaliDate: ValidateNepaliDateFn = (year, month, day) => { - const nepaliYearData = NEPALI_CALENDAR_DATA[year] - if (!nepaliYearData) { - return { - error: true, - validationCode: DateValidationResult.INVALID_DATE_IN_CALENDAR, - validationText: i18n.t(`Year {{year}} is out of range.`, { year }), - } - } - - if (month < 1 || month > 12) { - return { - error: true, - validationCode: DateValidationResult.INVALID_DATE_IN_CALENDAR, - validationText: i18n.t( - `Month {{month}} is out of range | 1 <= {{month}} <= 12.`, - { month } - ), - } - } - - const daysInMonth = nepaliYearData[month] - - if (day < 1 || day > daysInMonth) { - return { - error: true, - validationCode: DateValidationResult.INVALID_DATE_IN_CALENDAR, - validationText: i18n.t( - `Day {{day}} is out of range | 1 <= {{day}} <= {{daysInMonth}}.`, - { day, daysInMonth } - ), - } - } - - return { - error: false, - warning: false, - } -} +import { getCustomCalendarIfExists, isCustomCalendar } from './helpers' type ValidationOptions = { calendar?: SupportedCalendar @@ -136,20 +90,17 @@ export const validateDateString: ValidateDateStringFn = ( validationText: e?.message, } } - if (resolvedCalendar.toString() === 'nepali') { - // ToDo: double check why nepali can't just be handle with Temporal.PlainDate.from - return validateNepaliDate( - dateParts.year, - dateParts.month, - dateParts.day - ) - } let date: Temporal.PlainDate // Will throw if the year, month or day is out of range try { - date = Temporal.PlainDate.from( + date = isCustomCalendar(resolvedCalendar) + ? Temporal.Calendar.from(resolvedCalendar).dateFromFields( + dateParts, + { overflow: 'reject' } + ) // need to be handled separately for custom calendars + : Temporal.PlainDate.from( { ...dateParts, calendar: resolvedCalendar }, { overflow: 'reject' } )