@hebcal/leyning 6.2.2 → 6.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/bundle.js +365 -599
- package/dist/bundle.min.js +2 -2
- package/dist/index.js +50 -199
- package/dist/index.mjs +50 -197
- package/package.json +19 -15
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/leyning v6.2.
|
|
1
|
+
/*! @hebcal/leyning v6.2.4 */
|
|
2
2
|
import { flags, months, HDate, HebrewCalendar, Event, Locale, ParshaEvent } from '@hebcal/core';
|
|
3
3
|
|
|
4
4
|
const Genesis=[0,31,25,24,26,32,22,24,22,29,32,32,20,18,24,21,16,27,33,38,18,34,24,20,67,34,35,46,22,35,43,54,33,20,31,29,43,36,30,23,23,57,38,34,34,28,34,31,22,33,26];const Exodus=[0,22,25,22,31,23,30,29,28,35,29,10,51,22,31,27,36,16,27,25,26,37,30,33,18,40,37,21,43,46,38,18,35,23,35,35,38,29,31,43,38];const Leviticus=[0,17,16,17,35,26,23,38,36,24,20,47,8,59,57,33,34,16,30,37,27,24,33,44,23,55,46,34];const Numbers=[0,54,34,51,49,31,27,89,26,23,36,35,16,33,45,41,35,28,32,22,29,35,41,30,25,19,65,23,31,39,17,54,42,56,29,34,13];const Deuteronomy=[0,46,37,29,49,30,25,26,20,29,22,32,31,19,29,23,22,20,22,21,20,23,29,26,22,19,19,26,69,28,20,30,52,29,12];const Joshua=[0,18,24,17,24,15,27,26,35,27,43,23,24,33,15,63,10,18,28,51,9,45,34,16,33];const Judges=[0,36,23,31,24,31,40,25,35,57,18,40,15,25,20,20,31,13,31,30,48,25];const Ruth=[0,22,23,18,22];const Isaiah=[0,31,22,26,6,30,13,25,23,20,34,16,6,22,32,9,14,14,7,25,6,17,25,18,23,12,21,13,29,24,33,9,20,24,17,10,22,38,22,8,31,29,25,28,28,25,13,15,22,26,11,23,15,12,17,13,12,21,14,21,22,11,12,19,11,25,24];const Jeremiah=[0,19,37,25,31,31,30,34,23,25,25,23,17,27,22,21,21,27,23,15,18,14,30,40,10,38,24,22,17,32,24,40,44,26,22,19,32,21,28,18,16,18,22,13,30,5,28,7,47,39,46,64,34];const Lamentations=[0,22,22,66,22,22];const Baruch=[0,22,35,38,37,9,72];const Ezekiel=[0,28,10,27,17,17,14,27,18,11,22,25,28,23,23,8,63,24,32,14,44,37,31,49,27,17,21,36,26,21,26,18,32,33,31,15,38,28,23,29,49,26,20,27,31,25,24,23,35];const Daniel=[0,21,49,100,34,30,29,28,27,27,21,45,13,64,42];const Hosea=[0,9,25,5,19,15,11,16,14,17,15,11,15,15,10];const Joel=[0,20,27,5,21];const Amos=[0,15,16,15,13,27,14,17,14,15];const Obadiah=[0,21];const Jonah=[0,16,11,10,11];const Micah=[0,16,13,12,14,14,16,20];const Nachum=[0,14,14,19];const Habakkuk=[0,17,20,19];const Zephaniah=[0,18,15,20];const Haggai=[0,15,23];const Zechariah=[0,17,17,10,14,11,15,14,23,17,12,17,14,9,21];const Malachi=[0,14,17,24];var numverses = {Genesis:Genesis,Exodus:Exodus,Leviticus:Leviticus,Numbers:Numbers,Deuteronomy:Deuteronomy,Joshua:Joshua,Judges:Judges,Ruth:Ruth,"I Samuel":[0,28,36,21,22,12,21,17,22,27,27,15,25,23,52,35,23,58,30,24,42,16,23,28,23,43,25,12,25,11,31,13],"II Samuel":[0,27,32,39,12,25,23,29,18,13,19,27,31,39,33,37,23,29,32,44,26,22,51,39,25],"I Kings":[0,53,46,28,20,32,38,51,66,28,29,43,33,34,31,34,34,24,46,21,43,29,54],"II Kings":[0,18,25,27,44,27,33,20,29,37,36,20,22,25,29,38,20,41,37,37,21,26,20,37,20,30],Isaiah:Isaiah,Jeremiah:Jeremiah,Lamentations:Lamentations,Baruch:Baruch,Ezekiel:Ezekiel,Daniel:Daniel,Hosea:Hosea,Joel:Joel,Amos:Amos,Obadiah:Obadiah,Jonah:Jonah,Micah:Micah,Nachum:Nachum,Habakkuk:Habakkuk,Zephaniah:Zephaniah,Haggai:Haggai,Zechariah:Zechariah,Malachi:Malachi};
|
|
@@ -8,23 +8,21 @@ const Genesis=[0,31,25,24,26,32,22,24,22,29,32,32,20,18,24,21,16,27,33,38,18,34,
|
|
|
8
8
|
* @readonly
|
|
9
9
|
* @const {string[]}
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
11
|
const BOOK = ['', 'Genesis', 'Exodus', 'Leviticus', 'Numbers', 'Deuteronomy'];
|
|
12
|
+
|
|
13
13
|
/**
|
|
14
14
|
* Formats parsha as a string
|
|
15
15
|
* @param {string[]} parsha
|
|
16
16
|
* @return {string}
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
18
|
function parshaToString(parsha) {
|
|
20
19
|
let s = parsha[0];
|
|
21
|
-
|
|
22
20
|
if (parsha.length == 2) {
|
|
23
21
|
s += '-' + parsha[1];
|
|
24
22
|
}
|
|
25
|
-
|
|
26
23
|
return s;
|
|
27
24
|
}
|
|
25
|
+
|
|
28
26
|
/**
|
|
29
27
|
* Represents an aliyah
|
|
30
28
|
* @typedef {Object} Aliyah
|
|
@@ -40,10 +38,10 @@ function parshaToString(parsha) {
|
|
|
40
38
|
* @param {any} src
|
|
41
39
|
* @return {any}
|
|
42
40
|
*/
|
|
43
|
-
|
|
44
41
|
function clone(src) {
|
|
45
42
|
return JSON.parse(JSON.stringify(src));
|
|
46
43
|
}
|
|
44
|
+
|
|
47
45
|
/**
|
|
48
46
|
* Calculates the number of verses in an aliyah or haftara based on
|
|
49
47
|
* the `b` (begin verse), `e` (end verse) and `k` (book).
|
|
@@ -51,98 +49,85 @@ function clone(src) {
|
|
|
51
49
|
* @param {Aliyah} aliyah
|
|
52
50
|
* @return {number}
|
|
53
51
|
*/
|
|
54
|
-
|
|
55
52
|
function calculateNumVerses(aliyah) {
|
|
56
53
|
if (aliyah.v) {
|
|
57
54
|
return aliyah.v;
|
|
58
55
|
}
|
|
59
|
-
|
|
60
56
|
const chapVerseBegin = aliyah.b.split(':');
|
|
61
57
|
const chapVerseEnd = aliyah.e.split(':');
|
|
62
58
|
const c1 = parseInt(chapVerseBegin[0], 10);
|
|
63
59
|
const c2 = parseInt(chapVerseEnd[0], 10);
|
|
64
60
|
const v1 = parseInt(chapVerseBegin[1], 10);
|
|
65
61
|
const v2 = parseInt(chapVerseEnd[1], 10);
|
|
66
|
-
|
|
67
62
|
if (c1 === c2) {
|
|
68
63
|
aliyah.v = v2 - v1 + 1;
|
|
69
64
|
} else if (typeof aliyah.k === 'string') {
|
|
70
65
|
const numv = numverses[aliyah.k];
|
|
71
|
-
|
|
72
66
|
if (typeof numv !== 'object' || !numv.length) {
|
|
73
67
|
throw new ReferenceError(`Can't find numverses for ${aliyah.k}`);
|
|
74
68
|
}
|
|
75
|
-
|
|
76
69
|
let total = numv[c1] - v1 + 1;
|
|
77
|
-
|
|
78
70
|
for (let chap = c1 + 1; chap < c2; chap++) {
|
|
79
71
|
total += numv[chap];
|
|
80
72
|
}
|
|
81
|
-
|
|
82
73
|
total += v2;
|
|
83
74
|
aliyah.v = total;
|
|
84
75
|
}
|
|
85
|
-
|
|
86
76
|
return aliyah.v;
|
|
87
77
|
}
|
|
78
|
+
|
|
88
79
|
/**
|
|
89
80
|
* Formats an aliyah object like "Numbers 28:9-28:15"
|
|
90
81
|
* @param {Aliyah} a aliyah
|
|
91
82
|
* @return {string}
|
|
92
83
|
*/
|
|
93
|
-
|
|
94
84
|
function formatAliyahWithBook(a) {
|
|
95
85
|
return `${a.k} ${a.b}-${a.e}`;
|
|
96
86
|
}
|
|
87
|
+
|
|
97
88
|
/**
|
|
98
89
|
* Formats an aliyah object like "Numbers 28:9-15"
|
|
99
90
|
* @param {Aliyah} aliyah
|
|
100
91
|
* @param {boolean} showBook
|
|
101
92
|
* @return {string}
|
|
102
93
|
*/
|
|
103
|
-
|
|
104
94
|
function formatAliyahShort(aliyah, showBook) {
|
|
105
95
|
const begin = aliyah.b;
|
|
106
96
|
const end0 = aliyah.e;
|
|
107
97
|
const prefix = showBook ? aliyah.k + ' ' : '';
|
|
108
|
-
|
|
109
98
|
if (begin === end0) {
|
|
110
99
|
return `${prefix}${begin}`;
|
|
111
100
|
}
|
|
112
|
-
|
|
113
101
|
const cv1 = begin.split(':');
|
|
114
102
|
const cv2 = end0.split(':');
|
|
115
103
|
const end = cv1[0] === cv2[0] ? cv2[1] : end0;
|
|
116
104
|
return `${prefix}${begin}-${end}`;
|
|
117
105
|
}
|
|
106
|
+
|
|
118
107
|
/**
|
|
119
108
|
* Returns the total number of verses in an array of Aliyah (or haftarah) objects
|
|
120
109
|
* @param {Aliyah|Aliyah[]} aliyot
|
|
121
110
|
* @return {number}
|
|
122
111
|
*/
|
|
123
|
-
|
|
124
112
|
function sumVerses(aliyot) {
|
|
125
113
|
return Array.isArray(aliyot) ? aliyot.reduce((prev, cur) => prev + cur.v, 0) : aliyot.v;
|
|
126
114
|
}
|
|
115
|
+
|
|
127
116
|
/**
|
|
128
117
|
* @private
|
|
129
118
|
* @param {Aliyah|Aliyah[]} haft
|
|
130
119
|
* @return {Aliyah|Aliyah[]}
|
|
131
120
|
*/
|
|
132
|
-
|
|
133
121
|
function cloneHaftara(haft) {
|
|
134
122
|
if (!haft) {
|
|
135
123
|
return haft;
|
|
136
124
|
}
|
|
137
|
-
|
|
138
125
|
const dest = clone(haft);
|
|
139
|
-
|
|
140
126
|
if (Array.isArray(dest)) {
|
|
141
127
|
dest.map(calculateNumVerses);
|
|
142
128
|
} else {
|
|
143
129
|
calculateNumVerses(dest);
|
|
144
130
|
}
|
|
145
|
-
|
|
146
131
|
return dest;
|
|
147
132
|
}
|
|
148
133
|
|
|
@@ -152,39 +137,33 @@ function cloneHaftara(haft) {
|
|
|
152
137
|
* @param {string} b
|
|
153
138
|
* @return {boolean}
|
|
154
139
|
*/
|
|
155
|
-
|
|
156
140
|
function isChapVerseBefore(a, b) {
|
|
157
141
|
const cv1 = a.split(':').map(x => +x);
|
|
158
142
|
const cv2 = b.split(':').map(x => +x);
|
|
159
143
|
return cv1[0] * 100 + cv1[1] < cv2[0] * 100 + cv2[1];
|
|
160
144
|
}
|
|
145
|
+
|
|
161
146
|
/**
|
|
162
147
|
* Summarizes an `AliyotMap` by collapsing all adjacent aliyot.
|
|
163
148
|
* Finds any non-overlapping parts (e.g. special 7th aliyah or maftir)
|
|
164
149
|
* @param {Object<string,Aliyah>} aliyot
|
|
165
150
|
* @return {Aliyah[]}
|
|
166
151
|
*/
|
|
167
|
-
|
|
168
|
-
|
|
169
152
|
function makeLeyningParts(aliyot) {
|
|
170
153
|
const nums = Object.keys(aliyot).filter(x => x.length === 1);
|
|
171
154
|
let start = aliyot[nums[0]];
|
|
172
155
|
let end = start;
|
|
173
156
|
const parts = [];
|
|
174
|
-
|
|
175
157
|
for (let i = 0; i < nums.length; i++) {
|
|
176
158
|
const num = nums[i];
|
|
177
159
|
const aliyah = aliyot[num];
|
|
178
|
-
|
|
179
160
|
if (i === nums.length - 1 && aliyah.k === end.k && aliyah.e === end.e) {
|
|
180
161
|
// short-circuit when final aliyah is within the previous (e.g. M inside of 7)
|
|
181
162
|
continue;
|
|
182
163
|
}
|
|
183
|
-
|
|
184
164
|
const prevEndChap = +end.e.split(':')[0];
|
|
185
165
|
const curStartChap = +aliyah.b.split(':')[0];
|
|
186
166
|
const sameOrNextChap = curStartChap === prevEndChap || curStartChap === prevEndChap + 1;
|
|
187
|
-
|
|
188
167
|
if (i !== 0 && (aliyah.k !== start.k || isChapVerseBefore(aliyah.b, start.e) || !sameOrNextChap)) {
|
|
189
168
|
parts.push({
|
|
190
169
|
k: start.k,
|
|
@@ -193,10 +172,8 @@ function makeLeyningParts(aliyot) {
|
|
|
193
172
|
});
|
|
194
173
|
start = aliyah;
|
|
195
174
|
}
|
|
196
|
-
|
|
197
175
|
end = aliyah;
|
|
198
176
|
}
|
|
199
|
-
|
|
200
177
|
parts.push({
|
|
201
178
|
k: start.k,
|
|
202
179
|
b: start.b,
|
|
@@ -204,6 +181,7 @@ function makeLeyningParts(aliyot) {
|
|
|
204
181
|
});
|
|
205
182
|
return parts;
|
|
206
183
|
}
|
|
184
|
+
|
|
207
185
|
/**
|
|
208
186
|
* Returns a string representation of the leyning parts.
|
|
209
187
|
* Separate verse ranges read from the same book are separated
|
|
@@ -213,36 +191,30 @@ function makeLeyningParts(aliyot) {
|
|
|
213
191
|
* @param {Aliyah|Aliyah[]} parts
|
|
214
192
|
* @return {string}
|
|
215
193
|
*/
|
|
216
|
-
|
|
217
194
|
function makeSummaryFromParts(parts) {
|
|
218
195
|
if (!Array.isArray(parts)) {
|
|
219
196
|
parts = [parts];
|
|
220
197
|
}
|
|
221
|
-
|
|
222
198
|
let prev = parts[0];
|
|
223
199
|
let summary = formatAliyahShort(prev, true);
|
|
224
|
-
|
|
225
200
|
for (let i = 1; i < parts.length; i++) {
|
|
226
201
|
const part = parts[i];
|
|
227
|
-
|
|
228
202
|
if (part.k === prev.k) {
|
|
229
203
|
summary += ', ';
|
|
230
204
|
} else {
|
|
231
205
|
summary += `; ${part.k} `;
|
|
232
206
|
}
|
|
233
|
-
|
|
234
207
|
summary += formatAliyahShort(part, false);
|
|
235
208
|
prev = part;
|
|
236
209
|
}
|
|
237
|
-
|
|
238
210
|
return summary;
|
|
239
211
|
}
|
|
212
|
+
|
|
240
213
|
/**
|
|
241
214
|
* Makes a summary of the leyning, like "Genesis 6:9-11:32"
|
|
242
215
|
* @param {Object<string,Aliyah>} aliyot
|
|
243
216
|
* @return {string}
|
|
244
217
|
*/
|
|
245
|
-
|
|
246
218
|
function makeLeyningSummary(aliyot) {
|
|
247
219
|
const parts = makeLeyningParts(aliyot);
|
|
248
220
|
return makeSummaryFromParts(parts);
|
|
@@ -255,35 +227,28 @@ const Purim={fullkriyah:{"1":{p:16,k:2,b:"17:8",e:"17:10"},"2":{p:16,k:2,b:"17:1
|
|
|
255
227
|
* @param {string} holiday
|
|
256
228
|
* @return {boolean}
|
|
257
229
|
*/
|
|
258
|
-
|
|
259
230
|
function hasFestival(holiday) {
|
|
260
231
|
return typeof festivals[holiday] === 'object';
|
|
261
232
|
}
|
|
233
|
+
|
|
262
234
|
/**
|
|
263
235
|
* Returns the raw metadata for festival reading for `holiday`
|
|
264
236
|
* @param {string} holiday
|
|
265
237
|
* @return {any}
|
|
266
238
|
*/
|
|
267
|
-
|
|
268
239
|
function lookupFestival(holiday) {
|
|
269
240
|
let src = festivals[holiday];
|
|
270
|
-
|
|
271
241
|
if (typeof src === 'undefined') {
|
|
272
242
|
return undefined;
|
|
273
243
|
}
|
|
274
|
-
|
|
275
244
|
if (src.alias) {
|
|
276
245
|
const tmp = festivals[src.key];
|
|
277
|
-
|
|
278
246
|
if (typeof tmp === 'undefined') {
|
|
279
247
|
throw new Error(`Leyning alias ${holiday} => ${src.key} not found`);
|
|
280
248
|
}
|
|
281
|
-
|
|
282
249
|
src = tmp;
|
|
283
250
|
}
|
|
284
|
-
|
|
285
251
|
const result = src.fullkriyah ? clone(src) : src;
|
|
286
|
-
|
|
287
252
|
if (result.fullkriyah) {
|
|
288
253
|
Object.values(result.fullkriyah).forEach(aliyah => {
|
|
289
254
|
if (typeof aliyah.k === 'number') {
|
|
@@ -291,32 +256,27 @@ function lookupFestival(holiday) {
|
|
|
291
256
|
}
|
|
292
257
|
});
|
|
293
258
|
}
|
|
294
|
-
|
|
295
259
|
return result;
|
|
296
260
|
}
|
|
297
261
|
|
|
298
|
-
const HOLIDAY_IGNORE_MASK = flags.DAF_YOMI | flags.OMER_COUNT | flags.SHABBAT_MEVARCHIM | flags.MOLAD | flags.USER_EVENT | flags.HEBREW_DATE | flags.MISHNA_YOMI | flags.MODERN_HOLIDAY;
|
|
262
|
+
const HOLIDAY_IGNORE_MASK = flags.DAF_YOMI | flags.OMER_COUNT | flags.SHABBAT_MEVARCHIM | flags.MOLAD | flags.USER_EVENT | flags.HEBREW_DATE | flags.MISHNA_YOMI | flags.MODERN_HOLIDAY | flags.YERUSHALMI_YOMI;
|
|
263
|
+
|
|
299
264
|
/**
|
|
300
265
|
* Based on the event date, type and title, finds the relevant leyning key
|
|
301
266
|
* @param {Event} ev event
|
|
302
267
|
* @param {boolean} [il] true if Israel holiday scheme
|
|
303
268
|
* @return {string} key to look up in holiday-reading.json
|
|
304
269
|
*/
|
|
305
|
-
|
|
306
270
|
function getLeyningKeyForEvent(ev, il = false) {
|
|
307
271
|
const mask = ev.getFlags();
|
|
308
|
-
|
|
309
272
|
if (mask & HOLIDAY_IGNORE_MASK) {
|
|
310
273
|
return undefined;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
274
|
+
}
|
|
275
|
+
// Skip all Erevs except for Simchat Torah
|
|
314
276
|
const desc = ev.getDesc();
|
|
315
|
-
|
|
316
277
|
if (mask & flags.EREV && desc !== 'Erev Simchat Torah') {
|
|
317
278
|
return undefined;
|
|
318
279
|
}
|
|
319
|
-
|
|
320
280
|
const hd = ev.getDate();
|
|
321
281
|
const day = hd.getDate();
|
|
322
282
|
const dow = hd.abs() % 7;
|
|
@@ -325,15 +285,12 @@ function getLeyningKeyForEvent(ev, il = false) {
|
|
|
325
285
|
const isRoshChodesh = day == 1 || day == 30;
|
|
326
286
|
const holiday = ev.basename();
|
|
327
287
|
const isPesach = holiday === 'Pesach';
|
|
328
|
-
|
|
329
288
|
if (il && isPesach) {
|
|
330
289
|
if (isShabbat) {
|
|
331
290
|
return day === 15 || day === 21 ? desc + ' (on Shabbat)' : 'Pesach Shabbat Chol ha-Moed';
|
|
332
291
|
}
|
|
333
|
-
|
|
334
292
|
return desc;
|
|
335
293
|
}
|
|
336
|
-
|
|
337
294
|
if (day == 1 && month === months.TISHREI) {
|
|
338
295
|
return isShabbat ? 'Rosh Hashana I (on Shabbat)' : 'Rosh Hashana I';
|
|
339
296
|
} else if (ev.cholHaMoedDay) {
|
|
@@ -342,12 +299,10 @@ function getLeyningKeyForEvent(ev, il = false) {
|
|
|
342
299
|
return holiday + ' Shabbat Chol ha-Moed';
|
|
343
300
|
} else if (desc == 'Sukkot VII (Hoshana Raba)') {
|
|
344
301
|
return 'Sukkot Final Day (Hoshana Raba)';
|
|
345
|
-
}
|
|
302
|
+
}
|
|
303
|
+
// If Shabbat falls on the third day of Chol ha-Moed Pesach,
|
|
346
304
|
// the readings for the third, fourth, and fifth days are moved ahead
|
|
347
|
-
|
|
348
|
-
|
|
349
305
|
let cholHaMoedDay = ev.cholHaMoedDay;
|
|
350
|
-
|
|
351
306
|
if (isPesach && cholHaMoedDay >= 3) {
|
|
352
307
|
if (dow == 0 && cholHaMoedDay == 4) {
|
|
353
308
|
cholHaMoedDay = 3;
|
|
@@ -355,7 +310,6 @@ function getLeyningKeyForEvent(ev, il = false) {
|
|
|
355
310
|
cholHaMoedDay = 4;
|
|
356
311
|
}
|
|
357
312
|
}
|
|
358
|
-
|
|
359
313
|
return `${holiday} Chol ha-Moed Day ${cholHaMoedDay}`;
|
|
360
314
|
} else if (ev.chanukahDay) {
|
|
361
315
|
if (isShabbat && isRoshChodesh) {
|
|
@@ -368,54 +322,45 @@ function getLeyningKeyForEvent(ev, il = false) {
|
|
|
368
322
|
return `Chanukah Day ${ev.chanukahDay}`;
|
|
369
323
|
}
|
|
370
324
|
}
|
|
371
|
-
|
|
372
325
|
if (isRoshChodesh && (desc == 'Shabbat HaChodesh' || desc == 'Shabbat Shekalim')) {
|
|
373
326
|
return desc + ' (on Rosh Chodesh)';
|
|
374
327
|
}
|
|
375
|
-
|
|
376
328
|
if (desc == 'Shavuot') {
|
|
377
329
|
return 'Shavuot I';
|
|
378
330
|
} else if (il && desc == 'Shmini Atzeret') {
|
|
379
331
|
return 'Simchat Torah';
|
|
380
332
|
}
|
|
381
|
-
|
|
333
|
+
if (desc === 'Chag HaBanot') {
|
|
334
|
+
return undefined;
|
|
335
|
+
}
|
|
382
336
|
if (isShabbat && 'Shabbat' != desc.substring(0, 7)) {
|
|
383
337
|
if (isRoshChodesh) {
|
|
384
338
|
if (desc === 'Rosh Chodesh Tevet') {
|
|
385
339
|
return 'Shabbat Rosh Chodesh Chanukah';
|
|
386
340
|
}
|
|
387
|
-
|
|
388
341
|
return 'Shabbat Rosh Chodesh';
|
|
389
342
|
}
|
|
390
|
-
|
|
391
343
|
const desc2 = desc + ' (on Shabbat)';
|
|
392
|
-
|
|
393
344
|
if (hasFestival(desc2)) {
|
|
394
345
|
return desc2;
|
|
395
346
|
}
|
|
396
347
|
}
|
|
397
|
-
|
|
398
348
|
if (hasFestival(desc)) {
|
|
399
349
|
return desc;
|
|
400
350
|
}
|
|
401
|
-
|
|
402
351
|
if (isShabbat) {
|
|
403
352
|
const tommorow = hd.next().getDate();
|
|
404
|
-
|
|
405
353
|
if (tommorow === 30 || tommorow === 1) {
|
|
406
354
|
return 'Shabbat Machar Chodesh';
|
|
407
355
|
}
|
|
408
356
|
}
|
|
409
|
-
|
|
410
357
|
if (desc === 'Rosh Hashana LaBehemot') {
|
|
411
358
|
return undefined;
|
|
412
359
|
}
|
|
413
|
-
|
|
414
360
|
if (desc === 'Rosh Chodesh Tevet') {
|
|
415
361
|
if (isShabbat) {
|
|
416
362
|
return 'Shabbat Rosh Chodesh Chanukah';
|
|
417
363
|
}
|
|
418
|
-
|
|
419
364
|
if (day === 30 || HDate.shortKislev(hd.getFullYear())) {
|
|
420
365
|
return 'Chanukah Day 6'; // 30th of Kislev or 1st of Tevet
|
|
421
366
|
} else {
|
|
@@ -426,11 +371,9 @@ function getLeyningKeyForEvent(ev, il = false) {
|
|
|
426
371
|
if (isRoshChodesh) {
|
|
427
372
|
return desc;
|
|
428
373
|
}
|
|
429
|
-
|
|
430
374
|
if (desc === 'Tish\'a B\'Av (observed)') {
|
|
431
375
|
return 'Tish\'a B\'Av';
|
|
432
376
|
}
|
|
433
|
-
|
|
434
377
|
return undefined;
|
|
435
378
|
}
|
|
436
379
|
|
|
@@ -438,45 +381,40 @@ function getLeyningKeyForEvent(ev, il = false) {
|
|
|
438
381
|
* @private
|
|
439
382
|
* @param {Object<string,Aliyah>} aliyot
|
|
440
383
|
*/
|
|
441
|
-
|
|
442
384
|
function aliyotCombine67(aliyot) {
|
|
443
385
|
const a6 = clone(aliyot['6']);
|
|
444
386
|
const a7 = aliyot['7'];
|
|
445
|
-
|
|
446
387
|
if (a6.k !== a7.k) {
|
|
447
388
|
throw new Error('Impossible to combine aliyot 6 & 7: ' + JSON.stringify(aliyot));
|
|
448
389
|
}
|
|
449
|
-
|
|
450
390
|
delete aliyot['7'];
|
|
451
391
|
aliyot['6'] = {
|
|
452
392
|
k: a6.k,
|
|
453
393
|
b: a6.b,
|
|
454
394
|
e: a7.e
|
|
455
395
|
};
|
|
456
|
-
|
|
457
396
|
if (a6.v && a7.v) {
|
|
458
397
|
aliyot['6'].v = a6.v + a7.v;
|
|
459
398
|
}
|
|
460
399
|
}
|
|
400
|
+
|
|
461
401
|
/**
|
|
462
402
|
* @private
|
|
463
403
|
* @param {Object<string,Aliyah>} aliyot
|
|
464
404
|
* @param {Object<string,Aliyah>} special
|
|
465
405
|
*/
|
|
466
|
-
|
|
467
|
-
|
|
468
406
|
function mergeAliyotWithSpecial(aliyot, special) {
|
|
469
407
|
if (special['7']) {
|
|
470
408
|
aliyotCombine67(aliyot);
|
|
471
409
|
aliyot['7'] = clone(special['7']);
|
|
472
410
|
calculateNumVerses(aliyot['7']);
|
|
473
411
|
}
|
|
474
|
-
|
|
475
412
|
if (special['M']) {
|
|
476
413
|
aliyot['M'] = clone(special['M']);
|
|
477
414
|
calculateNumVerses(aliyot['M']);
|
|
478
415
|
}
|
|
479
416
|
}
|
|
417
|
+
|
|
480
418
|
/**
|
|
481
419
|
* Determines if the regular parashat haShavua coincides with an event that requires
|
|
482
420
|
* a special maftir or Haftara (for example Shabbat HaGadol, Shabbat Chanukah, Rosh
|
|
@@ -495,38 +433,32 @@ function mergeAliyotWithSpecial(aliyot, special) {
|
|
|
495
433
|
* @param {boolean} [wantSeph]
|
|
496
434
|
* @return {Aliyah | Aliyah[]}
|
|
497
435
|
*/
|
|
498
|
-
|
|
499
|
-
|
|
500
436
|
function specialReadings(hd, il, aliyot, reason, parsha, wantSeph = false) {
|
|
501
437
|
let haft;
|
|
502
438
|
let seph;
|
|
503
439
|
let specialHaft = false;
|
|
504
|
-
const parshaName = parsha ? parshaToString(parsha) : null;
|
|
440
|
+
const parshaName = parsha ? parshaToString(parsha) : null;
|
|
505
441
|
|
|
442
|
+
// eslint-disable-next-line require-jsdoc
|
|
506
443
|
function handleSpecial(key) {
|
|
507
444
|
const special = lookupFestival(key);
|
|
508
|
-
|
|
509
445
|
if (!special) {
|
|
510
446
|
return;
|
|
511
447
|
}
|
|
512
|
-
|
|
513
448
|
if (special.haft && !specialHaft) {
|
|
514
449
|
haft = cloneHaftara(special.haft);
|
|
515
450
|
reason.haftara = key;
|
|
516
451
|
specialHaft = true;
|
|
517
|
-
|
|
518
452
|
if (special.seph) {
|
|
519
453
|
seph = cloneHaftara(special.seph);
|
|
520
454
|
reason.sephardic = key;
|
|
521
455
|
}
|
|
522
456
|
}
|
|
523
|
-
|
|
524
457
|
if (special.fullkriyah) {
|
|
525
458
|
mergeAliyotWithSpecial(aliyot, special.fullkriyah);
|
|
526
459
|
Object.keys(special.fullkriyah).map(k => reason[k] = key);
|
|
527
460
|
}
|
|
528
461
|
}
|
|
529
|
-
|
|
530
462
|
const events0 = HebrewCalendar.getHolidaysOnDate(hd, il) || [];
|
|
531
463
|
const events = events0.filter(ev => !(ev.getFlags() & flags.ROSH_CHODESH));
|
|
532
464
|
events.forEach(ev => {
|
|
@@ -534,16 +466,13 @@ function specialReadings(hd, il, aliyot, reason, parsha, wantSeph = false) {
|
|
|
534
466
|
handleSpecial(`Shabbat Shuva (with ${parshaName})`);
|
|
535
467
|
} else {
|
|
536
468
|
const key = getLeyningKeyForEvent(ev, il);
|
|
537
|
-
|
|
538
469
|
if (key) {
|
|
539
470
|
handleSpecial(key);
|
|
540
471
|
}
|
|
541
472
|
}
|
|
542
473
|
});
|
|
543
|
-
|
|
544
474
|
if (!haft) {
|
|
545
475
|
const day = hd.getDate();
|
|
546
|
-
|
|
547
476
|
if (parshaName === 'Pinchas' && day > 17) {
|
|
548
477
|
// Pinchas is always read in Tamuz (never another month)
|
|
549
478
|
// either on the 14, 16, 17 (in Israel), 19, 21, 23, 24
|
|
@@ -553,13 +482,11 @@ function specialReadings(hd, il, aliyot, reason, parsha, wantSeph = false) {
|
|
|
553
482
|
handleSpecial(key);
|
|
554
483
|
} else {
|
|
555
484
|
const tommorow = hd.next().getDate();
|
|
556
|
-
|
|
557
485
|
if (tommorow === 30 || tommorow === 1) {
|
|
558
486
|
handleSpecial('Shabbat Machar Chodesh');
|
|
559
487
|
}
|
|
560
488
|
}
|
|
561
489
|
}
|
|
562
|
-
|
|
563
490
|
if (wantSeph && haft) {
|
|
564
491
|
return {
|
|
565
492
|
haft,
|
|
@@ -618,7 +545,6 @@ const Bereshit={num:1,hebrew:"בְּרֵאשִׁית",book:1,haft:{k:"Isaiah",b:
|
|
|
618
545
|
* @param {boolean} [il] true if Israel holiday scheme
|
|
619
546
|
* @return {Leyning} map of aliyot
|
|
620
547
|
*/
|
|
621
|
-
|
|
622
548
|
function getLeyningForHoliday(ev, il = false) {
|
|
623
549
|
if (typeof ev !== 'object' || !(ev instanceof Event)) {
|
|
624
550
|
throw new TypeError(`Bad event argument: ${ev}`);
|
|
@@ -627,11 +553,11 @@ function getLeyningForHoliday(ev, il = false) {
|
|
|
627
553
|
} else if (ev.getFlags() & HOLIDAY_IGNORE_MASK) {
|
|
628
554
|
return undefined;
|
|
629
555
|
}
|
|
630
|
-
|
|
631
556
|
const key = getLeyningKeyForEvent(ev, il);
|
|
632
557
|
const leyning = getLeyningForHolidayKey(key, ev.cholHaMoedDay);
|
|
633
558
|
return leyning;
|
|
634
559
|
}
|
|
560
|
+
|
|
635
561
|
/**
|
|
636
562
|
* Looks up leyning for a given holiday key. Key should be an
|
|
637
563
|
* (untranslated) string used in holiday-readings.json. Returns some
|
|
@@ -640,62 +566,50 @@ function getLeyningForHoliday(ev, il = false) {
|
|
|
640
566
|
* @param {number} [cholHaMoedDay]
|
|
641
567
|
* @return {Leyning} map of aliyot
|
|
642
568
|
*/
|
|
643
|
-
|
|
644
569
|
function getLeyningForHolidayKey(key, cholHaMoedDay) {
|
|
645
570
|
if (typeof key !== 'string') {
|
|
646
571
|
return undefined;
|
|
647
572
|
}
|
|
648
|
-
|
|
649
573
|
const src = lookupFestival(key);
|
|
650
|
-
|
|
651
574
|
if (typeof src === 'undefined') {
|
|
652
575
|
return undefined;
|
|
653
576
|
}
|
|
654
|
-
|
|
655
577
|
const leyning = {
|
|
656
578
|
name: {
|
|
657
579
|
en: key,
|
|
658
580
|
he: Locale.lookupTranslation(key, 'he')
|
|
659
581
|
}
|
|
660
582
|
};
|
|
661
|
-
|
|
662
583
|
if (src.fullkriyah) {
|
|
663
584
|
leyning.fullkriyah = clone(src.fullkriyah);
|
|
664
|
-
|
|
665
585
|
if (key === 'Sukkot Shabbat Chol ha-Moed' && cholHaMoedDay) {
|
|
666
586
|
leyning.fullkriyah['M'] = leyning.fullkriyah[`M-day${cholHaMoedDay}`];
|
|
667
|
-
|
|
668
587
|
for (let day = 1; day <= 5; day++) {
|
|
669
588
|
delete leyning.fullkriyah[`M-day${day}`];
|
|
670
589
|
}
|
|
671
590
|
}
|
|
672
|
-
|
|
673
591
|
if (typeof leyning.fullkriyah['1'] === 'object') {
|
|
674
592
|
const parts = makeLeyningParts(leyning.fullkriyah);
|
|
675
593
|
leyning.summary = makeSummaryFromParts(parts);
|
|
676
|
-
|
|
677
594
|
if (parts.length > 1) {
|
|
678
595
|
leyning.summaryParts = parts;
|
|
679
596
|
}
|
|
680
597
|
}
|
|
681
|
-
|
|
682
598
|
Object.values(leyning.fullkriyah).map(aliyah => calculateNumVerses(aliyah));
|
|
683
599
|
}
|
|
684
|
-
|
|
685
600
|
if (src.haft) {
|
|
686
601
|
const haft = leyning.haft = cloneHaftara(src.haft);
|
|
687
602
|
leyning.haftara = makeSummaryFromParts(haft);
|
|
688
603
|
leyning.haftaraNumV = sumVerses(haft);
|
|
689
604
|
}
|
|
690
|
-
|
|
691
605
|
if (src.seph) {
|
|
692
606
|
const seph = leyning.seph = cloneHaftara(src.seph);
|
|
693
607
|
leyning.sephardic = makeSummaryFromParts(seph);
|
|
694
608
|
leyning.sephardicNumV = sumVerses(seph);
|
|
695
609
|
}
|
|
696
|
-
|
|
697
610
|
return leyning;
|
|
698
611
|
}
|
|
612
|
+
|
|
699
613
|
/**
|
|
700
614
|
* on doubled parshiot, read only the second Haftarah
|
|
701
615
|
* except for Nitzavim-Vayelech
|
|
@@ -703,7 +617,6 @@ function getLeyningForHolidayKey(key, cholHaMoedDay) {
|
|
|
703
617
|
* @param {string[]} parsha
|
|
704
618
|
* @return {string}
|
|
705
619
|
*/
|
|
706
|
-
|
|
707
620
|
function getHaftaraKey(parsha) {
|
|
708
621
|
if (parsha.length == 1 || parsha[0] == 'Nitzavim') {
|
|
709
622
|
return parsha[0];
|
|
@@ -711,20 +624,17 @@ function getHaftaraKey(parsha) {
|
|
|
711
624
|
return parsha[1];
|
|
712
625
|
}
|
|
713
626
|
}
|
|
627
|
+
|
|
714
628
|
/**
|
|
715
629
|
* Looks up regular leyning for a weekly parsha with no special readings
|
|
716
630
|
* @param {string|string[]} parsha untranslated name like 'Pinchas' or ['Pinchas'] or ['Matot','Masei']
|
|
717
631
|
* @return {Leyning} map of aliyot
|
|
718
632
|
*/
|
|
719
|
-
|
|
720
|
-
|
|
721
633
|
function getLeyningForParsha(parsha) {
|
|
722
634
|
const isParshaString = typeof parsha === 'string';
|
|
723
|
-
|
|
724
635
|
if (!isParshaString && (!Array.isArray(parsha) || parsha.length !== 1 && parsha.length !== 2)) {
|
|
725
636
|
throw new TypeError(`Bad parsha argument: ${parsha}`);
|
|
726
637
|
}
|
|
727
|
-
|
|
728
638
|
const name = isParshaString ? parsha : parshaToString(parsha);
|
|
729
639
|
const raw = parshiyotObj[name];
|
|
730
640
|
const fullkriyah = {};
|
|
@@ -743,7 +653,6 @@ function getLeyningForParsha(parsha) {
|
|
|
743
653
|
const parts = makeLeyningParts(fullkriyah);
|
|
744
654
|
const summary = makeSummaryFromParts(parts);
|
|
745
655
|
/** @type {Leyning} */
|
|
746
|
-
|
|
747
656
|
const result = {
|
|
748
657
|
name: {
|
|
749
658
|
en: name,
|
|
@@ -754,28 +663,22 @@ function getLeyningForParsha(parsha) {
|
|
|
754
663
|
summary,
|
|
755
664
|
fullkriyah: fullkriyah
|
|
756
665
|
};
|
|
757
|
-
|
|
758
666
|
if (parts.length > 1) {
|
|
759
667
|
result.summaryParts = parts;
|
|
760
668
|
}
|
|
761
|
-
|
|
762
669
|
const hkey = getHaftaraKey(parshaNameArray);
|
|
763
670
|
const haft0 = parshiyotObj[hkey].haft;
|
|
764
|
-
|
|
765
671
|
if (haft0) {
|
|
766
672
|
const haft = result.haft = cloneHaftara(haft0);
|
|
767
673
|
result.haftara = makeSummaryFromParts(haft);
|
|
768
674
|
result.haftaraNumV = sumVerses(haft);
|
|
769
675
|
}
|
|
770
|
-
|
|
771
676
|
if (raw.seph) {
|
|
772
677
|
const seph = result.seph = cloneHaftara(raw.seph);
|
|
773
678
|
result.sephardic = makeSummaryFromParts(seph);
|
|
774
679
|
result.sephardicNumV = sumVerses(seph);
|
|
775
680
|
}
|
|
776
|
-
|
|
777
681
|
const weekdaySrc = raw.weekday || parshiyotObj[parshaNameArray[0]].weekday;
|
|
778
|
-
|
|
779
682
|
if (weekdaySrc) {
|
|
780
683
|
const weekday = result.weekday = {};
|
|
781
684
|
['1', '2', '3'].forEach(num => {
|
|
@@ -789,9 +692,9 @@ function getLeyningForParsha(parsha) {
|
|
|
789
692
|
weekday[num] = aliyah;
|
|
790
693
|
});
|
|
791
694
|
}
|
|
792
|
-
|
|
793
695
|
return result;
|
|
794
696
|
}
|
|
697
|
+
|
|
795
698
|
/**
|
|
796
699
|
* Looks up leyning for a regular Shabbat parsha, including any special
|
|
797
700
|
* maftir or Haftara.
|
|
@@ -799,42 +702,35 @@ function getLeyningForParsha(parsha) {
|
|
|
799
702
|
* @param {boolean} [il] in Israel
|
|
800
703
|
* @return {Leyning} map of aliyot
|
|
801
704
|
*/
|
|
802
|
-
|
|
803
705
|
function getLeyningForParshaHaShavua(ev, il = false) {
|
|
804
706
|
if (!ev instanceof Event) {
|
|
805
707
|
throw new TypeError(`Bad event argument: ${ev}`);
|
|
806
708
|
} else if (ev.getFlags() != flags.PARSHA_HASHAVUA) {
|
|
807
709
|
throw new TypeError(`Event must be parsha hashavua: ${ev.getDesc()}`);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
|
|
710
|
+
}
|
|
711
|
+
// first, collect the default aliyot and haftara
|
|
811
712
|
const parsha = ev.parsha;
|
|
812
713
|
const result = getLeyningForParsha(parsha);
|
|
813
714
|
const reason = {};
|
|
814
|
-
const hd = ev.getDate();
|
|
815
|
-
|
|
715
|
+
const hd = ev.getDate();
|
|
716
|
+
// Now, check for special maftir or haftara on same date
|
|
816
717
|
const specialHaftara = specialReadings(hd, il, result.fullkriyah, reason, parsha, true);
|
|
817
|
-
|
|
818
718
|
if (specialHaftara) {
|
|
819
719
|
const haft = result.haft = cloneHaftara(specialHaftara.haft);
|
|
820
720
|
result.haftara = makeSummaryFromParts(haft);
|
|
821
721
|
result.haftaraNumV = sumVerses(haft);
|
|
822
|
-
|
|
823
722
|
if (specialHaftara.seph) {
|
|
824
723
|
const seph = result.seph = cloneHaftara(specialHaftara.seph);
|
|
825
724
|
result.sephardic = makeSummaryFromParts(seph);
|
|
826
725
|
result.sephardicNumV = sumVerses(seph);
|
|
827
726
|
}
|
|
828
727
|
}
|
|
829
|
-
|
|
830
728
|
if (reason['7'] || reason['M']) {
|
|
831
729
|
const parts = makeLeyningParts(result.fullkriyah);
|
|
832
730
|
result.summary = makeSummaryFromParts(parts);
|
|
833
731
|
result.summaryParts = parts;
|
|
834
732
|
}
|
|
835
|
-
|
|
836
733
|
const reasons = Object.keys(reason);
|
|
837
|
-
|
|
838
734
|
if (reasons.length !== 0) {
|
|
839
735
|
result.reason = reason;
|
|
840
736
|
reasons.forEach(num => {
|
|
@@ -844,18 +740,17 @@ function getLeyningForParshaHaShavua(ev, il = false) {
|
|
|
844
740
|
hafts.forEach(haft => haft.reason = reason[num]);
|
|
845
741
|
} else {
|
|
846
742
|
const aliyah = result.fullkriyah[num];
|
|
847
|
-
|
|
848
743
|
if (typeof aliyah === 'object') {
|
|
849
744
|
aliyah.reason = reason[num];
|
|
850
745
|
}
|
|
851
746
|
}
|
|
852
747
|
});
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
|
|
748
|
+
}
|
|
749
|
+
// to avoid confusion, don't include Saturday mincha reading here
|
|
856
750
|
delete result.weekday;
|
|
857
751
|
return result;
|
|
858
752
|
}
|
|
753
|
+
|
|
859
754
|
/**
|
|
860
755
|
* Looks up leyning for a regular Shabbat, Monday/Thursday weekday or holiday.
|
|
861
756
|
*
|
|
@@ -873,28 +768,22 @@ function getLeyningForParshaHaShavua(ev, il = false) {
|
|
|
873
768
|
* @param {boolean} il in Israel
|
|
874
769
|
* @return {Leyning} map of aliyot
|
|
875
770
|
*/
|
|
876
|
-
|
|
877
771
|
function getLeyningOnDate(hdate, il) {
|
|
878
772
|
const dow = hdate.getDay();
|
|
879
773
|
const hyear = hdate.getFullYear();
|
|
880
774
|
const sedra = HebrewCalendar.getSedra(hyear, il);
|
|
881
775
|
const parsha = sedra.lookup(hdate);
|
|
882
|
-
|
|
883
776
|
if (dow === 6 && !parsha.chag) {
|
|
884
777
|
const parshaEvent = new ParshaEvent(hdate, parsha.parsha, il);
|
|
885
778
|
return getLeyningForParshaHaShavua(parshaEvent, il);
|
|
886
779
|
}
|
|
887
|
-
|
|
888
780
|
const events = HebrewCalendar.getHolidaysOnDate(hdate, il) || [];
|
|
889
|
-
|
|
890
781
|
for (let i = 0; i < events.length; i++) {
|
|
891
782
|
const reading = getLeyningForHoliday(events[i], il);
|
|
892
|
-
|
|
893
783
|
if (reading) {
|
|
894
784
|
return reading;
|
|
895
785
|
}
|
|
896
786
|
}
|
|
897
|
-
|
|
898
787
|
if (dow === 1 || dow === 4) {
|
|
899
788
|
const saturday = hdate.onOrAfter(6);
|
|
900
789
|
const parsha2 = findParshaHaShavua(saturday);
|
|
@@ -906,44 +795,38 @@ function getLeyningOnDate(hdate, il) {
|
|
|
906
795
|
weekday: reading.weekday
|
|
907
796
|
};
|
|
908
797
|
return result;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
|
|
798
|
+
}
|
|
799
|
+
// no reading today: it's not Shabbat, Mon/Thu, or a Torah-reading holiday
|
|
912
800
|
return undefined;
|
|
913
801
|
}
|
|
802
|
+
|
|
914
803
|
/**
|
|
915
804
|
* @private
|
|
916
805
|
* @param {HDate} saturday
|
|
917
806
|
* @param {boolean} il
|
|
918
807
|
* @return {Leyning}
|
|
919
808
|
*/
|
|
920
|
-
|
|
921
809
|
function findParshaHaShavua(saturday, il) {
|
|
922
810
|
const hyear = saturday.getFullYear();
|
|
923
811
|
const sedra = HebrewCalendar.getSedra(hyear, il);
|
|
924
812
|
const parsha = sedra.lookup(saturday);
|
|
925
|
-
|
|
926
813
|
if (!parsha.chag) {
|
|
927
814
|
return parsha;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
|
|
815
|
+
}
|
|
816
|
+
// Search for next regular parsha, which could even spill into next year
|
|
931
817
|
const endOfYear = new HDate(1, months.TISHREI, hyear + 1).abs() - 1;
|
|
932
818
|
const endAbs = endOfYear + 30;
|
|
933
|
-
|
|
934
819
|
for (let sat2 = saturday.abs() + 7; sat2 <= endAbs; sat2 += 7) {
|
|
935
820
|
const sedra2 = sat2 > endOfYear ? HebrewCalendar.getSedra(hyear + 1, il) : sedra;
|
|
936
821
|
const parsha2 = sedra2.lookup(sat2);
|
|
937
|
-
|
|
938
822
|
if (!parsha2.chag) {
|
|
939
823
|
return parsha2;
|
|
940
824
|
}
|
|
941
825
|
}
|
|
942
826
|
/* NOTREACHED */
|
|
943
|
-
|
|
944
|
-
|
|
945
827
|
return null;
|
|
946
828
|
}
|
|
829
|
+
|
|
947
830
|
/**
|
|
948
831
|
* Parsha metadata
|
|
949
832
|
* @typedef {Object} ParshaMeta
|
|
@@ -962,22 +845,16 @@ function findParshaHaShavua(saturday, il) {
|
|
|
962
845
|
* @param {string|string[]} parsha
|
|
963
846
|
* @return {ParshaMeta}
|
|
964
847
|
*/
|
|
965
|
-
|
|
966
|
-
|
|
967
848
|
function lookupParsha(parsha) {
|
|
968
849
|
const isParshaString = typeof parsha === 'string';
|
|
969
|
-
|
|
970
850
|
if (!isParshaString && (!Array.isArray(parsha) || parsha.length !== 1 && parsha.length !== 2)) {
|
|
971
851
|
throw new TypeError(`Bad parsha argument: ${parsha}`);
|
|
972
852
|
}
|
|
973
|
-
|
|
974
853
|
const name = isParshaString ? parsha : parshaToString(parsha);
|
|
975
854
|
const raw = parshiyotObj[name];
|
|
976
|
-
|
|
977
855
|
if (typeof raw !== 'object') {
|
|
978
856
|
throw new TypeError(`Bad parsha argument: ${parsha}`);
|
|
979
857
|
}
|
|
980
|
-
|
|
981
858
|
return raw;
|
|
982
859
|
}
|
|
983
860
|
|
|
@@ -986,23 +863,22 @@ const fmt = new Intl.DateTimeFormat('en-US', {
|
|
|
986
863
|
month: 'short',
|
|
987
864
|
day: '2-digit'
|
|
988
865
|
});
|
|
866
|
+
|
|
989
867
|
/**
|
|
990
868
|
* @private
|
|
991
869
|
* @param {Date} dt
|
|
992
870
|
* @return {string}
|
|
993
871
|
*/
|
|
994
|
-
|
|
995
872
|
function fmtDate(dt) {
|
|
996
873
|
const s = fmt.format(dt).split(' ');
|
|
997
874
|
return s[1].substring(0, 2) + '-' + s[0] + '-' + s[2];
|
|
998
875
|
}
|
|
876
|
+
|
|
999
877
|
/**
|
|
1000
878
|
* @private
|
|
1001
879
|
* @param {Event[]} events
|
|
1002
880
|
* @return {Object<string,boolean>}
|
|
1003
881
|
*/
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
882
|
function getParshaDates(events) {
|
|
1007
883
|
const parshaEvents = events.filter(ev => ev.getFlags() === flags.PARSHA_HASHAVUA);
|
|
1008
884
|
const parshaDates = parshaEvents.reduce((set, ev) => {
|
|
@@ -1011,13 +887,13 @@ function getParshaDates(events) {
|
|
|
1011
887
|
}, {});
|
|
1012
888
|
return parshaDates;
|
|
1013
889
|
}
|
|
890
|
+
|
|
1014
891
|
/**
|
|
1015
892
|
* @private
|
|
1016
893
|
* @param {fs.WriteStream} stream
|
|
1017
894
|
* @param {number} hyear
|
|
1018
895
|
* @param {boolean} il
|
|
1019
896
|
*/
|
|
1020
|
-
|
|
1021
897
|
function writeFullKriyahCsv(stream, hyear, il) {
|
|
1022
898
|
const events0 = HebrewCalendar.calendar({
|
|
1023
899
|
year: hyear,
|
|
@@ -1034,68 +910,61 @@ function writeFullKriyahCsv(stream, hyear, il) {
|
|
|
1034
910
|
}
|
|
1035
911
|
});
|
|
1036
912
|
}
|
|
913
|
+
|
|
1037
914
|
/**
|
|
1038
915
|
* @private
|
|
1039
916
|
* @param {Event} ev
|
|
1040
917
|
* @return {boolean}
|
|
1041
918
|
*/
|
|
1042
|
-
|
|
1043
919
|
function ignore(ev) {
|
|
1044
920
|
const mask = ev.getFlags();
|
|
1045
|
-
|
|
1046
921
|
if (mask === flags.SPECIAL_SHABBAT) {
|
|
1047
922
|
return true;
|
|
1048
923
|
}
|
|
1049
|
-
|
|
1050
924
|
if (mask !== flags.ROSH_CHODESH) {
|
|
1051
925
|
return false;
|
|
1052
926
|
}
|
|
1053
|
-
|
|
1054
927
|
return ev.getDate().getDay() === 6;
|
|
1055
928
|
}
|
|
929
|
+
|
|
1056
930
|
/**
|
|
1057
931
|
* @private
|
|
1058
932
|
* @param {fs.WriteStream} stream
|
|
1059
933
|
* @param {Event} ev
|
|
1060
934
|
* @param {boolean} il
|
|
1061
935
|
*/
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
936
|
function writeFullKriyahEvent(stream, ev, il) {
|
|
1065
937
|
if (ignore(ev)) {
|
|
1066
938
|
return;
|
|
1067
939
|
}
|
|
1068
|
-
|
|
1069
940
|
const mask = ev.getFlags();
|
|
1070
941
|
const isParsha = mask === flags.PARSHA_HASHAVUA;
|
|
1071
942
|
const reading = isParsha ? getLeyningForParshaHaShavua(ev, il) : getLeyningForHoliday(ev, il);
|
|
1072
|
-
|
|
1073
943
|
if (reading) {
|
|
1074
944
|
writeCsvLines(stream, ev, reading, il, isParsha);
|
|
1075
|
-
|
|
1076
945
|
if (!isParsha) {
|
|
1077
946
|
writeHolidayMincha(stream, ev, il);
|
|
1078
947
|
}
|
|
1079
948
|
}
|
|
1080
949
|
}
|
|
950
|
+
|
|
1081
951
|
/**
|
|
1082
952
|
* @private
|
|
1083
953
|
* @param {fs.WriteStream} stream
|
|
1084
954
|
* @param {Event} ev
|
|
1085
955
|
* @param {boolean} il
|
|
1086
956
|
*/
|
|
1087
|
-
|
|
1088
957
|
function writeHolidayMincha(stream, ev, il) {
|
|
1089
958
|
const desc = ev.getDesc();
|
|
1090
959
|
const minchaDesc1 = desc + ' (Mincha)';
|
|
1091
960
|
const readingMincha1 = getLeyningForHolidayKey(minchaDesc1);
|
|
1092
961
|
const readingMincha = readingMincha1 || getLeyningForHolidayKey(getLeyningKeyForEvent(ev, il) + ' (Mincha)');
|
|
1093
|
-
|
|
1094
962
|
if (readingMincha) {
|
|
1095
963
|
const minchaEv = new Event(ev.getDate(), minchaDesc1, flags.USER_EVENT);
|
|
1096
964
|
writeCsvLines(stream, minchaEv, readingMincha, il, false);
|
|
1097
965
|
}
|
|
1098
966
|
}
|
|
967
|
+
|
|
1099
968
|
/**
|
|
1100
969
|
* Formats reading for CSV
|
|
1101
970
|
* @param {fs.WriteStream} stream
|
|
@@ -1104,75 +973,59 @@ function writeHolidayMincha(stream, ev, il) {
|
|
|
1104
973
|
* @param {boolean} il
|
|
1105
974
|
* @param {boolean} isParsha
|
|
1106
975
|
*/
|
|
1107
|
-
|
|
1108
976
|
function writeCsvLines(stream, ev, reading, il, isParsha) {
|
|
1109
977
|
const parsha = isParsha ? ev.basename() : getLeyningKeyForEvent(ev, il) || ev.render();
|
|
1110
978
|
const date = fmtDate(ev.getDate().greg());
|
|
1111
979
|
const lines = getFullKriyahLines(reading);
|
|
1112
980
|
lines.forEach(s => {
|
|
1113
981
|
const code = s[0].charCodeAt(0);
|
|
1114
|
-
|
|
1115
982
|
if (code < 48 || code > 57) {
|
|
1116
983
|
s[0] = `"${s[0]}"`;
|
|
1117
984
|
}
|
|
1118
|
-
|
|
1119
985
|
stream.write(`${date},"${parsha}",${s[0]},"${s[1]}",${s[2]}\r\n`);
|
|
1120
986
|
});
|
|
1121
987
|
stream.write('\r\n');
|
|
1122
988
|
}
|
|
989
|
+
|
|
1123
990
|
/**
|
|
1124
991
|
* @private
|
|
1125
992
|
* @param {any} reading
|
|
1126
993
|
* @return {any[]}
|
|
1127
994
|
*/
|
|
1128
|
-
|
|
1129
995
|
function getFullKriyahLines(reading) {
|
|
1130
996
|
const lines = [];
|
|
1131
|
-
|
|
1132
997
|
if (reading.fullkriyah) {
|
|
1133
998
|
Object.keys(reading.fullkriyah).forEach(num => {
|
|
1134
999
|
const a = reading.fullkriyah[num];
|
|
1135
|
-
|
|
1136
1000
|
if (typeof a !== 'undefined') {
|
|
1137
1001
|
var _reading$reason;
|
|
1138
|
-
|
|
1139
1002
|
const k = num == 'M' ? 'maf' : num;
|
|
1140
1003
|
let aliyah = formatAliyahWithBook(a);
|
|
1141
|
-
|
|
1142
1004
|
if ((_reading$reason = reading.reason) !== null && _reading$reason !== void 0 && _reading$reason[num]) {
|
|
1143
1005
|
aliyah += ' | ' + reading.reason[num];
|
|
1144
1006
|
}
|
|
1145
|
-
|
|
1146
1007
|
lines.push([k, aliyah, a.v || '']);
|
|
1147
1008
|
}
|
|
1148
1009
|
});
|
|
1149
1010
|
}
|
|
1150
|
-
|
|
1151
1011
|
let specialHaftara = false;
|
|
1152
|
-
|
|
1153
1012
|
if (reading.haftara) {
|
|
1154
1013
|
var _reading$reason2;
|
|
1155
|
-
|
|
1156
1014
|
let haftara = reading.haftara.replace(/,/g, ';');
|
|
1157
|
-
|
|
1158
1015
|
if ((_reading$reason2 = reading.reason) !== null && _reading$reason2 !== void 0 && _reading$reason2.haftara) {
|
|
1159
1016
|
specialHaftara = true;
|
|
1160
1017
|
haftara += ' | ' + reading.reason.haftara;
|
|
1161
1018
|
}
|
|
1162
|
-
|
|
1163
1019
|
lines.push(['Haftara', haftara, reading.haftaraNumV || '']);
|
|
1164
1020
|
}
|
|
1165
|
-
|
|
1166
1021
|
if (reading.sephardic && !specialHaftara) {
|
|
1167
1022
|
const sephardic = reading.sephardic.replace(/,/g, ';');
|
|
1168
1023
|
lines.push(['Haftara for Sephardim', sephardic, reading.sephardicNumV || '']);
|
|
1169
1024
|
}
|
|
1170
|
-
|
|
1171
1025
|
if (reading.triHaftara) {
|
|
1172
1026
|
const haftara = reading.triHaftara.replace(/,/g, ';');
|
|
1173
1027
|
lines.push(['Alternate Haftara', haftara, reading.triHaftaraNumV || '']);
|
|
1174
1028
|
}
|
|
1175
|
-
|
|
1176
1029
|
return lines;
|
|
1177
1030
|
}
|
|
1178
1031
|
|