Omit responsories' own closing Gloria Patri throughout Passiontide
A different, wider rule than the psalm/canticle Gloria (Triduum-only): responsories drop their Gloria for the whole of Passiontide (Passion Sunday through Holy Saturday), except on a Sancti feast's own day — live-verified (St. Joseph, Duplex I, 2027-03-19, landing in Passiontide that year, keeps it; an ordinary ferial day in the same window omits it, at both Compline and Prime). Every responsory's stored text differs, Gloria-bearing vs Gloria-free, by exactly one fixed-wording line, so resolve-common.ts's new resolveResponsory filters that line out rather than requiring separate per-season files or a data migration — mechanism first, per the project's own stated content-authoring order. Wired into the four hours that have a real responsory (Compline, Prime, Lauds, Vespers); Lauds/ Vespers' existing hand-authored Passiontide-proper responsories were already Gloria-free and are unaffected.
This commit is contained in:
@@ -7,7 +7,7 @@ import { getHymnDoxologyId } from './hymn-doxology';
|
||||
import { getOpeningVersicleId } from './opening-versicle';
|
||||
import { getMarianAntiphonId, getMarianAntiphonLabel } from './marian-antiphon';
|
||||
import { isDoubleOrHigher } from './antiphon';
|
||||
import { resolveCommon, appendDoxology, splitNamedAntiphon } from './resolve-common';
|
||||
import { resolveCommon, appendDoxology, splitNamedAntiphon, resolveResponsory } from './resolve-common';
|
||||
import complineDefinitionData from '../data/hours/compline.yml';
|
||||
|
||||
const complineDefinition = complineDefinitionData as HourDefinition;
|
||||
@@ -36,10 +36,11 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
|
||||
return [{ kind: 'hymn', text: appendDoxology(body, doxology) }];
|
||||
}
|
||||
case 'chapter':
|
||||
case 'responsory':
|
||||
case 'versicle':
|
||||
case 'prayer':
|
||||
return [{ kind: part.kind, text: resolveCommon(part.textRef.id) }];
|
||||
case 'responsory':
|
||||
return [{ kind: 'responsory', text: resolveResponsory(resolveCommon(part.textRef.id), day) }];
|
||||
case 'preces':
|
||||
if (part.omitOnDouble && isDoubleOrHigher(day.winner)) {
|
||||
return [];
|
||||
|
||||
+3
-2
@@ -19,6 +19,7 @@ import {
|
||||
seasonalOfficeSuffix,
|
||||
isFerialOrVigil,
|
||||
getOfficeOverrideId,
|
||||
resolveResponsory,
|
||||
} from './resolve-common';
|
||||
import laudsDefinitionData from '../data/hours/lauds.yml';
|
||||
import laudsAntiphonsData from '../data/hours/lauds-antiphons.yml';
|
||||
@@ -192,7 +193,7 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
||||
if (chapter.status.la !== 'missing' || chapter.status.en !== 'missing') {
|
||||
return [
|
||||
{ kind: 'chapter', text: chapter },
|
||||
{ kind: 'responsory', text: resolveCommon(`lauds-responsory-${overrideId}`) },
|
||||
{ kind: 'responsory', text: resolveResponsory(resolveCommon(`lauds-responsory-${overrideId}`), day) },
|
||||
{ kind: 'hymn', text: resolveCommon(`lauds-hymn-${overrideId}`) },
|
||||
{ kind: 'versicle', text: resolveCommon(`lauds-versicle-${overrideId}`) },
|
||||
];
|
||||
@@ -202,7 +203,7 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
||||
const key = seasonSuffix ?? day.weekday;
|
||||
return [
|
||||
{ kind: 'chapter', text: resolveCommon(seasonSuffix ? `lauds-capitulum-${key}` : capitulumId(day.weekday)) },
|
||||
{ kind: 'responsory', text: resolveCommon(`lauds-responsory-${key}`) },
|
||||
{ kind: 'responsory', text: resolveResponsory(resolveCommon(`lauds-responsory-${key}`), day) },
|
||||
{ kind: 'hymn', text: resolveCommon(`lauds-hymn-${key}`) },
|
||||
{ kind: 'versicle', text: resolveCommon(`lauds-versicle-${key}`) },
|
||||
];
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ import {
|
||||
resolveOfficeWinner,
|
||||
resolveMinorHourAntiphon,
|
||||
isSundayOrFeastOffice,
|
||||
resolveResponsory,
|
||||
} from './resolve-common';
|
||||
import primeDefinitionData from '../data/hours/prime.yml';
|
||||
import antiphonsData from '../data/hours/prime-antiphons.yml';
|
||||
@@ -60,7 +61,7 @@ function resolvePart(part: HourPart, date: string, day: LiturgicalDay): Resolved
|
||||
if (part.resolve === 'by-season') {
|
||||
// Currently only the chapter responsory's verse uses this — see
|
||||
// hours/chapter-responsory.ts. by-feast-rank doesn't apply to Prime.
|
||||
return [{ kind: 'responsory', text: resolveCommon(getChapterResponsoryId(day.season, day.winner)) }];
|
||||
return [{ kind: 'responsory', text: resolveResponsory(resolveCommon(getChapterResponsoryId(day.season, day.winner)), day) }];
|
||||
}
|
||||
{
|
||||
const psalmRefs = getPsalmsFor('prime', day.weekday);
|
||||
|
||||
@@ -697,3 +697,46 @@ export function resolveGloriaPatri(day: LiturgicalDay): ResolvedText | undefined
|
||||
}
|
||||
return verifiedText(GLORIA_PATRI);
|
||||
}
|
||||
|
||||
// The responsory's own closing Gloria is a DIFFERENT rule from the psalm/
|
||||
// canticle one above: wider window (all of Passiontide, Passion Sunday
|
||||
// through Holy Saturday -- `season === 'passiontide'` already covers
|
||||
// exactly that span, no separate date-window helper needed), and it
|
||||
// doesn't apply to a Sancti (saint) feast's own day even within that
|
||||
// window -- live-verified: St. Joseph (Duplex I, 2027-03-19, landing in
|
||||
// Passiontide that year) keeps "In manus tuas"'s Gloria at Compline, while
|
||||
// an ordinary ferial day in the same window (2027-03-15) omits it, at both
|
||||
// Compline and Prime's chapter-responsory.
|
||||
//
|
||||
// Every currently-authored responsory -- Gloria-bearing or already
|
||||
// Gloria-free (e.g. lauds-responsory-passiontide.yml, a genuinely
|
||||
// different proper-of-season chant, not a stripped copy of the ordinary
|
||||
// one) -- ends the same way regardless: a short "R. [repetenda]" after
|
||||
// the verse, then (only when shown) this same fixed Gloria line, then
|
||||
// always a final "R. [full repetenda]" line. So the two forms differ by
|
||||
// exactly one known, fixed-wording line -- omitting it is a filter, not a
|
||||
// data migration.
|
||||
const RESPONSORY_GLORIA_LINE: BilingualText = {
|
||||
la: 'V. Glória Patri, et Fílio, * et Spirítui Sancto.',
|
||||
en: 'V. Glory be to the Father, and to the Son, * and to the Holy Ghost.',
|
||||
};
|
||||
|
||||
export function omitResponsoryGloria(day: LiturgicalDay): boolean {
|
||||
return day.season === 'passiontide' && day.winner.kind !== 'sanctoral';
|
||||
}
|
||||
|
||||
/** Strips the responsory's closing Gloria line from `text` when the day
|
||||
* calls for its omission (see omitResponsoryGloria); returns `text`
|
||||
* unchanged otherwise. Safe to call on already-Gloria-free text (e.g. the
|
||||
* proper-of-season responsories) -- the line just won't be found. */
|
||||
export function resolveResponsory(text: ResolvedText, day: LiturgicalDay): ResolvedText {
|
||||
if (!omitResponsoryGloria(day)) {
|
||||
return text;
|
||||
}
|
||||
const stripped: Partial<Record<string, string>> = {};
|
||||
for (const [lang, t] of Object.entries(text.text)) {
|
||||
const gloriaLine = RESPONSORY_GLORIA_LINE[lang];
|
||||
stripped[lang] = t && gloriaLine ? t.split('\n').filter((line) => line !== gloriaLine).join('\n') : t;
|
||||
}
|
||||
return { ...text, text: stripped };
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
seasonalOfficeSuffix,
|
||||
isFerialOrVigil,
|
||||
getOfficeOverrideId,
|
||||
resolveResponsory,
|
||||
} from './resolve-common';
|
||||
import vespersDefinitionData from '../data/hours/vespers.yml';
|
||||
import vespersAntiphonsData from '../data/hours/vespers-antiphons.yml';
|
||||
@@ -122,7 +123,7 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
||||
if (chapter.status.la !== 'missing' || chapter.status.en !== 'missing') {
|
||||
return [
|
||||
{ kind: 'chapter', text: chapter },
|
||||
{ kind: 'responsory', text: resolveCommon(`vespers-responsory-${overrideId}`) },
|
||||
{ kind: 'responsory', text: resolveResponsory(resolveCommon(`vespers-responsory-${overrideId}`), day) },
|
||||
{ kind: 'hymn', text: resolveCommon(`vespers-hymn-${overrideId}`) },
|
||||
{ kind: 'versicle', text: resolveCommon(`vespers-versicle-${overrideId}`) },
|
||||
];
|
||||
@@ -137,7 +138,7 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
||||
},
|
||||
{
|
||||
kind: 'responsory',
|
||||
text: resolveCommon(seasonSuffix ? `vespers-responsory-${key}` : vespersResponsoryId(day.weekday)),
|
||||
text: resolveResponsory(resolveCommon(seasonSuffix ? `vespers-responsory-${key}` : vespersResponsoryId(day.weekday)), day),
|
||||
},
|
||||
{ kind: 'hymn', text: resolveCommon(`vespers-hymn-${key}`) },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user