tonus 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/engines/chant/syllabify.js +21 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to tonus. Newest first.
|
|
4
4
|
|
|
5
|
+
## 0.10.1 — 2026-08-31
|
|
6
|
+
|
|
7
|
+
A capital ligature is a vowel like any other.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **`Æ` and `Œ` reached the nucleus unexpanded.** `selectVowel` expanded the
|
|
12
|
+
ligatures case-sensitively, and neither has an NFD decomposition (unlike
|
|
13
|
+
`á` → `a`), so a capital survived the scan and was reported AS the vowel:
|
|
14
|
+
`vowel: "æ"`, a two-letter answer to a one-letter promise. Consumers that
|
|
15
|
+
hold tonus to that contract throw on it. 136 chants carry one, every case
|
|
16
|
+
opening a word — 94 at the start of the lyric, the other 42 inside an
|
|
17
|
+
all-capital opening word (`SÆpe`, `PRÆ`, `HÆC`), which is exactly where a
|
|
18
|
+
capital lives. The gated shelf held almost none of them, so 0.10.0's re-cut
|
|
19
|
+
is what surfaced it; the defect is older.
|
|
20
|
+
- **An accented ligature accented the off-glide.** `œ́` is `œ` + combining
|
|
21
|
+
acute, with no precomposed form, so expanding it to `oe` + accent marked the
|
|
22
|
+
`e`: `selectVowel("œ́")` returned nucleus `"e"` where it should return `"o"`.
|
|
23
|
+
The pair is now rebuilt as `o` + accent + `e`. `ǽ`, which IS precomposed,
|
|
24
|
+
was always correct — the two agree now.
|
|
25
|
+
|
|
26
|
+
Note for consumers baking off `vowel`: 136 chants change nucleus, and `Æ`/`Œ`
|
|
27
|
+
now report `diphthong: "ae"`/`"oe"` where they reported `null`. Anything
|
|
28
|
+
derived from the vowel plane wants a re-bake.
|
|
29
|
+
|
|
5
30
|
## 0.10.0 — 2026-08-31
|
|
6
31
|
|
|
7
32
|
The corpus stores a melody once instead of once per book, the genus labels say
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
// cl, gl, fl) and the Greek digraphs th, ph, ch stay with the following
|
|
19
19
|
// vowel; all other clusters split after the first consonant
|
|
20
20
|
//
|
|
21
|
-
// Diacritics (áéíóúàèìòùâêîôû etc.) are treated as their base vowel throughout
|
|
21
|
+
// Diacritics (áéíóúàèìòùâêîôû etc.) are treated as their base vowel throughout,
|
|
22
|
+
// and the ligatures æ/œ expand to their pairs in either case (see selectVowel).
|
|
22
23
|
// ── Character classes ──
|
|
23
24
|
const VOWELS = new Set("aeiouyáéíóúàèìòùâêîôûäëïöüæœý");
|
|
24
25
|
const SOFT_HYPHEN = "\u00ad";
|
|
@@ -203,7 +204,25 @@ export function hyphenateWord(word) {
|
|
|
203
204
|
}
|
|
204
205
|
const ACCENTED = /[\u0301]/; // combining acute accent (NFD form)
|
|
205
206
|
export function selectVowel(text) {
|
|
206
|
-
|
|
207
|
+
// THE LIGATURES EXPAND BEFORE THE SCAN, IN EITHER CASE. æ and œ have no
|
|
208
|
+
// NFD decomposition (unlike á → a), so a ligature that survives to the loop
|
|
209
|
+
// below is reported AS the nucleus — a two-letter vowel, which breaks the
|
|
210
|
+
// one-letter contract `vowel` promises and throws downstream. This was
|
|
211
|
+
// case-sensitive until 2026-08-31 and so missed every capital: 135 chants,
|
|
212
|
+
// all of them word-initial (`Ægýptum`, the Nocturnale's Æ responsories),
|
|
213
|
+
// invisible while the shelf was gated because it carried almost none.
|
|
214
|
+
//
|
|
215
|
+
// The accent rides the NUCLEUS, not the glide. ǽ is precomposed, but œ́ is
|
|
216
|
+
// not — it is œ + combining acute — so the pair is rebuilt as o + accent + e
|
|
217
|
+
// rather than oe + accent, which would accent the off-glide and invert what
|
|
218
|
+
// `accent` reports. NFC first, so a decomposed source still matches here.
|
|
219
|
+
const expanded = text
|
|
220
|
+
.normalize("NFC")
|
|
221
|
+
.replace(/ǽ/gi, "áe")
|
|
222
|
+
.replace(/([æœ])(́?)/gi, (_m, lig, acc) => {
|
|
223
|
+
const pair = lig.toLowerCase() === "æ" ? "ae" : "oe";
|
|
224
|
+
return acc ? pair[0] + acc + pair[1] : pair;
|
|
225
|
+
});
|
|
207
226
|
const nfd = expanded.normalize("NFD");
|
|
208
227
|
let firstVowel = "";
|
|
209
228
|
let accentedVowel = "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tonus",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Medieval music analysis: GABC plainchant exports, liturgical calendar, tuning systems, ephemeris, and the harmony of the spheres",
|
|
6
6
|
"author": "Jeffrey Pierce <jeffrey@jeffreypierce.net>",
|