Compare commits

...

2 Commits

Author SHA1 Message Date
will f14d00bd73 Port seasonal office content to Lauds, closing the same pre-existing gap
Deploy / deploy (push) Successful in 56s
Lauds had the identical issue Vespers started with: resolveOffice only
ever rendered the plain weekday chapter/responsory/hymn/versicle,
year-round, with no Advent/Lent/Passiontide/Paschaltide override —
same source file (Major Special.txt) as Vespers', just never wired up.
Ports the same seasonalOfficeSuffix-based precedence (per-feast/octave
override -> season -> weekday default) and the matching seasonal
content, transcribed the same way as Vespers' own (Monastic hymn
variants applied from the source's substitution notation against each
base Roman text). Paschaltide's chapter is byte-identical to Vespers'
own — the source aliases "[Pasch Vespera] = @:Pasch Laudes" — so both
hours' data files intentionally carry the same text rather than one
importing the other's id.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 20:15:29 -04:00
will de83786793 Build the Vespers ordo: mechanism, weekday content, seasonal content
Wires resolveOrdo('vespers', ...) end to end: opening versicle,
weekday psalmody (4 groups, handling the joined Ps 115+116 and the
split Ps 138/143 via a PsalmRef-like shape), the chapter/responsory/
hymn/versicle office bundle, Magnificat, day-collects — reusing
resolveEveningDay so First/Second Vespers precedence and the cross-day
commemoration (both added in the previous commit) apply automatically
— and a closing that reuses Lauds' own conclusio, since no distinct
"Vespera" version of that exact text turned up in the source.

getMagnificatAntiphon mirrors getBenedictusAntiphon's saint/temporal-id
lookup order, but also falls back to real content Benedictus has no
equivalent of: the classic ferial set that quotes the Magnificat's own
text in sequence across the week, with the correct Monastic-rubric
variant picked for Tue/Thu/Fri/Sat (two of those needed a fresh
translation where the Monastic Latin diverges from the given English
in content, not just wording).

Also includes Vespers' own seasonal content (Advent/Lent/Passiontide/
Paschaltide chapter+responsory+hymn+versicle), transcribed from the
same source blocks as the weekday content, with the Monastic-specific
hymn variants hand-applied from the source's substitution notation
against each base Roman text (one transcription slip caught and fixed
mid-pass: the Passiontide hymn's closing lines had been copied from
the Roman text instead of the Monastic one actually being
transcribed). Passiontide's own responsory/hymn correctly omit the
Gloria Patri, matching real rubric and the source data as given.

All weekday/seasonal content marked `draft`, not `verified` — read
directly from the reference source, not cross-checked against a live
rendering per day the way the psalmody was.

Six other hours' resolvePart switches needed the three new HourPart
kinds ('vespers-psalmody', 'vespers-office', 'magnificat') added to
their exhaustive not-used lists so they still typecheck; three
pre-existing tests assumed Vespers was still "coming soon" and are
updated to exercise Matins (still the genuine stub) instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 20:14:19 -04:00
62 changed files with 2185 additions and 17 deletions
@@ -0,0 +1,64 @@
# The classic ferial Magnificat-antiphon set: each weekday quotes the
# Magnificat's own text in sequence (Monday = its opening verse, Tuesday =
# the next, and so on through Saturday). Sourced from Divinum Officium's
# Monastic block ("[Feria2 Ant 3]" through "[Feria7 Ant 3]", Psalterium/
# Special/Major Special.txt). Sunday has no entry here on purpose — its own
# source ("[Dominica Ant 3] = @:Dominica Ant 2 = /:ut in Proprio de
# Tempore:/") draws from that specific Sunday's own Proper of the Time, not
# a fixed weekly default; unauthored content for now (see
# hours/resolve-common.ts's getMagnificatAntiphon).
#
# Four of the six weekdays have a real Monastic-specific Latin variant,
# marked in the source "(sed rubrica tridentina aut rubrica monastica)" —
# used here in place of the plain/Roman line above it, per direct
# instruction to read this app's target rubric (pre-1955, Monastic
# Tridentinum 1617) straight from these branch labels rather than treat
# them as optional. The English source only tracks that same variant for
# Saturday; Tuesday's only differs by a verb ending (no translation
# impact), but Thursday's and Friday's Monastic Latin diverge from the
# English enough in *content* (not just wording) that the given English
# would misrepresent them — those two are translated fresh here instead,
# marked `draft` for that reason specifically, not just the general
# not-live-verified caveat the rest of this file carries.
#
# Not live-query-verified (see TODO.md) — read directly from source.
monday:
antiphon:
la: "Magníficat * ánima mea Dóminum, quia respéxit Deus humilitátem meam."
en: "My soul * magnifies the Lord, because God has regarded my lowliness."
tuesday:
antiphon:
la: "Exsúltet * spíritus meus in Deo salutári meo."
en: "My spirit rejoices * in God, in my Saviour."
wednesday:
antiphon:
la: "Respéxit Dóminus * humilitátem meam, et fecit in me magna, qui potens est."
en: "The Lord has regarded * my lowliness, and he who is mighty has done great things through me."
thursday:
# Monastic Latin diverges from the given (Roman-track) English in mood
# and content — translated fresh to match it; see file header. `status`
# marks the translation itself draft, distinct from the rest of this
# file's blanket "not live-verified" caveat.
antiphon:
la: "Fac Deus, * poténtiam in brácchio tuo: dispérde supérbos, et exálta húmiles."
en: "Shew, O God, * power in thy arm: scatter the proud, and exalt the humble."
status: { la: draft, en: draft }
friday:
# Monastic Latin diverges from the given (Roman-track) English in
# content — translated fresh to match it; see file header. `status`
# marks the translation itself draft, distinct from the rest of this
# file's blanket "not live-verified" caveat.
antiphon:
la: "Depósuit poténtes, * Sanctos persequéntes: et exaltávit húmiles, Christum confiténtes."
en: "He hath put down the mighty, * who persecuted the Saints: and exalted the humble, who confessed Christ."
status: { la: draft, en: draft }
saturday:
antiphon:
la: "Suscépit Deus * Israël, púerum suum: sicut locútus est ad Ábraham, et semen ejus: exaltáre húmiles usque in sǽculum."
en: "God hath received * Israel his servant: as he spoke to our fathers, to Abraham and to his seed, and hath exalted the humble forever."
+23
View File
@@ -0,0 +1,23 @@
# Ordo assembled from Divinum Officium's Monastic block (see the
# individual data/propers/common/vespers-*.yml and data/hours/vespers-
# antiphons.yml/vespers-magnificat-antiphons.yml files for sourcing) — not
# live-query-verified end-to-end (see TODO.md).
#
# Resolves off resolveEveningDay, not resolveDay — see hours/vespers.ts —
# so First/Second Vespers precedence and the cross-day commemoration both
# apply before any part below ever runs.
#
# The closing reuses `lauds-conclusio` (Benedicamus Domino / Fidelium
# animae) rather than a Vespers-specific id — no distinct "Vespera"
# version of this exact closing turned up in the source, and it's the
# same fixed formula in real practice after either hour; flagged here in
# case that assumption turns out wrong.
id: vespers
parts:
- kind: opening-versicle
- kind: vespers-psalmody
- kind: vespers-office
- kind: magnificat
- kind: day-collects
- kind: preces
textRef: { source: common, id: lauds-conclusio }
@@ -0,0 +1,13 @@
# Sourced from Divinum Officium's Monastic block ("[Adv Laudes_]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: lauds-capitulum-advent
text:
la: "Veníte, et ascendámus ad montem Dómini, et ad domum Dei Jacob, et docébit nos vias suas, et ambulábimus in sémitis ejus: quia de Sion exíbit lex, et verbum Dómini de Jerúsalem."
en: "Come and let us go up to the mountain of the Lord, and to the house of the God of Jacob, and he will teach us his ways, and we will walk in his paths: for the law shall come forth from Sion, and the word of the Lord from Jerusalem."
citation:
la: "Isa 2:3"
en: "Isa 2:3"
status:
la: draft
en: draft
@@ -0,0 +1,13 @@
# Sourced from Divinum Officium's Monastic block ("[Quad Laudes_]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: lauds-capitulum-lent
text:
la: "Clama, ne cesses, quasi tuba exálta vocem tuam, et annúntia pópulo meo scélera eórum, et dómui Jacob peccáta eórum."
en: "Cry, cease not, lift up thy voice like a trumpet, and show my people their wicked doings, and the house of Jacob their sins."
citation:
la: "Isa 58:1"
en: "Isa 58:1"
status:
la: draft
en: draft
@@ -0,0 +1,16 @@
# Sourced from Divinum Officium's Monastic block ("[Pasch Laudes]",
# Psalterium/Special/Major Special.txt) — Vespers shares this exact text
# (see vespers-capitulum-paschaltide.yml, "[Pasch Vespera] = @:Pasch
# Laudes" in the source). Covers the whole Easter-to-Pentecost span
# uniformly. Not live-query-verified (see TODO.md) — read directly from
# source.
id: lauds-capitulum-paschaltide
text:
la: "Christus resúrgens ex mórtuis jam non móritur, mors illi ultra non dominábitur. Quod enim mórtuus est peccáto, mórtuus est semel: quod autem vivit, vivit Deo."
en: "Knowing that Christ rising again from the dead, dieth now no more, death shall no more have dominion over him. For in that he died to sin, he died once; but in that he liveth, he liveth unto God."
citation:
la: "Rom 6:9-10"
en: "Rom 6:9-10"
status:
la: draft
en: draft
@@ -0,0 +1,13 @@
# Sourced from Divinum Officium's Monastic block ("[Quad5 Laudes_]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: lauds-capitulum-passiontide
text:
la: "Veníte, mittámus lignum in panem ejus, et eradámus eum de terra vivéntium, et nomen ejus non memorétur ámplius."
en: "Come, let us put wood on his bread, and cut him off from the land of the living, and let his name be remembered no more."
citation:
la: "Jer 11:19"
en: "Jer 11:19"
status:
la: draft
en: draft
@@ -0,0 +1,66 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Adv Laudes]",
# resolving to "[HymnusM Adv Laudes_]" on the non-Cistercian branch —
# Psalterium/Special/Major Special.txt) — full separate Monastic text
# ("Vox clara ecce íntonat"), not a substitution against the Roman "En
# clara vox redárguit". English is the familiar John Mason Neale
# translation ("Hark! a herald voice is calling"), traditionally used for
# both this hymn's Roman and Monastic/Sarum recensions — a closer match
# than the Advent Vespers hymn's English got. Not live-query-verified (see
# TODO.md).
id: lauds-hymn-advent
text:
la: |
Vox clara ecce íntonat,
Obscúra quæque íncrepat:
Pellántur éminus sómnia;
Ab æthre Christus prómicat.
Mens jam resúrgat tórpida
Quæ sorde exstat sáucia;
Sidus refúlget jam novum,
Ut tollat omne nóxium.
E sursum Agnus míttitur
Laxáre gratis débitum:
Omnes pro indulgéntia
Vocem demus cum lácrimis,
Secúndo ut cum fúlserit,
Mundúmque horror cínxerit,
Non pro reátu púniat,
Sed nos pius tunc prótegat.
Laus, honor, virtus, glória,
Deo Patri, et Fílio,
Sancto simul Paráclito,
In sæculórum sǽcula.
Amen.
en: |
Hark, a herald voice is calling;
"Christ is nigh," it seems to say;
"Cast away the dreams of darkness,
O ye children of the day."
Startled at the solemn warning,
Let the earth-bound soul arise;
Christ, her sun, all sloth dispelling,
Shines upon the morning skies.
Lo, the Lamb, so long expected,
Comes with pardon down from heaven;
Let us haste, with tears of sorrow,
One and all to be forgiven.
So when next he comes with glory,
Wrapping all the earth in fear,
May he then as our defender
On the clouds of heaven appear.
Honour, glory, virtue, merit,
To the Father and the Son,
With the co-eternal Spirit,
While eternal ages run.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,62 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Quad
# Laudes]", Psalterium/Special/Major Special.txt) — full separate
# Monastic text ("Jam Christe sol justítiæ"), not a substitution against
# the Roman "O sol salútis, íntimis". Not live-query-verified (see
# TODO.md).
id: lauds-hymn-lent
text:
la: |
Jam Christe sol justítiæ,
Mentis diéscant ténebræ:
Virtútum ut lux rédeat,
Terris diem cum réparas.
Dans tempus acceptábile,
Et pǽnitens cor tríbue,
Convértat ut benígnitas
Quos longa suffert píetas.
Quiddámque pæniténtiæ
Da ferre, quamvis grávium,
Majóre tuo múnere,
Quo démptio fit críminum.
Dies venit, dies tua,
In qua reflórent ómnia:
Lætémur in hac ad tuam
Per hanc redúcti grátiam.
Te rerum univérsitas,
Clemens, adóret, Trínitas,
Et nos novi per véniam,
Novum canámus cánticum.
Amen.
en: |
Jesu, salvation's Sun Divine,
Within our inmost bosoms shine,
With light all darkness drive away
And give the world a better day.
Now days of grace with mercy flow,
O Lord, the gift of tears bestow,
To wash our stains in every part,
Whilst heavenly fire consumes the heart.
Rise, crystal tears, from that same source
From whence our sins derive their course;
Nor cease, till hardened hearts relent,
And softened by your streams, repent.
Behold, the happy days return,
The days of joy for them that mourn;
May we of their indulgence share,
And bless the God that grants our prayer.
May heaven and earth aloud proclaim
The Trinity's almighty fame;
And we, restored to grace, rejoice
In newness both of heart and voice.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,72 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Pasch
# Laudes_]", the non-Dominican branch "[HymnusM Pasch Laudes]" resolves
# to — Psalterium/Special/Major Special.txt) — "Auróra lucis rútilat",
# full separate Monastic text (not a substitution against the Roman
# "Auróra cælum púrpurat"). Not live-query-verified (see TODO.md).
id: lauds-hymn-paschaltide
text:
la: |
Auróra lucis rútilat,
Cælum láudibus íntonat,
Mundus exsúltans júbilat,
Gemens inférnus úlulat:
Cum Rex ille fortíssimus,
Mortis confráctis víribus,
Pede concúlcans tártara,
Solvit a pœna míseros.
Ille qui clausus lápide
Custodítur sub mílite,
Triúmphans pompa nóbili,
Victor surgit de fúnere.
Solútis jam gemítibus,
Et inférni dolóribus,
Quia surréxit Dóminus,
Respléndens clamat Ángelus.
Quǽsumus, Auctor ómnium,
In hoc pascháli gáudio,
Ab omni mortis ímpetu
Tuum defénde pópulum.
Glória tibi Dómine,
Qui surrexísti a mórtuis,
Cum Patre et Sancto Spíritu,
In sempitérna sǽcula.
Amen.
en: |
The morn had spread her crimson rays,
When rang the skies with shouts of praise;
Earth joined the joyful hymn to swell,
That brought despair to vanquished hell.
He comes victorious from the grave,
The Lord omnipotent to save,
And brings with him to light of day
The saints who long imprisoned lay.
Vain is the cavern's three-fold ward —
The stone, the seal, the armed guard;
O death, no more thine arm we fear,
The Victor's tomb is now thy bier.
Let hymns of joy to grief succeed,
We know that Christ is risen indeed;
We hear his white-robed angel's voice,
And in our risen Lord rejoice.
With Christ we died, with Christ we rose,
When at the font his name we chose;
Oh, let not sin our robes defile,
And turn to grief the paschal smile.
To God the Father let us sing,
To God the Son, our risen King,
And equally let us adore
The Spirit, God forevermore.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,96 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Quad5
# Laudes]", Psalterium/Special/Major Special.txt) — "Lustris sex qui jam
# peráctis", full separate Monastic text (not a substitution against the
# Roman "Lustra sex qui jam perégit" — the two differ throughout, not
# just in wording). Not live-query-verified (see TODO.md).
id: lauds-hymn-passiontide
text:
la: |
Lustris sex qui jam peráctis,
Tempus implens córporis,
Se volénte natus ad hoc,
Passióni déditus,
Agnus in Crucis levátur
Immolándus stípite.
Hic acétum, fel, arúndo,
Sputa, clavi, láncea:
Mite corpus perforátur,
Sanguis, unda prófluit:
Terra, pontus, astra, mundus,
Quo lavántur flúmine!
Crux fidélis, inter omnes
Arbor una nóbilis:
Nulla silva talem profert
Fronde, flore, gérmine:
Dulce lignum, dulces clavos,
Dulce pondus sústinet.
Flecte ramos, arbor alta,
Tensa laxa víscera,
Et rigor lentéscat ille,
Quem dedit natívitas:
Ut supérni membra Regis
Miti tendas stípite.
Sola digna tu fuísti
Ferre sæcli prétium,
Atque portum præparáre
Nauta mundo náufrago,
Quem sacer cruor perúnxit,
Fusus Agni córpore.
Glória et honor Deo
Usquequáque altíssimo:
Una Patri, Filióque,
Inclyto Paráclito:
Cui laus est et potéstas
Per ætérna sǽcula.
Amen.
en: |
Thirty years among us dwelling,
His appointed time fulfilled,
Born for this, he meets his passion,
For that this he freely willed:
On the cross the Lamb is lifted,
Where his life-blood shall be spilled.
He endured the nails, the spitting,
Vinegar, and spear, and reed;
From that holy body broken
Blood and water forth proceed:
Earth, and stars, and sky, and ocean,
By that flood from stain are free.
Faithful cross! above all other,
One and only noble tree!
None in foliage, none in blossom,
None in fruit thy peers may be;
Sweetest wood and sweetest iron!
Sweetest weight is hung on thee.
Bend thy boughs, O tree of glory!
Thy relaxing sinews bend;
For awhile the ancient rigour,
That thy birth bestowed, suspend;
And the King of heavenly beauty
On thy bosom gently tend!
Thou alone wast counted worthy
This world's ransom to uphold;
For a shipwrecked race preparing
Harbour, like the ark of old;
With the sacred blood anointed
From the smitten Lamb that rolled.
To the Trinity be glory
Everlasting, as is meet;
Equal to the Father, equal
To the Son, and Paraclete:
Trinal Unity, whose praises
All created things repeat.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,22 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Adv
# Laudes]", Psalterium/Special/Major Special.txt). Not live-query-verified
# (see TODO.md) — read directly from source.
id: lauds-responsory-advent
text:
la: |
R.br. Veni ad liberándum nos * Dómine Deus virtútum.
R. Veni ad liberándum nos * Dómine Deus virtútum.
V. Osténde fáciem tuam et salvi érimus.
R. Dómine Deus virtútum.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Veni ad liberándum nos * Dómine Deus virtútum.
en: |
R.br. Come to my rescue, * O God, Lord of hosts.
R. Come to my rescue, * O God, Lord of hosts.
V. Show us thy face, and we shall be saved.
R. O God, Lord of hosts.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. Come to my rescue, * O God, Lord of hosts.
status:
la: draft
en: draft
@@ -0,0 +1,22 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Quad
# Laudes]", Psalterium/Special/Major Special.txt). Not live-query-verified
# (see TODO.md) — read directly from source.
id: lauds-responsory-lent
text:
la: |
R.br. Ipse liberávit me * de láqueo venántium.
R. Ipse liberávit me * de láqueo venántium.
V. Et a verbo áspero.
R. De láqueo venántium.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Ipse liberávit me * de láqueo venántium.
en: |
R.br. For he hath delivered me * from the snare of the hunters.
R. For he hath delivered me * from the snare of the hunters.
V. And from the sharp word.
R. From the snare of the hunters.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. For he hath delivered me * from the snare of the hunters.
status:
la: draft
en: draft
@@ -0,0 +1,26 @@
# Sourced from Divinum Officium's Monastic block: "[Responsory Pasch
# Laudes]" resolves (non-Cistercian branch) to "@Psalterium/Special/Minor
# Special:Responsory breve Pasch Tertia" -> "[Responsory breve Pasch
# Tertia_]" (Psalterium/Special/Minor Special.txt) — distinct from
# Vespers' own Paschaltide responsory (see
# vespers-responsory-paschaltide.yml). Not live-query-verified (see
# TODO.md) — read directly from source.
id: lauds-responsory-paschaltide
text:
la: |
R.br. Surréxit Dóminus de sepúlcro, * Allelúja, allelúja.
R. Surréxit Dóminus de sepúlcro, * Allelúja, allelúja.
V. Qui pro nobis pepéndit in ligno.
R. Allelúja, allelúja.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Surréxit Dóminus de sepúlcro, * Allelúja, allelúja.
en: |
R.br. The Lord is risen from the sepulchre, * alleluia, alleluia.
R. The Lord is risen from the sepulchre, * alleluia, alleluia.
V. Who for us was hanged on the tree.
R. Alleluia, alleluia.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. The Lord is risen from the sepulchre, * alleluia, alleluia.
status:
la: draft
en: draft
@@ -0,0 +1,23 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Quad5
# Laudes_]", the non-Cistercian branch "[Responsory Quad5 Laudes]"
# resolves to — Psalterium/Special/Major Special.txt). Real Passiontide
# practice omits the Gloria Patri here too — matches the source exactly
# (see vespers-responsory-passiontide.yml). Not live-query-verified (see
# TODO.md).
id: lauds-responsory-passiontide
text:
la: |
R.br. Érue a frámea * Deus ánimam meam.
R. Érue a frámea * Deus ánimam meam.
V. Et de manu canis únicam meam.
R. Deus ánimam meam.
R. Érue a frámea * Deus ánimam meam.
en: |
R.br. Deliver, * O God, my soul from the sword.
R. Deliver, * O God, my soul from the sword.
V. My only one from the hand of the dog.
R. O God, my soul from the sword.
R. Deliver, * O God, my soul from the sword.
status:
la: draft
en: draft
@@ -0,0 +1,14 @@
# Sourced from Divinum Officium's Monastic block ("[Adv Versum 2_]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: lauds-versicle-advent
text:
la: |
V. Vox clamántis in desérto: Paráte viam Dómini.
R. Rectas fácite sémitas ejus.
en: |
V. A voice of one crying in the wilderness: Prepare the way of the Lord.
R. Make straight his paths.
status:
la: draft
en: draft
@@ -0,0 +1,15 @@
# The versicle right before the Benedictus, in Lent. Sourced from Divinum
# Officium's Monastic block: "[Quad Versum 2] = @:Quad Versum 3" — a bare
# alias to the same text used at Vespers (see vespers-versicle-lent.yml).
# Not live-query-verified (see TODO.md) — read directly from source.
id: lauds-versicle-lent
text:
la: |
V. Ángelis suis Deus mandávit de te.
R. Ut custódiant te in ómnibus viis tuis.
en: |
V. God hath given His Angels charge over thee.
R. To keep thee in all thy ways.
status:
la: draft
en: draft
@@ -0,0 +1,16 @@
# Sourced from Divinum Officium's Monastic block ("[Pasch Versum 2_]",
# the non-Cistercian/non-Dominican branch "[Pasch Versum 2]" resolves to
# — Psalterium/Special/Major Special.txt). Distinct from Vespers' own
# Paschaltide versicle (see vespers-versicle-paschaltide.yml). Not
# live-query-verified (see TODO.md) — read directly from source.
id: lauds-versicle-paschaltide
text:
la: |
V. In resurrectióne tua, Christe, allelúja.
R. Cæli et terra læténtur, allelúja.
en: |
V. Christ, in thy resurrection, alleluia.
R. Let heaven and earth rejoice, alleluia.
status:
la: draft
en: draft
@@ -0,0 +1,14 @@
# Sourced from Divinum Officium's Monastic block ("[Quad5 Versum 2_]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: lauds-versicle-passiontide
text:
la: |
V. Éripe me de inimícis meis, Deus meus.
R. Et ab insurgéntibus in me líbera me.
en: |
V. Deliver me from my enemies, O my God.
R. And defend me from them that rise up against me.
status:
la: draft
en: draft
+38
View File
@@ -0,0 +1,38 @@
# Sourced from Divinum Officium's own canticle text (Latin/English
# Psalterium/Psalmorum/Psalm232.txt — the Magnificat, Luke 1:46-55, stored
# alongside the other canticles rather than the numbered psalms). Fixed
# year-round, same shape as benedictus.yml/nunc-dimittis.yml — the framing
# antiphon is resolved separately, by day (see hours/resolve-common.ts's
# getMagnificatAntiphon), not stored here. Not live-query-verified (see
# TODO.md) — read directly from source.
id: magnificat
text:
la: |
Magníficat ✠ ánima mea Dóminum.
Et exsultávit spíritus meus: * in Deo, salutári meo.
Quia respéxit humilitátem ancíllæ suæ: * ecce enim ex hoc beátam me dicent omnes generatiónes.
Quia fecit mihi magna qui potens est: * et sanctum nomen ejus.
Et misericórdia ejus, a progénie in progénies: * timéntibus eum.
Fecit poténtiam in brácchio suo: * dispérsit supérbos mente cordis sui.
Depósuit poténtes de sede: * et exaltávit húmiles.
Esuriéntes implévit bonis: * et dívites dimísit inánes.
Suscépit Israël púerum suum: * recordátus misericórdiæ suæ.
Sicut locútus est ad patres nostros: * Ábraham, et sémini ejus in sǽcula.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Sicut erat in princípio, et nunc, et semper, * et in sǽcula sæculórum. Amen.
en: |
My soul ✠ doth magnify the Lord.
And my spirit hath rejoiced * in God my Saviour.
Because he hath regarded the humility of his handmaid; * for behold from henceforth all generations shall call me blessed.
Because he that is mighty, hath done great things to me; * and holy is his name.
And his mercy is from generation unto generations, * to them that fear him.
He hath shewed might in his arm: * he hath scattered the proud in the conceit of their heart.
He hath put down the mighty from their seat, * and hath exalted the humble.
He hath filled the hungry with good things; * and the rich he hath sent empty away.
He hath received Israel his servant, * being mindful of his mercy:
As he spoke to our fathers, * to Abraham and to his seed for ever.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. As it was in the beginning, is now, * and ever shall be, world without end. Amen.
status:
la: verified
en: verified
@@ -0,0 +1,13 @@
# Sourced from Divinum Officium's Monastic block ("[Adv Vespera]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: vespers-capitulum-advent
text:
la: "Non auferétur sceptrum de Juda, et dux de fémore ejus, donec véniat qui mitténdus est; et ipse erit exspectátio géntium."
en: "The sceptre shall not be taken away from Juda, nor a ruler from his thigh, till he comes that is to be sent, and he shall be the expectation of nations."
citation:
la: "Gen 49:10"
en: "Gen 49:10"
status:
la: draft
en: draft
@@ -0,0 +1,13 @@
# Sourced from Divinum Officium's Monastic block ("[Quad Vespera_]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: vespers-capitulum-lent
text:
la: "Inter vestíbulum et altáre plorábunt sacerdótes, minístri Dómini, et dicent: Parce, Dómine, parce pópulo tuo: et ne des hereditátem tuam in oppróbrium, ut dominéntur eis natiónes."
en: "Between the porch and the altar the priests the Lord's ministers shall weep, and shall say: Spare, O Lord, spare thy people: and give not thy inheritance to reproach, that the heathen should rule over them."
citation:
la: "Joel 2:17"
en: "Joel 2:17"
status:
la: draft
en: draft
@@ -0,0 +1,16 @@
# Sourced from Divinum Officium's Monastic block: "[Pasch Vespera] =
# @:Pasch Laudes" — a bare alias, so Paschaltide Vespers shares its
# chapter with Paschaltide Lauds (see lauds-capitulum-paschaltide.yml).
# Covers the whole Easter-to-Pentecost span uniformly — no separate
# Ascensiontide/Pentecost-specific chapter exists in the source. Not
# live-query-verified (see TODO.md) — read directly from source.
id: vespers-capitulum-paschaltide
text:
la: "Christus resúrgens ex mórtuis jam non móritur, mors illi ultra non dominábitur. Quod enim mórtuus est peccáto, mórtuus est semel: quod autem vivit, vivit Deo."
en: "Knowing that Christ rising again from the dead, dieth now no more, death shall no more have dominion over him. For in that he died to sin, he died once; but in that he liveth, he liveth unto God."
citation:
la: "Rom 6:9-10"
en: "Rom 6:9-10"
status:
la: draft
en: draft
@@ -0,0 +1,13 @@
# Sourced from Divinum Officium's Monastic block ("[Quad5 Vespera]",
# Psalterium/Special/Major Special.txt). Not live-query-verified (see
# TODO.md) — read directly from source.
id: vespers-capitulum-passiontide
text:
la: "Tu autem, Dómine Sábaoth, qui júdicas juste, et probas renes et corda, vídeam ultiónem tuam ex eis: tibi enim revelávi causam meam, Dómine, Deus meus."
en: "But thou, O Lord of Sabaoth, who judgest justly, and triest the reins and hearts, let me see thy revenge on them: for to thee I have revealed my cause, O Lord my God."
citation:
la: "Jer 11:20"
en: "Jer 11:20"
status:
la: draft
en: draft
@@ -0,0 +1,18 @@
# Sourced from Divinum Officium's Monastic block: "[Feria Vespera]
# (feria 7)" = "@Tempora/Pent01-0:Capitulum Laudes" — Saturday Vespers'
# own chapter is a cross-reference to the temporal-proper file for the
# first ordinary Sunday after Pentecost's own Lauds chapter (TemporaM/
# Pent01-0.txt inherits this section unchanged from the base Tempora/
# Pent01-0.txt, no Monastic-specific override). Not live-query-verified
# (see TODO.md) — read directly from source, same confidence level as the
# Vespers psalmody.
id: vespers-capitulum-saturday
text:
la: "O Altitúdo divitiárum sapiéntiæ, et sciéntiæ Dei, quam incomprehensibília sunt judícia ejus, et investigábiles viæ ejus!"
en: "O the depth of the riches of the wisdom and of the knowledge of God! How incomprehensible are his judgments, and how unsearchable his ways!"
citation:
la: "Rom 11:33"
en: "Rom 11:33"
status:
la: draft
en: draft
@@ -0,0 +1,17 @@
# Sourced from Divinum Officium's Monastic block (Psalterium/Special/Major
# Special.txt): "[Dominica Vespera_]" gives the text directly; "[Feria
# Vespera] = @:Dominica Vespera" (Mon-Fri) is a bare alias to the same
# text, not a separate ferial chapter — so Sunday and the five weekdays
# genuinely share one chapter here. Not live-query-verified per weekday
# (see TODO.md) — read from the explicitly-labeled Monastic source block,
# same confidence level as the Vespers psalmody.
id: vespers-capitulum-sunday-ferial
text:
la: "Benedíctus Deus, et Pater Dómini nostri Jesu Christi, Pater misericordiárum, et Deus totíus consolatiónis, qui consolátur nos in omni tribulatióne nostra."
en: "Blessed be the God and Father of our Lord Jesus Christ, the Father of mercies, and the God of all comfort, who comforteth us in all our tribulation."
citation:
la: "2 Cor 1:3-4"
en: "2 Cor 1:3-4"
status:
la: draft
en: draft
@@ -0,0 +1,78 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Adv Vespera]",
# Psalterium/Special/Major Special.txt) — full separate Monastic text
# ("Cónditor alme síderum", the older/more familiar form of this hymn),
# not a substitution against the Roman "Creátor alme síderum". English is
# the given translation of the *Roman* text ("Bright builder of the
# heavenly poles... Jesus, Redeemer of mankind"), which differs from the
# Monastic Latin in specific imagery (stanza 2 especially — "lest the
# world perish by the deceit of the demon" vs. "grieving that the world
# would perish by the ruin of death"), not just word order — kept anyway
# as the closest available English, `draft`. Not live-query-verified (see
# TODO.md).
id: vespers-hymn-advent
text:
la: |
Cónditor alme síderum,
Ætérna lux credéntium,
Christe, Redémptor ómnium,
Exáudi preces súpplicum.
Qui cóndolens intéritu
Mortis períre sǽculum,
Salvásti mundum lánguidum,
Donans reis remédium,
Vergénte mundi véspere,
Uti sponsus de thálamo,
Egréssus honestíssima
Vírginis matris cláusula.
Cujus forti poténtiæ
Genu curvántur ómnia;
Cæléstia, terréstria
Nutu faténtur súbdita.
Te deprecámur, hágie,
Ventúre judex sǽculi,
Consérva nos in témpore
Hostis a telo pérfidi.
Laus, honor, virtus, glória,
Deo Patri, et Fílio,
Sancto simul Paráclito,
In sæculórum sǽcula.
Amen.
en: |
Bright builder of the heavenly poles,
Eternal light of faithful souls,
Jesus, Redeemer of mankind,
Our humble prayers vouchsafe to mind.
Who, lest the fraud of hell's black king
Should all men to destruction bring,
Didst, by an act of generous love,
The fainting world's physician prove.
Who, that thou mightst our ransom pay
And wash the stains of sin away,
Wouldst from a Virgin's womb proceed
And on the cross a victim bleed.
Whose glorious power, whose saving name
No sooner any voice can frame,
But heaven and earth and hell agree
To honour them with trembling knee.
Thee, Christ, who at the latter day
Shalt be our Judge, we humbly pray
Such arms of heavenly grace to send
As may thy Church from foes defend.
Be glory given and honour done
To God the Father and the Son
And to the Holy Ghost on high,
From age to age eternally.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,63 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Day5 Vespera]",
# Psalterium/Special/Major Special.txt): six substitutions against the base
# "[Hymnus Day5 Vespera]" text (replacing the opening line entirely,
# "Hóminis superne Cónditor" -> "Plasmátor hóminis Deus", and rewording
# most of stanzas 2-3), applied by hand here — not live-query-verified
# (see TODO.md). English has no separate Monastic variant in the source.
id: vespers-hymn-friday
text:
la: |
Plasmátor hóminis Deus,
Qui cuncta solus órdinans,
Humum jubes prodúcere
Reptántis et feræ genus:
Qui magna rerum córpora,
Dictu jubéntis vívida,
Ut sérviant per órdinem,
Subdens dedísti hómini:
Repélle, a servis tuis,
Quidquid per immundítiam
Aut móribus se súggerit,
Aut áctibus se intérserit.
Da gaudiórum prǽmia,
Da gratiárum múnera:
Dissólve litis víncula:
Astrínge pacis fœ́dera.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
Maker of man, who from thy throne
Dost order all things, God alone;
By whose decree the teeming earth
To reptile and to beast gave birth:
The mighty forms that fill the land,
Instinct with life at thy command,
Are given subdued to humankind
For service in their rank assigned.
From all thy servants drive away
Whate'er of thought impure to-day
Hath been with open action blent,
Or mingled with the heart's intent.
In heaven thine endless joys bestow,
And grant thy gifts of grace below;
From chains of strife our souls release,
Bind fast the gentle bands of peace.
Grant this, O Father, ever One
With Christ, thy sole-begotten Son,
Whom, with the Spirit we adore,
One God, both now and evermore.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,63 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Quad
# Vespera]", Psalterium/Special/Major Special.txt): two substitutions
# against the base "[Hymnus Quad Vespera]" text — a word-order swap in
# stanza 3 ("Ad nóminis laudem tui" -> "Ad laudem tui nóminis") and a full
# replacement of stanza 4 — applied by hand here. Not live-query-verified
# (see TODO.md). English has no separate Monastic variant in the source.
id: vespers-hymn-lent
text:
la: |
Audi, benígne Cónditor,
Nostras preces cum flétibus,
In hoc sacro jejúnio
Fusas quadragenário.
Scrutátor alme córdium,
Infírma tu scis vírium:
Ad te revérsis éxhibe
Remissiónis grátiam.
Multum quidem peccávimus,
Sed parce confiténtibus:
Ad laudem tui nóminis
Confer medélam lánguidis.
Sic corpus extra cónteri
Dona per abstinéntiam,
Jejúnet ut mens sóbria
A labe prorsus críminum.
Præsta, beáta Trínitas,
Concéde, simplex Únitas;
Ut fructuósa sint tuis
Jejuniórum múnera.
Amen.
en: |
O kind Creator, bow thine ear
To mark the cry, to know the tear
Before thy throne of mercy spent
In this thy holy fast of Lent.
Our hearts are open, Lord, to thee:
Thou knowest our infirmity;
Pour out on all who seek thy face
Abundance of thy pardoning grace.
Our sins are many, this we know;
Spare us, good Lord, thy mercy show;
And for the honour of thy name
Our fainting souls to life reclaim.
Give us the self-control that springs
From discipline of outward things,
That fasting inward secretly
The soul may purely dwell with thee.
We pray thee, Holy Trinity,
One God, unchanging Unity,
That we from this our abstinence
May reap the fruits of penitence.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,62 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Day1 Vespera]",
# Psalterium/Special/Major Special.txt): two word substitutions against the
# base "[Hymnus Day1 Vespera]" text ("adáugeat" -> "invéniat"; "Hæc" ->
# "Ut", in the 4th stanza), applied by hand here — not live-query-verified
# (see TODO.md). English has no separate Monastic variant in the source.
id: vespers-hymn-monday
text:
la: |
Imménse cæli Cónditor,
Qui mixta ne confúnderent,
Aquæ fluénta dívidens,
Cælum dedísti límitem.
Firmans locum cæléstibus,
Simúlque terræ rívulis;
Ut unda flammas témperet,
Terræ solum ne díssipent.
Infúnde nunc, piíssime,
Donum perénnis grátiæ:
Fraudis novæ ne cásibus
Nos error átterat vetus.
Lucem fides invéniat:
Sic lúminis jubar ferat:
Ut vana cuncta próterat:
Hanc falsa nulla cómprimant.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O great Creator of the sky,
Who wouldest not the floods on high
With earthly waters to confound,
But mad'st the firmament their bound;
The floods above thou didst ordain;
The floods below thou didst restrain:
That moisture might attemper heat,
Lest the parched earth should ruin meet.
Upon our souls, good Lord, bestow
Thy gift of grace in endless flow:
Lest some renewed deceit or wile
Of former sin should us beguile.
Let faith discover heav'nly light;
So shall its rays direct us right:
And let this faith each error chase,
And never give to falsehood place.
Grant this, O Father, ever One
With Christ, thy sole-begotten Son,
And Holy Ghost, whom all adore,
Reigning and blest forevermore.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,96 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Pasch
# Vespera]", Psalterium/Special/Major Special.txt) — "Ad cenam Agni
# próvidi", the older Monastic form, full separate text (not a
# substitution against the Roman Urban VIII revision, "Ad régias Agni
# dapes", which differs substantially stanza by stanza, not just in
# wording). English is the given translation of that Roman revision —
# conventionally paired with this older Latin in many hymnals despite the
# textual differences, but a real mismatch worth flagging, same caution
# as the Sunday Vespers hymn. Not live-query-verified (see TODO.md).
id: vespers-hymn-paschaltide
text:
la: |
Ad cenam Agni próvidi,
Et stolis albis cándidi,
Post tránsitum maris Rubri,
Christo canámus Príncipi.
Cujus corpus sanctíssimum,
In ara crucis tórridum,
Cruóre ejus róseo
Gustándo vívimus Deo.
Protécti Paschæ véspere
A devastánte Angelo,
Erépti de duríssimo
Pharaónis império.
Jam Pascha nostrum Christus est,
Qui immolátus agnus est:
Sinceritátis ázyma,
Caro ejus obláta est.
O vere digna hóstia,
Per quam fracta sunt tártara,
Redémpta plebs captiváta,
Réddita vitæ prǽmia.
Consúrgit Christus túmulo,
Victor redit de bárathro,
Tyránnum trudens vínculo,
Et Paradísum réserans.
Quǽsumus, Auctor ómnium,
In hoc pascháli gáudio,
Ab omni mortis ímpetu
Tuum defénde pópulum.
Glória tibi Dómine,
Qui surrexísti a mórtuis,
Cum Patre et Sancto Spíritu,
In sempitérna sǽcula.
Amen.
en: |
At the Lamb's high feast we sing
Praise to our victorious King,
Who hath washed us in the tide
Flowing from his pierced side.
Praise we him whose love divine
Gives the guests his blood for wine,
Gives his body for the feast,
Love the victim, love the priest.
Where the paschal blood is poured,
Death's dark angel sheathes his sword;
Israel's hosts triumphant go
Through the wave that drowns the foe.
Christ, the Lamb whose blood was shed,
Paschal victim, paschal bread;
With sincerity and love
Eat we manna from above.
Mighty victim from the sky,
Powers of hell beneath thee lie;
Death is conquered in the fight;
Thou hast brought us life and light.
Now thy banner thou dost wave;
Vanquished Satan and the grave;
Angels join his praise to tell —
See o'erthrown the prince of hell.
Paschal triumph, paschal joy,
Only sin can this destroy;
From the death of sin set free,
Souls re-born, dear Lord, in Thee.
Hymns of glory, songs of praise,
Father, unto thee we raise;
Risen Lord, all praise to thee,
Ever with the Spirit be.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,93 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Quad5
# Vespera]", Psalterium/Special/Major Special.txt) — "Vexílla Regis
# pródeunt", full separate Monastic text (not a substitution against the
# Roman version, which differs meaningfully in several stanzas — caught
# and fixed a first-pass transcription slip here where the second-to-last
# stanza's closing lines had been copied from the Roman text instead of
# the Monastic one actually being transcribed). The source marks that
# stanza's third line with a seasonal branch — "Hoc Passiónis témpore"
# (used here, for Passiontide proper) vs. "In hoc Pascháli gáudio"
# (Paschaltide, when this same hymn is reused for a Holy Cross feast
# falling then — not this app's concern). Also: real Passiontide practice
# omits the Gloria Patri from the last stanza — kept that way here,
# matching the source exactly (see vespers-responsory-passiontide.yml's
# own note). Not live-query-verified (see TODO.md).
id: vespers-hymn-passiontide
text:
la: |
Vexílla Regis pródeunt:
Fulget Crucis mystérium,
Quo carne carnis Cónditor
Suspénsus est patíbulo.
Quo vulnerátus ínsuper
Mucróne diro lánceæ,
Ut nos laváret crímine,
Manávit unda et sánguine.
Impléta sunt quæ cóncinit
David fidéli cármine,
Dicens: In natiónibus
Regnávit a ligno Deus.
Arbor decóra et fúlgida,
Ornáta Regis púrpura,
Elécta digno stípite
Tam sancta membra tángere.
Beáta, cujus bráchiis
Sæcli pepéndit prétium,
Statéra facta córporis,
Prædámque tulit tártari.
O Crux, ave, spes única,
In hac triúmphi glória
Hoc Passiónis témpore
Auge piis justítiam,
Reísque dona véniam.
Te summa, Deus, Trínitas,
Colláudet omnis spíritus:
Quos per Crucis mystérium
Salvas, rege per sǽcula.
Amen.
en: |
Abroad the regal banners fly,
Now shines the cross's mystery;
Upon it Life did death endure,
And yet by death did life procure.
Who, wounded with a direful spear,
Did, purposely to wash us clear
From stain of sin, pour out a flood
Of precious water mixed with blood.
That which the prophet-king of old
Hath in mysterious verse foretold,
Is now accomplished, whilst we see
God ruling nations from a tree.
O lovely and refulgent tree,
Adorned with purpled majesty;
Culled from a worthy stock, to bear
Those limbs which sanctified were.
Blest tree, whose happy branches bore
The wealth that did the world restore;
The beam that did that body weigh
Which raised up hell's expected prey.
O Cross, our one reliance, hail!
On this triumphant day avail,
This holy Passiontide,
To give fresh merit to the saint,
And pardon to the penitent.
Blest Trinity, salvation's spring,
May every soul thy praises sing;
To those thou grantest conquest by
The holy cross, rewards apply.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,43 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Vespera]" in
# Latin/TemporaM/Pent01-0.txt, referenced from "[HymnusM Day6 Vespera]" =
# "@Tempora/Pent01-0:HymnusM Vespera" in Psalterium/Special/Major
# Special.txt) — full separate Monastic text this time ("O lux beáta
# Trínitas"), not a substitution against a base hymn. Not
# live-query-verified (see TODO.md) — read directly from source.
id: vespers-hymn-saturday
text:
la: |
O lux beáta Trínitas,
Et principális Únitas,
Jam sol recédit ígneus,
Infúnde lumen córdibus.
Te mane laudum cármine,
Te deprecémur véspere:
Te nostra supplex glória
Per cuncta laudet sǽcula.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc, et in perpétuum.
Amen.
en: |
O Trinity of blessed Light,
O Unity of sovereign might,
as now the fiery sun departs,
shed Thou Thy beams within our hearts.
To Thee our morning song of praise,
to Thee our evening prayer we raise;
Thee may our glory evermore
in lowly reverence adore.
All laud to God the Father be;
all praise, Eternal Son, to Thee;
all glory, as is ever meet,
to God the Holy Paraclete.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,65 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Day0 Vespera]",
# Psalterium/Special/Major Special.txt). The Monastic Latin is stored there
# as two word-order/wording substitutions against the base "[Hymnus Day0
# Vespera]" text ("Illábitur tetrum chaos" -> "Tetrum chaos illábitur";
# "Cæléste pulset óstium:" -> "Cælórum pulset íntimum,"), applied by hand
# here rather than left as a diff — not live-query-verified (see TODO.md).
# English has no separate Monastic variant in the source (the wording
# differences don't affect translation), so it's the same text either way.
id: vespers-hymn-sunday
text:
la: |
Lucis Creátor óptime,
Lucem diérum próferens,
Primórdiis lucis novæ,
Mundi parans oríginem:
Qui mane junctum vésperi
Diem vocári prǽcipis:
Tetrum chaos illábitur,
Audi preces cum flétibus.
Ne mens graváta crímine,
Vitæ sit exsul múnere,
Dum nil perénne cógitat,
Seséque culpis ílligat.
Cælórum pulset íntimum,
Vitále tollat prǽmium:
Vitémus omne nóxium:
Purgémus omne péssimum.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O blest Creator of the light,
Who mak'st the day with radiance bright,
And o'er the forming world didst call
The light from chaos first of all;
Whose wisdom joined in meet array
The morn and eve, and named them day:
Night comes with all its darkling fears;
Regard thy people's prayers and tears.
Lest, sunk in sin, and whelmed with strife,
They lose the gift of endless life;
While thinking but the thoughts of time,
They weave new chains of woe and crime.
But grant them grace that they may strain
The heavenly gate and prize to gain:
Each harmful lure aside to cast,
And purge away each error past.
O Father, that we ask be done,
Through Jesus Christ, thine only Son;
Who, with the Holy Ghost and thee,
Doth live and reign eternally.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,64 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Day4 Vespera]",
# Psalterium/Special/Major Special.txt): five substitutions against the
# base "[Hymnus Day4 Vespera]" text ("fértili natos aqua" -> "ex aquis
# ortum genus"; "relínquis" -> "remíttis"; "érigens" -> "írrigans";
# "répleant" -> "rápiant"; "éfferat" -> "levet"), applied by hand here —
# not live-query-verified (see TODO.md). English has no separate Monastic
# variant in the source.
id: vespers-hymn-thursday
text:
la: |
Magnæ Deus poténtiæ,
Qui ex aquis ortum genus
Partim remíttis gúrgiti,
Partim levas in áëra.
Demérsa lymphis ímprimens,
Subvécta cælis írrigans:
Ut stirpe ab una pródita,
Divérsa rápiant loca:
Largíre cunctis sérvulis,
Quos mundat unda Sánguinis,
Nescíre lapsus críminum,
Nec ferre mortis tǽdium.
Ut culpa nullum déprimat:
Nullum levet jactántia:
Elísa mens ne cóncidat:
Eláta mens ne córruat.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O sovereign Lord of nature's might,
Who bad'st the water's birth divide;
Part in the heavens to take their flight,
And part in ocean's deep to hide;
These low obscured, on airy wing
Exalted those, that either race,
Though from one element they spring,
Might serve thee in a different place.
Grant, Lord, that we thy servants all,
Saved by thy tide of cleansing blood,
No more 'neath sin's dominion fall,
Nor fear the thought of death's dark flood!
Thy varied love each spirit bless,
The humble cheer, the high control;
Check in each heart its proud excess,
But raise the meek and contrite soul!
This boon, O Father, we entreat,
This blessing grant, Eternal Son,
And Holy Ghost, the Paraclete,
Both now, and while the ages run.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,64 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Day2 Vespera]",
# Psalterium/Special/Major Special.txt): four word substitutions against
# the base "[Hymnus Day2 Vespera]" text ("alme" -> "ingens"; "séparans" ->
# "éruens"; "dedísti" -> "dedíst[i]" — the source's own bracket notation,
# kept as-is; "ictum" -> "actum"), applied by hand here — not
# live-query-verified (see TODO.md). English has no separate Monastic
# variant in the source.
id: vespers-hymn-tuesday
text:
la: |
Tellúris ingens Cónditor,
Mundi solum qui éruens,
Pulsis aquæ moléstiis,
Terram dedíst[i] immóbilem:
Ut germen aptum próferens,
Fulvis decóra flóribus,
Fecúnda fructu sísteret,
Pastúmque gratum rédderet.
Mentis perústæ vúlnera
Munda viróre grátiæ:
Ut facta fletu díluat,
Motúsque pravos átterat.
Jussis tuis obtémperet:
Nullis malis appróximet:
Bonis repléri gáudeat,
Et mortis actum nésciat.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
Earth's mighty Maker, whose command
Raised from the sea the solid land;
And drove each billowy heap away,
And bade the earth stand firm for aye:
That so, with flowers of golden hue,
The seeds of each it might renew;
And fruit-trees bearing fruit might yield,
And pleasant pasture of the field:
Our spirit's rankling wounds efface
With dewy freshness of thy grace:
That grief may cleanse each deed of ill,
And o'er each lust may triumph still.
Let every soul thy law obey,
And keep from every evil way;
Rejoice each promised good to win,
And flee from every mortal sin.
Hear thou our prayer, Almighty King!
Hear thou our praises, while we sing,
Adoring with the heavenly host,
The Father, Son, and Holy Ghost!
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,64 @@
# Sourced from Divinum Officium's Monastic block ("[HymnusM Day3 Vespera]",
# Psalterium/Special/Major Special.txt): three substitutions against the
# base "[Hymnus Day3 Vespera]" text ("mundi plagas" -> "centrum poli";
# "Dum solis accéndis rotam" -> "Solis rotam constítuens"; "Expélle noctem
# córdium:" -> "Illúmina cor hóminum,"), applied by hand here — not
# live-query-verified (see TODO.md). English has no separate Monastic
# variant in the source.
id: vespers-hymn-wednesday
text:
la: |
Cæli Deus sanctíssime,
Qui lúcidas centrum poli
Candóre pingis ígneo,
Augens decóro lúmine:
Quarto die qui flámmeam
Solis rotam constítuens,
Lunæ minístras órdinem,
Vagósque cursus síderum:
Ut nóctibus, vel lúmini
Diremptiónis términum,
Primórdiis et ménsium
Signum dares notíssimum;
Illúmina cor hóminum,
Abstérge sordes méntium:
Resólve culpæ vínculum:
Evérte moles críminum.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O God, whose hand hath spread the sky,
And all its shining hosts on high,
And painting it with fiery light,
Made it so beauteous and so bright:
Thou, when the fourth day was begun,
Didst frame the circle of the sun,
And set the moon for ordered change,
And planets for their wider range:
To night and day, by certain line,
Their varying bounds thou didst assign;
And gav'st a signal, known and meet,
For months begun and months complete.
Enlighten thou the hearts of men:
Polluted souls make pure again:
Unloose the bands of guilt within:
Remove the burden of our sin.
Grant this, O Father, ever One
With Christ thy sole-begotten Son,
Whom, with the Spirit we adore,
One God, both now and evermore.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,23 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Adv
# Vespera_]", the non-Cistercian branch "[Responsory Adv Vespera]"
# resolves to — Psalterium/Special/Major Special.txt). Not
# live-query-verified (see TODO.md) — read directly from source.
id: vespers-responsory-advent
text:
la: |
R.br. Osténde nobis Dómine * Misericórdiam tuam.
R. Osténde nobis Dómine * Misericórdiam tuam.
V. Et salutáre tuum da nobis.
R. Misericórdiam tuam.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Osténde nobis Dómine * Misericórdiam tuam.
en: |
R.br. Show us, O Lord, * thy mercy.
R. Show us, O Lord, * thy mercy.
V. And grant us thy salvation.
R. Thy mercy.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. Show us, O Lord, * thy mercy.
status:
la: draft
en: draft
@@ -0,0 +1,23 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Feria
# Vespera_]", the non-Cistercian branch "[Responsory Feria Vespera]"
# resolves to — Psalterium/Special/Major Special.txt). Shared Mon-Fri.
# Not live-query-verified (see TODO.md) — read directly from source.
id: vespers-responsory-ferial
text:
la: |
R.br. Benedícam Dóminum * In omni témpore.
R. Benedícam Dóminum * In omni témpore.
V. Semper laus ejus in ore meo.
R. In omni témpore.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Benedícam Dóminum * In omni témpore.
en: |
R.br. I will bless the Lord * at all times.
R. I will bless the Lord * at all times.
V. His praise shall be always in my mouth.
R. At all times.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. I will bless the Lord * at all times.
status:
la: draft
en: draft
@@ -0,0 +1,22 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Quad
# Vespera]", Psalterium/Special/Major Special.txt). Not
# live-query-verified (see TODO.md) — read directly from source.
id: vespers-responsory-lent
text:
la: |
R.br. Scápulis suis * obumbrábit tibi.
R. Scápulis suis * obumbrábit tibi.
V. Et sub pennis ejus sperábis.
R. Obumbrábit tibi.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Scápulis suis * obumbrábit tibi.
en: |
R.br. He will overshadow * thee with his shoulders.
R. He will overshadow * thee with his shoulders.
V. And under his wings thou shalt trust.
R. Thee with his shoulders.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. He will overshadow * thee with his shoulders.
status:
la: draft
en: draft
@@ -0,0 +1,25 @@
# Sourced from Divinum Officium's Monastic block: "[Responsory Pasch
# Vespera]" resolves (non-Cistercian branch) to "@Psalterium/Special/
# Minor Special:Responsory breve Pasch Sexta" (Psalterium/Special/Minor
# Special.txt) — distinct from Lauds' own Paschaltide responsory (see
# lauds-responsory-paschaltide.yml). Not live-query-verified (see
# TODO.md) — read directly from source.
id: vespers-responsory-paschaltide
text:
la: |
R.br. Surréxit Dóminus vere, * Allelúja, allelúja.
R. Surréxit Dóminus vere, * Allelúja, allelúja.
V. Et appáruit Simóni.
R. Allelúja, allelúja.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Surréxit Dóminus vere, * Allelúja, allelúja.
en: |
R.br. The Lord is risen indeed, * alleluia, alleluia.
R. The Lord is risen indeed, * alleluia, alleluia.
V. And hath appeared to Simon.
R. Alleluia, alleluia.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. The Lord is risen indeed, * alleluia, alleluia.
status:
la: draft
en: draft
@@ -0,0 +1,21 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Quad5
# Vespera_]", the non-Cistercian branch "[Responsory Quad5 Vespera]"
# resolves to — Psalterium/Special/Major Special.txt). Not
# live-query-verified (see TODO.md) — read directly from source.
id: vespers-responsory-passiontide
text:
la: |
R.br. De ore leónis * líbera me, Dómine.
R. De ore leónis * líbera me, Dómine.
V. Et a córnibus unicórnium humilitátem meam.
R. Líbera me, Dómine.
R. De ore leónis * líbera me, Dómine.
en: |
R.br. From the lion's mouth, * O Lord, save me.
R. From the lion's mouth, * O Lord, save me.
V. And my lowness from the horns of the unicorns.
R. O Lord, save me.
R. From the lion's mouth, * O Lord, save me.
status:
la: draft
en: draft
@@ -0,0 +1,22 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Feria
# Vespera] (feria 7)", Psalterium/Special/Major Special.txt). Not
# live-query-verified (see TODO.md) — read directly from source.
id: vespers-responsory-saturday
text:
la: |
R.br. Magnus Dóminus noster, * et magna virtus ejus.
R. Magnus Dóminus noster, * et magna virtus ejus.
V. Et sapiéntiæ ejus non est númerus.
R. Et magna virtus ejus.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Magnus Dóminus noster, * et magna virtus ejus.
en: |
R.br. Great is our Lord, * and great is his power.
R. Great is our Lord, * and great is his power.
V. And of his wisdom there is no number.
R. And great is his power.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. Great is our Lord, * and great is his power.
status:
la: draft
en: draft
@@ -0,0 +1,22 @@
# Sourced from Divinum Officium's Monastic block ("[Responsory Dominica
# Vespera]", Psalterium/Special/Major Special.txt). Not live-query-verified
# (see TODO.md) — read directly from source.
id: vespers-responsory-sunday
text:
la: |
R.br. Quam magnificáta sunt * ópera tua, Dómine.
R. Quam magnificáta sunt * ópera tua, Dómine.
V. Ómnia in sapiéntia fecísti.
R. Ópera tua Dómine.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Quam magnificáta sunt * ópera tua, Dómine.
en: |
R.br. How great are thy works, * O Lord.
R. How great are thy works, * O Lord.
V. Thou hast made all things in wisdom.
R. Thy works, O Lord.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. How great are thy works, * O Lord.
status:
la: draft
en: draft
@@ -0,0 +1,15 @@
# The versicle right before the Magnificat, in Advent — the famous
# "Rorate cæli". Sourced from Divinum Officium's Monastic block ("[Adv
# Versum 3]", Psalterium/Special/Major Special.txt). Not
# live-query-verified (see TODO.md) — read directly from source.
id: vespers-versicle-advent
text:
la: |
V. Roráte, cæli, désuper, et nubes pluant justum.
R. Aperiátur terra, et gérminet Salvatórem.
en: |
V. Drop down dew, ye heavens, from above, and let the clouds rain the Just.
R. Let the earth be opened, and bud forth the Saviour.
status:
la: draft
en: draft
@@ -0,0 +1,17 @@
# The versicle right before the Magnificat, in Lent. Sourced from Divinum
# Officium's Monastic block ("[Quad Versum 3]", Psalterium/Special/Major
# Special.txt) — "[Quad Versum 2]" (Lauds' own) is a bare alias to this
# same text, so Lauds and Vespers share it here too (see
# lauds-versicle-lent.yml). Not live-query-verified (see TODO.md) — read
# directly from source.
id: vespers-versicle-lent
text:
la: |
V. Ángelis suis Deus mandávit de te.
R. Ut custódiant te in ómnibus viis tuis.
en: |
V. God hath given His Angels charge over thee.
R. To keep thee in all thy ways.
status:
la: draft
en: draft
@@ -0,0 +1,16 @@
# The versicle right before the Magnificat, in Paschaltide. Sourced from
# Divinum Officium's Monastic block ("[Pasch Versum 3]", Psalterium/
# Special/Major Special.txt). Distinct from Lauds' own Paschaltide
# versicle (see lauds-versicle-paschaltide.yml). Not live-query-verified
# (see TODO.md) — read directly from source.
id: vespers-versicle-paschaltide
text:
la: |
V. Mane nobíscum, Dómine, allelúja.
R. Quóniam advesperáscit, allelúja.
en: |
V. Stay with us, O Lord, alleluia.
R. Because it is towards evening, alleluia.
status:
la: draft
en: draft
@@ -0,0 +1,16 @@
# The versicle right before the Magnificat, in Passiontide. Sourced from
# Divinum Officium's Monastic block ("[Quad5 Versum 3_]", the
# non-Cistercian branch "[Quad5 Versum 3]" resolves to — Psalterium/
# Special/Major Special.txt). Not live-query-verified (see TODO.md) —
# read directly from source.
id: vespers-versicle-passiontide
text:
la: |
V. Éripe me, Dómine, ab hómine malo.
R. A viro iníquo éripe me.
en: |
V. Deliver me, O Lord, from the evil man.
R. Rescue me from the unjust man.
status:
la: draft
en: draft
@@ -0,0 +1,16 @@
# The versicle right before the Magnificat. Sourced from Divinum
# Officium's Monastic block ("[Feria Versum 3] (feria 7)", Psalterium/
# Special/Major Special.txt) — Saturday has its own, distinct from Sunday/
# the weekdays. Not live-query-verified (see TODO.md) — read directly from
# source.
id: vespers-versicle-saturday
text:
la: |
V. Vespertína orátio ascéndat ad te, Dómine.
R. Et descéndat super nos misericórdia tua.
en: |
V. Let the evening prayer ascend unto thee, O Lord.
R. And let there descend upon us thy mercy.
status:
la: draft
en: draft
@@ -0,0 +1,16 @@
# The versicle right before the Magnificat. Sourced from Divinum
# Officium's Monastic block: "[Dominica Versum 3]" gives the text
# directly; "[Feria Versum 3] = @:Dominica Versum 3" (Mon-Fri) is a bare
# alias to the same text — so Sunday and the five weekdays share this one.
# Not live-query-verified (see TODO.md) — read directly from source.
id: vespers-versicle-sunday-ferial
text:
la: |
V. Dirigátur, Dómine, orátio mea.
R. Sicut incénsum in conspéctu tuo.
en: |
V. O Lord, direct my prayer.
R. As incense in thy sight.
status:
la: draft
en: draft
+3
View File
@@ -91,6 +91,9 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
case 'suffrages': case 'suffrages':
case 'lauds-preces': case 'lauds-preces':
case 'day-collects': case 'day-collects':
case 'vespers-psalmody':
case 'vespers-office':
case 'magnificat':
throw new Error(`Compline's ordo doesn't support a '${part.kind}' part`); throw new Error(`Compline's ordo doesn't support a '${part.kind}' part`);
} }
} }
+15 -5
View File
@@ -17,6 +17,7 @@ import {
resolveOfficeWinner, resolveOfficeWinner,
ALWAYS_OVERRIDE_TEMPORAL_IDS, ALWAYS_OVERRIDE_TEMPORAL_IDS,
verifiedText, verifiedText,
seasonalOfficeSuffix,
} from './resolve-common'; } from './resolve-common';
import laudsDefinitionData from '../data/hours/lauds.yml'; import laudsDefinitionData from '../data/hours/lauds.yml';
import laudsAntiphonsData from '../data/hours/lauds-antiphons.yml'; import laudsAntiphonsData from '../data/hours/lauds-antiphons.yml';
@@ -187,7 +188,11 @@ function resolvePsalmody(day: LiturgicalDay): ResolvedPart[] {
* getPsalmodyOverrideFor) and leave this bundle at its plain weekday * getPsalmodyOverrideFor) and leave this bundle at its plain weekday
* default, which is exactly what falls back here when the id-keyed * default, which is exactly what falls back here when the id-keyed
* capitulum doesn't exist (same dual-missing-status "not authored" * capitulum doesn't exist (same dual-missing-status "not authored"
* signal used throughout this codebase, not a special case). */ * signal used throughout this codebase, not a special case). Falls to a
* *seasonal* default next (Advent/Lent/Passiontide/Paschaltide — see
* resolve-common.ts's seasonalOfficeSuffix), and only then the plain
* weekday default — a feast's own override always wins over the season
* it happens to fall in, same as everywhere else in this codebase. */
function resolveOffice(day: LiturgicalDay): ResolvedPart[] { function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
const overrideId = getPsalmodyOverrideFor(day)?.id; const overrideId = getPsalmodyOverrideFor(day)?.id;
if (overrideId) { if (overrideId) {
@@ -201,11 +206,13 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
]; ];
} }
} }
const seasonSuffix = seasonalOfficeSuffix(day.season);
const key = seasonSuffix ?? day.weekday;
return [ return [
{ kind: 'chapter', text: resolveCommon(capitulumId(day.weekday)) }, { kind: 'chapter', text: resolveCommon(seasonSuffix ? `lauds-capitulum-${key}` : capitulumId(day.weekday)) },
{ kind: 'responsory', text: resolveCommon(`lauds-responsory-${day.weekday}`) }, { kind: 'responsory', text: resolveCommon(`lauds-responsory-${key}`) },
{ kind: 'hymn', text: resolveCommon(`lauds-hymn-${day.weekday}`) }, { kind: 'hymn', text: resolveCommon(`lauds-hymn-${key}`) },
{ kind: 'versicle', text: resolveCommon(`lauds-versicle-${day.weekday}`) }, { kind: 'versicle', text: resolveCommon(`lauds-versicle-${key}`) },
]; ];
} }
@@ -344,6 +351,9 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
case 'variable': case 'variable':
case 'day-collect': case 'day-collect':
case 'nunc-dimittis': case 'nunc-dimittis':
case 'vespers-psalmody':
case 'vespers-office':
case 'magnificat':
throw new Error(`Lauds' ordo doesn't support a '${part.kind}' part`); throw new Error(`Lauds' ordo doesn't support a '${part.kind}' part`);
} }
} }
+3
View File
@@ -67,6 +67,9 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
case 'suffrages': case 'suffrages':
case 'lauds-preces': case 'lauds-preces':
case 'day-collects': case 'day-collects':
case 'vespers-psalmody':
case 'vespers-office':
case 'magnificat':
throw new Error(`None's ordo doesn't support a '${part.kind}' part`); throw new Error(`None's ordo doesn't support a '${part.kind}' part`);
} }
} }
+3
View File
@@ -123,6 +123,9 @@ function resolvePart(part: HourPart, date: string, day: LiturgicalDay): Resolved
case 'suffrages': case 'suffrages':
case 'lauds-preces': case 'lauds-preces':
case 'day-collects': case 'day-collects':
case 'vespers-psalmody':
case 'vespers-office':
case 'magnificat':
throw new Error(`Prime's ordo doesn't support a '${part.kind}' part`); throw new Error(`Prime's ordo doesn't support a '${part.kind}' part`);
} }
} }
+75 -1
View File
@@ -1,10 +1,23 @@
import type { ResolvedPart, ResolvedText } from './types'; import type { ResolvedPart, ResolvedText } from './types';
import type { Commemoration, DayWinner, LiturgicalDay } from '../calendar/types'; import type { Commemoration, DayWinner, LiturgicalDay, Weekday } from '../calendar/types';
import type { ProperText } from '../propers'; import type { ProperText } from '../propers';
import { getCommonProper, getTemporalProper } from '../propers'; import { getCommonProper, getTemporalProper } from '../propers';
import { getSaintRecord } from '../calendar/feasts'; import { getSaintRecord } from '../calendar/feasts';
import { resolveActiveOctave } from '../calendar'; import { resolveActiveOctave } from '../calendar';
import { splitAntiphon } from './antiphon'; import { splitAntiphon } from './antiphon';
import vespersMagnificatAntiphonsData from '../data/hours/vespers-magnificat-antiphons.yml';
type BilingualText = Partial<Record<string, string>>;
type TranslationStatus = 'verified' | 'draft' | 'missing';
interface MagnificatWeekdayDefault {
antiphon: BilingualText;
status?: Partial<Record<string, TranslationStatus>>;
}
// Monday-Saturday only — Sunday has no fixed weekday default (its own
// antiphon varies by Proper of the Time; see the data file's own header).
const vespersMagnificatAntiphons = vespersMagnificatAntiphonsData as Partial<
Record<Weekday, MagnificatWeekdayDefault>
>;
function toResolvedText(proper: ProperText): ResolvedText { function toResolvedText(proper: ProperText): ResolvedText {
return { text: proper.text, status: proper.status, citation: proper.citation }; return { text: proper.text, status: proper.status, citation: proper.citation };
@@ -163,6 +176,25 @@ export function getMinorHourOverrideId(day: LiturgicalDay): string | undefined {
*/ */
const PASCHALTIDE_SEASONS = new Set(['eastertide', 'ascensiontide', 'pentecost']); const PASCHALTIDE_SEASONS = new Set(['eastertide', 'ascensiontide', 'pentecost']);
/**
* Which seasonal office-content suffix (if any) a day's season maps to —
* shared by Lauds' and Vespers' own resolveOffice, both of which fall
* back to the plain weekday default when this is undefined (and both
* check a per-feast/octave override first, ahead of this). Paschaltide
* covers eastertide/ascensiontide/pentecost uniformly, matching the
* source's own single "Pasch" block for both hours — no separate
* Ascension/Pentecost-specific chapter/hymn exists there.
*/
export function seasonalOfficeSuffix(season: string): string | undefined {
if (season === 'advent' || season === 'lent' || season === 'passiontide') {
return season;
}
if (PASCHALTIDE_SEASONS.has(season)) {
return 'paschaltide';
}
return undefined;
}
/** /**
* The reference engine's mechanical Paschaltide fallback for a Common * The reference engine's mechanical Paschaltide fallback for a Common
* antiphon with no dedicated wholesale-different text of its own: a * antiphon with no dedicated wholesale-different text of its own: a
@@ -449,6 +481,48 @@ export function getBenedictusAntiphon(day: LiturgicalDay): ResolvedText {
return { text: {}, status: { la: 'missing', en: 'missing' } }; return { text: {}, status: { la: 'missing', en: 'missing' } };
} }
/**
* Vespers' Magnificat antiphon — mirrors getBenedictusAntiphon's lookup
* order exactly (temporal id, then a saint's own `${propers}-magnificat-
* antiphon`, then their Common category's `magnificat-antiphon-${common}`
* — none of that content authored yet, a separate future pass the same
* shape as the Benedictus one was), but with one real difference: a bare
* ferial weekday (Mon-Sat) has actual content to fall back to —
* data/hours/vespers-magnificat-antiphons.yml's classic "quote the
* Magnificat's own text in sequence" set — which Benedictus has no
* equivalent of. `withPaschaltideAlleluia` applied to that fallback too,
* by analogy with the Common-category treatment above; not independently
* confirmed for this specific case.
*/
export function getMagnificatAntiphon(day: LiturgicalDay): ResolvedText {
const winner = resolveOfficeWinner(day);
if (winner.kind === 'temporal') {
const named = toResolvedText(getTemporalProper(`${winner.id}-magnificat-antiphon`));
if (named.status.la !== 'missing' || named.status.en !== 'missing') {
return named;
}
const weekdayDefault = vespersMagnificatAntiphons[day.weekday];
if (weekdayDefault) {
const resolved = weekdayDefault.status
? { text: weekdayDefault.antiphon, status: weekdayDefault.status }
: verifiedText(weekdayDefault.antiphon);
return withPaschaltideAlleluia(resolved, day);
}
return named;
}
const saint = getSaintRecord(winner.id);
if (saint?.propers) {
const proper = resolveCommon(`${saint.propers}-magnificat-antiphon`);
if (proper.status.la !== 'missing' || proper.status.en !== 'missing') {
return proper;
}
}
if (saint?.benedictusCommon) {
return withPaschaltideAlleluia(resolveCommon(`magnificat-antiphon-${saint.benedictusCommon}`), day);
}
return { text: {}, status: { la: 'missing', en: 'missing' } };
}
export function verifiedText(text: Partial<Record<string, string>>): ResolvedText { export function verifiedText(text: Partial<Record<string, string>>): ResolvedText {
const status: Partial<Record<string, 'verified'>> = {}; const status: Partial<Record<string, 'verified'>> = {};
for (const lang of Object.keys(text)) { for (const lang of Object.keys(text)) {
+3
View File
@@ -67,6 +67,9 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
case 'suffrages': case 'suffrages':
case 'lauds-preces': case 'lauds-preces':
case 'day-collects': case 'day-collects':
case 'vespers-psalmody':
case 'vespers-office':
case 'magnificat':
throw new Error(`Sext's ordo doesn't support a '${part.kind}' part`); throw new Error(`Sext's ordo doesn't support a '${part.kind}' part`);
} }
} }
+3
View File
@@ -67,6 +67,9 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
case 'suffrages': case 'suffrages':
case 'lauds-preces': case 'lauds-preces':
case 'day-collects': case 'day-collects':
case 'vespers-psalmody':
case 'vespers-office':
case 'magnificat':
throw new Error(`Terce's ordo doesn't support a '${part.kind}' part`); throw new Error(`Terce's ordo doesn't support a '${part.kind}' part`);
} }
} }
+23
View File
@@ -105,6 +105,29 @@ export type HourPart =
// data/propers/common/lauds-{capitulum,responsory,hymn,versicle}-*.yml. // data/propers/common/lauds-{capitulum,responsory,hymn,versicle}-*.yml.
// Expands into 4 ResolvedParts (chapter, responsory, hymn, versicle). // Expands into 4 ResolvedParts (chapter, responsory, hymn, versicle).
| { kind: 'lauds-office' } | { kind: 'lauds-office' }
// Vespers only. The weekday-resolved 4-psalm-group psalmody — see
// hours/vespers.ts and data/hours/vespers-antiphons.yml. Opaque for the
// same reason as 'lauds-psalmody': each group's antiphon covers either
// one whole psalm, two whole psalms said together under one shared
// antiphon (Ps 115+116, Monday), or two verse-ranges of one psalm split
// under one shared antiphon (Ps 138/143, Thu/Fri) — no existing part
// kind represents that. No per-feast override mechanism yet (unlike
// Lauds' getPsalmodyOverrideFor) — every day renders the plain weekday
// default for now.
| { kind: 'vespers-psalmody' }
// Vespers only. The weekday-resolved chapter/short-responsory/hymn/
// versicle bundle that follows the psalmody — see hours/vespers.ts and
// data/propers/common/vespers-{capitulum,responsory,hymn,versicle}-*.yml.
// Expands into 4 ResolvedParts (chapter, responsory, hymn, versicle).
| { kind: 'vespers-office' }
// Vespers only. Magnificat (Luke 1:46-55), fixed text, framed by a
// day-resolved antiphon — see hours/resolve-common.ts's
// getMagnificatAntiphon, which mirrors getBenedictusAntiphon's
// saint/temporal-id lookup but also falls back to a real weekday
// default (data/hours/vespers-magnificat-antiphons.yml, Mon-Sat) that
// Benedictus has no equivalent of. Same incipit-or-full/full-after
// framing as benedictus/nunc-dimittis, gated by isDoubleOrHigher.
| { kind: 'magnificat' }
// Lauds only. Benedictus (Luke 1:68-79), fixed text (see propers/common/ // Lauds only. Benedictus (Luke 1:68-79), fixed text (see propers/common/
// benedictus.yml) framed by a day-resolved antiphon (see hours/ // benedictus.yml) framed by a day-resolved antiphon (see hours/
// resolve-common.ts's getBenedictusAntiphon) — same incipit-or-full/ // resolve-common.ts's getBenedictusAntiphon) — same incipit-or-full/
+165 -5
View File
@@ -1,7 +1,167 @@
import type { ResolvedOrdo } from './types'; import type { HourDefinition, HourPart, ResolvedOrdo, ResolvedPart } from './types';
import type { LiturgicalDay, Weekday } from '../calendar/types';
import { resolveEveningDay } from '../calendar/vespers';
import { getDayLabel } from '../calendar/day-label';
import { getPsalmVerses } from '../psalter';
import { getOpeningVersicleId } from './opening-versicle';
import { isDoubleOrHigher } from './antiphon';
import {
resolveCommon,
getDayCollects,
getMagnificatAntiphon,
splitNamedAntiphon,
resolveOfficeWinner,
verifiedText,
seasonalOfficeSuffix,
} from './resolve-common';
import vespersDefinitionData from '../data/hours/vespers.yml';
import vespersAntiphonsData from '../data/hours/vespers-antiphons.yml';
// Milestone 4, alongside Lauds — also has the first/second-Vespers overlap const vespersDefinition = vespersDefinitionData as HourDefinition;
// wrinkle (see OccurringFeast.vespersFrom). Not built yet.
export function resolveOrdo(date: string): ResolvedOrdo { type BilingualText = Partial<Record<string, string>>;
return { hourId: 'vespers', date, parts: [], notImplemented: true }; /** A whole psalm, or a `{number, verses}` verse-range slice of one same
* shape as psalter/distribution.ts's PsalmRef, needed here (unlike Lauds'
* plain `psalms: number[]`) because two of the week's groups split a
* single psalm into two ranges under one shared antiphon see
* vespers-antiphons.yml's own header. */
type PsalmRefLike = number | { number: number; verses?: string };
interface VespersGroup {
psalms: PsalmRefLike[];
antiphon: BilingualText;
}
interface VespersDay {
groups: VespersGroup[];
}
const vespersAntiphons = vespersAntiphonsData as Record<Weekday, VespersDay>;
function normalizePsalmRef(ref: PsalmRefLike): { number: number; verses?: string } {
return typeof ref === 'number' ? { number: ref } : ref;
}
/** One group's worth of psalm(s) under one shared antiphon the antiphon
* opens (incipit-or-full) before the first psalm/verse-range and repeats
* in full once, after the last. Mirrors lauds.ts's psalmParts, extended
* for verse-range entries (see PsalmRefLike). */
function psalmParts(group: VespersGroup, day: LiturgicalDay): ResolvedPart[] {
const { incipit, full } = splitNamedAntiphon(verifiedText(group.antiphon));
const opening = isDoubleOrHigher(resolveOfficeWinner(day)) ? full : incipit;
const refs = group.psalms.map(normalizePsalmRef);
const parts: ResolvedPart[] = refs.map((ref, i) => ({
kind: 'psalm' as const,
psalmNumber: ref.number,
antiphon: i === 0 ? opening : undefined,
verses: getPsalmVerses(ref.number, ref.verses).map((v) => ({ n: v.n, text: v.text, status: v.status })),
}));
parts.push({ kind: 'antiphon', text: full });
return parts;
}
/** The 4 weekday-variable psalm groups no fixed leading/trailing psalm
* the way Lauds has (Ps 66 / the Laudate psalms); Vespers is just these 4
* groups in sequence. No per-feast override mechanism yet see
* hours/types.ts's 'vespers-psalmody' doc comment. */
function resolvePsalmody(day: LiturgicalDay): ResolvedPart[] {
const wd = vespersAntiphons[day.weekday];
return wd.groups.flatMap((group) => psalmParts(group, day));
}
function vespersCapitulumId(weekday: Weekday): string {
return weekday === 'saturday' ? 'vespers-capitulum-saturday' : 'vespers-capitulum-sunday-ferial';
}
function vespersResponsoryId(weekday: Weekday): string {
if (weekday === 'sunday') return 'vespers-responsory-sunday';
if (weekday === 'saturday') return 'vespers-responsory-saturday';
return 'vespers-responsory-ferial';
}
function vespersVersicleId(weekday: Weekday): string {
return weekday === 'saturday' ? 'vespers-versicle-saturday' : 'vespers-versicle-sunday-ferial';
}
/** The chapter/responsory/hymn/versicle bundle following the psalmody
* see hours/types.ts's 'vespers-office' doc comment. No per-feast
* override mechanism yet, unlike Lauds' resolveOffice. Falls to a
* *seasonal* default first (Advent/Lent/Passiontide/Paschaltide see
* resolve-common.ts's seasonalOfficeSuffix), then the plain weekday
* default. */
function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
const seasonSuffix = seasonalOfficeSuffix(day.season);
const key = seasonSuffix ?? day.weekday;
return [
{
kind: 'chapter',
text: resolveCommon(seasonSuffix ? `vespers-capitulum-${key}` : vespersCapitulumId(day.weekday)),
},
{
kind: 'responsory',
text: resolveCommon(seasonSuffix ? `vespers-responsory-${key}` : vespersResponsoryId(day.weekday)),
},
{ kind: 'hymn', text: resolveCommon(`vespers-hymn-${key}`) },
{
kind: 'versicle',
text: resolveCommon(seasonSuffix ? `vespers-versicle-${key}` : vespersVersicleId(day.weekday)),
},
];
}
function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
switch (part.kind) {
case 'opening-versicle':
return [{ kind: 'versicle', text: resolveCommon(getOpeningVersicleId(day.season, day.winner)) }];
case 'vespers-psalmody':
return resolvePsalmody(day);
case 'vespers-office':
return resolveOffice(day);
case 'magnificat': {
const { incipit, full } = splitNamedAntiphon(getMagnificatAntiphon(day));
const opening = isDoubleOrHigher(resolveOfficeWinner(day)) ? full : incipit;
return [
{ kind: 'canticle', canticleId: 'magnificat', text: resolveCommon('magnificat'), antiphon: opening },
{ kind: 'antiphon', text: full },
];
}
case 'day-collects':
return getDayCollects(day);
case 'preces':
return [{ kind: 'preces', text: resolveCommon(part.textRef.id), label: part.label }];
case 'versicle':
case 'chapter':
case 'responsory':
case 'prayer':
return [{ kind: part.kind, text: resolveCommon(part.textRef.id) }];
// Not used by Vespers.
case 'hymn':
case 'lesson':
case 'psalm':
case 'canticle':
case 'martyrology':
case 'rule-reading':
case 'creed':
case 'closing-antiphon':
case 'by-day-kind':
case 'variable':
case 'day-collect':
case 'nunc-dimittis':
case 'lauds-psalmody':
case 'lauds-office':
case 'benedictus':
case 'suffrages':
case 'lauds-preces':
case 'marian-antiphon':
throw new Error(`Vespers' ordo doesn't support a '${part.kind}' part`);
}
}
export function resolveOrdo(date: string): ResolvedOrdo {
// Every part below is an evening-hour concern, same reasoning as
// Compline — resolves off whichever day's identity actually governs
// tonight, including the cross-day commemoration folded into
// day.commemorations by resolveEveningDay itself (see calendar/
// vespers.ts) — getDayCollects picks that up for free, no special
// handling needed here.
const day = resolveEveningDay(date);
const parts = vespersDefinition.parts.flatMap((part) => resolvePart(part, day));
return { hourId: 'vespers', date, parts, dayLabel: getDayLabel(day) };
} }
+21
View File
@@ -298,4 +298,25 @@ describe('resolveOrdo("lauds", ...)', () => {
expect(last?.kind).toBe('preces'); expect(last?.kind).toBe('preces');
expect(last?.kind === 'preces' ? last.label : undefined).toBe('Salve Regina'); expect(last?.kind === 'preces' ? last.label : undefined).toBe('Salve Regina');
}); });
it("renders Advent's seasonal chapter/hymn/versicle instead of the plain weekday default", () => {
// 2025-12-02 is a Tuesday in Advent (St. Bibiana, Simplex, merely
// commemorated — the day's own winner stays temporal either way).
const ordo = resolveOrdo('lauds', '2025-12-02');
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Isa 2:3');
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Vox clara ecce íntonat');
const versicle = ordo.parts.find((p) => p.kind === 'versicle' && p.text.text.la?.includes('Vox clamántis'));
expect(versicle).toBeDefined();
});
it("renders Paschaltide's seasonal office, sharing its chapter with Vespers", () => {
// 2026-04-20 is in eastertide (Easter 2026-04-05).
const ordo = resolveOrdo('lauds', '2026-04-20');
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Rom 6:9-10');
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Auróra lucis rútilat');
});
}); });
+2 -2
View File
@@ -226,8 +226,8 @@ describe('resolveOrdo("prime", ...)', () => {
}); });
describe('resolveOrdo for not-yet-built hours', () => { describe('resolveOrdo for not-yet-built hours', () => {
it('flags vespers as not implemented rather than throwing', () => { it('flags matins as not implemented rather than throwing', () => {
const ordo = resolveOrdo('vespers', MONDAY); const ordo = resolveOrdo('matins', MONDAY);
expect(ordo.notImplemented).toBe(true); expect(ordo.notImplemented).toBe(true);
expect(ordo.parts).toEqual([]); expect(ordo.parts).toEqual([]);
}); });
+138
View File
@@ -0,0 +1,138 @@
import { describe, expect, it } from 'vitest';
import { resolveOrdo } from '../../src/hours';
describe('resolveOrdo("vespers", ...)', () => {
it('is implemented and resolves Sunday psalmody in order', () => {
// 2026-08-16 is a Sunday, in ordinary time — no First Vespers claim
// from the following Monday (a plain feria), so this stays Sunday's
// own Second Vespers.
const ordo = resolveOrdo('vespers', '2026-08-16');
expect(ordo.notImplemented).toBeUndefined();
expect(ordo.hourId).toBe('vespers');
const psalmNumbers = ordo.parts
.filter((p) => p.kind === 'psalm')
.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
expect(psalmNumbers).toEqual([109, 110, 111, 112]);
});
it('joins Ps 115 and 116 under one shared antiphon on Monday', () => {
// 2026-08-17 is a Monday, in ordinary time.
const ordo = resolveOrdo('vespers', '2026-08-17');
const psalmParts = ordo.parts.filter((p) => p.kind === 'psalm');
const numbers = psalmParts.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
expect(numbers).toEqual([113, 114, 115, 116, 128]);
// Ps 116 (the second half of the joined pair) carries no antiphon of
// its own — only Ps 115 (the group's first entry) does.
const ps115 = psalmParts[2];
const ps116 = psalmParts[3];
expect(ps115?.kind === 'psalm' ? ps115.antiphon : undefined).toBeDefined();
expect(ps116?.kind === 'psalm' ? ps116.antiphon : undefined).toBeUndefined();
});
it('splits Ps 138 into two verse-ranges under one shared antiphon on Thursday', () => {
// 2026-08-20 is a Thursday, in ordinary time.
const ordo = resolveOrdo('vespers', '2026-08-20');
const psalmParts = ordo.parts.filter((p) => p.kind === 'psalm');
const numbers = psalmParts.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
expect(numbers).toEqual([138, 138, 139, 140]);
const [firstHalf, secondHalf] = psalmParts;
expect(firstHalf?.kind === 'psalm' ? firstHalf.verses.every((v) => v.n >= 1 && v.n <= 10) : false).toBe(true);
expect(secondHalf?.kind === 'psalm' ? secondHalf.verses.every((v) => v.n >= 11 && v.n <= 24) : false).toBe(true);
expect(secondHalf?.kind === 'psalm' ? secondHalf.antiphon : undefined).toBeUndefined();
});
it("resolves Saturday's own distinct chapter, responsory, hymn, and versicle", () => {
// 2026-08-15 is a Saturday and the Assumption (Duplex I. classis) —
// well above keepsOwnSecondVespers's threshold, so it keeps its own
// Vespers (weekday stays 'saturday') rather than ceding to tomorrow.
// No per-feast Vespers-office override exists yet (see hours/
// vespers.ts), so the plain Saturday weekday default still renders
// here regardless of the Assumption's own rank — exactly what this
// test wants to check.
const ordo = resolveOrdo('vespers', '2026-08-15');
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Rom 11:33');
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('O lux beáta Trínitas');
const versicle = ordo.parts.find((p) => p.kind === 'versicle' && p.text.text.la?.includes('Vespertína'));
expect(versicle).toBeDefined();
});
it('falls back to the classic weekday-default Magnificat antiphon on a bare ferial', () => {
// 2026-06-16 is a Tuesday, plain ordinary trinitytide, no saint, no
// active octave (same date already used by calendar/vespers.test.ts's
// "does not anticipate between two plain ferias").
const ordo = resolveOrdo('vespers', '2026-06-16');
const magnificatIndex = ordo.parts.findIndex((p) => p.kind === 'canticle' && p.canticleId === 'magnificat');
expect(magnificatIndex).toBeGreaterThanOrEqual(0);
const magnificat = ordo.parts[magnificatIndex];
expect(magnificat?.kind === 'canticle' ? magnificat.text.text.la : undefined).toContain('Magníficat ✠ ánima mea');
// The closing full-antiphon repeat is the very next part.
const closingAntiphon = ordo.parts[magnificatIndex + 1];
expect(closingAntiphon?.kind === 'antiphon' ? closingAntiphon.text.text.la : undefined).toContain('Exsúltet');
});
it('folds the cross-day Vespers commemoration into day-collects (St. James keeps Vespers, St. Anne commemorated)', () => {
// St. Christopher (same-day collision, commemorated under James
// already at the calendar level) and St. Anne (the cross-day Vespers
// commemoration from calendar/vespers.ts) are both sanctoral, so both
// render as 'preces' parts (see resolve-common.ts's
// sanctoralCommemorationPart) — only a *temporal* commemoration
// renders as 'prayer'.
const ordo = resolveOrdo('vespers', '2026-07-25');
const collectParts = ordo.parts.filter((p) => p.kind === 'prayer' || p.kind === 'preces');
// James's own collect ('prayer') + Christopher's + Anne's commemorations ('preces').
expect(collectParts.length).toBeGreaterThanOrEqual(3);
const anne = ordo.parts.find((p) => p.kind === 'preces' && p.label?.includes('Anne'));
expect(anne).toBeDefined();
});
it("renders Advent's seasonal chapter/hymn/versicle instead of the plain weekday default", () => {
// 2025-12-02 is a Tuesday in Advent (St. Bibiana, Simplex, merely
// commemorated — the day's own winner stays temporal either way).
const ordo = resolveOrdo('vespers', '2025-12-02');
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Gen 49:10');
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Cónditor alme síderum');
const versicle = ordo.parts.find((p) => p.kind === 'versicle' && p.text.text.la?.includes('Roráte'));
expect(versicle).toBeDefined();
});
it("renders Lent's seasonal office", () => {
// 2026-03-03 is a Tuesday in Lent, before Passiontide.
const ordo = resolveOrdo('vespers', '2026-03-03');
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Joel 2:17');
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Audi, benígne Cónditor');
});
it("renders Passiontide's seasonal office, with the Gloria Patri omitted from the responsory", () => {
// 2026-03-25 is a Wednesday in Passiontide (Passion Sunday 2026-03-22
// through Holy Saturday 2026-04-04).
const ordo = resolveOrdo('vespers', '2026-03-25');
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Jer 11:20');
const responsory = ordo.parts.find((p) => p.kind === 'responsory');
expect(responsory?.kind === 'responsory' ? responsory.text.text.la : undefined).not.toContain('Glória Patri');
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Vexílla Regis pródeunt');
});
it("renders Paschaltide's seasonal office, sharing its chapter with Lauds", () => {
// 2026-04-20 is in eastertide (Easter 2026-04-05).
const ordo = resolveOrdo('vespers', '2026-04-20');
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Rom 6:9-10');
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Ad cenam Agni próvidi');
const versicle = ordo.parts.find((p) => p.kind === 'versicle' && p.text.text.la?.includes('Mane nobíscum'));
expect(versicle).toBeDefined();
});
});
+4 -4
View File
@@ -41,12 +41,12 @@ describe('shell', () => {
const root = document.getElementById('app')!; const root = document.getElementById('app')!;
mountShell(root); mountShell(root);
const vespersBtn = Array.from(root.querySelectorAll<HTMLButtonElement>('[data-hour]')).find( const matinsBtn = Array.from(root.querySelectorAll<HTMLButtonElement>('[data-hour]')).find(
(btn) => btn.dataset.hour === 'vespers', (btn) => btn.dataset.hour === 'matins',
); );
vespersBtn?.click(); matinsBtn?.click();
expect(root.querySelector('.hour-view h2')?.textContent).toBe('Vespers'); expect(root.querySelector('.hour-view h2')?.textContent).toBe('Matins');
expect(root.querySelector('.hour-view-pending')).not.toBeNull(); expect(root.querySelector('.hour-view-pending')).not.toBeNull();
}); });