diff --git a/package.json b/package.json index 8cda336..41675a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@prayersconnect/configs", - "version": "3.6.0", + "version": "3.7.0", "description": "Country specific configuration for Prayers Connect", "main": "./lib/index.js", "typings": "./lib/index.d.ts", @@ -17,6 +17,7 @@ "build": "tsc --build tsconfig.json", "prepare": "husky install", "test": "jest", + "test:update": "jest --updateSnapshot", "test:watch": "jest --watch" }, "devDependencies": { @@ -41,7 +42,7 @@ "lib": "lib" }, "dependencies": { - "adhan-extended": "^5.0.2", + "adhan-extended": "^6.1.0", "luxon": "^3.3.0" } } diff --git a/src/adhan/calculate.ts b/src/adhan/calculate.ts index 8de6371..3847d6a 100644 --- a/src/adhan/calculate.ts +++ b/src/adhan/calculate.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-case-declarations */ import { CalculationMethod, Coordinates, @@ -62,6 +63,13 @@ const getMethodFromShortName = (shortName: string) => { return gaiae; case 'muis': return CalculationMethod.Singapore(); + case 'algeria': + const algeria = CalculationMethod.Other(); + algeria.fajrAngle = 18; + algeria.ishaAngle = 17; + algeria.methodAdjustments.sunset = 3; + algeria.methodAdjustments.maghrib = 3; + return algeria; default: return CalculationMethod.MuslimWorldLeague(); @@ -115,7 +123,7 @@ export function calculateAdhan( const coordinates = new Coordinates(coords.latitude, coords.longitude); const params = getCalculationParams(method, asrMethod, extras); - const timezone = date.zoneName; //ref: https://github.com/batoulapps/adhan-js#prayer-times + const timezone = date.zoneName || 'UTC'; //ref: https://github.com/batoulapps/adhan-js#prayer-times const calculated = new PrayerTimes(coordinates, date.toJSDate(), params); return { fajr: DateTime.fromJSDate(calculated.fajr).setZone(timezone), diff --git a/src/adhan/calculation-methods.test.ts b/src/adhan/calculation-methods.test.ts index dd7ee29..c35f9ba 100644 --- a/src/adhan/calculation-methods.test.ts +++ b/src/adhan/calculation-methods.test.ts @@ -16,10 +16,10 @@ describe('calculatePrayerTimes', () => { }, timezone: 'Europe/London', calculationMethod: 'MoonsightingCommittee', - asrCalculation: 'hanafi', + asrCalculation: 'Hanafi', highLatitudeRule: 'middleofthenight', shafaq: 'general', - midnightMethod: 'Standard', + midnightMethod: 'SunsetToSunrise', }, makkah: { location: { @@ -28,8 +28,8 @@ describe('calculatePrayerTimes', () => { }, timezone: 'Asia/Riyadh', calculationMethod: 'UmmAlQura', - asrCalculation: 'shafi', - midnightMethod: 'Standard', + asrCalculation: 'Standard', + midnightMethod: 'SunsetToSunrise', highLatitudeRule: 'middleofthenight', }, dubai: { @@ -39,9 +39,9 @@ describe('calculatePrayerTimes', () => { }, timezone: 'Asia/Dubai', calculationMethod: 'Dubai', - asrCalculation: 'shafi', + asrCalculation: 'Standard', highLatitudeRule: 'middleofthenight', - midnightMethod: 'Standard', + midnightMethod: 'SunsetToSunrise', }, turkey: { location: { @@ -50,9 +50,9 @@ describe('calculatePrayerTimes', () => { }, timezone: 'Europe/Istanbul', calculationMethod: 'Turkey', - asrCalculation: 'shafi', + asrCalculation: 'Standard', highLatitudeRule: 'middleofthenight', - midnightMethod: 'Standard', + midnightMethod: 'SunsetToSunrise', }, }; diff --git a/src/adhan/calculation-methods.ts b/src/adhan/calculation-methods.ts index ec1acfb..a062048 100644 --- a/src/adhan/calculation-methods.ts +++ b/src/adhan/calculation-methods.ts @@ -13,19 +13,27 @@ import { CalculationSettings, CalculationMethodEntry, PrayerTimesOptions, + CalculationMethodKey, + AsrCalculationType, } from './types'; import { DateTime } from 'luxon'; import { PrayerAndSunnahTimes } from './prayer-and-sunnah-times'; -export const CalculationMethods: Record = { +export const CalculationMethods: Record< + CalculationMethodKey, + CalculationMethodEntry +> = { Custom: { + calculationKey: 'Custom', label: 'Custom', info: 'Sets a Fajr angle of 0 and an Isha angle of 0.' as const, get: CalculationMethod.Other, }, Algeria: { + calculationKey: 'Algeria', label: 'Ministry of Religious Affairs and Wakfs, Algeria', + otherLabel: 'Ministry of Religious Affairs and Wakfs', info: 'Uses Fajr angle of 18, Isha angle of 17, + 3min maghrib', get: () => { const params = new CalculationParameters('Other', 18.0, 17.0); @@ -39,12 +47,15 @@ export const CalculationMethods: Record = { }, Brunei: { + calculationKey: 'Brunei', label: 'Kementrian Hal Ehwal Ugama (Brunei Darussalam)', + otherLabel: 'Brunei Darussalam', info: 'Uses Fajr angle of 20 and Isha angle of 18', get: () => new CalculationParameters('Other', 20.0, 18.0), }, Dubai: { + calculationKey: 'Dubai', label: 'The Gulf Region (Dubai)', info: 'Uses Fajr and Isha angles of 18.2 degrees.', url: 'https://www.awqaf.gov.ae/en/Pages/PrayerTimes.aspx', @@ -52,6 +63,7 @@ export const CalculationMethods: Record = { }, Egyptian: { + calculationKey: 'Egyptian', label: 'Egyptian General Survey Authority', info: 'Uses Fajr angle of 19.5 and an Isha angle of 17.5' as const, get: CalculationMethod.Egyptian, @@ -59,6 +71,7 @@ export const CalculationMethods: Record = { }, France: { + calculationKey: 'France', label: 'Union Organization Islamic de France', info: 'Uses a Fajr angle of 12 and an Isha angle of 12 by default but by setting alternativeCalculation to 15 or 18 it will updated accordingly.', region: 'France region' as const, @@ -81,51 +94,63 @@ export const CalculationMethods: Record = { }, Gulf: { + calculationKey: 'Gulf', label: 'Gulf region', info: 'Modified version of Umm al-Qura that uses a Fajr angle of 19.5.', get: () => new CalculationParameters('Other', 19.5, undefined, 90), }, Jafari: { + calculationKey: 'Jafari', label: 'Shia Ithna Ashari, Leva Institute, Qum', + otherLabel: 'Leva Institute, Qum', info: 'Uses Fajr angle of 16, Maghrib angle of 4 and Isha angle of 14', get: () => new CalculationParameters('Other', 16.0, 14.0, 0, 4.0), }, Karachi: { + calculationKey: 'Karachi', label: 'University of Islamic Sciences, Karachi', + otherLabel: 'University of Islamic Sciences', info: 'Uses Fajr angle of 18 and an Isha angle of 18' as const, get: CalculationMethod.Karachi, region: 'Pakistan, Bangladesh, India, Afghanistan, Parts of Europe' as const, }, - Kemenag: { + Indonesia: { + calculationKey: 'Indonesia', label: 'Kementrian Agama Republik Indonesia (KEMENAG)', + otherLabel: 'Kementrian Agama Republik Indonesia', info: 'Uses Fajr angle of 20.0 and Isha angle of 18', get: () => new CalculationParameters('Other', 20.0, 18.0), }, Kuwait: { + calculationKey: 'Kuwait', label: 'Kuwait', info: 'Uses a Fajr angle of 18 and an Isha angle of 17.5', get: CalculationMethod.Kuwait, }, MoonsightingCommittee: { + calculationKey: 'MoonsightingCommittee', label: 'Moonsighting Committee', info: 'Uses a Fajr angle of 18 and an Isha angle of 18. Also uses seasonal adjustment values.' as const, get: CalculationMethod.MoonsightingCommittee, + region: 'UK', }, MuslimWorldLeague: { + calculationKey: 'MuslimWorldLeague', label: 'Muslim World League', info: 'Uses Fajr angle of 18 and an Isha angle of 17' as const, get: CalculationMethod.MuslimWorldLeague, region: 'Europe, The Far East, Parts of the USA', }, - NorthAmerica: { + IslamicSocietyOfNorthAmerica: { + calculationKey: 'IslamicSocietyOfNorthAmerica', label: 'Islamic Society of North America - ISNA', info: 'Uses a Fajr angle of 15 and an Isha angle of 15.' as const, region: 'Parts of the USA, Canada, Parts of the UK' as const, @@ -133,6 +158,7 @@ export const CalculationMethods: Record = { }, Qatar: { + calculationKey: 'Qatar', label: 'Qatar', info: 'Modified version of Umm al-Qura that uses a Fajr angle of 18.', url: 'https://www.qatarch.com/home', @@ -140,12 +166,14 @@ export const CalculationMethods: Record = { }, Russia: { + calculationKey: 'Russia', label: 'Spiritual Administration of Muslims of Russia', info: 'Uses a Fajr angle of 16 and an Isha angle of 15.', get: () => new CalculationParameters('Other', 16.0, 15.0), }, Singapore: { + calculationKey: 'Singapore', label: 'Singapore', info: 'Uses a Fajr angle of 20 and an Isha angle of 18' as const, get: CalculationMethod.Singapore, @@ -154,12 +182,21 @@ export const CalculationMethods: Record = { }, Tehran: { + calculationKey: 'Tehran', label: 'Shia, Institute of Geophysics, University of Tehran', info: 'Uses Fajr angle of 17.7, Maghrib angle of 4.5 and Isha angle of 14', get: CalculationMethod.Tehran, }, + Tunisia: { + calculationKey: 'Tunisia', + label: 'Ministry of Religious Affairs of Tunisia', + info: 'Uses Fajr angle of 18 and Isha angle of 18', + get: () => new CalculationParameters('Other', 18.0, 18.0), + }, + Turkey: { + calculationKey: 'Turkey', label: 'Presidency of Religious Affairs, Turkey', info: 'Uses a Fajr angle of 18 and an Isha angle of 17.', url: 'https://kurul.diyanet.gov.tr/Karar-Mutalaa-Cevap/4093/45-enlemin-otesinde-namaz-vakitleri', @@ -200,9 +237,10 @@ export const CalculationMethods: Record = { prayerTimes.isha && prayerTimes.maghrib && prayerTimes.sunrise && + prayerTimes.dateTime.monthLong && monthsBetween.includes(prayerTimes.dateTime.monthLong) ) { - let intervalTime = + const intervalTime = prayerTimes.isha.diff(prayerTimes.maghrib).as('milliseconds') + 10 * 60 * 1000; @@ -215,6 +253,7 @@ export const CalculationMethods: Record = { }, UmmAlQura: { + calculationKey: 'UmmAlQura', label: 'Umm al-Qura University, Makkah', info: 'Uses a Fajr angle of 18.5 and an Isha interval of 90 minutes.\nNote: You should add a +30 minute custom adjustment of Isha during Ramadan.' as const, url: 'https://www.ummulqura.org.sa/Index.aspx' as const, @@ -346,9 +385,11 @@ function setHighLatitudeRule( function setMadhab( prayerTimeOptions: PrayerTimesOptions, - asrCalcSetting: typeof Madhab[keyof typeof Madhab] = Madhab.Shafi + asrCalcSetting: AsrCalculationType = 'Standard' ) { - prayerTimeOptions.calculationParameters.madhab = asrCalcSetting; + const type = + asrCalcSetting.toLowerCase() === 'hanafi' ? Madhab.Hanafi : Madhab.Shafi; + prayerTimeOptions.calculationParameters.madhab = type; } function setShafaq( diff --git a/src/adhan/prayer-and-sunnah-times.ts b/src/adhan/prayer-and-sunnah-times.ts index 7742d0b..da378cf 100644 --- a/src/adhan/prayer-and-sunnah-times.ts +++ b/src/adhan/prayer-and-sunnah-times.ts @@ -10,7 +10,7 @@ import { DateTime } from 'luxon'; import { IAdhanCalculatedType, PrayerTimesOptions, - formatOptions, + FormatOptions, } from './types'; import { ValueOf } from 'adhan-extended/lib/types/TypeUtils'; @@ -148,7 +148,7 @@ export class PrayerAndSunnahTimes { return this.prayerTimes.nextPrayer(date.toJSDate()); } - format(options: formatOptions): IAdhanCalculatedType { + format(options: FormatOptions): IAdhanCalculatedType { const timezone = options.timezone || 'UTC'; const formatString = options.use24HourFormat ? 'HH:mm' : 'h:mm a'; diff --git a/src/adhan/types.ts b/src/adhan/types.ts index a2a60bb..6077e53 100644 --- a/src/adhan/types.ts +++ b/src/adhan/types.ts @@ -1,16 +1,16 @@ import { - Madhab, MidnightMethod, HighLatitudeRule, Shafaq, CalculationParameters, Coordinates, - PrayerTimes, Rounding, } from 'adhan-extended'; import { DateTime } from 'luxon'; import { PrayerAndSunnahTimes } from './prayer-and-sunnah-times'; +export { MidnightMethod } from 'adhan-extended'; + export interface ICoords { latitude: number; longitude: number; @@ -34,8 +34,33 @@ export interface IAdhanCalculated { isha: DateTime; } +export type CalculationMethodKey = + | 'Custom' + | 'Algeria' + | 'Brunei' + | 'Dubai' + | 'Egyptian' + | 'France' + | 'Gulf' + | 'IslamicSocietyOfNorthAmerica' + | 'Jafari' + | 'Karachi' + | 'Indonesia' + | 'Kuwait' + | 'MoonsightingCommittee' + | 'MuslimWorldLeague' + | 'Qatar' + | 'Russia' + | 'Singapore' + | 'Tehran' + | 'Tunisia' + | 'Turkey' + | 'UmmAlQura'; + export type CalculationMethodEntry = { + calculationKey: CalculationMethodKey; label: string; + otherLabel?: string; info: string; url?: string; region?: string; @@ -69,7 +94,7 @@ export type PrayerTimesOptions = { calculationParameters: CalculationParameters; coordinates: Coordinates; calculationMethod?: CalculationMethodEntry; - midnightMethod: keyof typeof MidnightMethod; + midnightMethod?: keyof typeof MidnightMethod; /** Ajustments in minutes */ midnightAdjustment: number; }; @@ -88,6 +113,16 @@ export enum Prayer { Tahajjud = 'tahajjud', } +export enum JamaatPrayer { + Fajr = 'fajr', + Dhuhr = 'dhuhr', + Asr = 'asr', + Maghrib = 'maghrib', + Isha = 'isha', + Eid = 'eid', + Jumma = 'jumma', +} + export const NonPrayer = [ Prayer.Sunrise, Prayer.Sunset, @@ -109,47 +144,29 @@ export const PrayersInOrder = [ Prayer.Tahajjud, ]; -export type formatOptions = { +export type FormatOptions = { use24HourFormat: boolean; timezone?: string; }; -// FIX: Typescript intelisence -// export type CalculationMethodKey = keyof typeof CalculationMethods; -export type CalculationMethodKey = - | 'Custom' - | 'Algeria' - | 'Brunei' - | 'Dubai' - | 'Egyptian' - | 'France' - | 'Gulf' - | 'Jafari' - | 'Karachi' - | 'Kemenag' - | 'Kuwait' - | 'MoonsightingCommittee' - | 'MuslimWorldLeague' - | 'NorthAmerica' - | 'Qatar' - | 'Russia' - | 'Singapore' - | 'Tehran' - | 'Turkey' - | 'UmmAlQura'; +export type AsrCalculationType = 'Standard' | 'Hanafi'; export type CalculationSettings = { - location: Coordinates | undefined; + location: ICoords | undefined; calculationMethod: CalculationMethodKey; - asrCalculation: typeof Madhab[keyof typeof Madhab]; - midnightMethod: keyof typeof MidnightMethod; + asrCalculation: AsrCalculationType; // Used alternative calculation methods i.e france 12, 15, 18 degrees alternativeCalculation?: string; timezone?: string; + midnightMethod?: keyof typeof MidnightMethod; + highLatitudeRule?: - | typeof HighLatitudeRule[keyof typeof HighLatitudeRule] + | typeof HighLatitudeRule[keyof Omit< + typeof HighLatitudeRule, + 'recommended' + >] | undefined; shafaq?: typeof Shafaq[keyof typeof Shafaq]; polarResolution?: string; @@ -173,4 +190,5 @@ export type CalculationSettings = { // calendar hijriDateAdjustment?: number; + jummahReminder?: boolean; }; diff --git a/src/calc-methods/__snapshots__/index.test.ts.snap b/src/calc-methods/__snapshots__/index.test.ts.snap index c59f080..3944786 100644 --- a/src/calc-methods/__snapshots__/index.test.ts.snap +++ b/src/calc-methods/__snapshots__/index.test.ts.snap @@ -129,6 +129,14 @@ exports[`calc-methods getCalcMethods returns all methods 1`] = ` "isha": 18, }, }, + { + "label": "Ministry of Religious Affairs and Wakfs, Algeria", + "name": "algeria", + "values": { + "fajr": 18, + "isha": 17, + }, + }, ] `; @@ -185,6 +193,13 @@ exports[`calc-methods getCalcMethods returns all methods: values for Tehran 1`] } `; +exports[`calc-methods getCalcMethods returns all methods: values for algeria 1`] = ` +{ + "fajr": 18, + "isha": 17, +} +`; + exports[`calc-methods getCalcMethods returns all methods: values for france-15-degree 1`] = ` { "fajr": 15, diff --git a/src/calc-methods/index.ts b/src/calc-methods/index.ts index 4ffd6bf..ff2ec1f 100644 --- a/src/calc-methods/index.ts +++ b/src/calc-methods/index.ts @@ -1,5 +1,7 @@ import methodsData, { CalculationMethod } from './methods'; import { getConfigByISOName } from '../countries'; +import { CalculationMethodEntry, CalculationSettings } from '../adhan/types'; +import { CalculationMethods } from '../adhan/calculation-methods'; export interface IMethodResponse { method: string; @@ -20,6 +22,10 @@ export const getCalcMethods = (): CalculationMethod[] => { return methodsData; }; +export const getCalculationMethods = (): CalculationMethodEntry[] => { + return Object.values(CalculationMethods); +}; + /** * Returns the calculation method and asr method for a given country's ISO name * @param country ISO Country Name @@ -38,6 +44,22 @@ export const getCalcMethodsByCountry = ( }; }; +export const getCalculationMethodByCountry = ( + country: string | undefined +): CalculationSettings | null => { + if (!country) { + return null; + } + const countryConf = getConfigByISOName(country); + + return { + ...countryConf.calculationSettings, + calculationMethod: countryConf.calculationSettings.calculationMethod, + asrCalculation: + countryConf.calculationSettings.asrCalculation || 'Standard', + }; +}; + export const getJuristicMethods = (): IJuristicMethod[] => { return [ { name: 'Standard', label: 'Shafii, Maliki, Jafari & Hanbali' }, diff --git a/src/calc-methods/methods.ts b/src/calc-methods/methods.ts index e507314..952af00 100644 --- a/src/calc-methods/methods.ts +++ b/src/calc-methods/methods.ts @@ -130,4 +130,12 @@ export default [ isha: 18, }, }, + { + name: 'algeria', + label: 'Ministry of Religious Affairs and Wakfs, Algeria', + values: { + fajr: 18, + isha: 17, + }, + }, ] as CalculationMethod[]; diff --git a/src/countries/__snapshots__/index.test.ts.snap b/src/countries/__snapshots__/index.test.ts.snap index 80337ad..b49c790 100644 --- a/src/countries/__snapshots__/index.test.ts.snap +++ b/src/countries/__snapshots__/index.test.ts.snap @@ -3,6 +3,10 @@ exports[`country helpers getConfigByISOName country configs Australia 1`] = ` { "alpha2Code": "AU", + "calculationSettings": { + "asrCalculation": "Hanafi", + "calculationMethod": "MuslimWorldLeague", + }, "code": 36, "features": { "education": false, @@ -30,6 +34,10 @@ exports[`country helpers getConfigByISOName country configs Australia 1`] = ` exports[`country helpers getConfigByISOName country configs Bangladesh 1`] = ` { "alpha2Code": "BD", + "calculationSettings": { + "asrCalculation": "Hanafi", + "calculationMethod": "Karachi", + }, "code": 50, "features": { "education": false, @@ -57,6 +65,10 @@ exports[`country helpers getConfigByISOName country configs Bangladesh 1`] = ` exports[`country helpers getConfigByISOName country configs Brazil 1`] = ` { "alpha2Code": "BR", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 76, "features": { "education": false, @@ -84,6 +96,10 @@ exports[`country helpers getConfigByISOName country configs Brazil 1`] = ` exports[`country helpers getConfigByISOName country configs Canada 1`] = ` { "alpha2Code": "CA", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "IslamicSocietyOfNorthAmerica", + }, "code": 124, "features": { "education": false, @@ -111,6 +127,10 @@ exports[`country helpers getConfigByISOName country configs Canada 1`] = ` exports[`country helpers getConfigByISOName country configs DK 1`] = ` { "alpha2Code": "DK", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 208, "features": { "education": false, @@ -138,6 +158,10 @@ exports[`country helpers getConfigByISOName country configs DK 1`] = ` exports[`country helpers getConfigByISOName country configs DZ 1`] = ` { "alpha2Code": "DZ", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 12, "features": { "education": false, @@ -165,6 +189,10 @@ exports[`country helpers getConfigByISOName country configs DZ 1`] = ` exports[`country helpers getConfigByISOName country configs Egypt 1`] = ` { "alpha2Code": "EG", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "Egyptian", + }, "code": 818, "features": { "education": false, @@ -192,6 +220,10 @@ exports[`country helpers getConfigByISOName country configs Egypt 1`] = ` exports[`country helpers getConfigByISOName country configs France 1`] = ` { "alpha2Code": "FR", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "France", + }, "code": 250, "features": { "education": false, @@ -219,6 +251,10 @@ exports[`country helpers getConfigByISOName country configs France 1`] = ` exports[`country helpers getConfigByISOName country configs Germany 1`] = ` { "alpha2Code": "DE", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 276, "features": { "education": false, @@ -246,6 +282,10 @@ exports[`country helpers getConfigByISOName country configs Germany 1`] = ` exports[`country helpers getConfigByISOName country configs India 1`] = ` { "alpha2Code": "IN", + "calculationSettings": { + "asrCalculation": "Hanafi", + "calculationMethod": "Karachi", + }, "code": 356, "features": { "education": false, @@ -273,6 +313,10 @@ exports[`country helpers getConfigByISOName country configs India 1`] = ` exports[`country helpers getConfigByISOName country configs Ireland 1`] = ` { "alpha2Code": "IE", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 372, "features": { "education": false, @@ -300,6 +344,10 @@ exports[`country helpers getConfigByISOName country configs Ireland 1`] = ` exports[`country helpers getConfigByISOName country configs Italy 1`] = ` { "alpha2Code": "IT", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 380, "features": { "education": false, @@ -327,6 +375,10 @@ exports[`country helpers getConfigByISOName country configs Italy 1`] = ` exports[`country helpers getConfigByISOName country configs Malaysia 1`] = ` { "alpha2Code": "MY", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 458, "features": { "education": false, @@ -354,6 +406,10 @@ exports[`country helpers getConfigByISOName country configs Malaysia 1`] = ` exports[`country helpers getConfigByISOName country configs Mexico 1`] = ` { "alpha2Code": "MX", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 484, "features": { "education": false, @@ -381,6 +437,10 @@ exports[`country helpers getConfigByISOName country configs Mexico 1`] = ` exports[`country helpers getConfigByISOName country configs Netherlands 1`] = ` { "alpha2Code": "NL", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 528, "features": { "education": false, @@ -408,6 +468,10 @@ exports[`country helpers getConfigByISOName country configs Netherlands 1`] = ` exports[`country helpers getConfigByISOName country configs New Zealand 1`] = ` { "alpha2Code": "NZ", + "calculationSettings": { + "asrCalculation": "Hanafi", + "calculationMethod": "MuslimWorldLeague", + }, "code": 554, "features": { "education": false, @@ -435,6 +499,10 @@ exports[`country helpers getConfigByISOName country configs New Zealand 1`] = ` exports[`country helpers getConfigByISOName country configs Nigeria 1`] = ` { "alpha2Code": "NG", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 566, "features": { "education": false, @@ -462,6 +530,10 @@ exports[`country helpers getConfigByISOName country configs Nigeria 1`] = ` exports[`country helpers getConfigByISOName country configs Pakistan 1`] = ` { "alpha2Code": "PK", + "calculationSettings": { + "asrCalculation": "Hanafi", + "calculationMethod": "Karachi", + }, "code": 586, "features": { "education": false, @@ -489,6 +561,10 @@ exports[`country helpers getConfigByISOName country configs Pakistan 1`] = ` exports[`country helpers getConfigByISOName country configs Russia 1`] = ` { "alpha2Code": "RU", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "Russia", + }, "code": 643, "features": { "education": false, @@ -516,6 +592,10 @@ exports[`country helpers getConfigByISOName country configs Russia 1`] = ` exports[`country helpers getConfigByISOName country configs Saudi Arabia 1`] = ` { "alpha2Code": "SA", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "UmmAlQura", + }, "code": 682, "features": { "education": false, @@ -543,6 +623,10 @@ exports[`country helpers getConfigByISOName country configs Saudi Arabia 1`] = ` exports[`country helpers getConfigByISOName country configs Singapore 1`] = ` { "alpha2Code": "SG", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "Singapore", + }, "code": 702, "features": { "education": false, @@ -570,6 +654,10 @@ exports[`country helpers getConfigByISOName country configs Singapore 1`] = ` exports[`country helpers getConfigByISOName country configs Spain 1`] = ` { "alpha2Code": "ES", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 724, "features": { "education": false, @@ -597,6 +685,10 @@ exports[`country helpers getConfigByISOName country configs Spain 1`] = ` exports[`country helpers getConfigByISOName country configs Sudan 1`] = ` { "alpha2Code": "SD", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 729, "features": { "education": false, @@ -624,6 +716,10 @@ exports[`country helpers getConfigByISOName country configs Sudan 1`] = ` exports[`country helpers getConfigByISOName country configs Switzerland 1`] = ` { "alpha2Code": "CH", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 756, "features": { "education": false, @@ -651,6 +747,10 @@ exports[`country helpers getConfigByISOName country configs Switzerland 1`] = ` exports[`country helpers getConfigByISOName country configs Turkey 1`] = ` { "alpha2Code": "TR", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "Turkey", + }, "code": 792, "features": { "education": false, @@ -678,6 +778,10 @@ exports[`country helpers getConfigByISOName country configs Turkey 1`] = ` exports[`country helpers getConfigByISOName country configs Turkiye 1`] = ` { "alpha2Code": "TR", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "Turkey", + }, "code": 792, "features": { "education": false, @@ -705,6 +809,10 @@ exports[`country helpers getConfigByISOName country configs Turkiye 1`] = ` exports[`country helpers getConfigByISOName country configs United Arab Emirates 1`] = ` { "alpha2Code": undefined, + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "Gulf", + }, "code": 784, "features": { "education": false, @@ -732,6 +840,10 @@ exports[`country helpers getConfigByISOName country configs United Arab Emirates exports[`country helpers getConfigByISOName country configs United Kingdom 1`] = ` { "alpha2Code": "GB", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MoonsightingCommittee", + }, "code": 826, "features": { "education": false, @@ -759,6 +871,10 @@ exports[`country helpers getConfigByISOName country configs United Kingdom 1`] = exports[`country helpers getConfigByISOName country configs United States 1`] = ` { "alpha2Code": "US", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "IslamicSocietyOfNorthAmerica", + }, "code": 840, "features": { "education": true, @@ -786,6 +902,10 @@ exports[`country helpers getConfigByISOName country configs United States 1`] = exports[`country helpers getConfigByISOName country configs Venezuela 1`] = ` { "alpha2Code": "VE", + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": 862, "features": { "education": false, @@ -813,6 +933,10 @@ exports[`country helpers getConfigByISOName country configs Venezuela 1`] = ` exports[`country helpers getConfigByISOName returns default config if country not found 1`] = ` { "alpha2Code": undefined, + "calculationSettings": { + "asrCalculation": "Standard", + "calculationMethod": "MuslimWorldLeague", + }, "code": null, "features": { "education": false, diff --git a/src/countries/index.ts b/src/countries/index.ts index 61d7c6f..12e9c2c 100644 --- a/src/countries/index.ts +++ b/src/countries/index.ts @@ -61,17 +61,23 @@ function getCountryByPCName(name: string): ICountryOutput | null { } const hasNonAscii = (str: string): boolean => { - return /[^\x00-\x7F]/.test(str); + return /[\u0080-\uFFFF]/.test(str); }; +/** + * Get the ISO name for a country based on its non-ASCII name. + * + * @param name - The non-ASCII name of the country. + * @returns The ISO name of the country, or undefined if not found. + */ function getISONameFromNonAscii(name: string) { - const match = nonAsciiCountries.find((country) => { - if (country[0] === name) { - return country; - } - }); + // Find the matching country tuple where the first element matches the given name. + const matchingCountry = nonAsciiCountries.find( + (country) => country[0] === name + ); - return match?.[1]; + // Return the second element of the tuple, which is the ISO name. + return matchingCountry?.[1]; } export function getCountryByName(name: string): ICountryOutput | null { @@ -112,6 +118,10 @@ export function getConfigByISOName(name: string): ICountryConfig { ...defaultConfig.prayerSettings, ...countryConf?.prayerSettings, }, + calculationSettings: { + ...defaultConfig.calculationSettings, + ...countryConf?.calculationSettings, + }, mosque: { ...defaultConfig.mosque, ...countryConf.mosque, diff --git a/src/countries/prayers-configs.ts b/src/countries/prayers-configs.ts index d377a65..ebcb175 100644 --- a/src/countries/prayers-configs.ts +++ b/src/countries/prayers-configs.ts @@ -1,6 +1,7 @@ // for country code, visit https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes and get the corresponding numeric code for the country // value for calculation_method must match values defined in calculation-method.yml +import { CalculationSettings } from '../adhan/types'; import { ICountryConfigValues, ICountryFeatures, @@ -23,6 +24,10 @@ export const defaultConfig = { asr_method: 'Standard', calculation_method: 'MWL', } as IPrayerSettings, + calculationSettings: { + calculationMethod: 'MuslimWorldLeague', + asrCalculation: 'Standard', + } as CalculationSettings, mosque: { denomination: 'sunni', language_services: 'english', @@ -48,6 +53,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'ISNA', }, + calculationSettings: { + calculationMethod: 'IslamicSocietyOfNorthAmerica', + }, mosque: { language_services: 'english', denomination: 'sunni', @@ -70,6 +78,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'ISNA', }, + calculationSettings: { + calculationMethod: 'IslamicSocietyOfNorthAmerica', + }, features: { mosques: true, iqamahTimes: true, @@ -83,6 +94,10 @@ const prayersConfigs: allConfigs = { asr_method: 'Hanafi', calculation_method: 'Karachi', }, + calculationSettings: { + calculationMethod: 'Karachi', + asrCalculation: 'Hanafi', + }, mosque: { language_services: 'bangla', denomination: 'sunni', @@ -100,6 +115,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'turkey-presidency-of-religious-affairs', }, + calculationSettings: { + calculationMethod: 'Turkey', + }, mosque: { language_services: 'Türkçe', denomination: 'sunni', @@ -115,6 +133,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'MWL', }, + calculationSettings: { + calculationMethod: 'MoonsightingCommittee', + }, mosque: { language_services: 'english', denomination: 'sunni', @@ -134,6 +155,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { asr_method: 'Hanafi', }, + calculationSettings: { + asrCalculation: 'Hanafi', + }, features: { mosques: true, iqamahTimes: true, @@ -148,6 +172,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { asr_method: 'Hanafi', }, + calculationSettings: { + asrCalculation: 'Hanafi', + }, mosque: { language_services: 'english', denomination: 'sunni', @@ -164,6 +191,10 @@ const prayersConfigs: allConfigs = { calculation_method: 'Karachi', asr_method: 'Hanafi', }, + calculationSettings: { + calculationMethod: 'Karachi', + asrCalculation: 'Hanafi', + }, mosque: { language_services: 'hindi', denomination: 'sunni', @@ -179,6 +210,10 @@ const prayersConfigs: allConfigs = { calculation_method: 'Karachi', asr_method: 'Hanafi', }, + calculationSettings: { + calculationMethod: 'Karachi', + asrCalculation: 'Hanafi', + }, mosque: { language_services: 'urdu', denomination: 'sunni', @@ -190,6 +225,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'union-des-organisations-islamiques-de-france', }, + calculationSettings: { + calculationMethod: 'France', + }, features: { mosques: true, }, @@ -200,6 +238,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'Egypt', }, + calculationSettings: { + calculationMethod: 'Egyptian', + }, intl: { labelForProvince: 'Governorate', }, @@ -210,12 +251,18 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'Makkah', }, + calculationSettings: { + calculationMethod: 'UmmAlQura', + }, }, 'United Arab Emirates': { code: 784, prayerSettings: { calculation_method: 'gaiae', }, + calculationSettings: { + calculationMethod: 'Gulf', + }, }, Russia: { code: 643, @@ -223,6 +270,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'russia', }, + calculationSettings: { + calculationMethod: 'Russia', + }, mosque: { language_services: 'russian', denomination: 'sunni', @@ -345,6 +395,9 @@ const prayersConfigs: allConfigs = { prayerSettings: { calculation_method: 'muis', }, + calculationSettings: { + calculationMethod: 'Singapore', + }, }, }; diff --git a/src/countries/types.ts b/src/countries/types.ts index 9bee86e..3acc4fa 100644 --- a/src/countries/types.ts +++ b/src/countries/types.ts @@ -1,3 +1,5 @@ +import { CalculationMethodKey, CalculationSettings } from '../adhan/types'; + export interface ICountryOutput { gmap_name: string; // name defined in Google Maps. if this attribute is not defined, then the iso_name is used iso_name: string; @@ -50,6 +52,7 @@ export interface ICountryConfig { code: number | null; alpha2Code: string; //alpha-2 code from https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes prayerSettings: Required; + calculationSettings: Required; mosque: IMosqueSettings; features: ICountryFeatures; intl: Required; //internationalization params diff --git a/src/daylight-savings/__snapshots__/range-helpers.test.ts.snap b/src/daylight-savings/__snapshots__/range-helpers.test.ts.snap index c5fd8ed..aa713da 100644 --- a/src/daylight-savings/__snapshots__/range-helpers.test.ts.snap +++ b/src/daylight-savings/__snapshots__/range-helpers.test.ts.snap @@ -186,17 +186,17 @@ exports[`quick range helpers getRangesForYear New Zealand 2022 (Pacific/Auckland "2022-12-31", ], [ - "DST Period Sep, 2021 - Apr, 2022", + "DST Period Sept, 2021 - Apr, 2022", "2021-09-26", "2022-04-02", ], [ - "DST Period Sep, 2022 - Apr, 2023", + "DST Period Sept, 2022 - Apr, 2023", "2022-09-25", "2023-04-01", ], [ - "Non-DST Period Apr, 2022 - Sep, 2022", + "Non-DST Period Apr, 2022 - Sept, 2022", "2022-04-02", "2022-09-25", ], @@ -211,17 +211,17 @@ exports[`quick range helpers getRangesForYear New Zealand 2023 (Pacific/Auckland "2023-12-31", ], [ - "DST Period Sep, 2022 - Apr, 2023", + "DST Period Sept, 2022 - Apr, 2023", "2022-09-25", "2023-04-01", ], [ - "DST Period Sep, 2023 - Apr, 2024", + "DST Period Sept, 2023 - Apr, 2024", "2023-09-24", "2024-04-06", ], [ - "Non-DST Period Apr, 2023 - Sep, 2023", + "Non-DST Period Apr, 2023 - Sept, 2023", "2023-04-01", "2023-09-24", ], @@ -236,17 +236,17 @@ exports[`quick range helpers getRangesForYear New Zealand 2024 (Pacific/Auckland "2024-12-31", ], [ - "DST Period Sep, 2023 - Apr, 2024", + "DST Period Sept, 2023 - Apr, 2024", "2023-09-24", "2024-04-06", ], [ - "DST Period Sep, 2024 - Apr, 2025", + "DST Period Sept, 2024 - Apr, 2025", "2024-09-29", "2025-04-06", ], [ - "Non-DST Period Apr, 2024 - Sep, 2024", + "Non-DST Period Apr, 2024 - Sept, 2024", "2024-04-06", "2024-09-29", ], diff --git a/src/daylight-savings/index.ts b/src/daylight-savings/index.ts index 9647974..5ba251b 100644 --- a/src/daylight-savings/index.ts +++ b/src/daylight-savings/index.ts @@ -1,15 +1,14 @@ import list from './list'; function getRange(country: string, year: number) { + // Check if the country exists in the list const countryList = list[country]; - let yearList; - if (!countryList) { return null; } - yearList = countryList[year]; - + // Check if the year exists for the country + const yearList = countryList[year]; if (!yearList) { return null; } diff --git a/src/daylight-savings/range-helpers.ts b/src/daylight-savings/range-helpers.ts index 1c11d3b..4767990 100644 --- a/src/daylight-savings/range-helpers.ts +++ b/src/daylight-savings/range-helpers.ts @@ -3,12 +3,16 @@ import { DateTime } from 'luxon'; const formatString = 'yyyy-MM-dd'; -function parseDateInZone(date: string, timezone: string): DateTime { +function parseDateInZone(date: string, timezone: string | null): DateTime { + if (timezone == null) { + throw new Error('Invalid Time Zone'); + } + return DateTime.fromISO(date, { zone: timezone }).set({ hour: 3 }); } function getDSTRanges(dstStart: DateTime, dstEnd: DateTime, country: string) { - let ranges = []; + const ranges = []; if (dstStart.year === dstEnd.year) { ranges.push([ `DST Period ${dstStart.year}`, @@ -93,7 +97,9 @@ export function getRangesForYear( country: string, timezone: string ) { - const today = parseDateInZone(DateTime.local().toISODate(), timezone).set({ + const isoDate = DateTime.local().toISODate() as string; + + const today = parseDateInZone(isoDate, timezone).set({ year, }); const dstStart = parseDateInZone( @@ -106,7 +112,7 @@ export function getRangesForYear( timezone ); - let ranges = [ + const ranges = [ [ `Year ${dstStart.year}`, `${dstStart.startOf('year').toFormat(formatString)}`, diff --git a/src/index.ts b/src/index.ts index c58b19e..e796ec8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,9 @@ export { ICountryOutput } from './countries/types'; export { getCalcMethodByName, getCalcMethods, + getCalculationMethods, getCalcMethodsByCountry, + getCalculationMethodByCountry, getJuristicMethods, } from './calc-methods'; @@ -20,3 +22,21 @@ export { getDSTStart, getDSTEnd } from './daylight-savings/index'; export { getRangesForYear } from './daylight-savings/range-helpers'; export { calculateAdhan } from './adhan/calculate'; export { formatAdhanTimes } from './adhan/formatter'; + +export { calculatePrayerTimes } from './adhan/calculation-methods'; +export { + CalculationMethodKey, + CalculationSettings, + PrayerTimesOptions, + FormatOptions, + IAdhanCalculatedType, + Prayer, + NonPrayer, + PrayersInOrder, + MidnightMethod, + JamaatPrayer, + ICoords, + AsrCalculationType, +} from './adhan/types'; + +export { isFriday, isRamadan, getHijriMonth, MonthFormat } from './utils/date'; diff --git a/src/utils/date.ts b/src/utils/date.ts index ab7192b..8c55523 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,21 +1,44 @@ import { DateTime } from 'luxon'; +export enum MonthFormat { + NAME, + NUMBER, +} +export function isFriday(date: DateTime): boolean { + return date.weekday === 5; +} + export function isRamadan(date: DateTime): boolean { - return getHijriMonth(date) === 'Ramadan'; + return getHijriMonth(date, MonthFormat.NUMBER) === 9; } -function getHijriMonth(date: DateTime): string { +export function getHijriMonth( + date: DateTime, + format: MonthFormat +): string | number { + // Determine the month format for Intl.DateTimeFormat + const monthFormat = format === MonthFormat.NAME ? 'long' : 'numeric'; + const options: Intl.DateTimeFormatOptions = { year: 'numeric', - month: 'long', + month: monthFormat, day: 'numeric', }; - const format = new Intl.DateTimeFormat('en-u-ca-islamic-nu-latn', options); - const parts = format.formatToParts(date.toJSDate()); + const intlFormat = new Intl.DateTimeFormat( + 'en-u-ca-islamic-nu-latn', + options + ); + const parts = intlFormat.formatToParts(date.toJSDate()); // Extract the month from the formatted parts const monthPart = parts.find((part) => part.type === 'month'); - return monthPart ? monthPart.value : ''; + if (monthPart) { + return format === MonthFormat.NAME + ? monthPart.value + : parseInt(monthPart.value); + } + + return ''; } diff --git a/yarn.lock b/yarn.lock index 4dc6eda..a397fd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -728,10 +728,10 @@ dependencies: "@types/yargs-parser" "*" -adhan-extended@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/adhan-extended/-/adhan-extended-5.0.2.tgz#9c0f8a789ff6f010823814bc0c78752fe9b1fb66" - integrity sha512-le0yF4slZcsav1JCAR3EFlutQIeIgp/0X043FhsW2B9CsGJCK+TI4zkdVKG+m7/SeKdKmx9F2Su28s2b2VlNdA== +adhan-extended@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/adhan-extended/-/adhan-extended-6.1.0.tgz#faf7cdbe272e68f499f0a6160e9132299941f045" + integrity sha512-bnvnaiMh0l6fwax2oyFIxb66Rzu2NHiBtHTLNK/4lPoZRRweWaQa9k3J9yagmCCqCY3ySfP/UPxnfN32h9oTVw== ansi-escapes@^4.2.1: version "4.3.2"