Extend closing Gloria Patri to canticles, centralize instead of baking it in
Benedictus, Magnificat, and Nunc Dimittis had the Gloria Patri baked verbatim into their propers YAML with no Triduum suppression; Matins' Nocturn 3 OT canticles had none at all. Give the 'canticle' ResolvedPart the same centrally-attached gloriaPatri field psalms already got, strip the baked-in text, and drop Lauds' now-redundant local append/Triduum check — live-verified that canticles follow the exact same Triduum-only omission as psalms (e.g. Benedictus at Lauds of Holy Thursday).
This commit is contained in:
+8
-5
@@ -26,13 +26,16 @@ const registry: Record<HourId, Resolver> = {
|
||||
matins: matins.resolveOrdo,
|
||||
};
|
||||
|
||||
/** Attaches the closing Gloria Patri to every plain psalm part (recursing
|
||||
* into 'nocturn-psalmody' groups), so no per-hour builder has to remember
|
||||
* to do it — and so the Sacred Triduum omission (resolveGloriaPatri) is
|
||||
* enforced in exactly one place rather than once per hour file. */
|
||||
/** Attaches the closing Gloria Patri to every plain psalm and canticle part
|
||||
* (recursing into 'nocturn-psalmody' groups), so no per-hour builder has to
|
||||
* remember to do it — and so the Sacred Triduum omission
|
||||
* (resolveGloriaPatri) is enforced in exactly one place rather than once
|
||||
* per hour file. Live-verified (Divino Afflatu 1954, Tridentine 1906) that
|
||||
* canticles (e.g. Benedictus at Lauds of Holy Thursday) follow the exact
|
||||
* same Triduum-only omission as plain psalms — not a separate rule. */
|
||||
function withGloriaPatri(parts: ResolvedPart[], gloriaPatri: ResolvedText | undefined): ResolvedPart[] {
|
||||
return parts.map((part) => {
|
||||
if (part.kind === 'psalm') {
|
||||
if (part.kind === 'psalm' || part.kind === 'canticle') {
|
||||
return { ...part, gloriaPatri };
|
||||
}
|
||||
if (part.kind === 'nocturn-psalmody') {
|
||||
|
||||
+9
-17
@@ -1,7 +1,6 @@
|
||||
import type { HourDefinition, HourPart, ResolvedOrdo, ResolvedPart, ResolvedText } from './types';
|
||||
import type { LiturgicalDay, Weekday } from '../calendar/types';
|
||||
import { resolveDay, isSundayOrFeast, activeOctavesFor } from '../calendar';
|
||||
import { isInTriduum } from '../calendar/temporal';
|
||||
import { getDayLabel } from '../calendar/day-label';
|
||||
import { getTemporalFeastRecord } from '../calendar/temporal-feasts';
|
||||
import { getPsalmVerses } from '../psalter';
|
||||
@@ -93,22 +92,16 @@ function psalmParts(numbers: number[], antiphon: BilingualText, opening: Resolve
|
||||
|
||||
const STATUS_RANK = { verified: 0, draft: 1, missing: 2 } as const;
|
||||
|
||||
const GLORIA_PATRI = {
|
||||
la: 'V. Glória Patri, et Fílio, * et Spirítui Sancto.\nR. Sicut erat in princípio, et nunc, et semper, * et in sǽcula sæculórum. Amen.',
|
||||
en: 'V. Glory be to the Father, and to the Son, * and to the Holy Ghost.\nR. As it was in the beginning, is now, * and ever shall be, world without end. Amen.',
|
||||
};
|
||||
|
||||
/** Joins a canticle's verse array (or a `[start, end)` slice of it — see
|
||||
* Saturday's split canticle below) into one flowing text block, the same
|
||||
* shape nunc-dimittis/benedictus already use — Lauds' weekday canticles
|
||||
* are stored verse-by-verse (see lauds-canticles.ts) purely because that's
|
||||
* how they were transcribed, not because callers need per-verse access.
|
||||
* Appends the fixed Gloria Patri line every canticle (or canticle part)
|
||||
* ends with in real practice, same wording as benedictus.yml's own
|
||||
* trailing line — omitted during the Sacred Triduum, live-verified against
|
||||
* both Divino Afflatu 1954 and Tridentine 1906 (Benedictus at Lauds of
|
||||
* Holy Thursday omits it same as any psalm). */
|
||||
function canticleText(canticleId: string, slice: [number, number] | undefined, omitGloriaPatri: boolean): ResolvedText {
|
||||
* Does NOT append a closing Gloria Patri — that's attached centrally
|
||||
* (hours/index.ts) as its own 'canticle' field, same as every other
|
||||
* canticle/psalm, so the Sacred Triduum omission only has to be handled
|
||||
* in one place. */
|
||||
function canticleText(canticleId: string, slice?: [number, number]): ResolvedText {
|
||||
const canticle = getCanticle(canticleId);
|
||||
const verses = slice ? canticle.verses.slice(slice[0], slice[1]) : canticle.verses;
|
||||
const text: Partial<Record<string, string>> = {};
|
||||
@@ -118,7 +111,7 @@ function canticleText(canticleId: string, slice: [number, number] | undefined, o
|
||||
if (lines.length === 0) {
|
||||
continue;
|
||||
}
|
||||
text[lang] = omitGloriaPatri ? lines.join('\n') : `${lines.join('\n')}\n${GLORIA_PATRI[lang]}`;
|
||||
text[lang] = lines.join('\n');
|
||||
let worst: 'verified' | 'draft' | 'missing' = 'verified';
|
||||
for (const v of verses) {
|
||||
const s = v.status[lang] ?? 'missing';
|
||||
@@ -153,7 +146,6 @@ function resolvePsalmody(day: LiturgicalDay): ResolvedPart[] {
|
||||
const canticle = getCanticle(wd.canticle.id);
|
||||
const canticleOpening = opening(wd.canticle.antiphon);
|
||||
const canticleClosing = splitNamedAntiphon(verifiedText(wd.canticle.antiphon)).full;
|
||||
const omitGloriaPatri = isInTriduum(day.date);
|
||||
if (wd.canticle.split) {
|
||||
// Said in two pieces, own Gloria Patri each, one shared antiphon
|
||||
// framing both (opening before the first, full repeated only after
|
||||
@@ -162,19 +154,19 @@ function resolvePsalmody(day: LiturgicalDay): ResolvedPart[] {
|
||||
kind: 'canticle',
|
||||
canticleId: canticle.id,
|
||||
antiphon: canticleOpening,
|
||||
text: canticleText(canticle.id, [0, wd.canticle.split], omitGloriaPatri),
|
||||
text: canticleText(canticle.id, [0, wd.canticle.split]),
|
||||
});
|
||||
parts.push({
|
||||
kind: 'canticle',
|
||||
canticleId: canticle.id,
|
||||
text: canticleText(canticle.id, [wd.canticle.split, canticle.verses.length], omitGloriaPatri),
|
||||
text: canticleText(canticle.id, [wd.canticle.split, canticle.verses.length]),
|
||||
});
|
||||
} else {
|
||||
parts.push({
|
||||
kind: 'canticle',
|
||||
canticleId: canticle.id,
|
||||
antiphon: canticleOpening,
|
||||
text: canticleText(canticle.id, undefined, omitGloriaPatri),
|
||||
text: canticleText(canticle.id),
|
||||
});
|
||||
}
|
||||
parts.push({ kind: 'antiphon', text: canticleClosing });
|
||||
|
||||
+3
-1
@@ -204,7 +204,9 @@ export type ResolvedPart =
|
||||
// Sacred Triduum (calendar/temporal.ts's isInTriduum) — never omit it
|
||||
// when building a psalm part yourself.
|
||||
| { kind: 'psalm'; psalmNumber: number; antiphon?: ResolvedText; verses: ResolvedVerse[]; gloriaPatri?: ResolvedText }
|
||||
| { kind: 'canticle'; canticleId: string; text: ResolvedText; antiphon?: ResolvedText }
|
||||
// `gloriaPatri` filled in centrally, same as the 'psalm' kind above —
|
||||
// see that field's doc comment.
|
||||
| { kind: 'canticle'; canticleId: string; text: ResolvedText; antiphon?: ResolvedText; gloriaPatri?: ResolvedText }
|
||||
// A standalone antiphon, said on its own rather than framing a psalm —
|
||||
// see 'closing-antiphon' above.
|
||||
| { kind: 'antiphon'; text: ResolvedText }
|
||||
|
||||
Reference in New Issue
Block a user