@finbheara/domain 0.7.0 → 0.8.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
@@ -266,7 +266,10 @@ Age.fromTitle("10-11 Single Jig").token; // "10-11", a band, not
266
266
  Age.fromTitle("Competition 001-013 - Reel").token; // "", a competition number
267
267
  Age.fromTitle("Senior Boys Reel 15&16").token; // "15-16": a range beats the word
268
268
  Age.fromTitle("Beginner Adults Reel U40").token; // "adult u40": the adult band under 40
269
+ Age.fromTitle("Solo Championship - Adult O40").token; // "adult o40": adult, and 40 or over
270
+ Age.fromTitle("Adult Championship 18 - 29").token; // "adult 18-29": adult, and the range
269
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": senior or adult is not settled
270
273
  ```
271
274
 
272
275
  An adult word beside an `Under N` above 18 reads both: `adult u40` is adult (`isAdult()`), with
@@ -274,6 +277,14 @@ the adult floor of 18 and a ceiling of 40, so `Age.from("adult u40", { year: 202
274
277
  1986 to 2007. At `Under 18` the ceiling meets the floor and the word alone is read. Below 18 the
275
278
  youth band stands.
276
279
 
280
+ An adult word beside an and-over from 18 or a range from 18 reads both as well: `adult o40` and
281
+ `adult 18-29` are adult (`isAdult()`), and their `kind`, interval and birth years are the ones the
282
+ band alone reads on the same ladder, a range floored at 18 where no rung sits below it. So
283
+ `Age.from("adult o40", { year: 2026 })` is born 1985 or earlier, as `o40` is. An and-over under
284
+ 18 or a range opening under 18 (`Teen & Adult 13 & Over`) admits youth, and the band stands. A
285
+ title naming the senior rung beside the word (`Senior Adult Ladies 19 & Over`) reads the band
286
+ alone.
287
+
277
288
  An age group is the age on the first of January, so a title that admits the dancer who is
278
289
  `N` (`7 & Under`, `7/U`, `7 Years`) is the `Under N+1` group.
279
290
 
package/dist/age.js CHANGED
@@ -99,13 +99,22 @@ function ageTitleToken(title) {
99
99
  return words.token === "" && adultAside !== null ? adultAside : adultOverUnder(title, s, lead, words);
100
100
  }
101
101
  var ADULT_UNDER_MIN = 18;
102
+ var SENIOR_ADULT = /\bseniors?\s+adults?\b/i;
102
103
  function adultOverUnder(title, s, lead, t) {
104
+ const a = ADULT.exec(s);
105
+ if (a === null)
106
+ return t;
103
107
  const n = /^u(\d+)$/.exec(t.token)?.[1];
104
- if (n === undefined || Number(n) < ADULT_UNDER_MIN)
108
+ if (n !== undefined) {
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))
105
116
  return t;
106
- const a = ADULT.exec(s);
107
- const token = Number(n) > ADULT_UNDER_MIN ? `adult u${n}` : "adult";
108
- return a === null ? t : at(title, lead, a.index, a.index + a[0].length, token);
117
+ return { token: `adult ${t.token}`, span: t.span };
109
118
  }
110
119
 
111
120
  var YOUNGEST_FLOOR = 0;
@@ -127,6 +136,7 @@ var AND_OVER2 = /^(\d+)\s*(?:&|and\b)\s*(?:over|o)$/i;
127
136
  var RANGE2 = /^u?(\d+)\s*[-–]\s*(\d+)$/i;
128
137
  var ADULT_WORD = /^(?:adults?|ad|advanced|masters?)$/i;
129
138
  var ADULT_UNDER = /^(?:adults?|ad)[\s-]*(?:u|under\s*)(\d+)$/i;
139
+ var ADULT_BAND = /^(?:adults?|ad)[\s-]+(\S.*)$/i;
130
140
  var SENIOR_WORD = /^seniors?$/i;
131
141
  var NO_LADDER = Object.freeze({ caps: [], overs: [], ranges: [] });
132
142
  function maxWhere(xs, pred) {
@@ -193,6 +203,12 @@ function read(token, ladder, top) {
193
203
  clauses: ["adult-under-ceiling"],
194
204
  parts: [Number(au[1])]
195
205
  };
206
+ const ab = au === null ? ADULT_BAND.exec(token) : null;
207
+ if (ab !== null) {
208
+ const inner = read(ab[1].trim(), { ...ladder, adult: true }, top);
209
+ if (inner.kind === "over" || inner.kind === "range")
210
+ return { ...inner, clauses: [...inner.clauses, "adult-band"], adult: true };
211
+ }
196
212
  if (au !== null || ADULT_WORD.test(token))
197
213
  return {
198
214
  kind: "adult",
@@ -310,7 +326,7 @@ function fromPrint(print, context = {}) {
310
326
  return b.from !== null && b.from === b.to;
311
327
  },
312
328
  isAndOver: () => iv !== null && iv.hi === Number.POSITIVE_INFINITY,
313
- isAdult: () => reading.kind === "adult",
329
+ isAdult: () => reading.kind === "adult" || reading.adult === true,
314
330
  interval: () => iv,
315
331
  birthYears: (y) => {
316
332
  const at = y ?? year;
@@ -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" | "range-overlapping" | "range-as-under" | "range-top-meets-over" | "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" | "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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finbheara/domain",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Places, CLRG regions, school names, ages and dances as they are printed: read, compared and told apart",
5
5
  "keywords": [
6
6
  "places",
@@ -73,6 +73,6 @@
73
73
  "prepublishOnly": "bun scripts/build.ts && bun scripts/guard-tarball.ts"
74
74
  },
75
75
  "dependencies": {
76
- "@finbheara/names": "0.18.0"
76
+ "@finbheara/names": "0.20.0"
77
77
  }
78
78
  }