Skip to content

Commit

Permalink
Include alt Triennial Haftara in CSV
Browse files Browse the repository at this point in the history
  • Loading branch information
mjradwin committed Jul 8, 2022
1 parent 655df1f commit 8dde5c9
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 47 deletions.
1 change: 1 addition & 0 deletions bin/leyning-csv
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ for (let i = 0; i < numTriennialCycles; i++) {
const yearOffset = (i - 1) * 3;
const cycleStartYear = hyear - (yearNum - 1) + yearOffset;
const filename = `triennial-${cycleStartYear}-${cycleStartYear+2}.csv`;
console.log(`Creating ${filename}`);
const stream = fs.createWriteStream(filename, {flags: 'w'});
writeTriennialCsv(stream, cycleStartYear);
stream.end();
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"eslint-config-google": "^0.14.0",
"jsdoc": "^3.6.10",
"jsdoc-to-markdown": "^7.1.1",
"rollup": "^2.75.7",
"rollup": "^2.76.0",
"rollup-plugin-terser": "^7.0.2"
}
}
74 changes: 50 additions & 24 deletions src/csv.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {HebrewCalendar, flags} from '@hebcal/core';
import {getLeyningForParshaHaShavua, getLeyningForHoliday,
getLeyningKeyForEvent} from './leyning';
import {formatAliyahWithBook} from './common';
import {getTriennialForParshaHaShavua} from './triennial';
import {getTriennialForParshaHaShavua, getTriennialHaftaraForHoliday, Triennial} from './triennial';

const fmt = new Intl.DateTimeFormat('en-US', {
year: 'numeric', month: 'short', day: '2-digit',
Expand Down Expand Up @@ -85,26 +85,49 @@ export function writeTriennialEvent(stream, ev) {
if (ignore(ev)) {
return;
}
const isParsha = ev.getFlags() === flags.PARSHA_HASHAVUA;
const reading0 = isParsha ? getTriennialForParshaHaShavua(ev) : getLeyningForHoliday(ev, false);
if (!reading0) {
return;
}
let reading;
if (isParsha) {
const fk = getLeyningForParshaHaShavua(ev, false);
reading = {
haftara: fk.haftara,
haftaraNumV: fk.haftaraNumV,
sephardic: fk.sephardic,
sephardicNumV: fk.sephardicNumV,
reason: fk.reason,
fullkriyah: reading0,
};
if (ev.getFlags() === flags.PARSHA_HASHAVUA) {
writeTriennialEventParsha(stream, ev);
} else {
reading = reading0;
writeTriennialEventHoliday(stream, ev);
}
}

/**
* @private
* @param {fs.WriteStream} stream
* @param {Event} ev
*/
function writeTriennialEventHoliday(stream, ev) {
const il = false;
const reading = getLeyningForHoliday(ev, il);
if (reading) {
const key = getLeyningKeyForEvent(ev, il);
const year = ev.getDate().getFullYear();
const yearNum = Triennial.getYearNumber(year) - 1;
const triHaft = getTriennialHaftaraForHoliday(key, yearNum);
if (triHaft) {
reading.triHaftara = triHaft.haftara;
reading.triHaftaraNumV = triHaft.haftaraNumV;
}
writeCsvLines(stream, ev, reading, il, false);
}
}

/**
* @private
* @param {fs.WriteStream} stream
* @param {Event} ev
*/
function writeTriennialEventParsha(stream, ev) {
const triReading = getTriennialForParshaHaShavua(ev, true);
if (triReading) {
const il = false;
const reading = getLeyningForParshaHaShavua(ev, il);
reading.fullkriyah = triReading.aliyot;
reading.triHaftara = triReading.haftara;
reading.triHaftaraNumV = triReading.haftaraNumV;
writeCsvLines(stream, ev, reading, il, true);
}
writeCsvLines(stream, ev, reading, false);
}

/**
Expand Down Expand Up @@ -135,10 +158,9 @@ export function writeFullKriyahEvent(stream, ev, il) {
}
const isParsha = ev.getFlags() === flags.PARSHA_HASHAVUA;
const reading = isParsha ? getLeyningForParshaHaShavua(ev, il) : getLeyningForHoliday(ev, il);
if (!reading) {
return;
if (reading) {
writeCsvLines(stream, ev, reading, il, isParsha);
}
writeCsvLines(stream, ev, reading, il);
}

/**
Expand All @@ -147,9 +169,9 @@ export function writeFullKriyahEvent(stream, ev, il) {
* @param {Event} ev
* @param {Leyning} reading
* @param {boolean} il
* @param {boolean} isParsha
*/
function writeCsvLines(stream, ev, reading, il) {
const isParsha = ev.getFlags() === flags.PARSHA_HASHAVUA;
function writeCsvLines(stream, ev, reading, il, isParsha) {
const parsha = isParsha ? ev.basename() : getLeyningKeyForEvent(ev, il) || ev.render();
const date = fmtDate(ev.getDate().greg());
const lines = getFullKriyahLines(reading);
Expand Down Expand Up @@ -196,5 +218,9 @@ function getFullKriyahLines(reading) {
const sephardic = reading.sephardic.replace(/,/g, ';');
lines.push(['Haftara for Sephardim', sephardic, reading.sephardicNumV || '']);
}
if (reading.triHaftara) {
const haftara = reading.triHaftara.replace(/,/g, ';');
lines.push(['Alternate Haftara', haftara, reading.triHaftaraNumV || '']);
}
return lines;
}
40 changes: 40 additions & 0 deletions src/csv.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,43 @@ test('writeTriennialEvent-holiday', (t) => {
'', ''];
t.deepEqual(lines, expected);
});

test('writeTriennialEvent-parsha-alt-haftara', (t) => {
const ev = new ParshaEvent(new HDate(new Date(2016, 10, 19)), ['Vayera']);
const stream = new StringWritable();
writeTriennialEvent(stream, ev);
const lines = stream.toString().split('\r\n');
const expected = [
'19-Nov-2016,"Vayera",1,"Genesis 18:1-18:5",5',
'19-Nov-2016,"Vayera",2,"Genesis 18:6-18:8",3',
'19-Nov-2016,"Vayera",3,"Genesis 18:9-18:14",6',
'19-Nov-2016,"Vayera",4,"Genesis 18:15-18:21",7',
'19-Nov-2016,"Vayera",5,"Genesis 18:22-18:26",5',
'19-Nov-2016,"Vayera",6,"Genesis 18:27-18:30",4',
'19-Nov-2016,"Vayera",7,"Genesis 18:31-18:33",3',
'19-Nov-2016,"Vayera","maf","Genesis 18:31-18:33",3',
'19-Nov-2016,"Vayera","Haftara","II Kings 4:1-37",37',
'19-Nov-2016,"Vayera","Haftara for Sephardim","II Kings 4:1-23",23',
'19-Nov-2016,"Vayera","Alternate Haftara","II Kings 4:8-17",10',
'', ''];
t.deepEqual(lines, expected);
});

test('writeTriennialEvent-holiday-alt-haftara', (t) => {
const ev = new HolidayEvent(new HDate(16, months.TISHREI, 5789),
'Sukkot II', flags.CHAG | flags.YOM_TOV_ENDS | flags.CHUL_ONLY);
const stream = new StringWritable();
writeTriennialEvent(stream, ev);
const lines = stream.toString().split('\r\n');
const expected = [
'06-Oct-2028,"Sukkot II",1,"Leviticus 22:26-23:3",11',
'06-Oct-2028,"Sukkot II",2,"Leviticus 23:4-23:14",11',
'06-Oct-2028,"Sukkot II",3,"Leviticus 23:15-23:22",8',
'06-Oct-2028,"Sukkot II",4,"Leviticus 23:23-23:32",10',
'06-Oct-2028,"Sukkot II",5,"Leviticus 23:33-23:44",12',
'06-Oct-2028,"Sukkot II","maf","Numbers 29:12-29:16",5',
'06-Oct-2028,"Sukkot II","Haftara","I Kings 8:2-21",20',
'06-Oct-2028,"Sukkot II","Alternate Haftara","I Kings 8:2-13",12',
'', ''];
t.deepEqual(lines, expected);
});
35 changes: 35 additions & 0 deletions src/triHaft.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import test from 'ava';
import triennialHaft from './triennial-haft.json';
import numverses from './numverses.json';

// eslint-disable-next-line require-jsdoc
function testAliyah(t, name, haft) {
if (typeof haft === 'undefined') {
t.fail(`${name} => <undefined>`);
}
if (Array.isArray(haft)) {
for (const aliyah of haft) {
const numv = numverses[aliyah.k];
t.is(typeof numv, 'object', `${name} => ${aliyah.k}`);
}
} else {
const numv = numverses[haft.k];
t.is(typeof numv, 'object', `${name} => ${haft.k}`);
}
}

test('triennial-haft-spelling', (t) => {
for (const [parsha, triHaft] of Object.entries(triennialHaft)) {
if (parsha === '_holidays' || typeof triHaft === 'boolean') {
continue;
}
testAliyah(t, parsha, triHaft['1']);
testAliyah(t, parsha, triHaft['2']);
if (triHaft['3']) {
testAliyah(t, parsha, triHaft['3']);
}
}
for (const [holiday, haft] of Object.entries(triennialHaft._holidays)) {
testAliyah(t, holiday, haft);
}
});
19 changes: 9 additions & 10 deletions src/triennial-haft.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
},
"Vayetzei":{
"1":{"k":"Hosea","b":"12:3","e":"12:14","note":"Jacob story"},
"2":{"k":"Zekhariah","b":"1:7","e":"1:17","note":"striped horses //streaked sheep"},
"2":{"k":"Zechariah","b":"1:7","e":"1:17","note":"striped horses //streaked sheep"},
"3":{"k":"I Samuel","b":"19:11","e":"19:18","note":"deceit / terafim / female wiles // Rachel hides terafim"}
},
"Vayishlach":{
"1":[{"k":"Ovadiah","b":"1:10","e":"1:18","note":"Jacob defeats Edom (Babylon) // Jacob meets Esau"},
{"k":"Ovadiah","b":"1:21","e":"1:21"}],
"1":[{"k":"Obadiah","b":"1:10","e":"1:18","note":"Jacob defeats Edom (Babylon) // Jacob meets Esau"},
{"k":"Obadiah","b":"1:21","e":"1:21"}],
"2":{"k":"Jeremiah","b":"30:10","e":"30:22","note":"Jacob will return, settle // Jacob's early settling in Shechem and Bet El"},
"3":[{"k":"Amos","b":"1:1","e":"1:1","note":"prophecy against Edom // genealogy of Edom"},
{"k":"Amos","b":"1:11","e":"2:3"}]
Expand All @@ -55,7 +55,7 @@
},
"Vayigash":{
"1":{"k":"Ezekiel","b":"37:15","e":"37:28","note":"Judah and Joseph united"},
"2":{"k":"Zekhariah","b":"10:3","e":"10:12","note":"Judah and Joseph, return from Egypt // J & J, brothers return to Jacob"},
"2":{"k":"Zechariah","b":"10:3","e":"10:12","note":"Judah and Joseph, return from Egypt // J & J, brothers return to Jacob"},
"3":{"k":"Isaiah","b":"41:1","e":"41:10","note":"brother helps / Jacob not fear // Joseph settles his family in Goshen"}
},
"Vayechi":{
Expand Down Expand Up @@ -104,7 +104,7 @@
"3":{"k":"Joshua","b":"24:16","e":"24:28","note":"Joshua's covenant // na'aseh v'nishma"}
},
"Terumah":{
"1":{"k":"Zekhariah","b":"2:5","e":"2:17","note":"God's presence in Israelvshakhanti b'tokhekh"},
"1":{"k":"Zechariah","b":"2:5","e":"2:17","note":"God's presence in Israelvshakhanti b'tokhekh"},
"2":{"k":"I Kings","b":"6:1","e":"6:13","note":"Temple // Tabernacle"},
"3":{"k":"II Samuel","b":"7:1","e":"7:16","note":"Temple // Tabernacle"}
},
Expand Down Expand Up @@ -197,8 +197,8 @@
{"k":"Joel","b":"2:12","e":"2:14"}]
},
"Beha'alotcha":{
"1":[{"k":"Zekhariah","b":"3:1","e":"3:5","note":"Purifying kohen, Menorah // Menorah, purifying leviim"},
{"k":"Zekhariah","b":"4:1","e":"4:7"}],
"1":[{"k":"Zechariah","b":"3:1","e":"3:5","note":"Purifying kohen, Menorah // Menorah, purifying leviim"},
{"k":"Zechariah","b":"4:1","e":"4:7"}],
"2":[{"k":"Joshua","b":"3:3","e":"3:8","note":"Ark leads in travel"},
{"k":"Joshua","b":"3:17","e":" 4:7"}],
"3":{"k":"II Kings","b":"20:1","e":"20:11","note":"Hezekiah healed thru prayer // Miriam"}
Expand Down Expand Up @@ -248,7 +248,7 @@
"Eikev":{
"1":{"k":"Isaiah","b":"49:14","e":"49:26","note":"ani moshiekh"},
"2":{"k":"Isaiah","b":"50:1","e":"51:3","note":"sason v'simcha yimatze"},
"3":{"k":"Zekhariah","b":"8:1","e":"8:8","note":"be'emet u-vitzdakah"}
"3":{"k":"Zechariah","b":"8:1","e":"8:8","note":"be'emet u-vitzdakah"}
},
"Re'eh":{
"1":{"k":"Isaiah","b":"54:11","e":"55:5**","note":"aniya soarah"},
Expand All @@ -270,7 +270,7 @@
"Ki Tavo":{
"1":{"k":"Isaiah","b":"60:1","e":"60:9","note":"kumi ori"},
"2":{"k":"Isaiah","b":"60:13","e":"60:22","note":"amekh kulam tzadikim"},
"3":{"k":"Zekhariah","b":"8:11","e":"8:22","note":"emet umishpat shalom"}
"3":{"k":"Zechariah","b":"8:11","e":"8:22","note":"emet umishpat shalom"}
},
"Nitzavim":{
"1":{"k":"Isaiah","b":"61:10","e":"62:12","note":"sos asis"},
Expand Down Expand Up @@ -321,7 +321,6 @@
{"k":"Habakkuk","b":"3:1","e":"3:13"},
{"k":"Habakkuk","b":"3:18","e":"3:19"}
],
"Rosh Hashana I (on Shabbat)":{"k":"I Samuel","b":"1:1","e":"2:10"},
"Rosh Hashana II":{"k":"Jeremiah","b":"31:2","e":"31:20"},
"Yom Kippur":{"k":"Isaiah","b":"58:1","e":"58:14"},
"Yom Kippur (on Shabbat)":{"k":"Isaiah","b":"58:1","e":"58:14"},
Expand Down
7 changes: 4 additions & 3 deletions src/triennial.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,9 @@ export function getTriennialForParshaHaShavua(ev, context=false) {
* @return {Object}
*/
export function getTriennialHaftara(parsha, yearNum) {
const p1 = parsha[0];
const triHaft = parsha.length === 1 ? triennialHaft[p1] :
yearNum === 0 ? triennialHaft[p1] : triennialHaft[parsha[1]];
const idx = (parsha.length === 1 || yearNum === 0) ? 0 : 1;
const name = parsha[idx];
const triHaft = triennialHaft[name];
const triHaft2 = triHaft && triHaft[yearNum + 1];
if (typeof triHaft2 === 'object') {
const haft = cloneHaftara(triHaft2);
Expand Down Expand Up @@ -412,4 +412,5 @@ export function getTriennialHaftaraForHoliday(key, yearNum) {
haftaraNumV: calculateHaftaraNumV(haft),
};
}
return undefined;
}
4 changes: 4 additions & 0 deletions src/triennial.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,4 +386,8 @@ test('getTriennialHaftaraForHoliday', (t) => {
t.is(av9yr2.haftara, 'Jeremiah 9:1-10, 9:23');
const av9yr3 = getTriennialHaftaraForHoliday('Tish\'a B\'Av', 2);
t.is(av9yr3.haftara, 'Jeremiah 9:11-23');
const rh1 = getTriennialHaftaraForHoliday('Rosh Hashana I', 0);
t.is(rh1, undefined);
const rh2 = getTriennialHaftaraForHoliday('Rosh Hashana II', 0);
t.is(rh2.haftara, 'Jeremiah 31:2-20');
});

0 comments on commit 8dde5c9

Please sign in to comment.