@finbheara/domain 0.8.0 → 0.10.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 +13 -3
- package/dist/age.js +41 -17
- package/dist/chunks/{place-h7tvdfyp.js → place-tv86hmps.js} +66 -2
- package/dist/place.js +1 -1
- package/dist/school.js +5 -5
- package/dist/types/age-title.d.ts +1 -0
- package/dist/types/age.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -269,7 +269,12 @@ Age.fromTitle("Beginner Adults Reel U40").token; // "adult u40": the adul
|
|
|
269
269
|
Age.fromTitle("Solo Championship - Adult O40").token; // "adult o40": adult, and 40 or over
|
|
270
270
|
Age.fromTitle("Adult Championship 18 - 29").token; // "adult 18-29": adult, and the range
|
|
271
271
|
Age.fromTitle("Adult / Child Reel Under 10").token; // "u10": no adult dances in it
|
|
272
|
-
Age.fromTitle("Senior Adult Ladies 19 & Over").token; // "o19":
|
|
272
|
+
Age.fromTitle("Senior Adult Ladies 19 & Over").token; // "adult o19": "Senior Adult" is adult
|
|
273
|
+
Age.fromTitle("Senior Adult Men 17 & Over").token; // "o17": it admits under-18s
|
|
274
|
+
Age.fromTitle("Championship (Adult) (A40U)").token; // "adult u40": a split adult code
|
|
275
|
+
Age.fromTitle("Traditional Set (A40O)").token; // "adult o40"
|
|
276
|
+
adultBeside("o18"); // "adult o18": a band beside the adult word
|
|
277
|
+
adultBeside("o17"); // undefined: it admits youth
|
|
273
278
|
```
|
|
274
279
|
|
|
275
280
|
An adult word beside an `Under N` above 18 reads both: `adult u40` is adult (`isAdult()`), with
|
|
@@ -282,8 +287,13 @@ An adult word beside an and-over from 18 or a range from 18 reads both as well:
|
|
|
282
287
|
band alone reads on the same ladder, a range floored at 18 where no rung sits below it. So
|
|
283
288
|
`Age.from("adult o40", { year: 2026 })` is born 1985 or earlier, as `o40` is. An and-over under
|
|
284
289
|
18 or a range opening under 18 (`Teen & Adult 13 & Over`) admits youth, and the band stands. A
|
|
285
|
-
title naming the senior
|
|
286
|
-
|
|
290
|
+
title naming the senior word beside it reads the same: `Senior Adult` is the adult band, so
|
|
291
|
+
`Senior Adult Ladies 19 & Over` is `adult o19`. A closing split adult code keeps its split:
|
|
292
|
+
`(A40U)` is `adult u40`, `(A40O)` and `(A40&O)` are `adult o40`.
|
|
293
|
+
|
|
294
|
+
`adultBeside(band)` is that reading as one function, the band beside the adult word as one token,
|
|
295
|
+
or `undefined` where the band admits youth. A caller holding a band from another field asks it: a
|
|
296
|
+
platform's printed `18&O` beside a title that reads adult is `adult o18`.
|
|
287
297
|
|
|
288
298
|
An age group is the age on the first of January, so a title that admits the dancer who is
|
|
289
299
|
`N` (`7 & Under`, `7/U`, `7 Years`) is the `Under N+1` group.
|
package/dist/age.js
CHANGED
|
@@ -16,7 +16,7 @@ var YEARS = /(?<![a-z0-9])(?<!\d\s*(?:&|\/|\band\b|[-\u0096–—]|\bto\b)\s*)(\
|
|
|
16
16
|
var RANGE_DASH = String.raw`(?:\u00c2?[-\u0096–—]|\bto\b)`;
|
|
17
17
|
var RANGE = new RegExp(String.raw`(?<![0-9])(?<![0-9][a-z]*)(?<!(?:^|[^a-z0-9])[a-z])(?:u\s*)?(\d{1,2})\s*${RANGE_DASH}\s*(\d{1,2})(?![a-z0-9])`, "i");
|
|
18
18
|
var LEAD_RANGE = new RegExp(String.raw`^\s*([1-9]\d?)\s*${RANGE_DASH}\s*([1-9]\d?)(?![a-z0-9])(?!\s*[/&])`, "i");
|
|
19
|
-
var ADULT_CODE = /^\s*a(
|
|
19
|
+
var ADULT_CODE = /^\s*a(?:(\d{1,2})(u|o|&o))?\s*$/i;
|
|
20
20
|
var ADULT = /(?<!non[\s-])(?<!-)\b(?:adults?|advanced\s+adults?|masters?)\b/i;
|
|
21
21
|
var SENIOR = /(?<!-)\bseniors?\b/i;
|
|
22
22
|
var TITLE_RANGE_MIN = 3;
|
|
@@ -81,40 +81,63 @@ function ageTitleToken(title) {
|
|
|
81
81
|
const lead = title.length - title.trimStart().length;
|
|
82
82
|
PAREN.lastIndex = 0;
|
|
83
83
|
let adultAside = null;
|
|
84
|
+
let adultWord = null;
|
|
84
85
|
for (const m of s.matchAll(PAREN)) {
|
|
85
86
|
const inner = m[1] ?? "";
|
|
86
87
|
const from = lead + (m.index ?? 0) + 1;
|
|
87
88
|
const i = m.index ?? 0;
|
|
88
89
|
const tail = i + m[0].length === s.length && !/[a-z0-9]/i.test(s[i - 1] ?? "");
|
|
89
|
-
|
|
90
|
+
const code = tail ? ADULT_CODE.exec(inner) : null;
|
|
91
|
+
if (code !== null) {
|
|
92
|
+
const split = code[1] === undefined ? "" : `${/u/i.test(code[2] ?? "") ? "u" : "o"}${code[1]}`;
|
|
90
93
|
const a = inner.length - inner.trimStart().length;
|
|
91
|
-
adultAside = at(title, from, a, inner.trimEnd().length, "adult");
|
|
94
|
+
adultAside = at(title, from, a, inner.trimEnd().length, adultBeside(split) ?? "adult");
|
|
92
95
|
continue;
|
|
93
96
|
}
|
|
97
|
+
if (adultWord !== null)
|
|
98
|
+
continue;
|
|
94
99
|
const t = readAnchored(title, inner, from, true);
|
|
95
|
-
if (t.token
|
|
96
|
-
|
|
100
|
+
if (t.token === "")
|
|
101
|
+
continue;
|
|
102
|
+
if (t.token === "adult") {
|
|
103
|
+
adultWord = t;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
return adultOverUnder(title, s, lead, t);
|
|
97
107
|
}
|
|
108
|
+
if (adultWord !== null)
|
|
109
|
+
return adultAside ?? adultWord;
|
|
98
110
|
const words = readAnchored(title, s, lead);
|
|
99
|
-
return words.token === ""
|
|
111
|
+
return adultAside !== null && (words.token === "" || words.token === "adult") ? adultAside : adultOverUnder(title, s, lead, words);
|
|
100
112
|
}
|
|
101
113
|
var ADULT_UNDER_MIN = 18;
|
|
102
|
-
|
|
114
|
+
function adultBeside(band) {
|
|
115
|
+
const b = band.trim().toLowerCase();
|
|
116
|
+
if (b === "")
|
|
117
|
+
return "adult";
|
|
118
|
+
const n = /^u(\d+)$/.exec(b)?.[1];
|
|
119
|
+
if (n !== undefined) {
|
|
120
|
+
if (Number(n) < ADULT_UNDER_MIN)
|
|
121
|
+
return;
|
|
122
|
+
return Number(n) > ADULT_UNDER_MIN ? `adult u${Number(n)}` : "adult";
|
|
123
|
+
}
|
|
124
|
+
const floor = /^o(\d+)$/.exec(b)?.[1] ?? /^(\d+)-\d+$/.exec(b)?.[1];
|
|
125
|
+
if (floor === undefined)
|
|
126
|
+
return band;
|
|
127
|
+
return Number(floor) < ADULT_UNDER_MIN ? undefined : `adult ${b}`;
|
|
128
|
+
}
|
|
103
129
|
function adultOverUnder(title, s, lead, t) {
|
|
130
|
+
if (t.token === "")
|
|
131
|
+
return t;
|
|
104
132
|
const a = ADULT.exec(s);
|
|
105
133
|
if (a === null)
|
|
106
134
|
return t;
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
109
|
-
if (Number(n) < ADULT_UNDER_MIN)
|
|
110
|
-
return t;
|
|
111
|
-
const token = Number(n) > ADULT_UNDER_MIN ? `adult u${n}` : "adult";
|
|
112
|
-
return at(title, lead, a.index, a.index + a[0].length, token);
|
|
113
|
-
}
|
|
114
|
-
const floor = /^o(\d+)$/.exec(t.token)?.[1] ?? /^(\d+)-\d+$/.exec(t.token)?.[1];
|
|
115
|
-
if (floor === undefined || Number(floor) < ADULT_UNDER_MIN || SENIOR_ADULT.test(s))
|
|
135
|
+
const token = adultBeside(t.token);
|
|
136
|
+
if (token === undefined || token === t.token)
|
|
116
137
|
return t;
|
|
117
|
-
|
|
138
|
+
if (/^u\d+$/.test(t.token))
|
|
139
|
+
return at(title, lead, a.index, a.index + a[0].length, token);
|
|
140
|
+
return { token, span: t.span };
|
|
118
141
|
}
|
|
119
142
|
|
|
120
143
|
var YOUNGEST_FLOOR = 0;
|
|
@@ -586,6 +609,7 @@ export {
|
|
|
586
609
|
YOUNGEST_BAND_TOP,
|
|
587
610
|
YOUNGEST_FLOOR,
|
|
588
611
|
YOUNG_FLOOR,
|
|
612
|
+
adultBeside,
|
|
589
613
|
ageOnJanuary1,
|
|
590
614
|
ageRelation,
|
|
591
615
|
ageTitleToken,
|
|
@@ -199,14 +199,16 @@ var PLACE_NODES = [
|
|
|
199
199
|
geo: "USA",
|
|
200
200
|
admin: "IDTANA",
|
|
201
201
|
prints: [
|
|
202
|
+
"idtama",
|
|
202
203
|
"lar mheiricea",
|
|
203
204
|
"mid america",
|
|
204
205
|
"mid america region",
|
|
205
206
|
"mid america region usa",
|
|
207
|
+
"mid american region",
|
|
206
208
|
"reigiun lar meiricea",
|
|
207
209
|
"usa mid america region"
|
|
208
210
|
],
|
|
209
|
-
codes: ["MAO"],
|
|
211
|
+
codes: ["IDTAMA", "MAO"],
|
|
210
212
|
truncations: ["mid am"],
|
|
211
213
|
oireachtas: "MAO"
|
|
212
214
|
},
|
|
@@ -243,6 +245,7 @@ var PLACE_NODES = [
|
|
|
243
245
|
geo: "USA",
|
|
244
246
|
admin: "IDTANA",
|
|
245
247
|
prints: [
|
|
248
|
+
"idtana sr",
|
|
246
249
|
"reigiun an deiscirt",
|
|
247
250
|
"s usa",
|
|
248
251
|
"so usa",
|
|
@@ -4994,6 +4997,15 @@ var PLACE_NODES = [
|
|
|
4994
4997
|
prints: ["essex"],
|
|
4995
4998
|
codes: []
|
|
4996
4999
|
},
|
|
5000
|
+
{
|
|
5001
|
+
id: "GBR-ENG/surrey",
|
|
5002
|
+
kind: "city",
|
|
5003
|
+
name: "Surrey",
|
|
5004
|
+
geo: "GBR-ENG",
|
|
5005
|
+
admin: "ENG_SOUTH",
|
|
5006
|
+
prints: ["surrey"],
|
|
5007
|
+
codes: []
|
|
5008
|
+
},
|
|
4997
5009
|
{
|
|
4998
5010
|
id: "GBR-ENG/leeds",
|
|
4999
5011
|
kind: "city",
|
|
@@ -6800,7 +6812,7 @@ function createPlaceReader2(options = {}) {
|
|
|
6800
6812
|
return s.normalize("NFD").replace(/\p{M}+/gu, "").toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
6801
6813
|
}
|
|
6802
6814
|
function repair(print) {
|
|
6803
|
-
const s = print.normalize("NFC").replace(/\s+/g, " ").trim();
|
|
6815
|
+
const s = print.normalize("NFC").replace(/\p{Cf}+/gu, "").replace(/\p{Cc}+/gu, " ").replace(/\s+/g, " ").trim();
|
|
6804
6816
|
const opens = (s.match(/[([{]/g) ?? []).length;
|
|
6805
6817
|
const closes = (s.match(/[)\]}]/g) ?? []).length;
|
|
6806
6818
|
if (opens === closes)
|
|
@@ -7407,6 +7419,41 @@ function createPlaceReader2(options = {}) {
|
|
|
7407
7419
|
const found = (idx().byRunPrint.get(fold(piece)) ?? []).filter((n) => subs.some((s) => n.id !== s.id && isAncestor(s, n)));
|
|
7408
7420
|
return found.length === 1 ? found[0] : undefined;
|
|
7409
7421
|
}
|
|
7422
|
+
function continentOf(n) {
|
|
7423
|
+
const seen = new Set;
|
|
7424
|
+
for (let at = n;at !== undefined && !seen.has(at.id); ) {
|
|
7425
|
+
if (at.kind === "continent")
|
|
7426
|
+
return at;
|
|
7427
|
+
seen.add(at.id);
|
|
7428
|
+
at = at.geo === null ? undefined : idx().byId.get(at.geo);
|
|
7429
|
+
}
|
|
7430
|
+
return;
|
|
7431
|
+
}
|
|
7432
|
+
const POSTAL_COUNTRIES = new Set(["USA", "CAN"]);
|
|
7433
|
+
function qualifierAlone(left, right) {
|
|
7434
|
+
if (left.length === 0 || right.length === 0)
|
|
7435
|
+
return;
|
|
7436
|
+
if (left.some((l) => right.some((r) => relates(l, r))))
|
|
7437
|
+
return;
|
|
7438
|
+
const postal = right.filter((r) => r.kind === "subdivision" && POSTAL_COUNTRIES.has(countryOf(r)?.id ?? ""));
|
|
7439
|
+
if (postal.length > 0) {
|
|
7440
|
+
const theirs = new Set(postal.map((r) => countryOf(r)?.id));
|
|
7441
|
+
const fits = left.every((l) => l.kind === "city" || (l.kind === "country" || l.kind === "subdivision") && !theirs.has(countryOf(l)?.id));
|
|
7442
|
+
return fits ? postal : undefined;
|
|
7443
|
+
}
|
|
7444
|
+
if (!right.every((r) => r.kind === "country" || r.kind === "subdivision"))
|
|
7445
|
+
return;
|
|
7446
|
+
const continents = new Set(right.map((r) => continentOf(r)?.id));
|
|
7447
|
+
if (continents.has(undefined))
|
|
7448
|
+
return;
|
|
7449
|
+
const abroad = left.every((l) => {
|
|
7450
|
+
if (l.kind !== "city")
|
|
7451
|
+
return false;
|
|
7452
|
+
const c = continentOf(l)?.id;
|
|
7453
|
+
return c !== undefined && !continents.has(c);
|
|
7454
|
+
});
|
|
7455
|
+
return abroad ? right : undefined;
|
|
7456
|
+
}
|
|
7410
7457
|
function read(print, declared = false, smushed = true) {
|
|
7411
7458
|
const core = unbracket(repair(print));
|
|
7412
7459
|
if (fold(core) === "")
|
|
@@ -7432,6 +7479,7 @@ function createPlaceReader2(options = {}) {
|
|
|
7432
7479
|
const seen = new Set;
|
|
7433
7480
|
for (const split of subsets) {
|
|
7434
7481
|
const parts = [];
|
|
7482
|
+
const before = [null];
|
|
7435
7483
|
let space = tokens[0] ?? "";
|
|
7436
7484
|
let conj = space;
|
|
7437
7485
|
for (let i = 0;i < seps.length; i++) {
|
|
@@ -7439,6 +7487,7 @@ function createPlaceReader2(options = {}) {
|
|
|
7439
7487
|
const next = tokens[i + 1] ?? "";
|
|
7440
7488
|
if (split.includes(k)) {
|
|
7441
7489
|
parts.push({ space, conj });
|
|
7490
|
+
before.push(k);
|
|
7442
7491
|
space = next;
|
|
7443
7492
|
conj = next;
|
|
7444
7493
|
} else {
|
|
@@ -7466,6 +7515,21 @@ function createPlaceReader2(options = {}) {
|
|
|
7466
7515
|
refusal: null
|
|
7467
7516
|
};
|
|
7468
7517
|
}
|
|
7518
|
+
const qualified = (k) => k === "comma" || k === "space";
|
|
7519
|
+
const settled = reads.map((r, n) => {
|
|
7520
|
+
const prev = reads[n - 1];
|
|
7521
|
+
if (prev === undefined || !qualified(before[n]) || r.truncated)
|
|
7522
|
+
return;
|
|
7523
|
+
if (n - 1 > 0 && (qualified(before[n - 1]) || !qualified(before[n - 2])))
|
|
7524
|
+
return;
|
|
7525
|
+
return qualifierAlone(prev.heads, r.heads);
|
|
7526
|
+
});
|
|
7527
|
+
settled.forEach((heads, n) => {
|
|
7528
|
+
if (heads === undefined)
|
|
7529
|
+
return;
|
|
7530
|
+
reads[n - 1] = { ...reads[n - 1], heads };
|
|
7531
|
+
reads[n] = { ...reads[n], heads };
|
|
7532
|
+
});
|
|
7469
7533
|
if (reads.some((r) => r.heads.length === 0 || r.refusal !== null))
|
|
7470
7534
|
continue;
|
|
7471
7535
|
const together = combine(reads);
|
package/dist/place.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
placesRelation2,
|
|
16
16
|
probablySamePlace2,
|
|
17
17
|
sameReading2
|
|
18
|
-
} from "./chunks/place-
|
|
18
|
+
} from "./chunks/place-tv86hmps.js";
|
|
19
19
|
export {
|
|
20
20
|
DEFAULT_PLACE_CAPACITY2 as DEFAULT_PLACE_CAPACITY,
|
|
21
21
|
DEFAULT_PLACE_READER2 as DEFAULT_PLACE_READER,
|
package/dist/school.js
CHANGED
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
areAllPlaceTokens2,
|
|
9
9
|
placeRelation2,
|
|
10
10
|
sameReading2
|
|
11
|
-
} from "./chunks/place-
|
|
11
|
+
} from "./chunks/place-tv86hmps.js";
|
|
12
12
|
import {
|
|
13
13
|
validity
|
|
14
14
|
} from "./chunks/place-q9kwsmzd.js";
|
|
15
15
|
|
|
16
|
-
import { normalizeApostrophes } from "@finbheara/names/lexicon";
|
|
16
|
+
import { normalizeApostrophes as normalizeApostrophes2 } from "@finbheara/names/lexicon";
|
|
17
17
|
import { SURNAME_SEPARATOR, lexiconKey, titleCaseNamePart } from "@finbheara/names/normalize";
|
|
18
18
|
import { personName } from "@finbheara/names/normalize";
|
|
19
19
|
|
|
@@ -873,6 +873,7 @@ function truncatedInstitution(tail) {
|
|
|
873
873
|
return found;
|
|
874
874
|
}
|
|
875
875
|
|
|
876
|
+
import { normalizeApostrophes } from "@finbheara/names/lexicon";
|
|
876
877
|
var SCHOOL_FLUFF_WORDS = new Set([
|
|
877
878
|
"academy",
|
|
878
879
|
"irish",
|
|
@@ -929,12 +930,11 @@ function isDiscardedAnyway(token) {
|
|
|
929
930
|
function distinctiveTokens(tokens) {
|
|
930
931
|
return tokens.filter((t) => t.length > 2 && !SCHOOL_FLUFF_WORDS.has(t));
|
|
931
932
|
}
|
|
932
|
-
var APOSTROPHE_VARIANTS = /['`´‘’“”]/g;
|
|
933
933
|
function foldSchoolName(raw) {
|
|
934
934
|
let s = raw.toLowerCase();
|
|
935
935
|
s = s.normalize("NFD").replace(/[̀-ͯ]/g, "");
|
|
936
936
|
s = s.replace(/ß/g, "ss").replace(/æ/g, "ae").replace(/œ/g, "oe").replace(/ø/g, "o");
|
|
937
|
-
s = s
|
|
937
|
+
s = normalizeApostrophes(s);
|
|
938
938
|
s = s.replace(/'/g, "");
|
|
939
939
|
const words = [];
|
|
940
940
|
for (const word of s.split(/[^a-z0-9]+/)) {
|
|
@@ -1057,7 +1057,7 @@ function createSchoolNameReader(options = {}) {
|
|
|
1057
1057
|
return print.replace(SPACING_ACUTE_AFTER_VOWEL, "$1́").replace(SPACING_ACUTE, "'");
|
|
1058
1058
|
}
|
|
1059
1059
|
function renderSn1(print) {
|
|
1060
|
-
return
|
|
1060
|
+
return normalizeApostrophes2(readSpacingAcute(repairMojibake(print)).normalize("NFKC")).replace(/\p{Cf}+/gu, "").replace(/\p{Cc}+/gu, " ").replace(/\s+/gu, " ").trim();
|
|
1061
1061
|
}
|
|
1062
1062
|
const COMPOUND_OPENERS = new Set([
|
|
1063
1063
|
"hyphen",
|
package/dist/types/age.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type AgeTitleSpan } from "./age-title.ts";
|
|
2
2
|
import type { AgeArm, AgeClause, AgeComparison, AgeContext, AgeInterval, AgeKind, AgeLadder, AgeMisuse, AgeRefusal, AgeRelation, AgeRelationReason, AgeSource, AgeSpan, BirthYears, YOBContext, YoungFloorVerdict } from "./age-types.ts";
|
|
3
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";
|
|
4
|
+
export { type AgeTitleSpan, type AgeTitleToken, TITLE_RANGE_MAX, TITLE_RANGE_MIN, adultBeside, ageTitleToken, } from "./age-title.ts";
|
|
5
5
|
export type { AgeArm, AgeClause, AgeComparison, AgeContext, AgeInterval, AgeKind, AgeLadder, AgeMisuse, AgeRefusal, AgeRelation, AgeRelationReason, AgeSource, AgeSpan, BirthYears, EmptyReason, Validated, YOBContext, YoungFloorVerdict, };
|
|
6
6
|
export declare const YOUNGEST_FLOOR = 0;
|
|
7
7
|
export declare const ADULT_FLOOR = 18;
|