@finbheara/archive-client 0.33.0 → 0.35.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 +54 -0
- package/dist/chunks/{index-g8ab43kz.js → index-gt7yxxp8.js} +224 -19
- package/dist/cli.js +68 -1
- package/dist/index.js +9 -1
- package/dist/types/calendar.d.ts +79 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/release.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,6 +100,9 @@ c.features; // [{ feature: "dancers", state: "full" | "missing", missing: [...
|
|
|
100
100
|
| `upcoming.feises` | `upcoming.feises`, and the `next` of `feises.series` (null with the reason without it) | 285 |
|
|
101
101
|
| `upcoming.fields`, `upcoming.entrants` | `upcoming.fields`, `upcoming.entrants` (285 and 290 carry the tables empty) | 291 |
|
|
102
102
|
| `upcoming.fields.instance` | the `feis_instance_id` `upcoming.fields` carries; absent, never refused, without it | 320 |
|
|
103
|
+
| `calendar` | `calendar.get`, `calendar.list` | 320 |
|
|
104
|
+
| `calendar.expected` | each calendar stage's `expected`; absent, never refused, without it | 320 |
|
|
105
|
+
| `calendar.next` | `calendar.next` | 320 |
|
|
103
106
|
| `tabs`, `panels` | `tabs.query`, `tabs.stream`; `panels.query` | 184 |
|
|
104
107
|
| `feis-panels` | `feisPanels.query` | 260 |
|
|
105
108
|
| `staff.adjudicators` | `staff.adjudicators` | 230 |
|
|
@@ -752,6 +755,53 @@ the corpus `entrants/` part: its rows are schools' counts (`level_counts`), with
|
|
|
752
755
|
host with a registrant list publishes no such field. An unknown field or version answers no rows and says
|
|
753
756
|
why. On a release without the tables each call refuses by name.
|
|
754
757
|
|
|
758
|
+
## The feis calendar
|
|
759
|
+
|
|
760
|
+
```ts
|
|
761
|
+
const g = await rel.calendar.get("plf.2026"); // an instance, an event-year (`<event><year>`), a retired
|
|
762
|
+
// id, a capture (`fweb:PLF26`) or an occurrence id
|
|
763
|
+
g.via; // "instance" | "formerly" | "feis_id" | "occurrence_id" | null
|
|
764
|
+
g.entries; // [{ feis_instance_id, feis_brand_id, tier, name_printed, date_lo, date_hi, date_source,
|
|
765
|
+
// occurrence_ids, feis_ids, stages: { announced, syllabus, entrants, run, results },
|
|
766
|
+
// terminal, carried, formerly }]
|
|
767
|
+
g.entries[0].stages.results.expected;
|
|
768
|
+
// { date, basis, n, platform } or null: "announced" | "brand" | "platform" |
|
|
769
|
+
// "pooled" | "roster-window" | "unmeasured"
|
|
770
|
+
const l = await rel.calendar.list({ stage: "entrants", state: "observed", from: "2026-11-01" });
|
|
771
|
+
// brand, tier, from, to, stage, state, terminal ("none": still ahead)
|
|
772
|
+
const n = await rel.calendar.next({ brand: "plf" });
|
|
773
|
+
// [{ feis_brand_id, year, run_expected, run_expected_basis, run_expected_n,
|
|
774
|
+
// from_instance_id, from_date }]: a series' next edition no listing names yet
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
ONE ROW PER FEIS INSTANCE, on the id its results carry: a feis-series instance (`<brand>.<year>`),
|
|
778
|
+
announced, held or both, or a rated majors event-year. Each stage (`announced`, `syllabus`,
|
|
779
|
+
`entrants`, `run`, `results`) is `{ state, date, cite }`: `observed` (a capture showed it, `date`
|
|
780
|
+
the day it was first observed, null where no capture dates it, `cite` the capture), `pending` (the
|
|
781
|
+
release holds captures of that kind for the instance's platform, so a later one may show it) or
|
|
782
|
+
`not-captured` (it holds none). A day first observed never moves later from one release to the
|
|
783
|
+
next: a stage an earlier release observed keeps its day, named in `carried` (`["row"]` for a row
|
|
784
|
+
the cut no longer names, kept whole), and a retired id is listed in `formerly`. `terminal` is
|
|
785
|
+
`results`, `withdrawn` (every field withdrawn), `passed-no-results` (its first day is before the
|
|
786
|
+
cut's day), or null for a feis still ahead. Stage dates follow capture timing, not the feis's own
|
|
787
|
+
order: only results after the run is a belief. `get` tries the instance id, then `formerly`, then
|
|
788
|
+
a capture, then an occurrence id, and says which met (`via`). On a release without the table each
|
|
789
|
+
call refuses by name.
|
|
790
|
+
|
|
791
|
+
EXPECTED DAYS (`calendar.expected`): each stage carries `expected`, `{ date, basis, n, platform }`
|
|
792
|
+
or null. `announced` is the listing's own first day; `brand` the series' edition the year before
|
|
793
|
+
plus 364 days, `n` its held years; `platform` a platform's capture lag (the P90 of first results
|
|
794
|
+
capture less last day) or list lead (the median of first day less first list capture), measured
|
|
795
|
+
over the feiseanna run in the 180 days before the cut, `n` at least 10; `pooled` every platform's
|
|
796
|
+
results lags together, for a feis whose hosts have no capture form (`platform` `all`) and, NAMED, in
|
|
797
|
+
place of a platform measured on fewer than 10 (`platform` the host's); `roster-window` a majors event-year
|
|
798
|
+
no capture dates; `unmeasured` no day. A stage still ahead always carries one; an observed stage
|
|
799
|
+
carries the day its estimator gives it where one applies, so the misses can be read. The lags are
|
|
800
|
+
capture's own scrape cadence, re-measured every release. `next` lists each series with two or more
|
|
801
|
+
held years, the last the release's year or the one before, whose next edition is not on the
|
|
802
|
+
calendar: its year and expected first day. It is never an instance: an id is minted only once a
|
|
803
|
+
listing names the edition.
|
|
804
|
+
|
|
755
805
|
## Teachers and adjudicators
|
|
756
806
|
|
|
757
807
|
```ts
|
|
@@ -927,6 +977,10 @@ is passed to the dancer resolver as asked (`rel.dancers`, above).
|
|
|
927
977
|
idq upcoming [--release <spec>] [--state <s,...>] [--feis <id>] [--from <date>] [--to <date>]
|
|
928
978
|
idq upcoming --entrants <field_id> [--version <capture id>]
|
|
929
979
|
idq upcoming --feises [--state upcoming|no-results] [--brand <series>] [--from <date>] [--to <date>]
|
|
980
|
+
idq calendar [--release <spec>] <instance|feis id|occurrence id>
|
|
981
|
+
idq calendar [--brand <series>] [--tier <t>] [--from <date>] [--to <date>] [--stage <s>] [--state <s>]
|
|
982
|
+
[--terminal results|withdrawn|passed-no-results|none]
|
|
983
|
+
idq calendar --next [--brand <series>]
|
|
930
984
|
idq teacher [--release <spec>] <name|TD number>
|
|
931
985
|
idq adjudicator [--release <spec>] <name|TD number>
|
|
932
986
|
idq comp [--release <spec>] <feis> <code> [--year y] [--title t]
|
|
@@ -688,6 +688,60 @@ var FEATURES2 = [
|
|
|
688
688
|
since: 320,
|
|
689
689
|
calls: "upcoming.fields' `feis_instance_id` (absent, never null, without it)"
|
|
690
690
|
},
|
|
691
|
+
{
|
|
692
|
+
feature: "calendar",
|
|
693
|
+
needs: [
|
|
694
|
+
"feis_instance_id",
|
|
695
|
+
"feis_brand_id",
|
|
696
|
+
"tier",
|
|
697
|
+
"name_printed",
|
|
698
|
+
"date_lo",
|
|
699
|
+
"date_hi",
|
|
700
|
+
"date_source",
|
|
701
|
+
"occurrence_ids",
|
|
702
|
+
"feis_ids",
|
|
703
|
+
"announced_state",
|
|
704
|
+
"announced_date",
|
|
705
|
+
"announced_cite",
|
|
706
|
+
"syllabus_state",
|
|
707
|
+
"syllabus_date",
|
|
708
|
+
"syllabus_cite",
|
|
709
|
+
"entrants_state",
|
|
710
|
+
"entrants_date",
|
|
711
|
+
"entrants_cite",
|
|
712
|
+
"run_state",
|
|
713
|
+
"run_date",
|
|
714
|
+
"run_cite",
|
|
715
|
+
"results_state",
|
|
716
|
+
"results_date",
|
|
717
|
+
"results_cite",
|
|
718
|
+
"terminal",
|
|
719
|
+
"carried",
|
|
720
|
+
"formerly"
|
|
721
|
+
].map((c) => `results:feis_calendar.${c}`),
|
|
722
|
+
since: 320,
|
|
723
|
+
calls: "calendar.get, calendar.list"
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
feature: "calendar.expected",
|
|
727
|
+
needs: ["announced", "syllabus", "entrants", "run", "results"].flatMap((st) => ["", "_basis", "_n", "_platform"].map((x) => `results:feis_calendar.${st}_expected${x}`)),
|
|
728
|
+
since: 320,
|
|
729
|
+
calls: "each calendar stage's `expected` (absent, never refused, without it)"
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
feature: "calendar.next",
|
|
733
|
+
needs: [
|
|
734
|
+
"feis_brand_id",
|
|
735
|
+
"year",
|
|
736
|
+
"run_expected",
|
|
737
|
+
"run_expected_basis",
|
|
738
|
+
"run_expected_n",
|
|
739
|
+
"from_instance_id",
|
|
740
|
+
"from_date"
|
|
741
|
+
].map((c) => `results:feis_series_next.${c}`),
|
|
742
|
+
since: 320,
|
|
743
|
+
calls: "calendar.next"
|
|
744
|
+
},
|
|
691
745
|
{
|
|
692
746
|
feature: "upcoming.entrants",
|
|
693
747
|
needs: [
|
|
@@ -3825,6 +3879,155 @@ import {
|
|
|
3825
3879
|
} from "fs";
|
|
3826
3880
|
import { join as join3 } from "path";
|
|
3827
3881
|
|
|
3882
|
+
var CALENDAR_STAGES2 = [
|
|
3883
|
+
"announced",
|
|
3884
|
+
"syllabus",
|
|
3885
|
+
"entrants",
|
|
3886
|
+
"run",
|
|
3887
|
+
"results"
|
|
3888
|
+
];
|
|
3889
|
+
var CALENDAR_STAGE_STATES2 = [
|
|
3890
|
+
"observed",
|
|
3891
|
+
"pending",
|
|
3892
|
+
"not-captured"
|
|
3893
|
+
];
|
|
3894
|
+
var CALENDAR_TERMINALS2 = [
|
|
3895
|
+
"results",
|
|
3896
|
+
"withdrawn",
|
|
3897
|
+
"passed-no-results"
|
|
3898
|
+
];
|
|
3899
|
+
var json = (s, empty) => typeof s === "string" && s !== "" ? JSON.parse(s) : empty;
|
|
3900
|
+
function expectedOf(r, s) {
|
|
3901
|
+
const basis = r[`${s}_expected_basis`];
|
|
3902
|
+
if (basis === null || basis === undefined)
|
|
3903
|
+
return null;
|
|
3904
|
+
const n = r[`${s}_expected_n`];
|
|
3905
|
+
return {
|
|
3906
|
+
date: r[`${s}_expected`] ?? null,
|
|
3907
|
+
basis,
|
|
3908
|
+
n: n === null || n === undefined ? null : Number(n),
|
|
3909
|
+
platform: r[`${s}_expected_platform`] ?? null
|
|
3910
|
+
};
|
|
3911
|
+
}
|
|
3912
|
+
function entryOf2(r, expected) {
|
|
3913
|
+
const stages = Object.fromEntries(CALENDAR_STAGES2.map((s) => [
|
|
3914
|
+
s,
|
|
3915
|
+
{
|
|
3916
|
+
state: r[`${s}_state`],
|
|
3917
|
+
date: r[`${s}_date`] ?? null,
|
|
3918
|
+
cite: r[`${s}_cite`] ?? null,
|
|
3919
|
+
...expected ? { expected: expectedOf(r, s) } : {}
|
|
3920
|
+
}
|
|
3921
|
+
]));
|
|
3922
|
+
return {
|
|
3923
|
+
feis_instance_id: r.feis_instance_id,
|
|
3924
|
+
feis_brand_id: r.feis_brand_id ?? null,
|
|
3925
|
+
tier: r.tier,
|
|
3926
|
+
name_printed: r.name_printed ?? null,
|
|
3927
|
+
date_lo: r.date_lo ?? null,
|
|
3928
|
+
date_hi: r.date_hi ?? null,
|
|
3929
|
+
date_source: r.date_source ?? null,
|
|
3930
|
+
occurrence_ids: json(r.occurrence_ids, []),
|
|
3931
|
+
feis_ids: json(r.feis_ids, []),
|
|
3932
|
+
stages,
|
|
3933
|
+
terminal: r.terminal ?? null,
|
|
3934
|
+
carried: json(r.carried, []),
|
|
3935
|
+
formerly: json(r.formerly, [])
|
|
3936
|
+
};
|
|
3937
|
+
}
|
|
3938
|
+
var holds = (col) => `EXISTS (SELECT 1 FROM json_each(${col}) WHERE value = ?)`;
|
|
3939
|
+
|
|
3940
|
+
class CalendarFinder2 {
|
|
3941
|
+
rel;
|
|
3942
|
+
constructor(rel) {
|
|
3943
|
+
this.rel = rel;
|
|
3944
|
+
}
|
|
3945
|
+
async db() {
|
|
3946
|
+
await this.rel.fetch("results");
|
|
3947
|
+
await this.rel.require("calendar");
|
|
3948
|
+
return this.rel.db("results");
|
|
3949
|
+
}
|
|
3950
|
+
async expected() {
|
|
3951
|
+
return (await this.rel.capability("calendar.expected")).state === "full";
|
|
3952
|
+
}
|
|
3953
|
+
async next(q = {}) {
|
|
3954
|
+
await this.rel.fetch("results");
|
|
3955
|
+
await this.rel.require("calendar.next");
|
|
3956
|
+
const db = this.rel.db("results");
|
|
3957
|
+
const rows = q.brand === undefined ? db.query("SELECT * FROM feis_series_next ORDER BY run_expected, feis_brand_id").all() : db.query("SELECT * FROM feis_series_next WHERE feis_brand_id = ? ORDER BY run_expected").all(q.brand);
|
|
3958
|
+
return {
|
|
3959
|
+
tag: this.rel.tag,
|
|
3960
|
+
next: rows.map((r) => ({
|
|
3961
|
+
feis_brand_id: r.feis_brand_id,
|
|
3962
|
+
year: Number(r.year),
|
|
3963
|
+
run_expected: r.run_expected,
|
|
3964
|
+
run_expected_basis: "brand",
|
|
3965
|
+
run_expected_n: Number(r.run_expected_n),
|
|
3966
|
+
from_instance_id: r.from_instance_id,
|
|
3967
|
+
from_date: r.from_date
|
|
3968
|
+
}))
|
|
3969
|
+
};
|
|
3970
|
+
}
|
|
3971
|
+
async get(id) {
|
|
3972
|
+
const db = await this.db();
|
|
3973
|
+
const ways = [
|
|
3974
|
+
["instance", "feis_instance_id = ?"],
|
|
3975
|
+
["formerly", holds("formerly")],
|
|
3976
|
+
["feis_id", holds("feis_ids")],
|
|
3977
|
+
["occurrence_id", holds("occurrence_ids")]
|
|
3978
|
+
];
|
|
3979
|
+
for (const [via, where] of ways) {
|
|
3980
|
+
const rows = db.query(`SELECT * FROM feis_calendar WHERE ${where} ORDER BY feis_instance_id`).all(id);
|
|
3981
|
+
if (rows.length > 0) {
|
|
3982
|
+
const e = await this.expected();
|
|
3983
|
+
return { tag: this.rel.tag, asked: id, via, entries: rows.map((r) => entryOf2(r, e)) };
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
return {
|
|
3987
|
+
tag: this.rel.tag,
|
|
3988
|
+
asked: id,
|
|
3989
|
+
via: null,
|
|
3990
|
+
entries: [],
|
|
3991
|
+
why: `the calendar names no instance, capture or occurrence "${id}"`
|
|
3992
|
+
};
|
|
3993
|
+
}
|
|
3994
|
+
async list(q = {}) {
|
|
3995
|
+
if (q.stage !== undefined && !CALENDAR_STAGES2.includes(q.stage))
|
|
3996
|
+
throw new Error(`calendar.list: no stage "${q.stage}" (the stages are ${CALENDAR_STAGES2.join(", ")})`);
|
|
3997
|
+
if (q.state !== undefined && !CALENDAR_STAGE_STATES2.includes(q.state))
|
|
3998
|
+
throw new Error(`calendar.list: no state "${q.state}" (the states are ${CALENDAR_STAGE_STATES2.join(", ")})`);
|
|
3999
|
+
if (q.terminal !== undefined && q.terminal !== "none" && !CALENDAR_TERMINALS2.includes(q.terminal))
|
|
4000
|
+
throw new Error(`calendar.list: no terminal "${q.terminal}" (the terminals are ${CALENDAR_TERMINALS2.join(", ")}, none)`);
|
|
4001
|
+
const db = await this.db();
|
|
4002
|
+
const where = [];
|
|
4003
|
+
const args = [];
|
|
4004
|
+
const add = (sql, ...v) => {
|
|
4005
|
+
where.push(sql);
|
|
4006
|
+
args.push(...v);
|
|
4007
|
+
};
|
|
4008
|
+
if (q.brand !== undefined)
|
|
4009
|
+
add("feis_brand_id = ?", q.brand);
|
|
4010
|
+
if (q.tier !== undefined)
|
|
4011
|
+
add("tier = ?", q.tier);
|
|
4012
|
+
if (q.from !== undefined)
|
|
4013
|
+
add("date_lo >= ?", q.from);
|
|
4014
|
+
if (q.to !== undefined)
|
|
4015
|
+
add("date_lo <= ?", q.to);
|
|
4016
|
+
if (q.stage !== undefined)
|
|
4017
|
+
add(`${q.stage}_state = ?`, q.state ?? "observed");
|
|
4018
|
+
else if (q.state !== undefined)
|
|
4019
|
+
add(`(${CALENDAR_STAGES2.map((s) => `${s}_state = ?`).join(" OR ")})`, ...CALENDAR_STAGES2.map(() => q.state));
|
|
4020
|
+
if (q.terminal === "none")
|
|
4021
|
+
add("terminal IS NULL");
|
|
4022
|
+
else if (q.terminal !== undefined)
|
|
4023
|
+
add("terminal = ?", q.terminal);
|
|
4024
|
+
const sql = `SELECT * FROM feis_calendar${where.length > 0 ? ` WHERE ${where.join(" AND ")}` : ""} ORDER BY date_lo IS NULL, date_lo, feis_instance_id`;
|
|
4025
|
+
const rows = db.query(sql).all(...args);
|
|
4026
|
+
const e = await this.expected();
|
|
4027
|
+
return { tag: this.rel.tag, entries: rows.map((r) => entryOf2(r, e)) };
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
|
|
3828
4031
|
import { Age as Age3 } from "@finbheara/domain/age";
|
|
3829
4032
|
import { compTitle as compTitle3 } from "@finbheara/domain/title";
|
|
3830
4033
|
function youngest2(answers) {
|
|
@@ -4125,7 +4328,7 @@ var FIELD_STATES2 = [
|
|
|
4125
4328
|
"withdrawn"
|
|
4126
4329
|
];
|
|
4127
4330
|
var DEPARTURE_REASONS2 = FIELD_STATES2.filter((s) => s !== "pending");
|
|
4128
|
-
var
|
|
4331
|
+
var json2 = (s, empty) => typeof s === "string" && s !== "" ? JSON.parse(s) : empty;
|
|
4129
4332
|
function fieldOf(r) {
|
|
4130
4333
|
const countOnly = r.count_only === 1;
|
|
4131
4334
|
return {
|
|
@@ -4154,19 +4357,19 @@ function fieldOf(r) {
|
|
|
4154
4357
|
why: r.comp_why ?? null
|
|
4155
4358
|
},
|
|
4156
4359
|
state: r.state,
|
|
4157
|
-
flags:
|
|
4158
|
-
results_competitions:
|
|
4159
|
-
results_feis_ids:
|
|
4160
|
-
held_out:
|
|
4360
|
+
flags: json2(r.flags, []),
|
|
4361
|
+
results_competitions: json2(r.results_competitions, []),
|
|
4362
|
+
results_feis_ids: json2(r.results_feis_ids, []),
|
|
4363
|
+
held_out: json2(r.held_out, []),
|
|
4161
4364
|
merged_into: r.merged_into ?? null,
|
|
4162
4365
|
version: r.version,
|
|
4163
|
-
versions:
|
|
4366
|
+
versions: json2(r.versions, []),
|
|
4164
4367
|
captured_date: r.captured_date,
|
|
4165
4368
|
sha256: r.sha256,
|
|
4166
|
-
limits:
|
|
4369
|
+
limits: json2(r.limits, []),
|
|
4167
4370
|
entrants: r.entrants,
|
|
4168
4371
|
stated_rows: r.stated_rows ?? null,
|
|
4169
|
-
printed_total:
|
|
4372
|
+
printed_total: json2(r.printed_total, null)
|
|
4170
4373
|
};
|
|
4171
4374
|
}
|
|
4172
4375
|
function entrantOf(r) {
|
|
@@ -4183,30 +4386,30 @@ function entrantOf(r) {
|
|
|
4183
4386
|
school_printed: r.school_printed ?? null,
|
|
4184
4387
|
school_id: r.school_id ?? null,
|
|
4185
4388
|
school_rung: r.school_rung,
|
|
4186
|
-
school_candidates:
|
|
4187
|
-
competitions:
|
|
4188
|
-
field_ids:
|
|
4189
|
-
level_counts:
|
|
4389
|
+
school_candidates: json2(r.school_candidates, []),
|
|
4390
|
+
competitions: json2(r.competitions, []),
|
|
4391
|
+
field_ids: json2(r.field_ids, []),
|
|
4392
|
+
level_counts: json2(r.level_counts, null),
|
|
4190
4393
|
yob: r.yob ?? null,
|
|
4191
|
-
asked:
|
|
4394
|
+
asked: json2(r.asked, null),
|
|
4192
4395
|
arm: r.arm ?? null,
|
|
4193
|
-
candidates:
|
|
4194
|
-
flags:
|
|
4396
|
+
candidates: json2(r.candidates, []),
|
|
4397
|
+
flags: json2(r.flags, [])
|
|
4195
4398
|
};
|
|
4196
4399
|
}
|
|
4197
4400
|
function feisOf(r) {
|
|
4198
4401
|
return {
|
|
4199
4402
|
occurrence_id: r.occurrence_id,
|
|
4200
|
-
occurrence_ids:
|
|
4403
|
+
occurrence_ids: json2(r.occurrence_ids, []),
|
|
4201
4404
|
name_printed: r.name_printed,
|
|
4202
4405
|
date_lo: r.date_lo,
|
|
4203
4406
|
date_hi: r.date_hi ?? null,
|
|
4204
4407
|
year: r.year,
|
|
4205
|
-
hosts:
|
|
4408
|
+
hosts: json2(r.hosts, []),
|
|
4206
4409
|
feis_brand_id: r.feis_brand_id ?? null,
|
|
4207
4410
|
feis_instance_id: r.feis_instance_id ?? null,
|
|
4208
4411
|
series_basis: r.series_basis,
|
|
4209
|
-
brand_candidates:
|
|
4412
|
+
brand_candidates: json2(r.brand_candidates, []),
|
|
4210
4413
|
captured_id: r.captured_id,
|
|
4211
4414
|
state: r.results_state
|
|
4212
4415
|
};
|
|
@@ -4396,6 +4599,7 @@ class Release2 {
|
|
|
4396
4599
|
teams;
|
|
4397
4600
|
events;
|
|
4398
4601
|
upcoming;
|
|
4602
|
+
calendar;
|
|
4399
4603
|
tabs;
|
|
4400
4604
|
panels;
|
|
4401
4605
|
feisPanels;
|
|
@@ -4422,6 +4626,7 @@ class Release2 {
|
|
|
4422
4626
|
this.teams = new TeamFinder2(this);
|
|
4423
4627
|
this.events = new EventFinder2(this);
|
|
4424
4628
|
this.upcoming = new UpcomingFinder2(this);
|
|
4629
|
+
this.calendar = new CalendarFinder2(this);
|
|
4425
4630
|
this.tabs = new TabFinder2(this);
|
|
4426
4631
|
this.panels = new PanelFinder2(this);
|
|
4427
4632
|
this.feisPanels = new FeisPanelFinder2(this);
|
|
@@ -5145,4 +5350,4 @@ function staleWarning2(answered, latest, floor, tags = [], command = "idq") {
|
|
|
5145
5350
|
return `answered from ${answered}. ${floorTag ?? `cut ${floor.cut}`} is required${why}: run \`${command} use ${floor.cut}\` to get it`;
|
|
5146
5351
|
}
|
|
5147
5352
|
|
|
5148
|
-
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, TabFinder2, PanelFinder2, FeisPanelFinder2, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, rosterOf2, NO_CALENDAR2, NO_UPCOMING2, FeisFinder2, ADVANCEMENT_DANCES2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, LINEAGE_FILE2, linksOfLineage2, releaseSchoolGraph2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, syllabusSourceOf2, canonicalOf2, CompResolver2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, defaultRemote, FIELD_STATES2, DEPARTURE_REASONS2, UpcomingFinder2, resolveTag2, Release2, openRelease2, openCached2, DEFAULT_KEEP2, ReleaseManager2, releases2, LOCAL_DIR2, localRoot2, newerThan2, incomplete2, releaseVersion2, pickBuild2, buildTag2, lacks, openBuild2, sweepBuilds2, LATEST_CHECK_MS2, LATEST_CHECK_BUDGET_MS2, latestCheckPath2, readLatestCheck2, latestCheck2, within, staleWarning2 };
|
|
5353
|
+
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, TabFinder2, PanelFinder2, FeisPanelFinder2, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, rosterOf2, NO_CALENDAR2, NO_UPCOMING2, FeisFinder2, ADVANCEMENT_DANCES2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, LINEAGE_FILE2, linksOfLineage2, releaseSchoolGraph2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, syllabusSourceOf2, canonicalOf2, CompResolver2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, CALENDAR_STAGES2, CALENDAR_STAGE_STATES2, CALENDAR_TERMINALS2, CalendarFinder2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, defaultRemote, FIELD_STATES2, DEPARTURE_REASONS2, UpcomingFinder2, resolveTag2, Release2, openRelease2, openCached2, DEFAULT_KEEP2, ReleaseManager2, releases2, LOCAL_DIR2, localRoot2, newerThan2, incomplete2, releaseVersion2, pickBuild2, buildTag2, lacks, openBuild2, sweepBuilds2, LATEST_CHECK_MS2, LATEST_CHECK_BUDGET_MS2, latestCheckPath2, readLatestCheck2, latestCheck2, within, staleWarning2 };
|
package/dist/cli.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
latestCheck2,
|
|
22
22
|
within,
|
|
23
23
|
staleWarning2
|
|
24
|
-
} from "./chunks/index-
|
|
24
|
+
} from "./chunks/index-gt7yxxp8.js";
|
|
25
25
|
import"./chunks/index-hghdy980.js";
|
|
26
26
|
|
|
27
27
|
var USAGE_HEADER = "usage: idq <verb> [--cache <dir>] [--repo <owner/name>] [--json] [--live]";
|
|
@@ -392,6 +392,25 @@ var VERBS = [
|
|
|
392
392
|
" held-out competitions)"
|
|
393
393
|
]
|
|
394
394
|
},
|
|
395
|
+
{
|
|
396
|
+
verb: "calendar",
|
|
397
|
+
value: ["--release", "--brand", "--tier", "--from", "--to", "--stage", "--state", "--terminal"],
|
|
398
|
+
bool: ["--next"],
|
|
399
|
+
usage: [
|
|
400
|
+
" calendar [--release <spec>] <instance|feis id|occurrence id>",
|
|
401
|
+
" one feis instance's stages: announced, syllabus, entrants,",
|
|
402
|
+
" run and results, each observed, pending or not-captured,",
|
|
403
|
+
" the day first observed and the capture that observed it",
|
|
404
|
+
" calendar [--brand <series>] [--tier T1..T4] [--from <date>] [--to <date>]",
|
|
405
|
+
" [--stage announced|syllabus|entrants|run|results] [--state observed|pending|not-captured]",
|
|
406
|
+
" [--terminal results|withdrawn|passed-no-results|none]",
|
|
407
|
+
" the instances a query names, by first day; each stage's",
|
|
408
|
+
" expected day with its basis and n where the release has them",
|
|
409
|
+
" calendar --next [--brand <series>]",
|
|
410
|
+
" each series' next edition no listing names yet: its year",
|
|
411
|
+
" and expected first day from the year before (basis brand)"
|
|
412
|
+
]
|
|
413
|
+
},
|
|
395
414
|
{
|
|
396
415
|
verb: "teacher",
|
|
397
416
|
value: ["--release"],
|
|
@@ -508,6 +527,7 @@ function parseArgs(argv) {
|
|
|
508
527
|
return { positional, flags, bools };
|
|
509
528
|
}
|
|
510
529
|
var mb = (n) => `${(n / 1e6).toFixed(1)} MB`;
|
|
530
|
+
var expectedText = (e) => e === null || e === undefined ? "" : ` expected ${e.date ?? "-"} (${e.basis}${e.platform !== null ? ` ${e.platform}` : ""}${e.n !== null ? `, n ${e.n}` : ""})`;
|
|
511
531
|
function printPlan(p, say) {
|
|
512
532
|
for (const k of p.keep)
|
|
513
533
|
say(`keep ${k.tag} (${k.why})`);
|
|
@@ -799,6 +819,7 @@ var ANSWERING = new Set([
|
|
|
799
819
|
"teams",
|
|
800
820
|
"events",
|
|
801
821
|
"upcoming",
|
|
822
|
+
"calendar",
|
|
802
823
|
"teacher",
|
|
803
824
|
"adjudicator",
|
|
804
825
|
"comp",
|
|
@@ -1533,6 +1554,52 @@ async function main(argv, io = {}) {
|
|
|
1533
1554
|
rel.close();
|
|
1534
1555
|
}
|
|
1535
1556
|
}
|
|
1557
|
+
case "calendar": {
|
|
1558
|
+
const rel = await open(spec, { ...opts, assets: [] });
|
|
1559
|
+
try {
|
|
1560
|
+
const line = (e) => ` ${e.date_lo ?? "?"} ${e.feis_instance_id} ${e.tier} ${["announced", "syllabus", "entrants", "run", "results"].map((s) => `${s}:${e.stages[s].state === "observed" ? e.stages[s].date ?? "seen" : e.stages[s].state}`).join(" ")} [${e.terminal ?? "ahead"}]${e.name_printed !== null ? ` "${e.name_printed}"` : ""}`;
|
|
1561
|
+
if (p.bools.has("--next")) {
|
|
1562
|
+
const brand = p.flags.get("--brand");
|
|
1563
|
+
const a = await rel.calendar.next(brand === undefined ? {} : { brand });
|
|
1564
|
+
out(a, () => {
|
|
1565
|
+
for (const n of a.next)
|
|
1566
|
+
say(` ${n.run_expected} ${n.feis_brand_id} ${n.year} brand n ${n.run_expected_n} from ${n.from_instance_id} (${n.from_date})`);
|
|
1567
|
+
say(`${a.next.length} next edition(s) in ${a.tag}`);
|
|
1568
|
+
});
|
|
1569
|
+
return a.next.length === 0 ? 1 : 0;
|
|
1570
|
+
}
|
|
1571
|
+
if (rest.length > 0) {
|
|
1572
|
+
const a = await rel.calendar.get(rest.join(" "));
|
|
1573
|
+
out(a, () => {
|
|
1574
|
+
for (const e of a.entries) {
|
|
1575
|
+
say(line(e));
|
|
1576
|
+
for (const s of ["announced", "syllabus", "entrants", "run", "results"])
|
|
1577
|
+
say(` ${s} ${e.stages[s].state} ${e.stages[s].date ?? "-"} ${e.stages[s].cite ?? "-"}${e.carried.includes(s) ? " (carried)" : ""}${expectedText(e.stages[s].expected)}`);
|
|
1578
|
+
}
|
|
1579
|
+
say(`${a.entries.length} instance(s) for "${a.asked}"${a.via !== null ? ` by ${a.via}` : ""}${a.why !== undefined ? ` (${a.why})` : ""} in ${a.tag}`);
|
|
1580
|
+
});
|
|
1581
|
+
return a.entries.length === 0 ? 1 : 0;
|
|
1582
|
+
}
|
|
1583
|
+
const v = (f) => p.flags.get(f);
|
|
1584
|
+
const a = await rel.calendar.list({
|
|
1585
|
+
...v("--brand") !== undefined ? { brand: v("--brand") } : {},
|
|
1586
|
+
...v("--tier") !== undefined ? { tier: v("--tier") } : {},
|
|
1587
|
+
...v("--from") !== undefined ? { from: v("--from") } : {},
|
|
1588
|
+
...v("--to") !== undefined ? { to: v("--to") } : {},
|
|
1589
|
+
...v("--stage") !== undefined ? { stage: v("--stage") } : {},
|
|
1590
|
+
...v("--state") !== undefined ? { state: v("--state") } : {},
|
|
1591
|
+
...v("--terminal") !== undefined ? { terminal: v("--terminal") } : {}
|
|
1592
|
+
});
|
|
1593
|
+
out(a, () => {
|
|
1594
|
+
for (const e of a.entries)
|
|
1595
|
+
say(line(e));
|
|
1596
|
+
say(`${a.entries.length} instance(s) in ${a.tag}`);
|
|
1597
|
+
});
|
|
1598
|
+
return a.entries.length === 0 ? 1 : 0;
|
|
1599
|
+
} finally {
|
|
1600
|
+
rel.close();
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1536
1603
|
case "teacher":
|
|
1537
1604
|
case "adjudicator": {
|
|
1538
1605
|
if (rest.length === 0) {
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,10 @@ import {
|
|
|
44
44
|
ensureIndex2,
|
|
45
45
|
listIndexes2,
|
|
46
46
|
readPin2,
|
|
47
|
+
CALENDAR_STAGES2,
|
|
48
|
+
CALENDAR_STAGE_STATES2,
|
|
49
|
+
CALENDAR_TERMINALS2,
|
|
50
|
+
CalendarFinder2,
|
|
47
51
|
youngest2,
|
|
48
52
|
dancerResolverOf2,
|
|
49
53
|
RegistrationResolver2,
|
|
@@ -76,7 +80,7 @@ import {
|
|
|
76
80
|
readLatestCheck2,
|
|
77
81
|
latestCheck2,
|
|
78
82
|
staleWarning2
|
|
79
|
-
} from "./chunks/index-
|
|
83
|
+
} from "./chunks/index-gt7yxxp8.js";
|
|
80
84
|
import {
|
|
81
85
|
cacheRoot2,
|
|
82
86
|
repoOf2
|
|
@@ -93,6 +97,10 @@ import {
|
|
|
93
97
|
export {
|
|
94
98
|
ADVANCEMENT_DANCES2 as ADVANCEMENT_DANCES,
|
|
95
99
|
ARCHIVE_TAG2 as ARCHIVE_TAG,
|
|
100
|
+
CALENDAR_STAGES2 as CALENDAR_STAGES,
|
|
101
|
+
CALENDAR_STAGE_STATES2 as CALENDAR_STAGE_STATES,
|
|
102
|
+
CALENDAR_TERMINALS2 as CALENDAR_TERMINALS,
|
|
103
|
+
CalendarFinder2 as CalendarFinder,
|
|
96
104
|
CompResolver2 as CompResolver,
|
|
97
105
|
DATABASES2 as DATABASES,
|
|
98
106
|
DEFAULT_KEEP2 as DEFAULT_KEEP,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Release } from "./release.js";
|
|
2
|
+
export type CalendarStage = "announced" | "syllabus" | "entrants" | "run" | "results";
|
|
3
|
+
export declare const CALENDAR_STAGES: readonly CalendarStage[];
|
|
4
|
+
export type CalendarStageState = "observed" | "pending" | "not-captured";
|
|
5
|
+
export declare const CALENDAR_STAGE_STATES: readonly CalendarStageState[];
|
|
6
|
+
export type CalendarTerminal = "results" | "withdrawn" | "passed-no-results";
|
|
7
|
+
export declare const CALENDAR_TERMINALS: readonly CalendarTerminal[];
|
|
8
|
+
export type CalendarExpectedBasis = "announced" | "brand" | "platform" | "pooled" | "roster-window" | "unmeasured";
|
|
9
|
+
export interface CalendarExpected {
|
|
10
|
+
date: string | null;
|
|
11
|
+
basis: CalendarExpectedBasis;
|
|
12
|
+
n: number | null;
|
|
13
|
+
platform: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface CalendarStageValue {
|
|
16
|
+
state: CalendarStageState;
|
|
17
|
+
date: string | null;
|
|
18
|
+
cite: string | null;
|
|
19
|
+
expected?: CalendarExpected | null;
|
|
20
|
+
}
|
|
21
|
+
export interface CalendarEntry {
|
|
22
|
+
feis_instance_id: string;
|
|
23
|
+
feis_brand_id: string | null;
|
|
24
|
+
tier: string;
|
|
25
|
+
name_printed: string | null;
|
|
26
|
+
date_lo: string | null;
|
|
27
|
+
date_hi: string | null;
|
|
28
|
+
date_source: "run" | "announced" | null;
|
|
29
|
+
occurrence_ids: string[];
|
|
30
|
+
feis_ids: string[];
|
|
31
|
+
stages: Record<CalendarStage, CalendarStageValue>;
|
|
32
|
+
terminal: CalendarTerminal | null;
|
|
33
|
+
carried: string[];
|
|
34
|
+
formerly: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface CalendarQuery {
|
|
37
|
+
brand?: string;
|
|
38
|
+
tier?: string;
|
|
39
|
+
from?: string;
|
|
40
|
+
to?: string;
|
|
41
|
+
stage?: CalendarStage;
|
|
42
|
+
state?: CalendarStageState;
|
|
43
|
+
terminal?: CalendarTerminal | "none";
|
|
44
|
+
}
|
|
45
|
+
export interface CalendarAnswer {
|
|
46
|
+
tag: string;
|
|
47
|
+
entries: CalendarEntry[];
|
|
48
|
+
}
|
|
49
|
+
export interface CalendarNext {
|
|
50
|
+
feis_brand_id: string;
|
|
51
|
+
year: number;
|
|
52
|
+
run_expected: string;
|
|
53
|
+
run_expected_basis: "brand";
|
|
54
|
+
run_expected_n: number;
|
|
55
|
+
from_instance_id: string;
|
|
56
|
+
from_date: string;
|
|
57
|
+
}
|
|
58
|
+
export interface CalendarNextAnswer {
|
|
59
|
+
tag: string;
|
|
60
|
+
next: CalendarNext[];
|
|
61
|
+
}
|
|
62
|
+
export interface CalendarGetAnswer {
|
|
63
|
+
tag: string;
|
|
64
|
+
asked: string;
|
|
65
|
+
via: "instance" | "formerly" | "feis_id" | "occurrence_id" | null;
|
|
66
|
+
entries: CalendarEntry[];
|
|
67
|
+
why?: string;
|
|
68
|
+
}
|
|
69
|
+
export declare class CalendarFinder {
|
|
70
|
+
private readonly rel;
|
|
71
|
+
constructor(rel: Release);
|
|
72
|
+
private db;
|
|
73
|
+
private expected;
|
|
74
|
+
next(q?: {
|
|
75
|
+
brand?: string;
|
|
76
|
+
}): Promise<CalendarNextAnswer>;
|
|
77
|
+
get(id: string): Promise<CalendarGetAnswer>;
|
|
78
|
+
list(q?: CalendarQuery): Promise<CalendarAnswer>;
|
|
79
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -26,4 +26,5 @@ export { type EntryRow, type StreamCompetition, type StreamQuery, type StreamRow
|
|
|
26
26
|
export { type FeisPanelSeat, FeisPanelFinder, PanelFinder, type PanelSeat, type RegisterRow, type TabAnswer, TabFinder, type TabQuery, type TabRow, type TabStreamQuery, } from "./tabs.js";
|
|
27
27
|
export { EventFinder, type EventYear, type EventYearQuery, type ResultRoster, type RosterMember, type RosterTeam, TeamFinder, type TeamResult, } from "./teams.js";
|
|
28
28
|
export { type EntrantCandidate, FIELD_STATES, type FieldComp, DEPARTURE_REASONS, type DepartureReason, type FieldState, type HeldOut, type UpcomingDeparture, type UpcomingDepartureAnswer, type UpcomingDepartureQuery, type UpcomingEntrant, type UpcomingEntrantAnswer, type UpcomingEntrantQuery, type UpcomingFeis, type UpcomingFeisAnswer, type UpcomingFeisQuery, type UpcomingFeisState, type UpcomingField, type UpcomingFieldAnswer, type UpcomingFieldQuery, UpcomingFinder, type UpcomingHost, } from "./upcoming.js";
|
|
29
|
+
export { CALENDAR_STAGES, CALENDAR_STAGE_STATES, CALENDAR_TERMINALS, type CalendarAnswer, type CalendarEntry, type CalendarExpected, type CalendarExpectedBasis, type CalendarNext, type CalendarNextAnswer, CalendarFinder, type CalendarGetAnswer, type CalendarQuery, type CalendarStage, type CalendarStageState, type CalendarStageValue, type CalendarTerminal, } from "./calendar.js";
|
|
29
30
|
export { ARCHIVE_TAG, type ArchiveTag, type ReleaseSpec, compareTagsNewestFirst, cutOf, parseArchiveTag, parseReleaseSpec, pickTag, renderArchiveTag, } from "./tag.js";
|
package/dist/types/release.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
2
|
import { type AssetPlan, type LandedFile, type Receipt, type ReleaseManifest } from "./assets.js";
|
|
3
|
+
import { CalendarFinder } from "./calendar.js";
|
|
3
4
|
import { CompResolver } from "./comps.js";
|
|
4
5
|
import { type ClientOptions } from "./config.js";
|
|
5
6
|
import { DancerResolver } from "./dancers.js";
|
|
@@ -47,6 +48,7 @@ export declare class Release {
|
|
|
47
48
|
readonly teams: TeamFinder;
|
|
48
49
|
readonly events: EventFinder;
|
|
49
50
|
readonly upcoming: UpcomingFinder;
|
|
51
|
+
readonly calendar: CalendarFinder;
|
|
50
52
|
readonly tabs: TabFinder;
|
|
51
53
|
readonly panels: PanelFinder;
|
|
52
54
|
readonly feisPanels: FeisPanelFinder;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finbheara/archive-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.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",
|