@finbheara/domain 0.48.0 → 0.49.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
@@ -49,7 +49,7 @@ ESM, Node ≥ 22 or Bun ≥ 1.4.2. MIT. Not affiliated with or endorsed by any d
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
- | `@finbheara/domain/title` | `compTitle`, `titleRelation`, `matchTitle`, `ladderOf`, `populationIn`, `populationRelation`, `roundNumbersIn`: a competition title read and matched onto syllabus entries (below) |
52
+ | `@finbheara/domain/title` | `compTitle`, `titleRelation`, `matchTitle`, `ladderOf`, `populationIn`, `populationRelation`, `roundNumbersIn`, `codePopulation`, `secondIn`: a competition title read and matched onto syllabus entries, a code's sex suffix, a second chance (below) |
53
53
  | `@finbheara/domain/schedule` | `scheduleAt`, `sameHall`, `readRunningOrder`, the `ScheduleSlot` type: which entries a hall runs (below) |
54
54
 
55
55
  The library does no I/O and installs nothing process-wide. Every reader has a default and a
@@ -430,6 +430,23 @@ A band split into parallel competitions (`Girls Under 13 A`, `Girls Under 13 B`)
430
430
  split, unless the title prints the letter. A title naming no band names nothing. Hand in the
431
431
  entries of the kind you mean: a solo championship's ages are often a team event's too.
432
432
 
433
+ A code may carry the sex where the title does not. `codePopulation` reads a suffix against every
434
+ code the same event printed, as a letter alone also marks sections and merges: `B` beside `G` of
435
+ the same code (and no `A` or `C` of it) is the boys' and the girls' half, and a trailing `M` is
436
+ boys only beside the code without it. `secondIn` says whether a print names a second chance or a
437
+ supplementary competition beside the main one, from the words alone (`2nd Chance`, `2nd Chc`,
438
+ `Second Chance`, `Supplementary`, `2nd` before `Open` or `Prelim`), never from a code's digit.
439
+
440
+ ```ts
441
+ import { codePopulation, secondIn } from "@finbheara/domain/title";
442
+
443
+ codePopulation("720OCB", ["720OCB", "720OCG"]); // "boys"
444
+ codePopulation("512M", ["512", "512M"]); // "boys"
445
+ codePopulation("713OCM", ["713OCM", "714OC"]); // "": alone, it may be a merge
446
+ secondIn("Preliminary Champion, Supplementary Prelim (U15)"); // true
447
+ secondIn("Preliminary Champion, Hard Shoe (U10)"); // false
448
+ ```
449
+
433
450
  ## Ask a schedule
434
451
 
435
452
  A split band's competitions share their card numbers, so a card heard on a stage fits each of
@@ -24,6 +24,30 @@ function populationIn2(text) {
24
24
  return "boys";
25
25
  return "";
26
26
  }
27
+ function codePopulation2(code, codes) {
28
+ const c = code.trim().toUpperCase();
29
+ const all = new Set;
30
+ for (const x of codes)
31
+ all.add(x.trim().toUpperCase());
32
+ all.add(c);
33
+ if (!/\d/.test(c))
34
+ return "";
35
+ const pair = /^(.*\d[A-Z]*?)([BG])$/.exec(c);
36
+ if (pair !== null) {
37
+ const [, stem, letter] = pair;
38
+ const other = letter === "B" ? "G" : "B";
39
+ if (all.has(stem + other) && !all.has(`${stem}A`) && !all.has(`${stem}C`))
40
+ return letter === "B" ? "boys" : "girls";
41
+ }
42
+ const male = /^(.*\d[A-Z]*?)-?M$/.exec(c);
43
+ if (male !== null && all.has(male[1]))
44
+ return "boys";
45
+ return "";
46
+ }
47
+ var SECOND_WORDS = /\b(?:(?:2nd|second)[\s-]*ch(?:ance|c)?\b|supplementary\b|(?:2nd|second)\s+(?:open|prelim|preliminary)\b)/;
48
+ function secondIn2(text) {
49
+ return SECOND_WORDS.test(toAscii(text).toLowerCase());
50
+ }
27
51
  function roundNumbersIn2(folded, printed) {
28
52
  const out = new Set;
29
53
  for (const m of folded.matchAll(/ rounds? ((?:\d+ (?:and )?)+)/g))
@@ -136,4 +160,4 @@ function matchTitle2(print, entries, ctx = {}) {
136
160
  });
137
161
  }
138
162
 
139
- export { populationIn2, roundNumbersIn2, compTitle2, populationRelation2, titleRelation2, ladderOf2, matchTitle2 };
163
+ export { populationIn2, codePopulation2, secondIn2, roundNumbersIn2, compTitle2, populationRelation2, titleRelation2, ladderOf2, matchTitle2 };
package/dist/schedule.js CHANGED
@@ -2,7 +2,7 @@ import"./chunks/place-kmh59zkw.js";
2
2
  import {
3
3
  compTitle2,
4
4
  matchTitle2
5
- } from "./chunks/place-cdghn4v2.js";
5
+ } from "./chunks/place-k0p9af4f.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
@@ -1,19 +1,23 @@
1
1
  import {
2
2
  populationIn2,
3
+ codePopulation2,
4
+ secondIn2,
3
5
  roundNumbersIn2,
4
6
  compTitle2,
5
7
  populationRelation2,
6
8
  titleRelation2,
7
9
  ladderOf2,
8
10
  matchTitle2
9
- } from "./chunks/place-cdghn4v2.js";
11
+ } from "./chunks/place-k0p9af4f.js";
10
12
  import"./chunks/place-kmh59zkw.js";
11
13
  export {
14
+ codePopulation2 as codePopulation,
12
15
  compTitle2 as compTitle,
13
16
  ladderOf2 as ladderOf,
14
17
  matchTitle2 as matchTitle,
15
18
  populationIn2 as populationIn,
16
19
  populationRelation2 as populationRelation,
17
20
  roundNumbersIn2 as roundNumbersIn,
21
+ secondIn2 as secondIn,
18
22
  titleRelation2 as titleRelation
19
23
  };
@@ -5,6 +5,8 @@ export type { EmptyReason, Validated } from "./validated.ts";
5
5
  export type { AgeComparison, AgeLadder } from "./age.ts";
6
6
  export type Population = "girls" | "boys" | "mixed";
7
7
  export declare function populationIn(text: string): Population | "";
8
+ export declare function codePopulation(code: string, codes: Iterable<string>): Population | "";
9
+ export declare function secondIn(text: string): boolean;
8
10
  export declare function roundNumbersIn(folded: string, printed: boolean): Set<number>;
9
11
  export interface TitleContext {
10
12
  readonly year?: number | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finbheara/domain",
3
- "version": "0.48.0",
3
+ "version": "0.49.0",
4
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",
5
5
  "keywords": [
6
6
  "places",