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