@finbheara/archive-client 0.15.1 → 0.16.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 +24 -3
- package/dist/chunks/{index-9r4rw6xq.js → index-zspxdmkd.js} +49 -3
- package/dist/cli.js +1 -1
- package/dist/index.js +7 -1
- package/dist/types/dancers.d.ts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/school-links.d.ts +20 -0
- package/dist/types/schools.d.ts +4 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -184,8 +184,8 @@ s.next; // the next scheduled instance where the release knows one, else n
|
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
A series is asked by any id of it (a feis, instance or brand id, a retired one followed), by a
|
|
187
|
-
host code with or without its year (held codes `<stem><yy>` whose two digits are their own year
|
|
188
|
-
or by a name (a glob, or a plain word read as `*word*`). Two series answer `ambiguous` with both.
|
|
187
|
+
host code with or without its year (held codes `<stem><yy>` whose two digits are their own year,
|
|
188
|
+
never a host id of digits alone, which is a sequence number), or by a name (a glob, or a plain word read as `*word*`). Two series answer `ambiguous` with both.
|
|
189
189
|
A release holds a feis-year once its results are captured and carries no calendar, so `next` is
|
|
190
190
|
`null` today, with the reason.
|
|
191
191
|
|
|
@@ -212,6 +212,26 @@ rows were published under and their rows, so it agrees with each print lookup of
|
|
|
212
212
|
|
|
213
213
|
Every answer carries the release tag it came from.
|
|
214
214
|
|
|
215
|
+
### How two schools are linked
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const l = await rel.schools.links("ostrel-academy", "wyvern-academy", { year: 2026 });
|
|
219
|
+
l.arm; // "self" | "linked" | "none"
|
|
220
|
+
l.candidates; // [{ hops, steps: [{ at, next, link: { from, to, shape, year }, flags }], flags, confidence }]
|
|
221
|
+
|
|
222
|
+
const line = await rel.schools.line("ostrel-academy");
|
|
223
|
+
line.candidates; // every school on its line, nearest first, each with its paths
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The release's school lineage (a rename, an absorption, a merger, a split, or a `related` link of
|
|
227
|
+
unknown type, each dated where a year is known) read by `@finbheara/domain/school-graph`: every
|
|
228
|
+
simple path between two schools, each with its flags (`relatedHops`, `maxYearGap`, `datedAfter`,
|
|
229
|
+
`undated`, `provisional`, `redirected` and the rest), never a yes or a no. Pass a `policy`, your
|
|
230
|
+
reading over those flags, and the answer carries its verdict (`l.policy.passes`), exact however
|
|
231
|
+
many paths are listed. A retired id is followed to the live one. The release publishes no decision
|
|
232
|
+
behind an edge, so a path carries no `confidence` here. A release that publishes no lineage
|
|
233
|
+
refuses both calls by name.
|
|
234
|
+
|
|
215
235
|
## Dancers
|
|
216
236
|
|
|
217
237
|
```ts
|
|
@@ -562,7 +582,8 @@ held feis-year is still read from that feis-year's own competitions.
|
|
|
562
582
|
A feis the release holds names itself, its year and its series. A series instance or brand id
|
|
563
583
|
names the series. A feis id the release does not hold is placed in a series by its host code
|
|
564
584
|
(`<token>:<stem><yy>` where the held codes of that stem carry their own year), and a stem two
|
|
565
|
-
series share answers `ambiguous`. A
|
|
585
|
+
series share answers `ambiguous`. A host id of digits alone (`qf:926`, `fw:1001`) is a sequence
|
|
586
|
+
number and carries no stem: unheld, it is placed nowhere. A held feis-year never falls back to an earlier year, and two
|
|
566
587
|
competitions printing one code are never folded into one.
|
|
567
588
|
|
|
568
589
|
`kind` and `level` are read off the release's published rung (`feis_level`: 100 first feis to
|
|
@@ -244,6 +244,8 @@ class FeisFinder2 {
|
|
|
244
244
|
return { tag: this.rel.tag, feises, ...redirected !== undefined ? { redirected } : {} };
|
|
245
245
|
}
|
|
246
246
|
async codeStem(token, stem) {
|
|
247
|
+
if (/^\d+$/.test(stem))
|
|
248
|
+
return [];
|
|
247
249
|
const db = await this.rel.indexDb("feises");
|
|
248
250
|
const like = db.query("SELECT host_id, year, brand_id FROM feis WHERE token = ? AND host_id LIKE ? ESCAPE '\\' COLLATE NOCASE").all(token, `${stem.replace(/[\\%_]/g, (c) => `\\${c}`)}__`);
|
|
249
251
|
const fits = like.filter((f) => {
|
|
@@ -637,6 +639,41 @@ import {
|
|
|
637
639
|
DEFAULT_SCHOOL_NAME_READER,
|
|
638
640
|
schoolEncoder
|
|
639
641
|
} from "@finbheara/domain/school";
|
|
642
|
+
|
|
643
|
+
import {
|
|
644
|
+
schoolGraph
|
|
645
|
+
} from "@finbheara/domain/school-graph";
|
|
646
|
+
var LINEAGE_FILE2 = "school-lineage.jsonl";
|
|
647
|
+
var REDIRECTS_FILE = "school-redirects.jsonl";
|
|
648
|
+
function linksOfLineage2(lines) {
|
|
649
|
+
const seen = new Map;
|
|
650
|
+
for (const r of lines) {
|
|
651
|
+
if (r.id === r.other)
|
|
652
|
+
continue;
|
|
653
|
+
const [from, to] = r.direction === "succeeds" ? [r.other, r.id] : [r.id, r.other];
|
|
654
|
+
const year = typeof r.year === "number" ? r.year : null;
|
|
655
|
+
const k = `${from}\x00${to}\x00${r.shape}\x00${year}`;
|
|
656
|
+
const was = seen.get(k);
|
|
657
|
+
if (was === undefined)
|
|
658
|
+
seen.set(k, { from, to, shape: r.shape, year, provisional: r.provisional === true });
|
|
659
|
+
else if (r.provisional === true)
|
|
660
|
+
was.provisional = true;
|
|
661
|
+
}
|
|
662
|
+
return [...seen.values()];
|
|
663
|
+
}
|
|
664
|
+
async function releaseSchoolGraph2(rel) {
|
|
665
|
+
await rel.require("schools.lineage");
|
|
666
|
+
await rel.fetch(LINEAGE_FILE2);
|
|
667
|
+
const links = linksOfLineage2(readJsonl(rel.path(LINEAGE_FILE2)));
|
|
668
|
+
const redirects = new Map;
|
|
669
|
+
if (await rel.publishes(REDIRECTS_FILE)) {
|
|
670
|
+
await rel.fetch(REDIRECTS_FILE);
|
|
671
|
+
for (const r of readJsonl(rel.path(REDIRECTS_FILE)))
|
|
672
|
+
redirects.set(r.old_id, r.new_id);
|
|
673
|
+
}
|
|
674
|
+
return schoolGraph({ links, redirect: (id) => redirects.get(id) ?? null });
|
|
675
|
+
}
|
|
676
|
+
|
|
640
677
|
function readsSpanishNames2(candidates) {
|
|
641
678
|
return candidates.some((c) => c.spanishNames !== undefined && (c.spanishNames.file || c.prints.some((p) => c.spanishNames?.prints.includes(p.trim()))));
|
|
642
679
|
}
|
|
@@ -697,9 +734,18 @@ var schoolsIndex = {
|
|
|
697
734
|
|
|
698
735
|
class SchoolResolver2 {
|
|
699
736
|
rel;
|
|
737
|
+
graph;
|
|
700
738
|
constructor(rel) {
|
|
701
739
|
this.rel = rel;
|
|
702
740
|
}
|
|
741
|
+
async links(a, b, q = {}) {
|
|
742
|
+
this.graph ??= releaseSchoolGraph2(this.rel);
|
|
743
|
+
return { tag: this.rel.tag, ...(await this.graph).links(a.trim(), b.trim(), q) };
|
|
744
|
+
}
|
|
745
|
+
async line(a, q = {}) {
|
|
746
|
+
this.graph ??= releaseSchoolGraph2(this.rel);
|
|
747
|
+
return { tag: this.rel.tag, ...(await this.graph).line(a.trim(), q) };
|
|
748
|
+
}
|
|
703
749
|
async resolve(asked, q = {}) {
|
|
704
750
|
const db = await this.rel.indexDb("schools");
|
|
705
751
|
const reg = db.query("SELECT display, regions, places, spanish FROM registry WHERE school_id = ?");
|
|
@@ -1888,7 +1934,7 @@ class CompResolver2 {
|
|
|
1888
1934
|
return this.ofSeries(asked, only, y, "series");
|
|
1889
1935
|
}
|
|
1890
1936
|
const m = /^([^:]+):(.*?)(\d{2})$/.exec(asked);
|
|
1891
|
-
if (m !== null) {
|
|
1937
|
+
if (m !== null && !/^\d+$/.test(`${m[2]}${m[3]}`)) {
|
|
1892
1938
|
const [, token, stem, yy] = m;
|
|
1893
1939
|
const brands = await this.rel.feises.codeStem(token, stem);
|
|
1894
1940
|
const y = year ?? 2000 + Number(yy);
|
|
@@ -3069,7 +3115,7 @@ var FEATURES2 = [
|
|
|
3069
3115
|
feature: "schools.lineage",
|
|
3070
3116
|
needs: ["school-lineage.jsonl"],
|
|
3071
3117
|
since: 184,
|
|
3072
|
-
calls: "the `lineage` school evidence of dancers.resolve and dancers.search: no school is joined by lineage, never refused, on a release without it"
|
|
3118
|
+
calls: "schools.links and schools.line (refused on a release without it), and the `lineage` school evidence of dancers.resolve and dancers.search: no school is joined by lineage, never refused, on a release without it"
|
|
3073
3119
|
},
|
|
3074
3120
|
{
|
|
3075
3121
|
feature: "results.stream",
|
|
@@ -3783,4 +3829,4 @@ function releases2(opts = {}) {
|
|
|
3783
3829
|
return new ReleaseManager2(opts);
|
|
3784
3830
|
}
|
|
3785
3831
|
|
|
3786
|
-
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, canonicalOf2, CompResolver2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, ReleaseManager2, releases2 };
|
|
3832
|
+
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, LINEAGE_FILE2, linksOfLineage2, releaseSchoolGraph2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, canonicalOf2, CompResolver2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, ReleaseManager2, releases2 };
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
FEIS_LOCAL_ID_FLOOR2,
|
|
13
13
|
ResultFinder2,
|
|
14
14
|
MajorsFinder2,
|
|
15
|
+
LINEAGE_FILE2,
|
|
16
|
+
linksOfLineage2,
|
|
17
|
+
releaseSchoolGraph2,
|
|
15
18
|
readsSpanishNames2,
|
|
16
19
|
SchoolResolver2,
|
|
17
20
|
initialsOnly2,
|
|
@@ -47,7 +50,7 @@ import {
|
|
|
47
50
|
openCached2,
|
|
48
51
|
ReleaseManager2,
|
|
49
52
|
releases2
|
|
50
|
-
} from "./chunks/index-
|
|
53
|
+
} from "./chunks/index-zspxdmkd.js";
|
|
51
54
|
import {
|
|
52
55
|
cacheRoot2,
|
|
53
56
|
repoOf2
|
|
@@ -70,6 +73,7 @@ export {
|
|
|
70
73
|
FEATURES2 as FEATURES,
|
|
71
74
|
FEIS_LOCAL_ID_FLOOR2 as FEIS_LOCAL_ID_FLOOR,
|
|
72
75
|
FeisFinder2 as FeisFinder,
|
|
76
|
+
LINEAGE_FILE2 as LINEAGE_FILE,
|
|
73
77
|
MajorsFinder2 as MajorsFinder,
|
|
74
78
|
NAME_LEVELS2 as NAME_LEVELS,
|
|
75
79
|
NO_CALENDAR2 as NO_CALENDAR,
|
|
@@ -98,6 +102,7 @@ export {
|
|
|
98
102
|
indexPath2 as indexPath,
|
|
99
103
|
initialsOnly2 as initialsOnly,
|
|
100
104
|
isCurrent2 as isCurrent,
|
|
105
|
+
linksOfLineage2 as linksOfLineage,
|
|
101
106
|
listIndexes2 as listIndexes,
|
|
102
107
|
nameLevel2 as nameLevel,
|
|
103
108
|
needsRelease2 as needsRelease,
|
|
@@ -110,6 +115,7 @@ export {
|
|
|
110
115
|
readPin2 as readPin,
|
|
111
116
|
readPopulation2 as readPopulation,
|
|
112
117
|
readsSpanishNames2 as readsSpanishNames,
|
|
118
|
+
releaseSchoolGraph2 as releaseSchoolGraph,
|
|
113
119
|
releases2 as releases,
|
|
114
120
|
renderArchiveTag2 as renderArchiveTag,
|
|
115
121
|
repoOf2 as repoOf,
|
package/dist/types/dancers.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { type NameLevel } from "./dancers-names.js";
|
|
|
3
3
|
import type { IndexBuilder } from "./indexes.js";
|
|
4
4
|
import type { Release } from "./release.js";
|
|
5
5
|
import { FEIS_LOCAL_ID_FLOOR } from "./results.js";
|
|
6
|
+
export type Lineage = Map<string, Map<string, number | null>>;
|
|
7
|
+
export declare function schoolLine(lineage: Lineage, ids: readonly string[], year: number | null): Set<string>;
|
|
6
8
|
export declare function initialsOnly(name: PersonName): boolean;
|
|
7
9
|
export { FEIS_LOCAL_ID_FLOOR };
|
|
8
10
|
export type NameOrderAsked = "surname-first" | "given-first" | "unknown";
|
package/dist/types/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export { type OpenOptions, Release, openCached, openRelease, resolveTag, } from
|
|
|
14
14
|
export { type MajorCompetition, type MajorEvent, MajorsFinder, type ResultAnswer, ResultFinder, type ResultQuery, type ResultRow, } from "./results.js";
|
|
15
15
|
export { type DancerAnswerLike, type DancerQueryLike, type DancerResolverLike, type DancerUnavailable, type RegistrationRow, type ResolvedDancer, RegistrationResolver, type ResolvedRegistration, dancerResolverOf, youngest, } from "./registrations.js";
|
|
16
16
|
export { type SchoolAnswer, type SchoolCandidate, type SchoolQuery, SchoolResolver, type SchoolRung, readsSpanishNames, type SpanishNames, } from "./schools.js";
|
|
17
|
+
export { LINEAGE_FILE, type SchoolLineAnswer, type SchoolLinksAnswer, linksOfLineage, releaseSchoolGraph, } from "./school-links.js";
|
|
18
|
+
export type { LineCandidate, LinkPath, LinkPolicy, LinkQuery, LinkStep, PathFlags, SchoolLink, StepFlags, StepPolicy, } from "@finbheara/domain/school-graph";
|
|
17
19
|
export { type Capability, FEATURES, type Feature, type SchemaProbe, capabilityOf, columnsOf, needsRelease, } from "./schema.js";
|
|
18
20
|
export { type EntryRow, type StreamQuery, type StreamRow, type StreamScope, entryRank, } from "./stream.js";
|
|
19
21
|
export { EventFinder, type EventYear, type EventYearQuery, type ResultRoster, type RosterMember, type RosterTeam, TeamFinder, type TeamResult, } from "./teams.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type LineAnswer, type LinkAnswer, type LinkQuery, type SchoolGraph, type SchoolLink } from "@finbheara/domain/school-graph";
|
|
2
|
+
import type { Release } from "./release.js";
|
|
3
|
+
export declare const LINEAGE_FILE = "school-lineage.jsonl";
|
|
4
|
+
interface LineageLine {
|
|
5
|
+
id: string;
|
|
6
|
+
direction: "precedes" | "succeeds";
|
|
7
|
+
other: string;
|
|
8
|
+
shape: string;
|
|
9
|
+
year?: number | null;
|
|
10
|
+
provisional?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function linksOfLineage(lines: Iterable<LineageLine>): SchoolLink[];
|
|
13
|
+
export declare function releaseSchoolGraph(rel: Release): Promise<SchoolGraph>;
|
|
14
|
+
export type SchoolLinksAnswer = LinkAnswer & {
|
|
15
|
+
tag: string;
|
|
16
|
+
};
|
|
17
|
+
export type SchoolLineAnswer = LineAnswer & {
|
|
18
|
+
tag: string;
|
|
19
|
+
};
|
|
20
|
+
export type { LinkQuery };
|
package/dist/types/schools.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type SchoolNameParser } from "@finbheara/domain/school";
|
|
2
2
|
import type { IndexBuilder } from "./indexes.js";
|
|
3
3
|
import type { Release } from "./release.js";
|
|
4
|
+
import { type LinkQuery, type SchoolLineAnswer, type SchoolLinksAnswer } from "./school-links.js";
|
|
4
5
|
export type SchoolRung = "id" | "redirect" | "print" | "sn3" | "realWords";
|
|
5
6
|
export interface SchoolCandidate {
|
|
6
7
|
school_id: string;
|
|
@@ -52,6 +53,9 @@ export declare const GENERIC_SCHOOL_READER: SchoolReaderChoice;
|
|
|
52
53
|
export declare const schoolsIndex: IndexBuilder;
|
|
53
54
|
export declare class SchoolResolver {
|
|
54
55
|
private readonly rel;
|
|
56
|
+
private graph;
|
|
55
57
|
constructor(rel: Release);
|
|
58
|
+
links(a: string, b: string, q?: LinkQuery): Promise<SchoolLinksAnswer>;
|
|
59
|
+
line(a: string, q?: LinkQuery): Promise<SchoolLineAnswer>;
|
|
56
60
|
resolve(asked: string, q?: SchoolQuery): Promise<SchoolAnswer>;
|
|
57
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finbheara/archive-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Open a versioned release of an Irish dance results archive: download, verify, decompress and cache it by tag, keep the cache, and resolve feises and schools against it",
|
|
5
5
|
"keywords": ["irish-dance", "results", "release", "cache", "sqlite"],
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"prepublishOnly": "bun scripts/build.ts && bun ../../tools/checks/archive-client-tarball.ts"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@finbheara/domain": "0.
|
|
48
|
-
"@finbheara/names": "0.
|
|
47
|
+
"@finbheara/domain": "0.56.0",
|
|
48
|
+
"@finbheara/names": "0.28.0",
|
|
49
49
|
"hyparquet": "1.31.2"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|