@finbheara/domain 0.4.0 → 0.6.2

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.
@@ -4,6 +4,9 @@ import {
4
4
  candidateRelation,
5
5
  isDanceTypePrint2
6
6
  } from "./place-htxgptyv.js";
7
+ import {
8
+ validity
9
+ } from "./place-q9kwsmzd.js";
7
10
 
8
11
  function node(id, name, irish, family, formation, opts = {}) {
9
12
  const kind = "round" in formation ? "round" : ("long" in formation) ? "long" : "set";
@@ -169,6 +172,7 @@ function reading(print, folded, candidates, score, match, refusal, misses) {
169
172
  score,
170
173
  match,
171
174
  refusal,
175
+ ...validity(refusal === "empty", refusal === "empty" ? null : refusal),
172
176
  misses: Object.freeze([...misses]),
173
177
  ceili: candidates.length === 1 ? candidates[0] : undefined,
174
178
  isCeili: () => candidates.length > 0,
@@ -0,0 +1,11 @@
1
+ function validity(empty, refusal) {
2
+ const reason = empty ? "empty" : refusal;
3
+ return {
4
+ isEmpty: () => empty,
5
+ isRefused: () => !empty && refusal !== null,
6
+ isValid: () => reason === null,
7
+ invalidReason: () => reason
8
+ };
9
+ }
10
+
11
+ export { validity };
@@ -6,13 +6,16 @@ import {
6
6
  rhythmOfTime2,
7
7
  isDanceTypePrint2
8
8
  } from "./place-htxgptyv.js";
9
+ import {
10
+ validity
11
+ } from "./place-q9kwsmzd.js";
9
12
 
10
13
  var SET_MIN_SPEED2 = Object.freeze({
11
14
  jig: 66,
12
15
  hornpipe: 76
13
16
  });
14
17
  var PLAUSIBLE_SET_TEMPO_MAX2 = 150;
15
- function node(id, name, irish, time, opts = {}) {
18
+ function node(id, name, irish, time, [stepBars, setBars], opts = {}) {
16
19
  return Object.freeze({
17
20
  id,
18
21
  name,
@@ -21,124 +24,126 @@ function node(id, name, irish, time, opts = {}) {
21
24
  irishPrints: Object.freeze(opts.irishPrints ?? []),
22
25
  time,
23
26
  traditionalSpeed: opts.traditionalSpeed ?? null,
24
- maxSpeed: null
27
+ maxSpeed: null,
28
+ stepBars,
29
+ setBars
25
30
  });
26
31
  }
27
32
  var TUNE_NODES2 = Object.freeze([
28
- node("blackbird", "The Blackbird", "An Lon Dubh", "2/4", {
33
+ node("blackbird", "The Blackbird", "An Lon Dubh", "2/4", [15, 30], {
29
34
  prints: ["Blackbird", "Blackbird (Traditional)"],
30
35
  irishPrints: ["An Londubh"],
31
36
  traditionalSpeed: 144
32
37
  }),
33
- node("lodge-road", "The Lodge Road", "Bóthar an Lóiste", "2/4", {
38
+ node("lodge-road", "The Lodge Road", "Bóthar an Lóiste", "2/4", [8, 20], {
34
39
  irishPrints: ["Bóthar An Lóiste"]
35
40
  }),
36
- node("downfall-of-paris", "Downfall of Paris", "Titim Phárais", "2/4", {
41
+ node("downfall-of-paris", "Downfall of Paris", "Titim Phárais", "2/4", [8, 16], {
37
42
  prints: ["The Downfall of Paris"],
38
43
  irishPrints: ["Titim Paris", "Titim Páras"]
39
44
  }),
40
- node("planxty-davis", "Planxty Davis", "Plancstaí Dáibhéis", "2/4", {
45
+ node("planxty-davis", "Planxty Davis", "Plancstaí Dáibhéis", "2/4", [16, 16], {
41
46
  irishPrints: ["Plancstaí Daibhéis"]
42
47
  }),
43
- node("king-of-the-fairies", "King of the Fairies", "Rí na Síog", "2/4", {
48
+ node("king-of-the-fairies", "King of the Fairies", "Rí na Síog", "2/4", [8, 16], {
44
49
  traditionalSpeed: 130
45
50
  }),
46
- node("rodneys-glory", "Rodney's Glory", "Glóir Rodney", "2/4", {
51
+ node("rodneys-glory", "Rodney's Glory", "Glóir Rodney", "2/4", [8, 12], {
47
52
  irishPrints: ["Glór Rodnaí"]
48
53
  }),
49
- node("ace-and-deuce-of-pipering", "Ace and Deuce of Pipering", "Aon agus dó na Píobaireachta", "4/4", {
54
+ node("ace-and-deuce-of-pipering", "Ace and Deuce of Pipering", "Aon agus dó na Píobaireachta", "4/4", [12, 12], {
50
55
  prints: ["Ace & Deuce of Pipering"],
51
56
  irishPrints: ["Aon agus Dó na Píobaireachta"]
52
57
  }),
53
- node("kilkenny-races", "Kilkenny Races", "Rásaí Chill Choinnigh", "4/4", {
58
+ node("kilkenny-races", "Kilkenny Races", "Rásaí Chill Choinnigh", "4/4", [8, 24], {
54
59
  prints: ["Killkenny Races"]
55
60
  }),
56
- node("blue-eyed-rascal", "The Blue-Eyed Rascal", "Cladhaire na Súile Gorma", "4/4", {
61
+ node("blue-eyed-rascal", "The Blue-Eyed Rascal", "Cladhaire na Súile Gorma", "4/4", [8, 12], {
57
62
  prints: ["Blue Eyed Rascal"]
58
63
  }),
59
- node("madame-bonaparte", "Madame Bonaparte", "Madame Bonaparte", "4/4"),
60
- node("bonapartes-retreat", "Bonaparte's Retreat", "Cúlú Bhonaparte", "4/4", {
64
+ node("madame-bonaparte", "Madame Bonaparte", "Madame Bonaparte", "4/4", [8, 12]),
65
+ node("bonapartes-retreat", "Bonaparte's Retreat", "Cúlú Bhonaparte", "4/4", [8, 20], {
61
66
  irishPrints: ["Cúlú Bonaparte"]
62
67
  }),
63
- node("piper", "The Piper Through the Meadow Astraying", "An Píobaire sa Mhóinéar ar Strae/Fáin", "4/4", {
68
+ node("piper", "The Piper Through the Meadow Astraying", "An Píobaire sa Mhóinéar ar Strae/Fáin", "4/4", [8, 12], {
64
69
  prints: ["The Piper", "The Piper thro' the Meadow Straying"],
65
70
  irishPrints: ["An Píobaire"]
66
71
  }),
67
- node("four-masters", "The Four Masters", "Na Ceithre Máistrí", "4/4"),
68
- node("rambling-rake", "Rambling Rake", "An Réice Fáin", "4/4", {
72
+ node("four-masters", "The Four Masters", "Na Ceithre Máistrí", "4/4", [8, 12]),
73
+ node("rambling-rake", "Rambling Rake", "An Réice Fáin", "4/4", [8, 16], {
69
74
  prints: ["The Rambling Rake"]
70
75
  }),
71
- node("garden-of-daisies", "Garden of Daisies", "Gáirdíní na Nóinín", "4/4", {
76
+ node("garden-of-daisies", "Garden of Daisies", "Gáirdíní na Nóinín", "4/4", [8, 16], {
72
77
  irishPrints: ["Gairdín na Nóiníní", "Gáirdíní na Nóiníní"],
73
78
  traditionalSpeed: 138
74
79
  }),
75
- node("roving-pedlar", "The Roving Pedlar", "An Mangaire Fáin", "4/4"),
76
- node("hunt", "The Hunt", "An Fiach", "4/4"),
77
- node("white-blanket", "White Blanket", "An Súisín Bán", "4/4", {
80
+ node("roving-pedlar", "The Roving Pedlar", "An Mangaire Fáin", "4/4", [8, 14]),
81
+ node("hunt", "The Hunt", "An Fiach", "4/4", [8, 12]),
82
+ node("white-blanket", "White Blanket", "An Súisín Bán", "4/4", [6, 12], {
78
83
  prints: ["The White Blanket"]
79
84
  }),
80
- node("job-of-journeywork", "Job of Journeywork", "An Greas Giúrnála", "4/4", {
85
+ node("job-of-journeywork", "Job of Journeywork", "An Greas Giúrnála", "4/4", [8, 14], {
81
86
  irishPrints: ["Greas Giúrnála"],
82
87
  traditionalSpeed: 138
83
88
  }),
84
- node("youghal-harbour", "Youghal Harbour", "Cuan Eochaille", "4/4"),
85
- node("blackthorn-stick", "Blackthorn Stick", "An Maide Droighneáin", "6/8", {
89
+ node("youghal-harbour", "Youghal Harbour", "Cuan Eochaille", "4/4", [6, 14]),
90
+ node("blackthorn-stick", "Blackthorn Stick", "An Maide Droighneáin", "6/8", [15, 15], {
86
91
  prints: ["The Blackthorn Stick"],
87
92
  irishPrints: ["An Maide Droighnéan"]
88
93
  }),
89
- node("planxty-drury", "Planxty Drury", "Plancstaí Drúirí", "6/8", {
94
+ node("planxty-drury", "Planxty Drury", "Plancstaí Drúirí", "6/8", [12, 16], {
90
95
  prints: ["Planxy Drury"]
91
96
  }),
92
- node("charlady", "The Charlady", "An Bhean Ghlantacháin", "6/8", {
97
+ node("charlady", "The Charlady", "An Bhean Ghlantacháin", "6/8", [8, 24], {
93
98
  irishPrints: ["Bean an Ghlantacháin"]
94
99
  }),
95
- node("planxty-hugh-odonnell", "Planxty Hugh O'Donnell", "Plancstaí Aodh Uí Dhomhnaill", "6/8", {
100
+ node("planxty-hugh-odonnell", "Planxty Hugh O'Donnell", "Plancstaí Aodh Uí Dhomhnaill", "6/8", [16, 16], {
96
101
  irishPrints: ["Plancstaí Aodh Ó Domhnaill"]
97
102
  }),
98
- node("drunken-gauger", "Drunken Gauger", "An Gaueger Meisceach", "6/8", {
103
+ node("drunken-gauger", "Drunken Gauger", "An Gaueger Meisceach", "6/8", [15, 15], {
99
104
  prints: ["The Drunken Gauger", "The Funny Tailor"]
100
105
  }),
101
- node("rub-the-bag", "Rub the Bag", "Cuimil an Mála", "6/8"),
102
- node("fiddler-around-the-fairy-green", "The Fiddler Around the Fairy Green", "An Bheidhleadóir ag an Crann Sí", "6/8", { prints: ["The Fiddler 'Round the Fairy Tree", "The Fiddler Around the Fairy Tree"] }),
103
- node("st-patricks-day", "St. Patrick's Day", "Lá Fhéile Phádraig", "6/8", {
106
+ node("rub-the-bag", "Rub the Bag", "Cuimil an Mála", "6/8", [8, 14]),
107
+ node("fiddler-around-the-fairy-green", "The Fiddler Around the Fairy Green", "An Bheidhleadóir ag an Crann Sí", "6/8", [8, 12], { prints: ["The Fiddler 'Round the Fairy Tree", "The Fiddler Around the Fairy Tree"] }),
108
+ node("st-patricks-day", "St. Patrick's Day", "Lá Fhéile Phádraig", "6/8", [8, 14], {
104
109
  irishPrints: ["Lá Fhéile Pádraig", "Lá Féile Phádraig"],
105
110
  traditionalSpeed: 94
106
111
  }),
107
- node("humours-of-bandon", "Humours of Bandon", "Pléarácha na Banndon", "6/8", {
112
+ node("humours-of-bandon", "Humours of Bandon", "Pléarácha na Banndon", "6/8", [8, 16], {
108
113
  prints: ["Humour's of Bandon"],
109
114
  irishPrints: ["Pléaracha na Bandan"]
110
115
  }),
111
- node("story-teller", "The Story-Teller", "An Scéalaí", "6/8", {
116
+ node("story-teller", "The Story-Teller", "An Scéalaí", "6/8", [8, 16], {
112
117
  prints: ["The Storyteller"]
113
118
  }),
114
- node("hurling-boys", "The Hurling Boys", "Na Buachaillí Báire", "6/8", {
119
+ node("hurling-boys", "The Hurling Boys", "Na Buachaillí Báire", "6/8", [8, 14], {
115
120
  prints: ["The Hurling Boy"]
116
121
  }),
117
- node("sprig-of-shillelagh", "The Sprig of Shillelagh", "An Ghéag Sail Éille", "6/8", {
122
+ node("sprig-of-shillelagh", "The Sprig of Shillelagh", "An Ghéag Sail Éille", "6/8", [6, 10], {
118
123
  prints: ["The Spring of Shillelagh"],
119
124
  irishPrints: ["An Geag Síléaladh"]
120
125
  }),
121
- node("hurry-the-jug", "Hurry the Jug", "Cuir Thart an Crúsca", "6/8"),
122
- node("three-sea-captains", "The Three Sea Captains", "An Triúr Chaptaen Mara", "6/8", {
126
+ node("hurry-the-jug", "Hurry the Jug", "Cuir Thart an Crúsca", "6/8", [8, 16]),
127
+ node("three-sea-captains", "The Three Sea Captains", "An Triúr Chaptaen Mara", "6/8", [8, 20], {
123
128
  prints: ["Three Sea Captains"],
124
129
  irishPrints: ["Na Trí Captéin Maraí", "Triúr Captaen Mara"],
125
130
  traditionalSpeed: 96
126
131
  }),
127
- node("jockey-to-the-fair", "Jockey to the Fair", "An Marcach Chuig an Aonach", "6/8", {
132
+ node("jockey-to-the-fair", "Jockey to the Fair", "An Marcach Chuig an Aonach", "6/8", [8, 14], {
128
133
  traditionalSpeed: 90
129
134
  }),
130
- node("vanishing-lake", "Vanishing Lake", "An Loch Mhadhma", "6/8", {
135
+ node("vanishing-lake", "Vanishing Lake", "An Loch Mhadhma", "6/8", [14, 18], {
131
136
  prints: ["The Vanishing Lake"],
132
137
  irishPrints: ["Luch An Mhadhma"]
133
138
  }),
134
- node("miss-browns-fancy", "Miss Brown's Fancy", "Rogha Iníon De Brún", "6/8"),
135
- node("wandering-musician", "The Wandering Musician", "An Ceoltóir Fáin", "6/8", {
139
+ node("miss-browns-fancy", "Miss Brown's Fancy", "Rogha Iníon De Brún", "6/8", [8, 16]),
140
+ node("wandering-musician", "The Wandering Musician", "An Ceoltóir Fáin", "6/8", [8, 16], {
136
141
  prints: ["Wandering Musicianr"]
137
142
  }),
138
- node("orange-rogue", "Orange Rogue", "An Rógaire Buí", "6/8", {
143
+ node("orange-rogue", "Orange Rogue", "An Rógaire Buí", "6/8", [8, 16], {
139
144
  prints: ["The Orange Rogue"]
140
145
  }),
141
- node("is-the-big-man-within", "Is the Big Man Within?", "An bhfuil an Fear Mór Istigh?", "6/8+9/8", {
146
+ node("is-the-big-man-within", "Is the Big Man Within?", "An bhfuil an Fear Mór Istigh?", "6/8+9/8", [8, 8], {
142
147
  irishPrints: ["An ‘Bhfuil an Fear Mór Istigh?"]
143
148
  })
144
149
  ]);
@@ -164,7 +169,9 @@ function makeTune(n) {
164
169
  if (n.traditionalSpeed !== null)
165
170
  return n.traditionalSpeed;
166
171
  return setting === "traditional" ? null : range;
167
- }
172
+ },
173
+ stepBars: () => n.stepBars,
174
+ setBars: () => n.setBars
168
175
  });
169
176
  }
170
177
  var TUNES = Object.freeze(TUNE_NODES2.map(makeTune));
@@ -231,6 +238,7 @@ function reading(print, folded, bpm, candidates, score, match, refusal, misses)
231
238
  score,
232
239
  match,
233
240
  refusal,
241
+ ...validity(refusal === "empty", refusal === "empty" ? null : refusal),
234
242
  misses: Object.freeze([...misses]),
235
243
  tune: candidates.length === 1 ? candidates[0] : undefined,
236
244
  isTune: () => candidates.length > 0,
package/dist/dance.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import"./chunks/place-htxgptyv.js";
2
2
  import {
3
3
  ceili2
4
- } from "./chunks/place-0ehc2q69.js";
4
+ } from "./chunks/place-kk48pfja.js";
5
5
  import {
6
6
  tune2
7
- } from "./chunks/place-2ja9yx08.js";
7
+ } from "./chunks/place-yndzaae5.js";
8
+ import {
9
+ validity
10
+ } from "./chunks/place-q9kwsmzd.js";
8
11
 
9
12
  function dance(print, round) {
10
13
  const setting = round === "traditional-set" ? "traditional" : undefined;
@@ -25,7 +28,11 @@ function dance(print, round) {
25
28
  }
26
29
  misses.push(...tunes.misses, ...ceilis.misses);
27
30
  const candidates = Object.freeze([...tunes.candidates, ...ceilis.candidates]);
31
+ const empty = tunes.isEmpty() && ceilis.isEmpty();
32
+ const refused = !empty && !tunes.isValid() && !ceilis.isValid();
33
+ const reason = !refused ? null : tunes.invalidReason() === "dance-type" || ceilis.invalidReason() === "dance-type" ? "dance-type" : "unmatched";
28
34
  return Object.freeze({
35
+ ...validity(empty, reason),
29
36
  print,
30
37
  tunes,
31
38
  ceilis,
package/dist/place.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  placesRelation2,
16
16
  probablySamePlace2,
17
17
  sameReading2
18
- } from "./chunks/place-qbp3xfb4.js";
18
+ } from "./chunks/place-h7tvdfyp.js";
19
19
  export {
20
20
  DEFAULT_PLACE_CAPACITY2 as DEFAULT_PLACE_CAPACITY,
21
21
  DEFAULT_PLACE_READER2 as DEFAULT_PLACE_READER,
package/dist/promotion.js CHANGED
@@ -46,7 +46,7 @@ function samePromotedRow(was, now) {
46
46
  }
47
47
  var STOOD_FOR = /^(?:'|(?![A-Za-z])\p{L})$/u;
48
48
  function questionMarksRead(was, now) {
49
- const a = [...collapse(was)];
49
+ const a = [...collapse(mojibakeRead(was))];
50
50
  if (!a.includes("?"))
51
51
  return a.join("");
52
52
  const b = [...collapse(now)];
@@ -67,6 +67,19 @@ function questionMarksRead(was, now) {
67
67
  }
68
68
  return out.join("");
69
69
  }
70
+ function mojibakeRead(print) {
71
+ let out = print;
72
+ const codes = [...out].map((c) => c.codePointAt(0) ?? 0);
73
+ if (codes.some((c) => c >= 128) && codes.every((c) => c <= 255)) {
74
+ const bytes = Uint8Array.from(codes);
75
+ try {
76
+ const decoded = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
77
+ if (decoded !== out)
78
+ out = decoded;
79
+ } catch {}
80
+ }
81
+ return out.replace(/\uFFFD/gu, "?");
82
+ }
70
83
  function samePromotedName(was, now) {
71
84
  const read = questionMarksRead(was, now);
72
85
  if (read === null)
@@ -86,20 +99,27 @@ function samePromotedName(was, now) {
86
99
  return glued !== "" && (glued === nameFold(`${given}${surname}`) || glued === nameFold(`${surname}${given}`));
87
100
  }
88
101
  function samePromotedHeir(was, now) {
89
- if (was.name !== "" && was.name === now.name)
102
+ if (collapse(was.name) !== "" && collapse(was.name) === collapse(now.name))
90
103
  return true;
91
104
  const school = questionMarksRead(was.school, now.school);
92
105
  if (school === null || !samePromotedSchool(school, now.school))
93
106
  return false;
107
+ if (collapse(was.name) === "" && collapse(now.name) !== "")
108
+ return true;
94
109
  return samePromotedName(was.name, now.name);
95
110
  }
111
+ function samePromotedPair(was, now) {
112
+ return samePromotedRow(was, now) || samePromotedHeir(was, now);
113
+ }
96
114
  export {
97
115
  CHAR_SYNONYM_CLASSES,
98
116
  collapse,
99
117
  foldCharSynonyms,
118
+ mojibakeRead,
100
119
  questionMarksRead,
101
120
  samePromotedHeir,
102
121
  samePromotedName,
122
+ samePromotedPair,
103
123
  samePromotedRow,
104
124
  samePromotedSchool
105
125
  };
package/dist/school.js CHANGED
@@ -1,11 +1,17 @@
1
1
  import {
2
+ NEVER_NAME,
3
+ printZones,
4
+ opensLocation,
2
5
  place2,
3
6
  isPlaceToken2,
4
7
  countryCodeOf2,
5
8
  areAllPlaceTokens2,
6
9
  placeRelation2,
7
10
  sameReading2
8
- } from "./chunks/place-qbp3xfb4.js";
11
+ } from "./chunks/place-h7tvdfyp.js";
12
+ import {
13
+ validity
14
+ } from "./chunks/place-q9kwsmzd.js";
9
15
 
10
16
  import { normalizeApostrophes } from "@finbheara/names/lexicon";
11
17
  import { SURNAME_SEPARATOR, lexiconKey, titleCaseNamePart } from "@finbheara/names/normalize";
@@ -867,130 +873,6 @@ function truncatedInstitution(tail) {
867
873
  return found;
868
874
  }
869
875
 
870
- var QUALIFIER_DELIMITER = /[,;:()[\]/–—-]/;
871
- var NEVER_PLACE = new Map([
872
- ["de", "name particle: `De <Surname>`, and Spanish `de <Place>`"],
873
- ["ni", "Irish patronymic particle: `Ní <Surname>`"],
874
- ["mo", "Irish possessive: `Mo <Word>`"],
875
- ["na", "Irish article: `Rince na <Word>`"],
876
- ["in", "Irish preposition: `<Word> In <Word>`; and `Inc` truncated to `In`"],
877
- ["co", "Company: `<Surname> & Co.`. Bracketed `(US-CO)` is still Colorado"],
878
- ["id", "Irish Dance: `<Surname> School of ID`"],
879
- ["sd", "School of Dance: `<Surname> SD`"]
880
- ]);
881
- var NEVER_NAME = new Map([
882
- ["de", "name particle: `De <Surname>`; and Spanish `de <Place>`"],
883
- ["ni", "Irish patronymic particle: `Ní <Surname>`"],
884
- ["ui", "Irish patronymic particle: `Uí <Surname>`"],
885
- ["mo", "Irish possessive: `Mo <Word>`"],
886
- ["na", "Irish article: `Rince na <Word>`"],
887
- ["an", "Irish article: `<Word> an Rince`"],
888
- ["in", "Irish preposition: `<Word> In <Word>`; and `Inc` truncated to `In`"],
889
- ["co", "Company: `<Surname> & Co`"],
890
- ["id", "Irish Dance: `ID de <Place>` keys the place, as `Irish Dancing de <Place>` does"],
891
- ["sd", "School of Dance: `<Surname> SD`"],
892
- ["da", "`Dance` truncated: `<Name> Academy of Irish Da` keys the name"]
893
- ]);
894
- var GENERIC_TLD = "com|net|org|edu|gov|mil|int|info|biz";
895
- var WEB_SPAN = new RegExp([
896
- "[A-Za-z][A-Za-z0-9+.-]*://\\S+",
897
- "(?:^|[\\s([])www\\.\\S+",
898
- "[^\\s@]+@[^\\s@]+\\.[A-Za-z]{2,}",
899
- `(?<![A-Za-z0-9.@-])(?:[A-Za-z0-9][A-Za-z0-9-]*\\.)*[A-Za-z0-9][A-Za-z0-9-]+\\.(?:${GENERIC_TLD})(?![A-Za-z0-9-])`
900
- ].join("|"), "giu");
901
- function printZones(raw) {
902
- const qualifier = new Set;
903
- const bracketed = new Set;
904
- const qualifierAny = new Set;
905
- const runs = [...raw.matchAll(/[A-Za-z0-9]+/g)];
906
- const web = [];
907
- for (const m of raw.matchAll(WEB_SPAN))
908
- web.push([m.index ?? 0, (m.index ?? 0) + m[0].length]);
909
- const inside = new Set;
910
- const outside = new Set;
911
- const trailing = new Set;
912
- for (let i = runs.length - 1;i > 0; i--) {
913
- const here = runs[i];
914
- const prev = runs[i - 1];
915
- if (here === undefined || prev === undefined)
916
- break;
917
- const gap = raw.slice((prev.index ?? 0) + prev[0].length, here.index ?? 0);
918
- if (!QUALIFIER_DELIMITER.test(gap))
919
- break;
920
- if (i - 1 === 0)
921
- break;
922
- trailing.add(i - 1);
923
- }
924
- let depth = 0;
925
- let cursor = 0;
926
- for (let i = 0;i < runs.length; i++) {
927
- const run = runs[i];
928
- const text = run?.[0];
929
- if (run === undefined || text === undefined)
930
- continue;
931
- const at = run.index ?? cursor;
932
- for (const ch of raw.slice(cursor, at)) {
933
- if (ch === "(" || ch === "[")
934
- depth++;
935
- else if ((ch === ")" || ch === "]") && depth > 0)
936
- depth--;
937
- }
938
- cursor = at + text.length;
939
- const folded = text.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "");
940
- (web.some(([s, e]) => at >= s && at < e) ? inside : outside).add(folded);
941
- const before = raw.slice(0, at).trimEnd().slice(-1);
942
- const after = raw.slice(cursor).trimStart().slice(0, 1);
943
- const atQualifier = i === runs.length - 1 || before !== "" && QUALIFIER_DELIMITER.test(before) || after !== "" && QUALIFIER_DELIMITER.test(after) && trailing.has(i);
944
- if (atQualifier)
945
- qualifierAny.add(folded);
946
- if (folded.length > 2)
947
- continue;
948
- if (atQualifier)
949
- qualifier.add(folded);
950
- if (depth > 0)
951
- bracketed.add(folded);
952
- }
953
- const webOnly = new Set([...inside].filter((f) => !outside.has(f)));
954
- return { qualifier, bracketed, qualifierAny, web, webOnly, tailCode: tailCode(raw, runs) };
955
- }
956
- var GOVERNS_THE_NEXT_WORD = new Set(["de", "mo"]);
957
- function tailCode(raw, runs) {
958
- const last = runs[runs.length - 1];
959
- const prev = runs[runs.length - 2];
960
- if (last === undefined || prev === undefined)
961
- return null;
962
- const text = last[0];
963
- if (text.length > 2 || text !== text.toUpperCase() || !/^[A-Z]+$/.test(text))
964
- return null;
965
- const at = last.index ?? 0;
966
- const folded = text.toLowerCase();
967
- const gap = raw.slice((prev.index ?? 0) + prev[0].length, at);
968
- const marked = /[,;:/\\\u2013\u2014]/u.test(gap) || /\s-|-\s/u.test(gap);
969
- const bare = GOVERNS_THE_NEXT_WORD.has(folded) && /^\s+$/u.test(gap) && /\p{Ll}/u.test(raw);
970
- if (!marked && !bare)
971
- return null;
972
- const only = runs.filter((r) => r[0].toLowerCase() === folded).length === 1;
973
- return { folded, at, only };
974
- }
975
- function opensLocation(folded, at, index) {
976
- if (index === undefined ? at.webOnly.has(folded) : inWebSpan(at, index))
977
- return false;
978
- if (folded.length > 2)
979
- return true;
980
- if (NEVER_PLACE.has(folded))
981
- return at.bracketed.has(folded) || isTailCode(folded, at, index);
982
- return at.qualifier.has(folded);
983
- }
984
- function isTailCode(folded, at, index) {
985
- const tail = at.tailCode;
986
- if (tail === null || tail.folded !== folded)
987
- return false;
988
- return index === undefined ? tail.only : index === tail.at;
989
- }
990
- function inWebSpan(at, index) {
991
- return at.web.some(([start, end]) => index >= start && index < end);
992
- }
993
-
994
876
  var SCHOOL_FLUFF_WORDS = new Set([
995
877
  "academy",
996
878
  "irish",
@@ -1162,8 +1044,13 @@ function createSchoolNameReader(options = {}) {
1162
1044
  }
1163
1045
  return s;
1164
1046
  }
1047
+ const SPACING_ACUTE_AFTER_VOWEL = /((?<=\p{L})[AEIOUaeiou]|[AEIUaeiu])[´ˊ](?![sS]\b)/gu;
1048
+ const SPACING_ACUTE = /[´ˊ]/gu;
1049
+ function readSpacingAcute(print) {
1050
+ return print.replace(SPACING_ACUTE_AFTER_VOWEL, "$1́").replace(SPACING_ACUTE, "'");
1051
+ }
1165
1052
  function renderSn1(print) {
1166
- return normalizeApostrophes(repairMojibake(print).normalize("NFKC")).replace(/\p{Cf}+/gu, "").replace(/\p{Cc}+/gu, " ").replace(/\s+/gu, " ").trim();
1053
+ return normalizeApostrophes(readSpacingAcute(repairMojibake(print)).normalize("NFKC")).replace(/\p{Cf}+/gu, "").replace(/\p{Cc}+/gu, " ").replace(/\s+/gu, " ").trim();
1167
1054
  }
1168
1055
  const COMPOUND_OPENERS = new Set([
1169
1056
  "hyphen",
@@ -1782,7 +1669,7 @@ function createSchoolNameReader(options = {}) {
1782
1669
  institution: b.institution,
1783
1670
  location: b.location,
1784
1671
  refusal: b.refusal,
1785
- isEmpty: () => b.empty,
1672
+ ...validity(b.empty, b.refusal?.reason ?? null),
1786
1673
  isSchool: () => !b.empty && b.refusal === null,
1787
1674
  surnames: () => b.surnames,
1788
1675
  concerns: b.concerns
@@ -2032,8 +1919,8 @@ function isColumnCutOf(a, b) {
2032
1919
  if (!comparable(a) || !comparable(b))
2033
1920
  return false;
2034
1921
  const cutFrom = (cut, whole) => {
2035
- const c = foldPrint(cut.sn0);
2036
- const w = foldPrint(whole.sn0);
1922
+ const c = foldPrint(cut.sn1);
1923
+ const w = foldPrint(whole.sn1);
2037
1924
  if (c.length === 0 || c.length >= w.length || !w.startsWith(c))
2038
1925
  return false;
2039
1926
  if (w[c.length] === " ")
package/dist/tune.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  settingAt2,
9
9
  tune2,
10
10
  tuneRelation2
11
- } from "./chunks/place-2ja9yx08.js";
11
+ } from "./chunks/place-yndzaae5.js";
12
12
  import"./chunks/place-htxgptyv.js";
13
13
  export {
14
14
  PLAUSIBLE_SET_TEMPO_MAX2 as PLAUSIBLE_SET_TEMPO_MAX,
@@ -0,0 +1,12 @@
1
+ export declare const TITLE_RANGE_MIN = 3;
2
+ export declare const TITLE_RANGE_MAX = 40;
3
+ export interface AgeTitleSpan {
4
+ readonly start: number;
5
+ readonly end: number;
6
+ readonly text: string;
7
+ }
8
+ export interface AgeTitleToken {
9
+ readonly token: string;
10
+ readonly span: AgeTitleSpan | null;
11
+ }
12
+ export declare function ageTitleToken(title: string): AgeTitleToken;
@@ -9,8 +9,10 @@ export interface BirthYears {
9
9
  export interface AgeLadder {
10
10
  readonly caps: readonly number[];
11
11
  readonly overs: readonly number[];
12
- readonly ranges: readonly number[];
12
+ readonly ranges: readonly AgeSpan[];
13
+ readonly adult?: boolean;
13
14
  }
15
+ export type AgeSpan = readonly [number, number];
14
16
  export interface YOBContext {
15
17
  readonly year?: number | null;
16
18
  }
@@ -21,9 +23,9 @@ export interface AgeContext {
21
23
  }
22
24
  export type AgeArm = "band" | "yob" | "open" | "empty";
23
25
  export type AgeKind = "under" | "over" | "range" | "adult" | "senior" | "yob";
24
- export type AgeRefusal = "not-a-band" | "backwards-range" | "senior-without-ladder" | "below-youngest-band" | "year-out-of-range";
26
+ export type AgeRefusal = "not-a-band" | "backwards-range" | "overlapping-ranges" | "senior-without-ladder" | "below-youngest-band" | "year-out-of-range";
25
27
  export type AgeSource = "sibling-narrowed" | "printed-band" | "printed-range" | "printed-yob" | "open";
26
- export type AgeClause = "under-floored-on-rung" | "youngest-absorbs" | "over-ceiling-from-next-over" | "over-ceiling-refused-gap" | "and-over-no-ceiling" | "range-overlapping" | "range-inclusive" | "range-floor-on-rung" | "range-floor-widened" | "range-adult-floor";
28
+ export type AgeClause = "under-floored-on-rung" | "youngest-absorbs" | "over-ceiling-from-next-over" | "over-ceiling-refused-gap" | "and-over-no-ceiling" | "range-overlapping" | "range-as-under" | "range-top-meets-over" | "range-adult-floor";
27
29
  export type AgeRelation = "same" | "contains" | "overlaps" | "disjoint" | "silent";
28
30
  export type AgeRelationReason = "equal" | "a-contains-b" | "b-contains-a" | "partial" | "a-older" | "a-younger" | "a-not-a-band" | "b-not-a-band";
29
31
  export interface AgeComparison {
@@ -1,6 +1,8 @@
1
- import type { AgeArm, AgeClause, AgeComparison, AgeContext, AgeInterval, AgeKind, AgeLadder, AgeMisuse, AgeRefusal, AgeRelation, AgeRelationReason, AgeSource, BirthYears, YOBContext, YoungFloorVerdict } from "./age-types.ts";
2
- import type { Validated } from "./validated.ts";
3
- export type { AgeArm, AgeClause, AgeComparison, AgeContext, AgeInterval, AgeKind, AgeLadder, AgeMisuse, AgeRefusal, AgeRelation, AgeRelationReason, AgeSource, BirthYears, Validated, YOBContext, YoungFloorVerdict, };
1
+ import { type AgeTitleSpan } from "./age-title.ts";
2
+ import type { AgeArm, AgeClause, AgeComparison, AgeContext, AgeInterval, AgeKind, AgeLadder, AgeMisuse, AgeRefusal, AgeRelation, AgeRelationReason, AgeSource, AgeSpan, BirthYears, YOBContext, YoungFloorVerdict } from "./age-types.ts";
3
+ import { type EmptyReason, type Validated } from "./validated.ts";
4
+ export { type AgeTitleSpan, type AgeTitleToken, TITLE_RANGE_MAX, TITLE_RANGE_MIN, ageTitleToken, } from "./age-title.ts";
5
+ export type { AgeArm, AgeClause, AgeComparison, AgeContext, AgeInterval, AgeKind, AgeLadder, AgeMisuse, AgeRefusal, AgeRelation, AgeRelationReason, AgeSource, AgeSpan, BirthYears, EmptyReason, Validated, YOBContext, YoungFloorVerdict, };
4
6
  export declare const YOUNGEST_FLOOR = 0;
5
7
  export declare const ADULT_FLOOR = 18;
6
8
  export declare const MAJORS_FLOOR_YEARS = 3;
@@ -17,7 +19,7 @@ export declare const MIN_MAJOR_AGE = 4;
17
19
  export declare const MIN_FEIS_AGE = 3;
18
20
  export declare const YOUNGEST_BAND_TOP = 3;
19
21
  export declare const YOB_RANGE: Readonly<{
20
- readonly first: 1900;
22
+ readonly first: 1901;
21
23
  readonly last: 2099;
22
24
  }>;
23
25
  export declare const DANCE_UP_YEARS = 1;
@@ -38,7 +40,6 @@ export interface Age extends Validated<AgeRefusal> {
38
40
  readonly clauses: readonly AgeClause[];
39
41
  readonly ladder: AgeLadder;
40
42
  readonly year: number | null;
41
- isEmpty(): boolean;
42
43
  isAge(): boolean;
43
44
  isExact(): boolean;
44
45
  isAndOver(): boolean;
@@ -55,9 +56,16 @@ export declare class AgeMisuseError extends Error {
55
56
  }
56
57
  declare function fromPrint(print: string, context?: AgeContext): Age;
57
58
  declare function fromYOB(from: number | null, to?: number | null, context?: YOBContext): Age;
59
+ export interface AgeInTitle {
60
+ readonly age: Age;
61
+ readonly token: string;
62
+ readonly span: AgeTitleSpan | null;
63
+ }
64
+ declare function fromTitle(title: string, context?: AgeContext): AgeInTitle;
58
65
  export declare const Age: Readonly<{
59
66
  from: typeof fromPrint;
60
67
  fromYOB: typeof fromYOB;
68
+ fromTitle: typeof fromTitle;
61
69
  }>;
62
70
  export declare function birthYearsOfInterval(iv: AgeInterval | null, year: number): BirthYears;
63
71
  export declare function ageRelation(a: Age, b: Age): AgeComparison;
@@ -1,4 +1,6 @@
1
1
  import { type DanceMatch, type DanceRelation } from "./dance-match.ts";
2
+ import { type Validated } from "./validated.ts";
3
+ export type { EmptyReason, Validated } from "./validated.ts";
2
4
  export type CeiliFamily = "eight-hand" | "four-hand" | "handbook";
3
5
  export type CeiliFormation = "set" | "long" | "round";
4
6
  export interface CeiliNode {
@@ -33,7 +35,7 @@ export interface CeiliContext {
33
35
  readonly hands?: number;
34
36
  }
35
37
  export type CeiliRefusal = "empty" | "dance-type" | "unmatched";
36
- export interface CeiliReading {
38
+ export interface CeiliReading extends Validated<Exclude<CeiliRefusal, "empty">> {
37
39
  readonly [Symbol.toStringTag]: "CeiliReading";
38
40
  readonly print: string;
39
41
  readonly folded: string;
@@ -1,7 +1,10 @@
1
1
  import { type Ceili, type CeiliReading } from "./ceili.ts";
2
2
  import { type Tune, type TuneReading } from "./tune.ts";
3
+ import { type Validated } from "./validated.ts";
4
+ export type { EmptyReason, Validated } from "./validated.ts";
3
5
  export type DanceRound = "set" | "traditional-set" | "ceili" | "eight-hand" | "four-hand";
4
- export interface DanceReading {
6
+ export type DanceRefusal = "dance-type" | "unmatched";
7
+ export interface DanceReading extends Validated<DanceRefusal> {
5
8
  readonly print: string;
6
9
  readonly tunes: TuneReading;
7
10
  readonly ceilis: CeiliReading;