@finbheara/domain 0.18.0 → 0.20.0

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/README.md CHANGED
@@ -262,6 +262,7 @@ Age.fromTitle("Open Championship 15-16", { year: 2026 }).token; // "15-
262
262
  Age.fromTitle("Competition 719OC - Open Championship (O18)").token; // "o18", not "o9"
263
263
  Age.fromTitle("Treble Reel Special", { year: 2026 }).age.isEmpty(); // true
264
264
  Age.fromTitle("Mixed Reel 7 & Under").token; // "u8": a 7-year-old dances in it
265
+ Age.fromTitle("Mixed Reel Under 08 / 2 yr").token; // "u8/2yr": the two ages under 8
265
266
  Age.fromTitle("Girls 8 and under 9 years").token; // "8-9"
266
267
  Age.fromTitle("Junior Boys 12 Years").token; // "u13"
267
268
  Age.fromTitle("10-11 Single Jig").token; // "10-11", a band, not a number
@@ -300,6 +301,12 @@ platform's printed `18&O` beside a title that reads adult is `adult o18`.
300
301
  An age group is the age on the first of January, so a title that admits the dancer who is
301
302
  `N` (`7 & Under`, `7/U`, `7 Years`) is the `Under N+1` group.
302
303
 
304
+ An under band may print its stride, the number of ages it holds: `Under 08 / 2 yr` is the ages 6
305
+ and 7, and reads `u8/2yr`. `Age.from("u8/2yr")` is `[6, 8)` whatever the ladder offers, since the
306
+ page states the floor (`clauses` is `["under-stride"]`), where a plain `u8` takes the rung below
307
+ it. So `Age.from("u8/2yr", { year: 2026 })` is born 2018 or 2019. Beside the adult word the stride
308
+ never opens below 18: `adult u40/10yr` is `[30, 40)`.
309
+
303
310
  A value the reader cannot stand behind is returned, not thrown. An `Age` is `Validated` (above):
304
311
  an age group under `U3` admits nobody old enough to dance, and a year of birth outside 1901 to
305
312
  2099 is not one, so the placeholders `1000` and `1900` are refused. An invalid `Age` has no
package/dist/age.js CHANGED
@@ -9,6 +9,7 @@ var OVER_WORD = /(?:\bover\s*|\bos\s+cionn\s*|(?<![a-z0-9])o[./]?\s*)(\d{1,2})(?
9
9
  var OVER_GLUED = /(?<![a-z0-9])(\d{1,2})\s*o(?![a-z'’])/i;
10
10
  var OVER_PLUS = /(?<![a-z0-9])(\d{1,2})\s*\+/;
11
11
  var UNDER = /(?:\bunder\s*(?:age\s*)?|\bfaoi\s*|(?<![a-z0-9])u\.?\s*)(\d{1,2})(?![0-9])(?![a-z][a-z0-9])/i;
12
+ var UNDER_STRIDE = /^\s*\/\s*0*([1-9]\d?)\s*yrs?(?![a-z0-9])/i;
12
13
  var AND_UNDER = /(?<![a-z0-9])(\d{1,2})\s*(?:years?\s*)?(?:&|\/|\band\b)\s*u(?:nder)?(?![a-z])(?!\s*\d)/i;
13
14
  var AND_UNDER_RANGE = /(?<![a-z0-9])(\d{1,2})\s*(?:&|\band\b)\s*under\s*(\d{1,2})(?![a-z0-9])/i;
14
15
  var AND_RANGE = /(?<![a-z0-9])(?<!\b(?:under|und|over|faoi|cionn|u|o)\.?\s*)(?<!\d\s*,\s*)(?<!\(\s*)(\d{1,2})\s*(?:&|\band\b)\s*(\d{1,2})(?![a-z0-9])(?!\s*-?\s*hand)(?!\s*(?:&|\+|\/|,|\)|\band\b|\bor\b))/i;
@@ -65,8 +66,13 @@ function readAnchored(title, s, offset, aside = false) {
65
66
  if (au?.[1] !== undefined)
66
67
  return at(title, offset, au.index, au.index + au[0].length, `u${Number(au[1]) + 1}`);
67
68
  const m = UNDER.exec(s);
68
- if (m?.[1] !== undefined)
69
- return at(title, offset, m.index, m.index + m[0].length, `u${Number(m[1])}`);
69
+ if (m?.[1] !== undefined) {
70
+ const end = m.index + m[0].length;
71
+ const k = UNDER_STRIDE.exec(s.slice(end));
72
+ if (k?.[1] !== undefined)
73
+ return at(title, offset, m.index, end + k[0].length, `u${Number(m[1])}/${Number(k[1])}yr`);
74
+ return at(title, offset, m.index, end, `u${Number(m[1])}`);
75
+ }
70
76
  const y = YEARS.exec(s) ?? AGE_N.exec(s);
71
77
  if (y?.[1] !== undefined)
72
78
  return at(title, offset, y.index, y.index + y[0].length, `u${Number(y[1]) + 1}`);
@@ -123,11 +129,12 @@ function adultBeside(band) {
123
129
  const b = band.trim().toLowerCase();
124
130
  if (b === "")
125
131
  return "adult";
126
- const n = /^u(\d+)$/.exec(b)?.[1];
132
+ const u = /^u(\d+)(\/\d+yr)?$/.exec(b);
133
+ const n = u?.[1];
127
134
  if (n !== undefined) {
128
135
  if (Number(n) < ADULT_UNDER_MIN)
129
136
  return;
130
- return Number(n) > ADULT_UNDER_MIN ? `adult u${Number(n)}` : "adult";
137
+ return Number(n) > ADULT_UNDER_MIN ? `adult u${Number(n)}${u?.[2] ?? ""}` : "adult";
131
138
  }
132
139
  const floor = /^o(\d+)$/.exec(b)?.[1] ?? /^(\d+)-\d+$/.exec(b)?.[1];
133
140
  if (floor === undefined)
@@ -145,7 +152,7 @@ function adultOverUnder(title, s, lead, t) {
145
152
  const token = adultBeside(t.token);
146
153
  if (token === undefined || token === t.token)
147
154
  return t;
148
- if (/^u\d+$/.test(t.token))
155
+ if (/^u\d+(?:\/\d+yr)?$/.test(t.token))
149
156
  return at(title, lead, a.index, a.index + a[0].length, token);
150
157
  return { token, span: t.span };
151
158
  }
@@ -163,12 +170,12 @@ var YOB_RANGE = Object.freeze({ first: 1901, last: 2099 });
163
170
  var DANCE_UP_YEARS = 1;
164
171
  var ageOnJanuary1 = (year, born) => year - born - 1;
165
172
  var yearsSinceBirth = (year, born) => year - born;
166
- var UNDER2 = /^(?:u|under\s*)(\d+)$/i;
173
+ var UNDER2 = /^(?:u|under\s*)(\d+)(?:\/([1-9]\d*)yr)?$/i;
167
174
  var OVER = /^(?:o|over\s*)(\d+)$/i;
168
175
  var AND_OVER2 = /^(\d+)\s*(?:&|and\b)\s*(?:over|o)$/i;
169
176
  var RANGE2 = /^u?(\d+)\s*[-–]\s*(\d+)$/i;
170
177
  var ADULT_WORD = /^(?:adults?|ad|advanced|masters?)$/i;
171
- var ADULT_UNDER = /^(?:adults?|ad)[\s-]*(?:u|under\s*)(\d+)$/i;
178
+ var ADULT_UNDER = /^(?:adults?|ad)[\s-]*(?:u|under\s*)(\d+)(?:\/([1-9]\d*)yr)?$/i;
172
179
  var ADULT_BAND = /^(?:adults?|ad)[\s-]+(\S.*)$/i;
173
180
  var SENIOR_WORD = /^seniors?$/i;
174
181
  var NO_LADDER = Object.freeze({ caps: [], overs: [], ranges: [] });
@@ -223,19 +230,28 @@ function readRange(a, b, ladder) {
223
230
  parts: [a, b]
224
231
  };
225
232
  }
233
+ function strideOf(k) {
234
+ if (k === undefined)
235
+ return null;
236
+ const n = Number(k);
237
+ return Number.isInteger(n) && n >= 1 ? n : null;
238
+ }
226
239
  function read(token, ladder, top) {
227
240
  const r = RANGE2.exec(token);
228
241
  if (r !== null)
229
242
  return readRange(Number(r[1]), Number(r[2]), ladder);
230
243
  const au = ADULT_UNDER.exec(token);
231
- if (au !== null && Number(au[1]) > ADULT_FLOOR)
244
+ if (au !== null && Number(au[1]) > ADULT_FLOOR) {
245
+ const k = strideOf(au[2]);
246
+ const hi = Number(au[1]);
232
247
  return {
233
248
  kind: "adult",
234
- interval: { lo: ADULT_FLOOR, hi: Number(au[1]) },
249
+ interval: { lo: k === null ? ADULT_FLOOR : Math.max(ADULT_FLOOR, hi - k), hi },
235
250
  refusal: null,
236
- clauses: ["adult-under-ceiling"],
237
- parts: [Number(au[1])]
251
+ clauses: k === null ? ["adult-under-ceiling"] : ["adult-under-ceiling", "under-stride"],
252
+ parts: k === null ? [hi] : [hi, k]
238
253
  };
254
+ }
239
255
  const ab = au === null ? ADULT_BAND.exec(token) : null;
240
256
  if (ab !== null) {
241
257
  const inner = read(ab[1].trim(), { ...ladder, adult: true }, top);
@@ -263,6 +279,15 @@ function read(token, ladder, top) {
263
279
  const u = UNDER2.exec(token);
264
280
  if (u !== null) {
265
281
  const n = Number(u[1]);
282
+ const k = strideOf(u[2]);
283
+ if (k !== null)
284
+ return {
285
+ kind: "under",
286
+ interval: { lo: Math.max(YOUNGEST_FLOOR, n - k), hi: n },
287
+ refusal: null,
288
+ clauses: ["under-stride"],
289
+ parts: [n, k]
290
+ };
266
291
  const below = maxWhere(ladder.caps, (c) => c < n);
267
292
  return {
268
293
  kind: "under",
@@ -367,7 +392,7 @@ function fromPrint(print, context = {}) {
367
392
  throw new Error(`Age.from(${JSON.stringify(print)}): birthYears needs a competition year`);
368
393
  return birthYearsOfInterval(iv, at);
369
394
  },
370
- floorObserved: () => reading.kind !== "under" && reading.kind !== "range" || iv === null ? null : reading.clauses.includes("under-floored-on-rung") || reading.clauses.includes("range-adult-floor")
395
+ floorObserved: () => reading.kind !== "under" && reading.kind !== "range" || iv === null ? null : reading.clauses.includes("under-floored-on-rung") || reading.clauses.includes("range-adult-floor") || reading.clauses.includes("under-stride")
371
396
  });
372
397
  }
373
398
  function fromYOB(from, to = from, context = {}) {
@@ -422,6 +447,8 @@ function sourceOf(r) {
422
447
  switch (r.kind) {
423
448
  case "range":
424
449
  case "under":
450
+ if (r.clauses.includes("under-stride"))
451
+ return "printed-band";
425
452
  return iv.lo > YOUNGEST_FLOOR ? "sibling-narrowed" : "printed-band";
426
453
  case "over":
427
454
  return iv.hi === Number.POSITIVE_INFINITY ? "printed-band" : "sibling-narrowed";
@@ -6924,29 +6924,49 @@ var PLACE_NODES = [
6924
6924
  ];
6925
6925
 
6926
6926
  var QUALIFIER_DELIMITER = /[,;:()[\]/–—-]/;
6927
- var NEVER_PLACE = new Map([
6928
- ["de", "name particle: `De <Surname>`, and Spanish `de <Place>`"],
6929
- ["ni", "Irish patronymic particle: `Ní <Surname>`"],
6930
- ["mo", "Irish possessive: `Mo <Word>`"],
6931
- ["na", "Irish article: `Rince na <Word>`"],
6932
- ["in", "Irish preposition: `<Word> In <Word>`; and `Inc` truncated to `In`"],
6933
- ["co", "Company: `<Surname> & Co.`. Bracketed `(US-CO)` is still Colorado"],
6934
- ["id", "Irish Dance: `<Surname> School of ID`"],
6935
- ["sd", "School of Dance: `<Surname> SD`"]
6936
- ]);
6937
- var NEVER_NAME = new Map([
6938
- ["de", "name particle: `De <Surname>`; and Spanish `de <Place>`"],
6939
- ["ni", "Irish patronymic particle: `Ní <Surname>`"],
6940
- ["ui", "Irish patronymic particle: `Uí <Surname>`"],
6941
- ["mo", "Irish possessive: `Mo <Word>`"],
6942
- ["na", "Irish article: `Rince na <Word>`"],
6943
- ["an", "Irish article: `<Word> an Rince`"],
6944
- ["in", "Irish preposition: `<Word> In <Word>`; and `Inc` truncated to `In`"],
6945
- ["co", "Company: `<Surname> & Co`"],
6946
- ["id", "Irish Dance: `ID de <Place>` keys the place, as `Irish Dancing de <Place>` does"],
6947
- ["sd", "School of Dance: `<Surname> SD`"],
6948
- ["da", "`Dance` truncated: `<Name> Academy of Irish Da` keys the name"]
6949
- ]);
6927
+ var SHORT_TOKEN_BARS = [
6928
+ {
6929
+ spelling: "de",
6930
+ place: true,
6931
+ name: true,
6932
+ why: "name particle: `De <Surname>`, and Spanish `de <Place>`"
6933
+ },
6934
+ { spelling: "ni", place: true, name: true, why: "Irish patronymic particle: `Ní <Surname>`" },
6935
+ { spelling: "ui", place: false, name: true, why: "Irish patronymic particle: `Uí <Surname>`" },
6936
+ { spelling: "mo", place: true, name: true, why: "Irish possessive: `Mo <Word>`" },
6937
+ { spelling: "na", place: true, name: true, why: "Irish article: `Rince na <Word>`" },
6938
+ { spelling: "an", place: false, name: true, why: "Irish article: `<Word> an Rince`" },
6939
+ {
6940
+ spelling: "in",
6941
+ place: true,
6942
+ name: true,
6943
+ why: "Irish preposition: `<Word> In <Word>`, and `Inc` truncated to `In`"
6944
+ },
6945
+ {
6946
+ spelling: "co",
6947
+ place: true,
6948
+ name: true,
6949
+ why: "Company: `<Surname> & Co.`. Bracketed `(US-CO)` is still Colorado"
6950
+ },
6951
+ {
6952
+ spelling: "id",
6953
+ place: true,
6954
+ name: true,
6955
+ why: "Irish Dance: `<Surname> School of ID`, and `ID de <Place>` keys the place, as `Irish Dancing de <Place>` does"
6956
+ },
6957
+ { spelling: "sd", place: true, name: true, why: "School of Dance: `<Surname> SD`" },
6958
+ {
6959
+ spelling: "da",
6960
+ place: false,
6961
+ name: true,
6962
+ why: "`Dance` truncated: `<Name> Academy of Irish Da` keys the name"
6963
+ }
6964
+ ];
6965
+ function barred(flag) {
6966
+ return new Map(SHORT_TOKEN_BARS.filter((row) => row[flag]).map((row) => [row.spelling, row.why]));
6967
+ }
6968
+ var NEVER_PLACE = barred("place");
6969
+ var NEVER_NAME = barred("name");
6950
6970
  var GENERIC_TLD = "com|net|org|edu|gov|mil|int|info|biz";
6951
6971
  var WEB_SPAN = new RegExp([
6952
6972
  "[A-Za-z][A-Za-z0-9+.-]*://\\S+",
@@ -7873,7 +7893,11 @@ function createPlaceReader2(options = {}) {
7873
7893
  return;
7874
7894
  if (n - 1 > 0 && (qualified(before[n - 1]) || !qualified(before[n - 2])))
7875
7895
  return;
7876
- return qualifierAlone(prev.heads, r.heads) ?? (prev.truncated || before[n] !== "comma" || listed(before[n + 1]) ? undefined : townInCounty(prev.heads, r.heads));
7896
+ const alone = qualifierAlone(prev.heads, r.heads);
7897
+ const run = alone === undefined ? undefined : runInside(parts[n - 1].space, alone.filter((q) => q.kind === "subdivision"));
7898
+ if (run !== undefined)
7899
+ return [run];
7900
+ return alone ?? (prev.truncated || before[n] !== "comma" || listed(before[n + 1]) ? undefined : townInCounty(prev.heads, r.heads));
7877
7901
  });
7878
7902
  settled.forEach((heads, n) => {
7879
7903
  if (heads === undefined)
package/dist/place.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  placesRelation2,
18
18
  probablySamePlace2,
19
19
  sameReading2
20
- } from "./chunks/place-2hdp50r3.js";
20
+ } from "./chunks/place-s3gefhzm.js";
21
21
  import"./chunks/place-tcgfvemw.js";
22
22
  export {
23
23
  DEFAULT_PLACE_CAPACITY2 as DEFAULT_PLACE_CAPACITY,
package/dist/school.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  areAllPlaceTokens2,
13
13
  placeRelation2,
14
14
  sameReading2
15
- } from "./chunks/place-2hdp50r3.js";
15
+ } from "./chunks/place-s3gefhzm.js";
16
16
  import {
17
17
  validity
18
18
  } from "./chunks/place-q9kwsmzd.js";
@@ -716,7 +716,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
716
716
  kind: "word",
717
717
  position: "suffix",
718
718
  truncatable: true,
719
- glued: true
719
+ glued: true,
720
+ matchKey: true
720
721
  }
721
722
  ],
722
723
  [
@@ -727,7 +728,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
727
728
  kind: "word",
728
729
  position: "suffix",
729
730
  truncatable: false,
730
- glued: false
731
+ glued: false,
732
+ matchKey: false
731
733
  }
732
734
  ],
733
735
  [
@@ -738,7 +740,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
738
740
  kind: "word",
739
741
  position: "suffix",
740
742
  truncatable: false,
741
- glued: false
743
+ glued: false,
744
+ matchKey: false
742
745
  }
743
746
  ],
744
747
  [
@@ -749,7 +752,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
749
752
  kind: "word",
750
753
  position: "suffix",
751
754
  truncatable: false,
752
- glued: false
755
+ glued: false,
756
+ matchKey: false
753
757
  }
754
758
  ],
755
759
  [
@@ -760,7 +764,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
760
764
  kind: "word",
761
765
  position: "suffix",
762
766
  truncatable: true,
763
- glued: true
767
+ glued: true,
768
+ matchKey: true
764
769
  }
765
770
  ],
766
771
  [
@@ -771,7 +776,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
771
776
  kind: "word",
772
777
  position: "suffix",
773
778
  truncatable: false,
774
- glued: false
779
+ glued: false,
780
+ matchKey: false
775
781
  }
776
782
  ],
777
783
  [
@@ -782,7 +788,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
782
788
  kind: "word",
783
789
  position: "suffix",
784
790
  truncatable: false,
785
- glued: false
791
+ glued: false,
792
+ matchKey: false
786
793
  }
787
794
  ],
788
795
  [
@@ -793,7 +800,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
793
800
  kind: "word",
794
801
  position: "prefix",
795
802
  truncatable: false,
796
- glued: false
803
+ glued: false,
804
+ matchKey: false
797
805
  }
798
806
  ],
799
807
  [
@@ -804,7 +812,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
804
812
  kind: "word",
805
813
  position: "prefix",
806
814
  truncatable: false,
807
- glued: false
815
+ glued: false,
816
+ matchKey: false
808
817
  }
809
818
  ],
810
819
  [
@@ -815,7 +824,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
815
824
  kind: "word",
816
825
  position: "prefix",
817
826
  truncatable: false,
818
- glued: false
827
+ glued: false,
828
+ matchKey: true
819
829
  }
820
830
  ],
821
831
  [
@@ -826,7 +836,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
826
836
  kind: "phrase",
827
837
  position: "prefix",
828
838
  truncatable: false,
829
- glued: false
839
+ glued: false,
840
+ matchKey: true
830
841
  }
831
842
  ],
832
843
  [
@@ -837,7 +848,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
837
848
  kind: "phrase",
838
849
  position: "prefix",
839
850
  truncatable: false,
840
- glued: false
851
+ glued: false,
852
+ matchKey: false
841
853
  }
842
854
  ],
843
855
  [
@@ -848,7 +860,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
848
860
  kind: "word",
849
861
  position: "prefix",
850
862
  truncatable: false,
851
- glued: false
863
+ glued: false,
864
+ matchKey: false
852
865
  }
853
866
  ],
854
867
  [
@@ -859,7 +872,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
859
872
  kind: "word",
860
873
  position: "suffix",
861
874
  truncatable: true,
862
- glued: false
875
+ glued: false,
876
+ matchKey: true
863
877
  }
864
878
  ],
865
879
  [
@@ -870,7 +884,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
870
884
  kind: "word",
871
885
  position: "suffix",
872
886
  truncatable: false,
873
- glued: false
887
+ glued: false,
888
+ matchKey: false
874
889
  }
875
890
  ],
876
891
  [
@@ -881,7 +896,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
881
896
  kind: "word",
882
897
  position: "suffix",
883
898
  truncatable: true,
884
- glued: false
899
+ glued: false,
900
+ matchKey: true
885
901
  }
886
902
  ],
887
903
  [
@@ -892,7 +908,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
892
908
  kind: "word",
893
909
  position: "suffix",
894
910
  truncatable: true,
895
- glued: false
911
+ glued: false,
912
+ matchKey: true
896
913
  }
897
914
  ],
898
915
  [
@@ -903,7 +920,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
903
920
  kind: "word",
904
921
  position: "suffix",
905
922
  truncatable: true,
906
- glued: false
923
+ glued: false,
924
+ matchKey: true
907
925
  }
908
926
  ],
909
927
  [
@@ -914,7 +932,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
914
932
  kind: "word",
915
933
  position: "suffix",
916
934
  truncatable: false,
917
- glued: false
935
+ glued: false,
936
+ matchKey: true
918
937
  }
919
938
  ],
920
939
  [
@@ -925,7 +944,8 @@ var SCHOOL_INSTITUTION_VOCABULARY = new Map([
925
944
  kind: "word",
926
945
  position: "suffix",
927
946
  truncatable: false,
928
- glued: false
947
+ glued: false,
948
+ matchKey: false
929
949
  }
930
950
  ]
931
951
  ]);
@@ -958,28 +978,14 @@ function truncatedInstitution(tail) {
958
978
  }
959
979
  return found;
960
980
  }
981
+ var MATCH_KEY_INSTITUTION_WORDS = [
982
+ ...new Set([...SCHOOL_INSTITUTION_VOCABULARY].filter(([, v]) => v.matchKey).flatMap(([k]) => k.split(" ")))
983
+ ].sort();
961
984
 
962
985
  import { normalizeApostrophes } from "@finbheara/names/lexicon";
963
986
  var SCHOOL_FLUFF_WORDS = new Set([
964
- "academy",
965
- "irish",
966
- "dance",
967
- "dancing",
968
- "dancers",
969
- "school",
970
- "company",
971
- "traditional",
972
- "the",
973
- "of",
974
- "and",
975
- "studio",
976
- "center",
977
- "centre",
978
- "institute",
979
- "scoil",
980
- "rince",
981
- "na",
982
- "an"
987
+ ...[...SCHOOL_FLUFF_VOCABULARY.values()].filter((entry) => entry.tokenFluff).map((entry) => entry.canonical),
988
+ ...MATCH_KEY_INSTITUTION_WORDS
983
989
  ]);
984
990
  var SCHOOL_GENERIC_NAME_PARTS = new Set(["celtic", "clann"]);
985
991
  function hasSpecificToken(tokens) {
@@ -25,7 +25,7 @@ export type AgeArm = "band" | "yob" | "open" | "empty";
25
25
  export type AgeKind = "under" | "over" | "range" | "adult" | "senior" | "yob";
26
26
  export type AgeRefusal = "not-a-band" | "backwards-range" | "overlapping-ranges" | "senior-without-ladder" | "below-youngest-band" | "year-out-of-range";
27
27
  export type AgeSource = "sibling-narrowed" | "printed-band" | "printed-range" | "printed-yob" | "open";
28
- export type AgeClause = "under-floored-on-rung" | "youngest-absorbs" | "over-ceiling-from-next-over" | "over-ceiling-refused-gap" | "and-over-no-ceiling" | "adult-under-ceiling" | "adult-band" | "range-overlapping" | "range-as-under" | "range-top-meets-over" | "range-adult-floor";
28
+ export type AgeClause = "under-floored-on-rung" | "under-stride" | "youngest-absorbs" | "over-ceiling-from-next-over" | "over-ceiling-refused-gap" | "and-over-no-ceiling" | "adult-under-ceiling" | "adult-band" | "range-overlapping" | "range-as-under" | "range-top-meets-over" | "range-adult-floor";
29
29
  export type AgeRelation = "same" | "contains" | "overlaps" | "disjoint" | "silent";
30
30
  export type AgeRelationReason = "equal" | "a-contains-b" | "b-contains-a" | "partial" | "a-older" | "a-younger" | "a-not-a-band" | "b-not-a-band";
31
31
  export interface AgeComparison {
@@ -8,6 +8,7 @@ export interface SchoolInstitution {
8
8
  position: InstitutionPosition;
9
9
  truncatable: boolean;
10
10
  glued: boolean;
11
+ matchKey: boolean;
11
12
  }
12
13
  export declare const SCHOOL_INSTITUTION_VOCABULARY: ReadonlyMap<string, SchoolInstitution>;
13
14
  export declare function schoolInstitution(text: string): SchoolInstitution | undefined;
@@ -18,3 +19,4 @@ export declare const INSTITUTION_TYPES: readonly InstitutionType[];
18
19
  export declare const INSTITUTION_PHRASES: readonly string[];
19
20
  export declare const GLUED_INSTITUTION_SUFFIXES: readonly string[];
20
21
  export declare function truncatedInstitution(tail: string): SchoolInstitution | undefined;
22
+ export declare const MATCH_KEY_INSTITUTION_WORDS: readonly string[];
@@ -1,5 +1,4 @@
1
1
  import type { InstitutionType as RegisterType } from "./school-institution-vocabulary.ts";
2
- export declare const LEGACY_EXCEPTION_PHRASES: ReadonlySet<string>;
3
2
  export type SchoolTokenClass = "NAME_PART" | "INSTITUTION_TYPE" | "FLUFF" | "LOCATION_HINT";
4
3
  export interface SchoolToken {
5
4
  text: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finbheara/domain",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "Places, CLRG regions, school names, ages, dances and a person's print in its role, as they are printed: read, compared and told apart",
5
5
  "keywords": [
6
6
  "places",