/*
Hebcal - A Jewish Calendar Generator
Copyright (c) 1994-2020 Danny Sadinoff
Portions copyright Eyal Schachter and Michael J. Radwin
https://github.com/hebcal/hebcal-es6
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/*
* Many of the following algorithms were taken from hebrew calendar
* routines by Maimonedes, from his Mishneh Torah, and implemented by
* Nachum Dershowitz Department of Computer Science
* (217) 333-4219 University of Illinois at Urbana-Champaign
* nachum@cs.uiuedu 1304 West Springfield Avenue
* Urbana, Illinois 61801
*
* The routines were included in the emacs 19 distribution.
*
*/
import {HDate, months} from '@hebcal/hdate';
import QuickLRU from 'quick-lru';
import './locale.js'; // Adds Hebrew and Ashkenazic translations
const INCOMPLETE = 0;
const REGULAR = 1;
const COMPLETE = 2;
function yearType(hyear: number): number {
const longC = HDate.longCheshvan(hyear);
const shortK = HDate.shortKislev(hyear);
if (longC && !shortK) {
return COMPLETE;
}
if (!longC && shortK) {
return INCOMPLETE;
}
return REGULAR;
}
/** The result from `Sedra.lookup()` */
export type SedraResult = {
/**
* Name of the parsha (or parshiyot) read on
* Hebrew date, e.g. `['Noach']` or `['Matot', 'Masei']`
*/
parsha: string[];
/**
* False if this is a regular parashat HaShavua reading.
* True if it's a special holiday reading.
*/
chag: boolean;
/**
* The parsha number (or numbers) using 1-indexing.
* A `number` for a regular (single) parsha, and a `number[]`
* for a doubled parsha.
* For Parashat *Bereshit*, `num` would be equal to `1`, and for
* *Matot-Masei* it would be `[42, 43]`
* For a chag (holiday) reading, `num` will be `0`.
*/
num: number | number[];
/** The date of the Shabbat this parsha is read */
hdate: HDate;
/** true if Israel, false for Diaspora */
il: boolean;
};
/**
* Represents the weekly Torah-reading (Parashat HaShavua) schedule for an
* entire Hebrew year.
*
* The schedule depends on the year's *keviyah* — the day of week of Rosh
* Hashana, whether the year is leap, whether Cheshvan/Kislev are long or
* short, and whether the schedule is for Israel or the Diaspora (since
* Israel and the Diaspora diverge in some years when the 8th day of Pesach
* or the 2nd day of Shavuot fall on Shabbat).
*
* Prefer {@link getSedra} over
* calling this constructor directly, since both cache their results.
*
* @example
* import {Sedra, HDate, months} from '@hebcal/core';
* const sedra = new Sedra(5784, false);
* const result = sedra.lookup(new HDate(15, months.CHESHVAN, 5784));
* console.log(result.parsha); // ['Vayera']
*/
export class Sedra {
private readonly year: number;
private readonly il: boolean;
private readonly rh: number;
private readonly firstSaturday: number;
private readonly theSedraArray: readonly NumberOrString[];
private readonly yearKey: string;
/**
* Calculates the Parashat HaShavua schedule for an entire Hebrew year.
* @param hyear - Hebrew year (e.g. 5749)
* @param il - Use Israel sedra schedule (false for Diaspora)
*/
constructor(hyear: number, il: boolean) {
hyear = +hyear;
this.year = hyear;
const rh0 = new HDate(1, months.TISHREI, hyear);
const rh = (this.rh = rh0.abs());
const rhDay = rh0.getDay() + 1;
// find the first Saturday on or after Rosh Hashana
this.firstSaturday = HDate.dayOnOrBefore(6, rh + 6);
const leap = +HDate.isLeapYear(hyear);
this.il = Boolean(il);
const type = yearType(hyear);
let key = `${leap}${rhDay}${type}`;
if (types[key]) {
this.theSedraArray = types[key];
this.yearKey = key;
} else {
key = key + +this.il; // cast to num, then concat
this.theSedraArray = types[key];
this.yearKey = key;
}
if (!this.theSedraArray) {
throw new Error(`improper sedra year type ${key} calculated for ${hyear}`);
}
}
/**
* Returns the date a parsha is read this year, or `null` if it does not
* occur in this year's schedule.
*
* A doubled parsha (e.g. `'Matot-Masei'`) will only return a date in years
* where that pair is actually read together; in years where they are read
* separately, this returns `null`. Use {@link findContaining} to find the
* date a parsha is read regardless of whether it is doubled.
*
* Throws `RangeError` for an out-of-range numeric input or an invalid
* doubled-parsha pair, and `TypeError` for a malformed array argument.
* @example
* import {Sedra} from '@hebcal/core';
* const sedra = new Sedra(5784, false);
* sedra.find('Noach')?.toString(); // '6 Cheshvan 5784'
* sedra.find(1)?.toString(); // '6 Cheshvan 5784', by 0-based index
* // Matot and Masei are doubled in 5784, so the pair has a date...
* sedra.find('Matot-Masei')?.toString(); // '28 Tamuz 5784'
* sedra.find(['Matot', 'Masei'])?.toString(); // '28 Tamuz 5784'
* // ...but neither half is read on its own that year:
* sedra.find('Matot'); // null
* @param parsha if a `string`, specified with Sephardic transliterations
* like `'Noach'` or `'Matot-Masei'`. If an array, must be a 1- or 2-element
* array such as `['Noach']` or `['Matot', 'Masei']`. If a `number`, should
* be a 0-based parsha index (`0` for Bereshit, `1` for Noach) or a negative
* number for a doubled parsha (e.g. `-21` for Vayakhel-Pekudei).
* Note that this index is 0-based, unlike {@link SedraResult.num} which
* is 1-based.
*/
find(parsha: number | string | string[]): HDate | null {
if (typeof parsha === 'number') {
if (parsha >= parshiot.length || (parsha < 0 && !isValidDouble(parsha))) {
throw new RangeError(`Invalid parsha number: ${parsha}`);
}
return this.findInternal(parsha);
}
if (typeof parsha === 'string') {
const num = parsha2id.get(parsha);
if (typeof num === 'number') {
return this.find(num);
}
if (parsha.includes('-')) {
if (parsha === CHMPESACH || parsha === CHMSUKOT) {
return this.findInternal(parsha);
}
return this.find(parsha.split('-'));
}
// try to find Saturday holiday like 'Yom Kippur'
return this.findInternal(parsha);
}
if (Array.isArray(parsha)) {
const plen = parsha.length;
if ((plen !== 1 && plen !== 2) || typeof parsha[0] !== 'string') {
throw new TypeError(`Invalid parsha argument: ${JSON.stringify(parsha)}`);
}
if (plen === 1) {
return this.find(parsha[0]);
}
const p1 = parsha[0];
const p2 = parsha[1];
const num1 = parsha2id.get(p1);
const num2 = parsha2id.get(p2);
if (
typeof num1 !== 'number' ||
typeof num2 !== 'number' ||
num2 !== num1 + 1 ||
!isValidDouble(-num1)
) {
throw new RangeError(`Unrecognized parsha name: ${p1}-${p2}`);
}
return this.find(-num1);
}
return null; /* NOTREACHED */
}
private findInternal(parsha: NumberOrString): HDate | null {
const idx = this.theSedraArray.indexOf(parsha);
if (idx === -1) {
return null; // doesn't occur this year
}
return new HDate(this.firstSaturday + idx * 7);
}
/**
* Returns the date a parsha is read this year, looking through both
* single and doubled forms.
*
* For example, if `'Matot'` is read individually this year, this returns
* its date; if it is read as part of `'Matot-Masei'` this year, this
* returns the date of `'Matot-Masei'` (and similarly for `'Masei'`).
* Conversely, asking for `'Matot-Masei'` in a year where they are split
* will return the date of `'Matot'` alone.
* @example
* import {Sedra} from '@hebcal/core';
* // Matot and Masei are doubled in 5784, so each half resolves to the
* // date of the combined reading:
* const sedra = new Sedra(5784, false);
* sedra.findContaining('Matot')?.toString(); // '28 Tamuz 5784'
* sedra.findContaining('Masei')?.toString(); // '28 Tamuz 5784'
* @example
* import {Sedra} from '@hebcal/core';
* // They are read separately in 5795, so each half has its own date, and
* // asking for the doubled name returns the date of the first half:
* const sedra = new Sedra(5795, false);
* sedra.findContaining('Matot')?.toString(); // '21 Tamuz 5795'
* sedra.findContaining('Masei')?.toString(); // '28 Tamuz 5795'
* sedra.findContaining('Matot-Masei')?.toString(); // '21 Tamuz 5795'
*/
findContaining(parsha: number | string): HDate | null {
const hdate = this.find(parsha);
if (hdate) {
return hdate;
}
if (typeof parsha === 'number') {
// a valid negative number (double parsha in a year where they are
// combined) would've been found above, and a invalid negative number
// would've thrown an error, so this parsha must be a positive number
// representing either p1 or p2
const p1 = -parsha;
if (isValidDouble(p1)) {
return this.find(p1);
} else {
// this must be the second individual parsha of a doubled pair
// for example 29 for Kedoshim, so check for -28 for Achrei Mot-Kedoshim
return this.find(p1 + 1);
}
} else {
const num = parsha2id.get(parsha);
if (num) {
// parsha is either the first or second individual parsha of
// a pair that is doubled this year
const p1 = -num;
if (isValidDouble(p1)) {
return this.find(p1);
} else {
return this.find(p1 + 1);
}
} else {
// this was indeed a doubled parsha, so return date of the first half
const [p1] = parsha.split('-');
return this.find(p1);
}
}
}
/**
* Returns the underlying annual reading schedule as an array, where each
* entry corresponds to one Saturday (starting from the first Shabbat on
* or after Rosh Hashana). Entries are either:
* - a non-negative `number`: a 0-based parsha index (e.g. `0` for
* *Bereshit*)
* - a negative `number`: the negated first index of a doubled parsha
* (e.g. `-21` for *Vayakhel-Pekudei*)
* - a `string`: a holiday name when a Yom Tov displaces the weekly reading
* (e.g. `'Pesach Shabbat Chol ha-Moed'`, `'Yom Kippur'`)
*
* Used by `@hebcal/triennial`.
*/
getSedraArray(): readonly NumberOrString[] {
return this.theSedraArray;
}
/**
* Returns the R.D. (Rata Die / Fixed Date) absolute day number of the
* first Saturday on or after Rosh Hashana of this year. This is the
* anchor point for {@link getSedraArray} — index `0` of that array
* corresponds to this date.
*/
getFirstSaturday(): number {
return this.firstSaturday;
}
/** Returns the Hebrew year this `Sedra` instance covers. */
getYear(): number {
return this.year;
}
/**
* Returns details about the parsha read on the first Saturday on or after
* `hd`. If `hd` is itself a Saturday, the reading for that date is
* returned; otherwise the reading for the upcoming Saturday is returned.
*
* If the given date falls in the final days of the Hebrew year (after
* the last reading of this year's schedule), this method transparently
* delegates to the next year's `Sedra`.
* @example
* import {Sedra, HDate, months} from '@hebcal/core';
* const sedra = new Sedra(5784, false);
* // A Friday — returns the upcoming Shabbat's reading
* const result = sedra.lookup(new HDate(12, months.CHESHVAN, 5784));
* console.log(result.parsha); // ['Lech-Lecha']
* console.log(result.chag); // false
* console.log(result.hdate.toString()); // '13 Cheshvan 5784' (Saturday)
* @param hd Hebrew date or R.D. days
*/
lookup(hd: HDate | number): SedraResult {
const abs = toAbsInYear(hd, this.rh, this.year);
// find the first saturday on or after today's date
const saturday = HDate.dayOnOrBefore(6, abs + 6);
const weekNum = (saturday - this.firstSaturday) / 7;
const index = this.theSedraArray[weekNum];
if (index === undefined) {
const sedra = getSedra(this.year + 1, this.il);
return sedra.lookup(saturday); // must be next year
}
const hdate = new HDate(saturday);
if (typeof index === 'string') {
// Shabbat has a chag. Return a description
return {parsha: [index], chag: true, hdate, il: this.il, num: 0};
}
if (index >= 0) {
return {
parsha: [parshiot[index]],
chag: false,
num: index + 1,
hdate,
il: this.il,
};
}
const p1 = D(index); // undouble the parsha
return {
parsha: [parshiot[p1], parshiot[p1 + 1]],
chag: false,
num: [p1 + 1, p1 + 2],
hdate,
il: this.il,
};
}
/**
* Returns details about the parsha read on Monday or Thursday for `hd`, or
* `undefined` if `hd` is not a Monday or Thursday.
*
* Weekday Torah readings generally begin the upcoming Shabbat parsha. When
* the upcoming Shabbat is a holiday, this method returns the next regular
* parsha instead.
*
* For the Tishrei weekdays before Sukkot or Simchat Torah, the weekday
* reading is *Vezot Haberakhah* even though it is not read on Shabbat.
* @example
* import {Sedra, HDate, months} from '@hebcal/core';
* const sedra = new Sedra(5784, false);
* // Monday 8 Cheshvan — begins the upcoming Shabbat's parsha
* sedra.lookupWeekday(new HDate(8, months.CHESHVAN, 5784))?.parsha; // ['Lech-Lecha']
* // Tuesday is neither Monday nor Thursday
* sedra.lookupWeekday(new HDate(9, months.CHESHVAN, 5784)); // undefined
* // Thursday 17 Nisan — the upcoming Shabbat is Chol ha-Moed Pesach,
* // so the next regular parsha is returned instead
* sedra.lookupWeekday(new HDate(17, months.NISAN, 5784))?.parsha; // ['Achrei Mot']
* @param hd Hebrew date or R.D. days
*/
lookupWeekday(hd: HDate | number): SedraResult | undefined {
const abs = toAbsInYear(hd, this.rh, this.year);
const hdate = new HDate(abs);
const day = hdate.getDay();
if (day !== 1 && day !== 4) {
return undefined;
}
const saturday = new HDate(HDate.dayOnOrBefore(6, abs + 6));
const parsha = this.lookup(saturday);
if (!parsha.chag) {
return parsha;
}
return this.findWeekdayParsha(saturday);
}
private findWeekdayParsha(saturday: HDate): SedraResult {
const hyear = saturday.getFullYear();
const il = this.il;
if (saturday.getMonth() === months.TISHREI) {
const dd = saturday.getDate();
const simchatTorah = il ? 22 : 23;
if (dd > 2 && dd <= simchatTorah) {
return {
parsha: ['Vezot Haberakhah'],
chag: false,
num: 54,
hdate: saturday,
il,
};
}
}
const sedra = hyear === this.year ? this : getSedra(hyear, il);
const endOfYear = new HDate(1, months.TISHREI, hyear + 1).abs() - 1;
const endAbs = endOfYear + 30;
for (let sat2 = saturday.abs() + 7; sat2 <= endAbs; sat2 += 7) {
const sedra2 = sat2 > endOfYear ? getSedra(hyear + 1, il) : sedra;
const parsha2 = sedra2.lookup(sat2);
if (!parsha2.chag) {
return parsha2;
}
}
/* NOTREACHED */
throw new Error(`can't find weekday parsha for ${saturday}/${il}`);
}
}
/**
* The 54 parshiyot of the Torah as transilterated strings.
* * parshiot[0] == `Bereshit`
* * parshiot[1] == `Noach`
* * parshiot[52] == `Ha'azinu`
* * parshiot[53] == `Vezot Haberakhah`
*/
export const parshiot: readonly string[] = [
'Bereshit',
'Noach',
'Lech-Lecha',
'Vayera',
'Chayei Sara',
'Toldot',
'Vayetzei',
'Vayishlach',
'Vayeshev',
'Miketz',
'Vayigash',
'Vayechi',
'Shemot',
'Vaera',
'Bo',
'Beshalach',
'Yitro',
'Mishpatim',
'Terumah',
'Tetzaveh',
'Ki Tisa',
'Vayakhel',
'Pekudei',
'Vayikra',
'Tzav',
'Shmini',
'Tazria',
'Metzora',
'Achrei Mot',
'Kedoshim',
'Emor',
'Behar',
'Bechukotai',
'Bamidbar',
'Nasso',
"Beha'alotcha",
"Sh'lach",
'Korach',
'Chukat',
'Balak',
'Pinchas',
'Matot',
'Masei',
'Devarim',
'Vaetchanan',
'Eikev',
"Re'eh",
'Shoftim',
'Ki Teitzei',
'Ki Tavo',
'Nitzavim',
'Vayeilech',
"Ha'azinu",
'Vezot Haberakhah',
] as const;
/**
* Converts a `Sedra.lookup*()` argument to R.D. days, validating that it is a
* date on or after Rosh Hashana of `year` (whose R.D. day is `rh`)
*/
function toAbsInYear(hd: HDate | number, rh: number, year: number): number {
const abs = typeof hd === 'number' ? hd : HDate.isHDate(hd) ? hd.abs() : NaN;
if (isNaN(abs)) {
throw new TypeError(`Bad date argument: ${hd}`);
}
if (abs < rh) {
throw new RangeError(`Date ${hd} before start of Hebrew year ${year}`);
}
return abs;
}
// 0-based parsha IDs
const parsha2id = new Map(parshiot.map((name, id) => [name, id] as const));
// 0-based parsha IDs
const doubles: ReadonlySet = new Set([
21, // Vayakhel-Pekudei
26, // Tazria-Metzora
28, // Achrei Mot-Kedoshim
31, // Behar-Bechukotai
38, // Chukat-Balak
41, // Matot-Masei
50, // Nitzavim-Vayeilech
]);
/**
* @param id a negative number
*/
function isValidDouble(id: number): boolean {
return doubles.has(-id);
}
/**
* parsha doubler/undoubler
* @param p
*/
function D(p: number): number {
return -p;
}
const RH = 'Rosh Hashana'; // 0
const YK = 'Yom Kippur'; // 1
const SUKKOT = 'Sukkot'; // 0
const CHMSUKOT = 'Sukkot Shabbat Chol ha-Moed'; // 0
const SHMINI = 'Shmini Atzeret'; // 0
const PESACH = 'Pesach'; // 25
const PESACH1 = 'Pesach I';
const CHMPESACH = 'Pesach Shabbat Chol ha-Moed'; // 25
const PESACH7 = 'Pesach VII'; // 25
const PESACH8 = 'Pesach VIII';
const SHAVUOT = 'Shavuot'; // 33
/**
* Returns an array from start to end
* @param start beginning number, inclusive
* @param stop ending number, inclusive
*/
function range(start: number, stop: number): readonly number[] {
return Array.from({length: stop - start + 1}, (_, k) => k + start);
}
/**
* An entry in the array returned by {@link Sedra.getSedraArray}: either a
* `number` identifying a parsha (or, when negative, a doubled parsha) or a
* `string` naming the holiday that displaces the weekly reading.
*/
export type NumberOrString = number | string;
const yearStartVayeilech: readonly NumberOrString[] = [51, 52, CHMSUKOT];
const yearStartHaazinu: readonly NumberOrString[] = [52, YK, CHMSUKOT];
const yearStartRH: readonly NumberOrString[] = [RH, 52, SUKKOT, SHMINI];
const r020 = range(0, 20);
const r027 = range(0, 27);
const r3340 = range(33, 40);
const r4349 = range(43, 49);
const r4350 = range(43, 50);
/**
* The ordinary year types (keviot)
* names are leap/nonleap - day - incomplete/regular/complete - diaspora/Israel
*/
const types: Record = {
/* Hebrew year that starts on Monday, is `incomplete' (Heshvan and
* Kislev each have 29 days), and has Passover start on Tuesday. */
// e.g. 5753
'020': yearStartVayeilech.concat(
r020,
D(21),
23,
24,
CHMPESACH,
25,
D(26),
D(28),
30,
D(31),
r3340,
D(41),
r4349,
D(50)
),
/* Hebrew year that starts on Monday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Thursday. */
// e.g. 5756
'0220': yearStartVayeilech.concat(
r020,
D(21),
23,
24,
CHMPESACH,
25,
D(26),
D(28),
30,
D(31),
33,
SHAVUOT,
range(34, 37),
D(38),
40,
D(41),
r4349,
D(50)
),
/* Hebrew year that starts on Thursday, is `regular' (Heshvan has 29
* days and Kislev has 30 days), and has Passover start on Saturday. */
// e.g. 5701
'0510': yearStartHaazinu.concat(
r020,
D(21),
23,
24,
PESACH1,
PESACH8,
25,
D(26),
D(28),
30,
D(31),
r3340,
D(41),
r4350
),
/* Hebrew year that starts on Thursday, is `regular' (Heshvan has 29
* days and Kislev has 30 days), and has Passover start on Saturday. */
// e.g. 5745
'0511': yearStartHaazinu.concat(
r020,
D(21),
23,
24,
PESACH,
25,
D(26),
D(28),
range(30, 40),
D(41),
r4350
),
/* Hebrew year that starts on Thursday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Sunday. */
// e.g. 5754
'052': yearStartHaazinu.concat(
range(0, 24),
PESACH7,
25,
D(26),
D(28),
30,
D(31),
r3340,
D(41),
r4350
),
/* Hebrew year that starts on Saturday, is `incomplete' (Heshvan and Kislev
* each have 29 days), and has Passover start on Sunday. */
// e.g. 5761
'070': yearStartRH.concat(
r020,
D(21),
23,
24,
PESACH7,
25,
D(26),
D(28),
30,
D(31),
r3340,
D(41),
r4350
),
/* Hebrew year that starts on Saturday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Tuesday. */
// e.g. 5716
'072': yearStartRH.concat(
r020,
D(21),
23,
24,
CHMPESACH,
25,
D(26),
D(28),
30,
D(31),
r3340,
D(41),
r4349,
D(50)
),
/* -- The leap year types (keviot) -- */
/* Hebrew year that starts on Monday, is `incomplete' (Heshvan and
* Kislev each have 29 days), and has Passover start on Thursday. */
// e.g. 5746
'1200': yearStartVayeilech.concat(
r027,
CHMPESACH,
range(28, 33),
SHAVUOT,
range(34, 37),
D(38),
40,
D(41),
r4349,
D(50)
),
/* Hebrew year that starts on Monday, is `incomplete' (Heshvan and
* Kislev each have 29 days), and has Passover start on Thursday. */
// e.g. 5746
'1201': yearStartVayeilech.concat(
r027,
CHMPESACH,
range(28, 40),
D(41),
r4349,
D(50)
),
/* Hebrew year that starts on Monday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Saturday. */
// e.g.5752
'1220': yearStartVayeilech.concat(
r027,
PESACH1,
PESACH8,
range(28, 40),
D(41),
r4350
),
/* Hebrew year that starts on Monday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Saturday. */
// e.g.5752
'1221': yearStartVayeilech.concat(r027, PESACH, range(28, 50)),
/* Hebrew year that starts on Thursday, is `incomplete' (Heshvan and
* Kislev both have 29 days), and has Passover start on Sunday. */
// e.g. 5768
'150': yearStartHaazinu.concat(range(0, 28), PESACH7, range(29, 50)),
/* Hebrew year that starts on Thursday, is `complete' (Heshvan and
* Kislev both have 30 days), and has Passover start on Tuesday. */
// eg. 5771
'152': yearStartHaazinu.concat(range(0, 28), CHMPESACH, range(29, 49), D(50)),
/* Hebrew year that starts on Saturday, is `incomplete' (Heshvan and
* Kislev each have 29 days), and has Passover start on Tuesday. */
// e.g.5757
'170': yearStartRH.concat(r027, CHMPESACH, range(28, 40), D(41), r4349, D(50)),
/* Hebrew year that starts on Saturday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Thursday. */
'1720': yearStartRH.concat(
r027,
CHMPESACH,
range(28, 33),
SHAVUOT,
range(34, 37),
D(38),
40,
D(41),
r4349,
D(50)
),
};
/* Hebrew year that starts on Monday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Thursday. */
types['0221'] = types['020'];
/* Hebrew year that starts on Tuesday, is `regular' (Heshvan has 29
* days and Kislev has 30 days), and has Passover start on Thursday. */
// e.g. 5715
types['0310'] = types['0220'];
/* Hebrew year that starts on Tuesday, is `regular' (Heshvan has 29
* days and Kislev has 30 days), and has Passover start on Thursday. */
types['0311'] = types['020'];
/* Hebrew year that starts on Tuesday, is `regular' (Heshvan has 29
* days and Kislev has 30 days), and has Passover start on Saturday. */
// e.g. 5715
types['1310'] = types['1220'];
/* Hebrew year that starts on Tuesday, is `regular' (Heshvan has 29
* days and Kislev has 30 days), and has Passover start on Saturday. */
types['1311'] = types['1221'];
/* Hebrew year that starts on Saturday, is `complete' (Heshvan and
* Kislev each have 30 days), and has Passover start on Thursday. */
types['1721'] = types['170'];
const sedraCache = new QuickLRU({maxSize: 120});
/**
* Convenience function to create an instance of {@link Sedra} or reuse a
* previously created and cached instance for the same year and schedule.
*
* Prefer this over `new Sedra(...)` when calling repeatedly — an internal
* LRU cache (~120 entries) avoids recomputing the keviyah-specific schedule.
* @example
* import {getSedra, HDate, months} from '@hebcal/core';
* const sedra = getSedra(5784, false);
* const {parsha} = sedra.lookup(new HDate(15, months.CHESHVAN, 5784));
* console.log(parsha); // ['Vayera']
* @param hyear Hebrew year
* @param il Use Israel sedra schedule (`false` for Diaspora)
*/
export function getSedra(hyear: number, il: boolean): Sedra {
const cacheKey = `${hyear}-${il ? 1 : 0}`;
let sedra = sedraCache.get(cacheKey);
if (!sedra) {
sedra = new Sedra(hyear, il);
sedraCache.set(cacheKey, sedra);
}
return sedra;
}