@finbheara/domain 0.50.0 → 0.52.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 +71 -1
- package/dist/age.js +3 -1
- package/dist/chunks/{place-7jfd4m3j.js → place-dn6qk21g.js} +7 -3
- package/dist/chunks/{place-kmh59zkw.js → place-w6d4xfzc.js} +85 -23
- package/dist/code.js +136 -0
- package/dist/schedule.js +2 -2
- package/dist/title.js +2 -2
- package/dist/types/adult-keywords.d.ts +7 -0
- package/dist/types/age-title.d.ts +4 -1
- package/dist/types/age-types.d.ts +1 -0
- package/dist/types/age.d.ts +2 -1
- package/dist/types/code.d.ts +41 -0
- package/dist/types/title.d.ts +1 -0
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -44,12 +44,13 @@ ESM, Node ≥ 22 or Bun ≥ 1.4.2. MIT. Not affiliated with or endorsed by any d
|
|
|
44
44
|
| `@finbheara/domain/tune` | `tune()`, `tuneRelation`, `tempoLegal`, `settingAt`, `TUNE_NODES`: the CLRG set dance list, each tune with its time, speeds and bars |
|
|
45
45
|
| `@finbheara/domain/ceili` | `ceili()`, `ceiliRelation`, `CEILI_NODES`: the céilí handbook dances |
|
|
46
46
|
| `@finbheara/domain/dance` | `dance()`: a print read as a tune and a céilí dance, narrowed by its round |
|
|
47
|
-
| `@finbheara/domain/age` | `Age.from`, `Age.fromYOB`, `Age.fromTitle`, `ageTitleToken`, `ageRelation`, `canOverlap`, `averageAge`, `isAveraged`, `intersectBirthYears`, `validYOB`, the age constants |
|
|
47
|
+
| `@finbheara/domain/age` | `Age.from`, `Age.fromYOB`, `Age.fromTitle`, `ageTitleToken`, `ageRelation`, `canOverlap`, `averageAge`, `isAveraged`, `intersectBirthYears`, `validYOB`, `DEFAULT_ADULT_KEYWORDS`, the age constants |
|
|
48
48
|
| `@finbheara/domain/noun-index` | `createIndex`, `indexSchema`, `personEncoder`, `roleEncoder`, `roleSchoolGlob`, and the `SqlHandle`/`NounEncoder` types: a database-backed name map (below) |
|
|
49
49
|
| `@finbheara/domain/dance-types` | `danceTypes()`, `DANCE_TYPES`, `rhythmOfTime`, and the shared `DanceMatch`/`DanceRelation`/`SetRhythm`/`TimeSignature` types |
|
|
50
50
|
| `@finbheara/domain/promotion` | `samePromotedRow`, `samePromotedSchool`, `samePromotedHeir`, `samePromotedName`, `questionMarksRead`, `foldCharSynonyms`: is a row the same row after a promotion (below) |
|
|
51
51
|
| `@finbheara/domain/person` | `seatName`, `dancerName`, `teacherName`, `roleName`, `roleSentinelOf`, `rolePrintsNoName`, `dancerPrintsNoName`, the role lists and `SHARED_ROW_SENTINELS`: a person's print read in its role (below) |
|
|
52
52
|
| `@finbheara/domain/title` | `compTitle`, `titleRelation`, `matchTitle`, `ladderOf`, `populationIn`, `populationRelation`, `roundNumbersIn`, `roundFold`, `codePopulation`, `secondIn`: a competition title read and matched onto syllabus entries, a code's sex suffix, a second chance (below) |
|
|
53
|
+
| `@finbheara/domain/code` | `createCodeReader`, `compCode`, `DEFAULT_CODE_READER`, the `CompCode` type: a competition code read at the feis it belongs to, from that feis's syllabus or, on a platform you name as standardized, from the code alone (below) |
|
|
53
54
|
| `@finbheara/domain/schedule` | `scheduleAt`, `sameHall`, `readRunningOrder`, the `ScheduleSlot` type: which entries a hall runs (below) |
|
|
54
55
|
|
|
55
56
|
The library does no I/O and installs nothing process-wide. Every reader has a default and a
|
|
@@ -353,6 +354,31 @@ band alone reads on the same ladder. So
|
|
|
353
354
|
`Senior Adult` beside an and-over is its oldest youth championship, an open championship that
|
|
354
355
|
qualifies for the Worlds, so `Senior Adult Ladies 19 & Over` is `o19`. A closing split
|
|
355
356
|
adult code keeps its split: `(A40U)` is `adult u40`, `(A40O)` and `(A40&O)` are `adult o40`.
|
|
357
|
+
An age cell that names a level beside the adult word, either side (`Advanced Adult`, `Open
|
|
358
|
+
Adults`, `Novice Adult`, `Adult Beginner`, `Adult Prelim`), is the adult rung, 18 and over: the
|
|
359
|
+
level is the competition's grade. A level word alone (`Novice`, `Open`) reads no age.
|
|
360
|
+
|
|
361
|
+
**The adult category is not an age of 18 or over.** `O18`, `18 & Over`, `Over 21` and `Senior` are
|
|
362
|
+
open-age competitions, danced mostly by dancers who came up through the youth bands: they read
|
|
363
|
+
their band, and `isAdult()` is false. `Adult`, `Novice Adult`, `Adult Beginner`, `Adult Masters` and
|
|
364
|
+
`Masters` name the adult category, a division with entry rules of its own (no youth competition
|
|
365
|
+
for some years, or never danced as a youth): they read `[18, ∞)` unless a band beside them splits
|
|
366
|
+
it, and `isAdult()` is true. Ask `isAdult()` for the category and `interval()` for the age.
|
|
367
|
+
|
|
368
|
+
Which words name the category is set by whoever runs the competition, and it differs by place and
|
|
369
|
+
year. Pass the list you hold for the competition as `adultKeywords` (on `Age.from`, `Age.fromTitle`
|
|
370
|
+
and `compTitle`). `DEFAULT_ADULT_KEYWORDS` is `["Adult", "Masters"]`. A keyword matches in either
|
|
371
|
+
case and its plural, several in a row read as one (`Adult Masters`), and the keyword `Adult` also
|
|
372
|
+
brings `Ad`, a bare `Advanced` and the `(A)` code. `[]` says no word names the category there.
|
|
373
|
+
|
|
374
|
+
```ts
|
|
375
|
+
import { Age, DEFAULT_ADULT_KEYWORDS } from "@finbheara/domain/age";
|
|
376
|
+
|
|
377
|
+
Age.from("O18", { year: 2026 }).isAdult(); // false: an age
|
|
378
|
+
Age.from("Adult Masters", { year: 2026 }).isAdult(); // true: the category
|
|
379
|
+
Age.from("Veterans", { year: 2026, adultKeywords: ["Veteran"] }).isAdult(); // true, by your list
|
|
380
|
+
Age.fromTitle("Adult Ladies Over 21", { year: 2011, adultKeywords: [] }).token; // "o21"
|
|
381
|
+
```
|
|
356
382
|
|
|
357
383
|
`adultBeside(band)` is that reading as one function, the band beside the adult word as one token,
|
|
358
384
|
or `undefined` where the band admits youth. A caller holding a band from another field asks it: a
|
|
@@ -454,6 +480,50 @@ secondIn("Preliminary Champion, Supplementary Prelim (U15)"); // true
|
|
|
454
480
|
secondIn("Preliminary Champion, Hard Shoe (U10)"); // false
|
|
455
481
|
```
|
|
456
482
|
|
|
483
|
+
## Read a competition code
|
|
484
|
+
|
|
485
|
+
A code is a feis's own number for a competition. Some platforms number every feis by one
|
|
486
|
+
grammar: a level digit (`1` first feis to `7` open championship), two digits for the age column
|
|
487
|
+
(fifty more for a boys' column, `99` for adults) and letters for the dance, so `512SJ` is a
|
|
488
|
+
prizewinner slip jig under 12 wherever it is printed. Most platforms let each feis number as it
|
|
489
|
+
likes, and the same `344` is a novice under 11 at one feis and a beginner reel at the next. Read
|
|
490
|
+
with the grammar, such a code gives an age and a level that look right and are wrong.
|
|
491
|
+
|
|
492
|
+
So a code is read only at a feis. `read` takes the platform and the feis's address or slug, and
|
|
493
|
+
answers from the feis's syllabus where you hand it in, on any platform. With no syllabus, only a
|
|
494
|
+
platform you name as standardized reads its code alone. Everything else is refused, with its
|
|
495
|
+
reason: `no-feis`, `feis-specific`, `not-in-syllabus`, `two-entries` or `not-a-code`. An empty
|
|
496
|
+
`syllabus: []` is no syllabus, never a syllabus that prints no code. The default
|
|
497
|
+
reader names no platform, so with no configuration a code reads only from a syllabus. A title is
|
|
498
|
+
not a code: `compTitle` still reads it at any feis.
|
|
499
|
+
|
|
500
|
+
```ts
|
|
501
|
+
import { createCodeReader } from "@finbheara/domain/code";
|
|
502
|
+
|
|
503
|
+
const codes = createCodeReader({ standardized: ["examplefeis"] });
|
|
504
|
+
|
|
505
|
+
const c = codes.read("512SJ", { platform: "examplefeis", feis: "ex:1001" });
|
|
506
|
+
c.age.ag1; // "u12"
|
|
507
|
+
c.level; // 500
|
|
508
|
+
c.source; // "code"
|
|
509
|
+
|
|
510
|
+
codes.read("344", { platform: "other", feis: "x:ABC26" }).invalidReason(); // "feis-specific"
|
|
511
|
+
codes.read("512SJ", { platform: "examplefeis", feis: null }).invalidReason(); // "no-feis"
|
|
512
|
+
|
|
513
|
+
const syllabus = [{ code: "344", title: "Novice Girls Under 11 Light Jig" }];
|
|
514
|
+
const s = codes.read("344", { platform: "other", feis: "x:ABC26", syllabus });
|
|
515
|
+
s.age.ag1; // "u11"
|
|
516
|
+
s.entry; // the entry: read its level yourself
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
The level comes from the grammar's level digit only. A set, a treble reel, a figure and a future
|
|
520
|
+
champions competition run off the grade ladder and read no level, and a syllabus answer reads none,
|
|
521
|
+
on a standardized platform too (the syllabus wins, and the package reads no level word): the
|
|
522
|
+
matching `entry` comes back for you to read. The oldest
|
|
523
|
+
column a feis offers in one series is its and-over (`719OC` is 18 and over where it is the top
|
|
524
|
+
open column). Hand in every code the feis printed (`codes`) to read the top column and a level
|
|
525
|
+
split by sex. Without them a column reads as its `Under` band and who dances is not said.
|
|
526
|
+
|
|
457
527
|
## Ask a schedule
|
|
458
528
|
|
|
459
529
|
A split band's competitions share their card numbers, so a card heard on a stage fits each of
|
package/dist/age.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DEFAULT_ADULT_KEYWORDS2,
|
|
2
3
|
printsUnderOpen2,
|
|
3
4
|
printsAdultCode2,
|
|
4
5
|
TITLE_RANGE_MIN2,
|
|
@@ -39,13 +40,14 @@ import {
|
|
|
39
40
|
youngFloor2,
|
|
40
41
|
tooYoungForMajor2,
|
|
41
42
|
tooYoungForFeis2
|
|
42
|
-
} from "./chunks/place-
|
|
43
|
+
} from "./chunks/place-w6d4xfzc.js";
|
|
43
44
|
export {
|
|
44
45
|
ADULT_FLOOR2 as ADULT_FLOOR,
|
|
45
46
|
AVERAGE_AGE_DECIMALS2 as AVERAGE_AGE_DECIMALS,
|
|
46
47
|
Age2 as Age,
|
|
47
48
|
AgeMisuseError2 as AgeMisuseError,
|
|
48
49
|
DANCE_UP_YEARS2 as DANCE_UP_YEARS,
|
|
50
|
+
DEFAULT_ADULT_KEYWORDS2 as DEFAULT_ADULT_KEYWORDS,
|
|
49
51
|
MAJORS_FLOOR_YEARS2 as MAJORS_FLOOR_YEARS,
|
|
50
52
|
MIN_FEIS_AGE2 as MIN_FEIS_AGE,
|
|
51
53
|
MIN_MAJOR_AGE2 as MIN_MAJOR_AGE,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Age2,
|
|
3
3
|
ageRelation2
|
|
4
|
-
} from "./place-
|
|
4
|
+
} from "./place-w6d4xfzc.js";
|
|
5
5
|
import {
|
|
6
6
|
validity
|
|
7
7
|
} from "./place-q9kwsmzd.js";
|
|
@@ -79,7 +79,11 @@ function roundFold2(print) {
|
|
|
79
79
|
var SPLIT = / ([a-d]) $|(?:\d|girls?|boys?|lad(?:y|ies)|m[ae]n|mixed) ([a-d])(?= )/;
|
|
80
80
|
var spoken = (print) => print.replace(/\b(under|over|u|o)-(?=[ \t]*\d)/giu, "$1 ");
|
|
81
81
|
function read(print, ctx, agePrint) {
|
|
82
|
-
const actx = {
|
|
82
|
+
const actx = {
|
|
83
|
+
year: ctx.year ?? null,
|
|
84
|
+
...ctx.ladder ? { ladder: ctx.ladder } : {},
|
|
85
|
+
...ctx.adultKeywords ? { adultKeywords: ctx.adultKeywords } : {}
|
|
86
|
+
};
|
|
83
87
|
let age;
|
|
84
88
|
let ageSpan = null;
|
|
85
89
|
if (agePrint !== undefined && agePrint.trim() !== "") {
|
|
@@ -130,7 +134,7 @@ function ladderOf2(bands) {
|
|
|
130
134
|
const bare = Age2.from(b.ag0, { year: null });
|
|
131
135
|
if (!bare.isValid())
|
|
132
136
|
continue;
|
|
133
|
-
if (
|
|
137
|
+
if (b.isAdult())
|
|
134
138
|
adult = true;
|
|
135
139
|
const [p, q] = bare.parts;
|
|
136
140
|
if (bare.kind === "under" && p !== undefined)
|
|
@@ -2,6 +2,29 @@ import {
|
|
|
2
2
|
validity
|
|
3
3
|
} from "./place-q9kwsmzd.js";
|
|
4
4
|
|
|
5
|
+
var DEFAULT_ADULT_KEYWORDS2 = Object.freeze(["Adult", "Masters"]);
|
|
6
|
+
var ADULT_STEM = "adult";
|
|
7
|
+
var escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8
|
+
function stem(keyword) {
|
|
9
|
+
const k = keyword.trim().toLowerCase().replace(/\s+/g, " ");
|
|
10
|
+
return k.length > 2 && k.endsWith("s") ? k.slice(0, -1) : k;
|
|
11
|
+
}
|
|
12
|
+
var cache = new Map;
|
|
13
|
+
function adultPatterns(keywords) {
|
|
14
|
+
const stems = [...new Set((keywords ?? DEFAULT_ADULT_KEYWORDS2).map(stem))].filter((s) => s !== "").sort((a, b) => b.length - a.length || a.localeCompare(b));
|
|
15
|
+
const key = stems.join("\x00");
|
|
16
|
+
const hit = cache.get(key);
|
|
17
|
+
if (hit !== undefined)
|
|
18
|
+
return hit;
|
|
19
|
+
const adult = stems.includes(ADULT_STEM);
|
|
20
|
+
const words = stems.map((s) => s === ADULT_STEM ? "adults?|ad" : `${escape(s).replace(/ /g, "[\\s-]+")}s?`);
|
|
21
|
+
const one = words.length === 0 ? null : words.join("|");
|
|
22
|
+
const run = one === null ? null : `(?:${one})(?:[\\s-]+(?:${one}))*`;
|
|
23
|
+
const out = Object.freeze({ adult, one, run });
|
|
24
|
+
cache.set(key, out);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
5
28
|
var LEAD_ID = /^\s*(?:comp(?:etition)?\.?\s*)?\d+[a-z]*(?:[/-]\d*[a-z]*)*\s*[-:.]?\s*/i;
|
|
6
29
|
var PAREN = /\(([^)]*)\)/g;
|
|
7
30
|
var AND_OVER = /(?<![0-9])(?<![0-9][a-z]*)(?<!(?:^|[^a-z0-9])[a-z])(\d{1,2})\s*(?:years?\s*)?(?:&|\+|\band\b)\s*(?:over|older|up|o)(?![a-z])/i;
|
|
@@ -27,7 +50,21 @@ var RANGE = new RegExp(String.raw`(?<![0-9])(?<![0-9][a-z]*)(?<!(?:^|[^a-z0-9])[
|
|
|
27
50
|
var LEAD_RANGE = new RegExp(String.raw`^\s*([1-9]\d?)\s*${RANGE_DASH}\s*([1-9]\d?)(?![a-z0-9])(?!\s*[/&])`, "i");
|
|
28
51
|
var ADULT_CODE = /^\s*a(?:(\d{1,2})(u|o|&o))?\s*$/i;
|
|
29
52
|
var printsAdultCode2 = (phrase) => ADULT_CODE.test(phrase);
|
|
30
|
-
var
|
|
53
|
+
var adultTitleCache = new Map;
|
|
54
|
+
function adultTitleWords(keywords) {
|
|
55
|
+
const p = adultPatterns(keywords);
|
|
56
|
+
const key = `${p.adult}\x00${p.one ?? ""}`;
|
|
57
|
+
const hit = adultTitleCache.get(key);
|
|
58
|
+
if (hit !== undefined)
|
|
59
|
+
return hit;
|
|
60
|
+
const one = p.one === null ? null : p.adult ? `advanced\\s+adults?|${p.one}` : p.one;
|
|
61
|
+
const out = Object.freeze({
|
|
62
|
+
word: one === null ? null : new RegExp(`(?<!non[\\s-])(?<!-)\\b(?:${one})\\b`, "i"),
|
|
63
|
+
code: p.adult
|
|
64
|
+
});
|
|
65
|
+
adultTitleCache.set(key, out);
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
31
68
|
var SENIOR = /(?<!-)\bseniors?\b/i;
|
|
32
69
|
var TITLE_RANGE_MIN2 = 3;
|
|
33
70
|
var TITLE_RANGE_MAX2 = 40;
|
|
@@ -59,7 +96,7 @@ function readJoined(title, s, offset) {
|
|
|
59
96
|
return NONE;
|
|
60
97
|
return at(title, offset, j.index, end, `u${Math.max(...caps)}`);
|
|
61
98
|
}
|
|
62
|
-
function readAnchored(title, s, offset, aside = false) {
|
|
99
|
+
function readAnchored(title, s, offset, adultWord, aside = false) {
|
|
63
100
|
const joined = readJoined(title, s, offset);
|
|
64
101
|
if (joined !== null)
|
|
65
102
|
return joined;
|
|
@@ -106,7 +143,7 @@ function readAnchored(title, s, offset, aside = false) {
|
|
|
106
143
|
const p = OVER_PLUS.exec(s);
|
|
107
144
|
if (p?.[1] !== undefined)
|
|
108
145
|
return at(title, offset, p.index, p.index + p[0].length, `o${Number(p[1])}`);
|
|
109
|
-
const a =
|
|
146
|
+
const a = adultWord?.exec(s) ?? null;
|
|
110
147
|
if (a !== null)
|
|
111
148
|
return at(title, offset, a.index, a.index + a[0].length, "adult");
|
|
112
149
|
const n = SENIOR.exec(s);
|
|
@@ -114,7 +151,8 @@ function readAnchored(title, s, offset, aside = false) {
|
|
|
114
151
|
return at(title, offset, n.index, n.index + n[0].length, "senior");
|
|
115
152
|
return NONE;
|
|
116
153
|
}
|
|
117
|
-
function ageTitleToken2(title) {
|
|
154
|
+
function ageTitleToken2(title, options = {}) {
|
|
155
|
+
const aw = adultTitleWords(options.adultKeywords);
|
|
118
156
|
const s = title.trim();
|
|
119
157
|
if (s === "")
|
|
120
158
|
return NONE;
|
|
@@ -127,7 +165,7 @@ function ageTitleToken2(title) {
|
|
|
127
165
|
const from = lead + (m.index ?? 0) + 1;
|
|
128
166
|
const i = m.index ?? 0;
|
|
129
167
|
const tail = i + m[0].length === s.length && !/[a-z0-9]/i.test(s[i - 1] ?? "");
|
|
130
|
-
const code = tail ? ADULT_CODE.exec(inner) : null;
|
|
168
|
+
const code = tail && aw.code ? ADULT_CODE.exec(inner) : null;
|
|
131
169
|
if (code !== null) {
|
|
132
170
|
const split = code[1] === undefined ? "" : `${/u/i.test(code[2] ?? "") ? "u" : "o"}${code[1]}`;
|
|
133
171
|
const a = inner.length - inner.trimStart().length;
|
|
@@ -136,19 +174,19 @@ function ageTitleToken2(title) {
|
|
|
136
174
|
}
|
|
137
175
|
if (adultWord !== null)
|
|
138
176
|
continue;
|
|
139
|
-
const t = readAnchored(title, inner, from, true);
|
|
177
|
+
const t = readAnchored(title, inner, from, aw.word, true);
|
|
140
178
|
if (t.token === "")
|
|
141
179
|
continue;
|
|
142
180
|
if (t.token === "adult") {
|
|
143
181
|
adultWord = t;
|
|
144
182
|
continue;
|
|
145
183
|
}
|
|
146
|
-
return adultOverUnder(title, s, lead, t);
|
|
184
|
+
return adultOverUnder(title, s, lead, t, aw.word);
|
|
147
185
|
}
|
|
148
186
|
if (adultWord !== null)
|
|
149
187
|
return adultAside ?? adultWord;
|
|
150
|
-
const words = readAnchored(title, s, lead);
|
|
151
|
-
return adultAside !== null && (words.token === "" || words.token === "adult") ? adultAside : adultOverUnder(title, s, lead, words);
|
|
188
|
+
const words = readAnchored(title, s, lead, aw.word);
|
|
189
|
+
return adultAside !== null && (words.token === "" || words.token === "adult") ? adultAside : adultOverUnder(title, s, lead, words, aw.word);
|
|
152
190
|
}
|
|
153
191
|
var ADULT_UNDER_MIN = 18;
|
|
154
192
|
var SENIOR_ADULT_OVER = /\bsenior\s+adult\b/i;
|
|
@@ -172,10 +210,10 @@ function adultBeside2(band) {
|
|
|
172
210
|
return band;
|
|
173
211
|
return Number(floor) < ADULT_UNDER_MIN ? undefined : `adult ${b}`;
|
|
174
212
|
}
|
|
175
|
-
function adultOverUnder(title, s, lead, t) {
|
|
213
|
+
function adultOverUnder(title, s, lead, t, adultWord) {
|
|
176
214
|
if (t.token === "")
|
|
177
215
|
return t;
|
|
178
|
-
const a =
|
|
216
|
+
const a = adultWord?.exec(s) ?? null;
|
|
179
217
|
if (a === null)
|
|
180
218
|
return t;
|
|
181
219
|
if (/^o\d+$/.test(t.token) && SENIOR_ADULT_OVER.test(s))
|
|
@@ -206,9 +244,31 @@ var UNDER2 = /^(?:u|under\s*)(\d+)(?:\/([1-9]\d*)yr)?$/i;
|
|
|
206
244
|
var OVER = /^(?:o|over\s*)(\d+)$/i;
|
|
207
245
|
var AND_OVER2 = /^(\d+)\s*(?:&|and\b)\s*(?:over|o)$/i;
|
|
208
246
|
var RANGE2 = /^u?(\d+)\s*[-–]\s*(\d+)$/i;
|
|
209
|
-
var
|
|
210
|
-
var
|
|
211
|
-
|
|
247
|
+
var LEVEL_WORDS = "first[\\s-]*feis|(?:advanced[\\s-]+)?beginners?(?:[\\s-]*(?:1|2|i|ii))?|novice|prizewinners?|intermediate|advanced|open|prelim(?:inary)?|champions?(?:hip)?s?|champs?";
|
|
248
|
+
var NO_ADULT_WORDS = Object.freeze({
|
|
249
|
+
word: null,
|
|
250
|
+
level: null,
|
|
251
|
+
under: null,
|
|
252
|
+
band: null
|
|
253
|
+
});
|
|
254
|
+
var adultWordsCache = new Map;
|
|
255
|
+
function adultWordsOf(keywords) {
|
|
256
|
+
const p = adultPatterns(keywords);
|
|
257
|
+
if (p.run === null)
|
|
258
|
+
return NO_ADULT_WORDS;
|
|
259
|
+
const hit = adultWordsCache.get(p.run);
|
|
260
|
+
if (hit !== undefined)
|
|
261
|
+
return hit;
|
|
262
|
+
const run = p.run;
|
|
263
|
+
const out = Object.freeze({
|
|
264
|
+
word: new RegExp(`^(?:${run}${p.adult ? "|advanced" : ""})$`, "i"),
|
|
265
|
+
level: new RegExp(`^(?:(?:${LEVEL_WORDS})[\\s-]+(?:${run})|(?:${run})[\\s-]+(?:${LEVEL_WORDS}))$`, "i"),
|
|
266
|
+
under: new RegExp(`^(?:${run})[\\s-]*(?:u|under\\s*)(\\d+)(?:\\/([1-9]\\d*)yr)?$`, "i"),
|
|
267
|
+
band: new RegExp(`^(?:${run})[\\s-]+(\\S.*)$`, "i")
|
|
268
|
+
});
|
|
269
|
+
adultWordsCache.set(p.run, out);
|
|
270
|
+
return out;
|
|
271
|
+
}
|
|
212
272
|
var SENIOR_WORD = /^seniors?$/i;
|
|
213
273
|
var NO_LADDER = Object.freeze({ caps: [], overs: [], ranges: [] });
|
|
214
274
|
function maxWhere(xs, pred) {
|
|
@@ -270,11 +330,11 @@ function strideOf(k) {
|
|
|
270
330
|
const n = Number(k);
|
|
271
331
|
return Number.isInteger(n) && n >= 1 ? n : null;
|
|
272
332
|
}
|
|
273
|
-
function read(token, ladder, top) {
|
|
333
|
+
function read(token, ladder, top, aw) {
|
|
274
334
|
const r = RANGE2.exec(token);
|
|
275
335
|
if (r !== null)
|
|
276
336
|
return readRange(Number(r[1]), Number(r[2]), ladder);
|
|
277
|
-
const au =
|
|
337
|
+
const au = aw.under?.exec(token) ?? null;
|
|
278
338
|
if (au !== null && Number(au[1]) > ADULT_FLOOR2) {
|
|
279
339
|
const k = strideOf(au[2]);
|
|
280
340
|
const hi = Number(au[1]);
|
|
@@ -286,13 +346,13 @@ function read(token, ladder, top) {
|
|
|
286
346
|
parts: k === null ? [hi] : [hi, k]
|
|
287
347
|
};
|
|
288
348
|
}
|
|
289
|
-
const ab = au === null ?
|
|
349
|
+
const ab = au === null ? aw.band?.exec(token) ?? null : null;
|
|
290
350
|
if (ab !== null) {
|
|
291
|
-
const inner = read(ab[1].trim(), { ...ladder, adult: true }, top);
|
|
351
|
+
const inner = read(ab[1].trim(), { ...ladder, adult: true }, top, aw);
|
|
292
352
|
if (inner.kind === "over" || inner.kind === "range")
|
|
293
353
|
return { ...inner, clauses: [...inner.clauses, "adult-band"], adult: true };
|
|
294
354
|
}
|
|
295
|
-
if (au !== null ||
|
|
355
|
+
if (au !== null || aw.word?.test(token) === true || aw.level?.test(token) === true)
|
|
296
356
|
return {
|
|
297
357
|
kind: "adult",
|
|
298
358
|
interval: { lo: ADULT_FLOOR2, hi: Number.POSITIVE_INFINITY },
|
|
@@ -394,7 +454,7 @@ function fromPrint(print, context = {}) {
|
|
|
394
454
|
const ladder = context.ladder ?? NO_LADDER;
|
|
395
455
|
const year = context.year === undefined ? currentYear() : context.year;
|
|
396
456
|
const ag1 = print.trim().toLowerCase();
|
|
397
|
-
const reading = ag1 === "" ? { kind: null, interval: null, refusal: null, clauses: [], parts: [] } : refuseAboveOldest(refuseBelowYoungest(read(print.trim(), ladder, context.top === true)));
|
|
457
|
+
const reading = ag1 === "" ? { kind: null, interval: null, refusal: null, clauses: [], parts: [] } : refuseAboveOldest(refuseBelowYoungest(read(print.trim(), ladder, context.top === true, adultWordsOf(context.adultKeywords))));
|
|
398
458
|
const iv = reading.interval;
|
|
399
459
|
const arm = ag1 === "" ? "empty" : iv === null ? "open" : "band";
|
|
400
460
|
const ag2 = iv !== null ? display(iv) : ag1 === "" ? "" : `${ag1}?`;
|
|
@@ -475,9 +535,11 @@ function fromYOB(from, to = from, context = {}) {
|
|
|
475
535
|
});
|
|
476
536
|
}
|
|
477
537
|
function fromTitle(title, context = {}) {
|
|
478
|
-
const t = ageTitleToken2(title);
|
|
479
|
-
|
|
538
|
+
const t = ageTitleToken2(title, { adultKeywords: context.adultKeywords });
|
|
539
|
+
const age = fromPrint(t.token, { ...context, adultKeywords: TOKEN_ADULT_KEYWORDS });
|
|
540
|
+
return Object.freeze({ age, token: t.token, span: t.span });
|
|
480
541
|
}
|
|
542
|
+
var TOKEN_ADULT_KEYWORDS = Object.freeze(["adult"]);
|
|
481
543
|
var Age2 = Object.freeze({ from: fromPrint, fromYOB, fromTitle });
|
|
482
544
|
function sourceOf(r) {
|
|
483
545
|
const iv = r.interval;
|
|
@@ -669,4 +731,4 @@ function youngFloor2(year, oldest) {
|
|
|
669
731
|
var tooYoungForMajor2 = (year, oldest) => yearsSinceBirth2(year, oldest) < MIN_MAJOR_AGE2;
|
|
670
732
|
var tooYoungForFeis2 = (year, oldest) => yearsSinceBirth2(year, oldest) < MIN_FEIS_AGE2;
|
|
671
733
|
|
|
672
|
-
export { printsUnderOpen2, printsAdultCode2, TITLE_RANGE_MIN2, TITLE_RANGE_MAX2, ageTitleToken2, readsSeniorAdult2, adultBeside2, YOUNGEST_FLOOR2, ADULT_FLOOR2, MAJORS_FLOOR_YEARS2, UNDER_CAP2, UNDER_CAP_MAX_TOP2, YOUNG_FLOOR2, MIN_MAJOR_AGE2, MIN_FEIS_AGE2, YOUNGEST_BAND_TOP2, OLDEST_BAND_FLOOR2, YOB_RANGE2, DANCE_UP_YEARS2, ageOnJanuary12, yearsSinceBirth2, AgeMisuseError2, Age2, birthYearsOfInterval2, ageRelation2, canOverlap2, AVERAGE_AGE_DECIMALS2, roundedMeanHundredths2, isAveraged2, averageAge2, birthYearsDisjoint2, intersectBirthYears2, birthYearsMeet2, underCapApplies2, underCappedYears2, underCapRefuses2, validYOB2, youngFloor2, tooYoungForMajor2, tooYoungForFeis2 };
|
|
734
|
+
export { DEFAULT_ADULT_KEYWORDS2, printsUnderOpen2, printsAdultCode2, TITLE_RANGE_MIN2, TITLE_RANGE_MAX2, ageTitleToken2, readsSeniorAdult2, adultBeside2, YOUNGEST_FLOOR2, ADULT_FLOOR2, MAJORS_FLOOR_YEARS2, UNDER_CAP2, UNDER_CAP_MAX_TOP2, YOUNG_FLOOR2, MIN_MAJOR_AGE2, MIN_FEIS_AGE2, YOUNGEST_BAND_TOP2, OLDEST_BAND_FLOOR2, YOB_RANGE2, DANCE_UP_YEARS2, ageOnJanuary12, yearsSinceBirth2, AgeMisuseError2, Age2, birthYearsOfInterval2, ageRelation2, canOverlap2, AVERAGE_AGE_DECIMALS2, roundedMeanHundredths2, isAveraged2, averageAge2, birthYearsDisjoint2, intersectBirthYears2, birthYearsMeet2, underCapApplies2, underCappedYears2, underCapRefuses2, validYOB2, youngFloor2, tooYoungForMajor2, tooYoungForFeis2 };
|
package/dist/code.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Age2
|
|
3
|
+
} from "./chunks/place-w6d4xfzc.js";
|
|
4
|
+
import {
|
|
5
|
+
populationIn2,
|
|
6
|
+
compTitle2
|
|
7
|
+
} from "./chunks/place-dn6qk21g.js";
|
|
8
|
+
import {
|
|
9
|
+
validity
|
|
10
|
+
} from "./chunks/place-q9kwsmzd.js";
|
|
11
|
+
|
|
12
|
+
var TRAILING = /(?:-[A-Za-z0-9]+|\[[A-Za-z0-9]+\])$/;
|
|
13
|
+
var GROUP = /^([1-7])(\d{2})([A-Za-z]+?)2?$/;
|
|
14
|
+
var OFF_LADDER = new Set(["TR", "TS", "SD", "FD", "FC"]);
|
|
15
|
+
function group(print) {
|
|
16
|
+
let s = print.trim();
|
|
17
|
+
let male = false;
|
|
18
|
+
let female = false;
|
|
19
|
+
for (let m = TRAILING.exec(s);m !== null; m = TRAILING.exec(s)) {
|
|
20
|
+
const t = m[0].toUpperCase();
|
|
21
|
+
if (t === "-M" || t === "[M]")
|
|
22
|
+
male = true;
|
|
23
|
+
if (t === "-F" || t === "[F]")
|
|
24
|
+
female = true;
|
|
25
|
+
s = s.slice(0, m.index);
|
|
26
|
+
}
|
|
27
|
+
const g = GROUP.exec(s);
|
|
28
|
+
if (g === null)
|
|
29
|
+
return null;
|
|
30
|
+
const mm = Number(g[2]);
|
|
31
|
+
const plus50 = mm >= 50 && mm <= 89;
|
|
32
|
+
return {
|
|
33
|
+
digit: g[1],
|
|
34
|
+
letters: g[3].toUpperCase(),
|
|
35
|
+
column: mm === 99 ? null : plus50 ? mm - 50 : mm,
|
|
36
|
+
boys: plus50 || male,
|
|
37
|
+
girls: female
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function groups(print) {
|
|
41
|
+
const out = [];
|
|
42
|
+
for (const part of print.split("/")) {
|
|
43
|
+
const g = group(part);
|
|
44
|
+
if (g === null)
|
|
45
|
+
return null;
|
|
46
|
+
out.push(g);
|
|
47
|
+
}
|
|
48
|
+
return out.length === 0 ? null : out;
|
|
49
|
+
}
|
|
50
|
+
function decode(print, year, codes) {
|
|
51
|
+
const gs = groups(print);
|
|
52
|
+
if (gs === null)
|
|
53
|
+
return null;
|
|
54
|
+
const first = gs[0];
|
|
55
|
+
if (gs.some((g) => g.digit !== first.digit))
|
|
56
|
+
return null;
|
|
57
|
+
const adult = gs.filter((g) => g.column === null).length;
|
|
58
|
+
if (adult > 0 && adult < gs.length)
|
|
59
|
+
return null;
|
|
60
|
+
const level = OFF_LADDER.has(first.letters) ? null : Number(first.digit) * 100;
|
|
61
|
+
const others = codes === null ? [] : codes.flatMap((c) => groups(c) ?? []);
|
|
62
|
+
const boys = gs.every((g) => g.boys);
|
|
63
|
+
const split = others.some((g) => g.digit === first.digit && g.boys);
|
|
64
|
+
const population = gs.some((g) => g.boys) && !boys ? "mixed" : boys ? "boys" : codes === null ? "" : split || first.girls && others.some((g) => g.boys) ? "girls" : "mixed";
|
|
65
|
+
if (adult > 0)
|
|
66
|
+
return { age: Age2.from("Adult", { year }), level, population };
|
|
67
|
+
const cols = gs.map((g) => g.column);
|
|
68
|
+
const lo = Math.min(...cols);
|
|
69
|
+
const hi = Math.max(...cols);
|
|
70
|
+
const series = others.filter((g) => g.digit === first.digit && g.letters === first.letters && g.boys === boys);
|
|
71
|
+
const offered = series.map((g) => g.column).filter((c) => c !== null);
|
|
72
|
+
const top = offered.length > 1 && hi >= Math.max(...offered);
|
|
73
|
+
const band = top ? `O${lo - 1}` : lo === hi ? `U${hi}` : `U${hi}/${hi - lo + 1}yr`;
|
|
74
|
+
return { age: Age2.from(band, { year }), level, population };
|
|
75
|
+
}
|
|
76
|
+
var foldCode = (code) => code.trim().toUpperCase();
|
|
77
|
+
var NO_AGE = Age2.from("", { year: null });
|
|
78
|
+
function createCodeReader(options = {}) {
|
|
79
|
+
const standardized = new Set([...options.standardized ?? []].map((p) => p.trim().toLowerCase()));
|
|
80
|
+
const scheme = (platform) => standardized.has(platform.trim().toLowerCase()) ? "standardized" : "feis-specific";
|
|
81
|
+
function read(code, ctx) {
|
|
82
|
+
const s = scheme(ctx.platform);
|
|
83
|
+
const feis = (ctx.feis ?? "").trim() === "" ? null : ctx.feis.trim();
|
|
84
|
+
const year = ctx.year ?? null;
|
|
85
|
+
const make = (refusal, source, age, level, population, entry) => {
|
|
86
|
+
const v = validity(code.trim() === "", refusal);
|
|
87
|
+
return Object.freeze({
|
|
88
|
+
[Symbol.toStringTag]: "CompCode",
|
|
89
|
+
...v,
|
|
90
|
+
print: code,
|
|
91
|
+
platform: ctx.platform,
|
|
92
|
+
feis,
|
|
93
|
+
scheme: s,
|
|
94
|
+
source: v.isValid() ? source : null,
|
|
95
|
+
age: v.isValid() ? age : NO_AGE,
|
|
96
|
+
level: v.isValid() ? level : null,
|
|
97
|
+
population: v.isValid() ? population : "",
|
|
98
|
+
entry: v.isValid() ? entry : null,
|
|
99
|
+
isComp: () => v.isValid() && age.isAge()
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
const refuse = (r) => make(r, null, NO_AGE, null, "", null);
|
|
103
|
+
if (code.trim() === "")
|
|
104
|
+
return refuse("not-a-code");
|
|
105
|
+
if (feis === null)
|
|
106
|
+
return refuse("no-feis");
|
|
107
|
+
const codes = ctx.codes === undefined ? null : [...ctx.codes];
|
|
108
|
+
if (ctx.syllabus !== undefined && ctx.syllabus.length > 0) {
|
|
109
|
+
const hits = ctx.syllabus.filter((e) => foldCode(e.code) === foldCode(code));
|
|
110
|
+
if (hits.length === 0)
|
|
111
|
+
return refuse("not-in-syllabus");
|
|
112
|
+
if (hits.length > 1)
|
|
113
|
+
return refuse("two-entries");
|
|
114
|
+
const e = hits[0];
|
|
115
|
+
const printed = e.age !== undefined && e.age.trim() !== "" ? Age2.from(e.age, { year }) : null;
|
|
116
|
+
const age = printed?.isAge() === true ? printed : compTitle2(e.title, { year }).age;
|
|
117
|
+
return make(null, "syllabus", age, null, populationIn2(e.title), e);
|
|
118
|
+
}
|
|
119
|
+
if (s === "feis-specific")
|
|
120
|
+
return refuse("feis-specific");
|
|
121
|
+
const decoded = decode(code, year, codes);
|
|
122
|
+
if (decoded === null || !decoded.age.isAge())
|
|
123
|
+
return refuse("not-a-code");
|
|
124
|
+
return make(null, "code", decoded.age, decoded.level, decoded.population, null);
|
|
125
|
+
}
|
|
126
|
+
return Object.freeze({ scheme, read });
|
|
127
|
+
}
|
|
128
|
+
var DEFAULT_CODE_READER = createCodeReader();
|
|
129
|
+
function compCode(code, ctx) {
|
|
130
|
+
return DEFAULT_CODE_READER.read(code, ctx);
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
DEFAULT_CODE_READER,
|
|
134
|
+
compCode,
|
|
135
|
+
createCodeReader
|
|
136
|
+
};
|
package/dist/schedule.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import"./chunks/place-
|
|
1
|
+
import"./chunks/place-w6d4xfzc.js";
|
|
2
2
|
import {
|
|
3
3
|
compTitle2,
|
|
4
4
|
matchTitle2
|
|
5
|
-
} from "./chunks/place-
|
|
5
|
+
} from "./chunks/place-dn6qk21g.js";
|
|
6
6
|
|
|
7
7
|
function hallKey(hall) {
|
|
8
8
|
return hall.normalize("NFKD").replace(/\p{M}/gu, "").toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
package/dist/title.js
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
titleRelation2,
|
|
10
10
|
ladderOf2,
|
|
11
11
|
matchTitle2
|
|
12
|
-
} from "./chunks/place-
|
|
13
|
-
import"./chunks/place-
|
|
12
|
+
} from "./chunks/place-dn6qk21g.js";
|
|
13
|
+
import"./chunks/place-w6d4xfzc.js";
|
|
14
14
|
export {
|
|
15
15
|
codePopulation2 as codePopulation,
|
|
16
16
|
compTitle2 as compTitle,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DEFAULT_ADULT_KEYWORDS: readonly string[];
|
|
2
|
+
export interface AdultPatterns {
|
|
3
|
+
readonly adult: boolean;
|
|
4
|
+
readonly one: string | null;
|
|
5
|
+
readonly run: string | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function adultPatterns(keywords: readonly string[] | undefined): AdultPatterns;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export declare const printsUnderOpen: (print: string) => boolean;
|
|
2
2
|
export declare const printsAdultCode: (phrase: string) => boolean;
|
|
3
|
+
export interface AgeTitleOptions {
|
|
4
|
+
readonly adultKeywords?: readonly string[];
|
|
5
|
+
}
|
|
3
6
|
export declare const TITLE_RANGE_MIN = 3;
|
|
4
7
|
export declare const TITLE_RANGE_MAX = 40;
|
|
5
8
|
export interface AgeTitleSpan {
|
|
@@ -11,6 +14,6 @@ export interface AgeTitleToken {
|
|
|
11
14
|
readonly token: string;
|
|
12
15
|
readonly span: AgeTitleSpan | null;
|
|
13
16
|
}
|
|
14
|
-
export declare function ageTitleToken(title: string): AgeTitleToken;
|
|
17
|
+
export declare function ageTitleToken(title: string, options?: AgeTitleOptions): AgeTitleToken;
|
|
15
18
|
export declare function readsSeniorAdult(title: string, span: AgeTitleSpan): boolean;
|
|
16
19
|
export declare function adultBeside(band: string): string | undefined;
|
|
@@ -20,6 +20,7 @@ export interface AgeContext {
|
|
|
20
20
|
readonly ladder?: AgeLadder;
|
|
21
21
|
readonly year?: number | null;
|
|
22
22
|
readonly top?: boolean;
|
|
23
|
+
readonly adultKeywords?: readonly string[];
|
|
23
24
|
}
|
|
24
25
|
export type AgeArm = "band" | "yob" | "open" | "empty";
|
|
25
26
|
export type AgeKind = "under" | "over" | "range" | "adult" | "senior" | "yob";
|
package/dist/types/age.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
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 {
|
|
4
|
+
export { DEFAULT_ADULT_KEYWORDS } from "./adult-keywords.ts";
|
|
5
|
+
export { type AgeTitleOptions, type AgeTitleSpan, type AgeTitleToken, TITLE_RANGE_MAX, TITLE_RANGE_MIN, adultBeside, ageTitleToken, printsAdultCode, printsUnderOpen, readsSeniorAdult, } from "./age-title.ts";
|
|
5
6
|
export type { AgeArm, AgeClause, AgeComparison, AgeContext, AgeInterval, AgeKind, AgeLadder, AgeMisuse, AgeRefusal, AgeRelation, AgeRelationReason, AgeSource, AgeSpan, BirthYears, EmptyReason, Validated, YOBContext, YoungFloorVerdict, };
|
|
6
7
|
export declare const YOUNGEST_FLOOR = 0;
|
|
7
8
|
export declare const ADULT_FLOOR = 18;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Age } from "./age.ts";
|
|
2
|
+
import { type Population } from "./title.ts";
|
|
3
|
+
import { type Validated } from "./validated.ts";
|
|
4
|
+
export type { EmptyReason, Validated } from "./validated.ts";
|
|
5
|
+
export type CodeScheme = "standardized" | "feis-specific";
|
|
6
|
+
export type CodeRefusal = "no-feis" | "feis-specific" | "not-in-syllabus" | "two-entries" | "not-a-code";
|
|
7
|
+
export interface CodeEntry {
|
|
8
|
+
readonly code: string;
|
|
9
|
+
readonly title: string;
|
|
10
|
+
readonly age?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CodeContext<E extends CodeEntry = CodeEntry> {
|
|
13
|
+
readonly platform: string;
|
|
14
|
+
readonly feis: string | null | undefined;
|
|
15
|
+
readonly year?: number | null;
|
|
16
|
+
readonly syllabus?: readonly E[];
|
|
17
|
+
readonly codes?: Iterable<string>;
|
|
18
|
+
}
|
|
19
|
+
export interface CompCode<E extends CodeEntry = CodeEntry> extends Validated<CodeRefusal> {
|
|
20
|
+
readonly [Symbol.toStringTag]: "CompCode";
|
|
21
|
+
readonly print: string;
|
|
22
|
+
readonly platform: string;
|
|
23
|
+
readonly feis: string | null;
|
|
24
|
+
readonly scheme: CodeScheme;
|
|
25
|
+
readonly source: "syllabus" | "code" | null;
|
|
26
|
+
readonly age: Age;
|
|
27
|
+
readonly level: number | null;
|
|
28
|
+
readonly population: Population | "";
|
|
29
|
+
readonly entry: E | null;
|
|
30
|
+
isComp(): boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface CodeReaderOptions {
|
|
33
|
+
readonly standardized?: Iterable<string>;
|
|
34
|
+
}
|
|
35
|
+
export interface CodeReader {
|
|
36
|
+
scheme(platform: string): CodeScheme;
|
|
37
|
+
read<E extends CodeEntry>(code: string, ctx: CodeContext<E>): CompCode<E>;
|
|
38
|
+
}
|
|
39
|
+
export declare function createCodeReader(options?: CodeReaderOptions): CodeReader;
|
|
40
|
+
export declare const DEFAULT_CODE_READER: CodeReader;
|
|
41
|
+
export declare function compCode<E extends CodeEntry>(code: string, ctx: CodeContext<E>): CompCode<E>;
|
package/dist/types/title.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare function roundFold(print: string): string;
|
|
|
12
12
|
export interface TitleContext {
|
|
13
13
|
readonly year?: number | null;
|
|
14
14
|
readonly ladder?: AgeLadder;
|
|
15
|
+
readonly adultKeywords?: readonly string[];
|
|
15
16
|
}
|
|
16
17
|
export type TitleRefusal = "no-age";
|
|
17
18
|
export interface CompTitle extends Validated<TitleRefusal> {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finbheara/domain",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Places, CLRG regions, school names, ages, dances, competition titles and schedules, and a person's print in its role, as they are printed: read, compared and told apart",
|
|
3
|
+
"version": "0.52.0",
|
|
4
|
+
"description": "Places, CLRG regions, school names, ages, dances, competition titles, codes and schedules, and a person's print in its role, as they are printed: read, compared and told apart",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"places",
|
|
7
7
|
"regions",
|
|
@@ -73,6 +73,10 @@
|
|
|
73
73
|
"types": "./dist/types/schedule.d.ts",
|
|
74
74
|
"default": "./dist/schedule.js"
|
|
75
75
|
},
|
|
76
|
+
"./code": {
|
|
77
|
+
"types": "./dist/types/code.d.ts",
|
|
78
|
+
"default": "./dist/code.js"
|
|
79
|
+
},
|
|
76
80
|
"./package.json": "./package.json"
|
|
77
81
|
},
|
|
78
82
|
"files": ["dist/*.js", "dist/chunks/*.js", "dist/types/**/*.d.ts", "README.md", "LICENSE"],
|
|
@@ -89,7 +93,7 @@
|
|
|
89
93
|
"prepublishOnly": "bun scripts/build.ts && bun scripts/guard-tarball.ts"
|
|
90
94
|
},
|
|
91
95
|
"dependencies": {
|
|
92
|
-
"@finbheara/names": "0.
|
|
96
|
+
"@finbheara/names": "0.25.0"
|
|
93
97
|
},
|
|
94
98
|
"devDependencies": {
|
|
95
99
|
"typescript": "7.0.2"
|