@sportsdataverse/sdvplot 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/NOTICE.md +94 -0
- package/README.md +908 -2
- package/dist/_web-D7Aa5Rd8.d.ts +69 -0
- package/dist/aaf-GJ3SH34T.js +13 -0
- package/dist/aaf-HCYN5T6Y.js +37 -0
- package/dist/aaf-ZAE5KS2Y.js +13 -0
- package/dist/ahl-E66MDVCU.js +66 -0
- package/dist/ahl-NPQQWZEV.js +249 -0
- package/dist/ahl-QRDU73XX.js +309 -0
- package/dist/axis-CraWQRUJ.d.ts +49 -0
- package/dist/bins.d.ts +174 -0
- package/dist/bins.js +4 -0
- package/dist/bins.js.map +1 -0
- package/dist/cfb-F42SVS4X.js +5000 -0
- package/dist/cfb-P3SHEYRZ.js +692 -0
- package/dist/cfb-WXRZANLP.js +10226 -0
- package/dist/chartjs-surface.d.ts +42 -0
- package/dist/chartjs-surface.js +65 -0
- package/dist/chartjs-surface.js.map +1 -0
- package/dist/chartjs.d.ts +132 -0
- package/dist/chartjs.js +339 -0
- package/dist/chartjs.js.map +1 -0
- package/dist/chunk-4C3GX6QO.js +92 -0
- package/dist/chunk-4C3GX6QO.js.map +1 -0
- package/dist/chunk-C2CDY5OG.js +137 -0
- package/dist/chunk-C2CDY5OG.js.map +1 -0
- package/dist/chunk-E7G7VSLV.js +43 -0
- package/dist/chunk-E7G7VSLV.js.map +1 -0
- package/dist/chunk-J6R2LEJ7.js +58 -0
- package/dist/chunk-J6R2LEJ7.js.map +1 -0
- package/dist/chunk-JJFTD4VB.js +175 -0
- package/dist/chunk-JJFTD4VB.js.map +1 -0
- package/dist/chunk-KKH6ABMA.js +223 -0
- package/dist/chunk-KKH6ABMA.js.map +1 -0
- package/dist/chunk-NLPH2VZT.js +127 -0
- package/dist/chunk-NLPH2VZT.js.map +1 -0
- package/dist/chunk-OKEE4AH6.js +30 -0
- package/dist/chunk-OKEE4AH6.js.map +1 -0
- package/dist/chunk-QY65DUEF.js +306 -0
- package/dist/chunk-QY65DUEF.js.map +1 -0
- package/dist/chunk-RMT2GMFH.js +97 -0
- package/dist/chunk-RMT2GMFH.js.map +1 -0
- package/dist/chunk-SEBO35DV.js +76 -0
- package/dist/chunk-SEBO35DV.js.map +1 -0
- package/dist/chunk-TAXO3VXH.js +556 -0
- package/dist/chunk-TAXO3VXH.js.map +1 -0
- package/dist/chunk-TDNBAEQB.js +105 -0
- package/dist/chunk-TDNBAEQB.js.map +1 -0
- package/dist/cricket-KPCYG2HL.js +493 -0
- package/dist/cricket-NDXLE25B.js +116 -0
- package/dist/cricket-YUUF7P6M.js +160 -0
- package/dist/d3.d.ts +234 -0
- package/dist/d3.js +198 -0
- package/dist/d3.js.map +1 -0
- package/dist/echarts.d.ts +121 -0
- package/dist/echarts.js +228 -0
- package/dist/echarts.js.map +1 -0
- package/dist/echl-3CR4RGFC.js +241 -0
- package/dist/echl-NPC32C23.js +107 -0
- package/dist/echl-PI33DGJC.js +64 -0
- package/dist/export.d.ts +130 -0
- package/dist/export.js +258 -0
- package/dist/export.js.map +1 -0
- package/dist/headshots-B2J_LOO8.d.ts +40 -0
- package/dist/index.d.ts +182 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/interact.d.ts +567 -0
- package/dist/interact.js +809 -0
- package/dist/interact.js.map +1 -0
- package/dist/marks-DH-tQIP-.d.ts +75 -0
- package/dist/mbb-3TRLVW3H.js +3619 -0
- package/dist/mbb-DQUHCHZP.js +5111 -0
- package/dist/mbb-PRAIO2P5.js +371 -0
- package/dist/milb-6IQ6NCEW.js +291 -0
- package/dist/milb-EYY5MD4T.js +1752 -0
- package/dist/milb-EYZ4SZLI.js +797 -0
- package/dist/mlb-4PBUJSVQ.js +35 -0
- package/dist/mlb-FHPY3GQJ.js +701 -0
- package/dist/mlb-REVGL3N2.js +665 -0
- package/dist/nba-ATT775GS.js +485 -0
- package/dist/nba-LKM4UHVU.js +482 -0
- package/dist/nba-YX7PXM3R.js +35 -0
- package/dist/nbagl-3WGZCZ4S.js +37 -0
- package/dist/nbagl-LP4XJRAL.js +229 -0
- package/dist/nbagl-VTTOU7LN.js +499 -0
- package/dist/ncaa_baseball-UV75LNVR.js +2670 -0
- package/dist/ncaa_baseball-VD5J5C72.js +419 -0
- package/dist/ncaa_baseball-YRBS32D6.js +4592 -0
- package/dist/ncaa_mhockey-IMYHS7QS.js +1033 -0
- package/dist/ncaa_mhockey-TXTKWHE3.js +115 -0
- package/dist/ncaa_mhockey-U3MFW5VT.js +663 -0
- package/dist/ncaa_softball-6WR6KS64.js +420 -0
- package/dist/ncaa_softball-RZCTIE56.js +2654 -0
- package/dist/ncaa_softball-VOD4PVGY.js +4599 -0
- package/dist/ncaa_whockey-6XXGUTBK.js +607 -0
- package/dist/ncaa_whockey-AKKYKY67.js +53 -0
- package/dist/ncaa_whockey-KBEKXFBB.js +293 -0
- package/dist/nfl-BDB2HYAR.js +625 -0
- package/dist/nfl-EHYHDLJD.js +37 -0
- package/dist/nfl-VF4NJCHY.js +514 -0
- package/dist/nfl_gsis-UY64JO37.js +4 -0
- package/dist/nhl-6WPHME7H.js +511 -0
- package/dist/nhl-EMIJFZHY.js +884 -0
- package/dist/nhl-ISFUKRFU.js +37 -0
- package/dist/ohl-2FEM554G.js +113 -0
- package/dist/ohl-C5Q4W6JB.js +32 -0
- package/dist/ohl-TQ4J46VC.js +66 -0
- package/dist/phf-H7POU2KW.js +32 -0
- package/dist/phf-K5IFMZUM.js +13 -0
- package/dist/phf-TWJI3BOW.js +20 -0
- package/dist/plot.d.ts +449 -0
- package/dist/plot.js +711 -0
- package/dist/plot.js.map +1 -0
- package/dist/plotly.d.ts +129 -0
- package/dist/plotly.js +360 -0
- package/dist/plotly.js.map +1 -0
- package/dist/pwhl-OX3BO4JI.js +53 -0
- package/dist/pwhl-W44OC3C6.js +17 -0
- package/dist/pwhl-ZJGG3H7W.js +23 -0
- package/dist/qmjhl-5HISEHLL.js +35 -0
- package/dist/qmjhl-DA3UHKE5.js +125 -0
- package/dist/qmjhl-YG4BOQPF.js +614 -0
- package/dist/react.d.ts +101 -0
- package/dist/react.js +164 -0
- package/dist/react.js.map +1 -0
- package/dist/resolve-CQW-jzvr.d.ts +28 -0
- package/dist/selection-D4T3PkRt.d.ts +140 -0
- package/dist/shots.d.ts +364 -0
- package/dist/shots.js +85 -0
- package/dist/shots.js.map +1 -0
- package/dist/soccer-7BH3ZLVL.js +7898 -0
- package/dist/soccer-MRU25OGE.js +2636 -0
- package/dist/soccer-PF4IPPVA.js +12342 -0
- package/dist/surfaces-ChaD9nei.d.ts +38 -0
- package/dist/testing.d.ts +75 -0
- package/dist/testing.js +240 -0
- package/dist/testing.js.map +1 -0
- package/dist/tiers-B6pUBPcE.d.ts +93 -0
- package/dist/types-C7n6gJF3.d.ts +62 -0
- package/dist/ufl-7VLZTLTT.js +143 -0
- package/dist/ufl-CCMBLPSW.js +100 -0
- package/dist/ufl-F2BJRXME.js +16 -0
- package/dist/usfl-4CR5RMZJ.js +32 -0
- package/dist/usfl-LD7HP2YK.js +14 -0
- package/dist/usfl-VU4YSJQD.js +19 -0
- package/dist/ushl-CPG2LB4L.js +73 -0
- package/dist/ushl-PQL6HJAD.js +88 -0
- package/dist/ushl-ZT2ATPHK.js +22 -0
- package/dist/vega.d.ts +85 -0
- package/dist/vega.js +362 -0
- package/dist/vega.js.map +1 -0
- package/dist/wbb-3KHCDYTK.js +5087 -0
- package/dist/wbb-BMX53Q3Q.js +369 -0
- package/dist/wbb-QNRN2CJJ.js +3620 -0
- package/dist/whl-4ATYZWUB.js +97 -0
- package/dist/whl-RVFPL6MH.js +79 -0
- package/dist/whl-Y7ASKYMM.js +28 -0
- package/dist/wnba-FWX5SFVI.js +232 -0
- package/dist/wnba-GX6HZR4B.js +220 -0
- package/dist/wnba-NTMWIPP6.js +20 -0
- package/dist/xfl-43R2JMJK.js +30 -0
- package/dist/xfl-H3BXQPZZ.js +16 -0
- package/dist/xfl-XON7A7FI.js +69 -0
- package/package.json +154 -3
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { hex6, contrast } from './chunk-J6R2LEJ7.js';
|
|
2
|
+
import { loadLeague, preloadAll, LEAGUES, resolveSync, getLeagueSync, MANIFEST_LAST_MODIFIED, INDEX_VERSION } from './chunk-TAXO3VXH.js';
|
|
3
|
+
import { InputError } from './chunk-E7G7VSLV.js';
|
|
4
|
+
|
|
5
|
+
// src/teams.ts
|
|
6
|
+
async function teams(league) {
|
|
7
|
+
if (league) return (await loadLeague(league)).teams;
|
|
8
|
+
await preloadAll();
|
|
9
|
+
return (await Promise.all(LEAGUES.map(loadLeague))).flatMap((d) => d.teams);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/rows.ts
|
|
13
|
+
function rowsFrom(columns) {
|
|
14
|
+
const keys = Object.keys(columns);
|
|
15
|
+
const n = keys.length ? columns[keys[0]].length : 0;
|
|
16
|
+
for (const k of keys) {
|
|
17
|
+
const len = columns[k].length;
|
|
18
|
+
if (len !== n) throw new InputError(`rowsFrom: column "${k}" has length ${len}, expected ${n}`);
|
|
19
|
+
}
|
|
20
|
+
return Array.from({ length: n }, (_, i) => {
|
|
21
|
+
const row = {};
|
|
22
|
+
for (const k of keys) row[k] = columns[k][i];
|
|
23
|
+
return row;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/matchup-colors.ts
|
|
28
|
+
var MIN_DELTA_E = 20;
|
|
29
|
+
var MIN_CONTRAST = 2.5;
|
|
30
|
+
var BACKGROUNDS = { light: "#ffffff", dark: "#181a1b" };
|
|
31
|
+
var NO_COLOR = "#2394fd";
|
|
32
|
+
function lab(hex) {
|
|
33
|
+
const [r, g, b] = [1, 3, 5].map((i) => {
|
|
34
|
+
const s = Number.parseInt(hex.slice(i, i + 2), 16) / 255;
|
|
35
|
+
return s > 0.04045 ? ((s + 0.055) / 1.055) ** 2.4 : s / 12.92;
|
|
36
|
+
});
|
|
37
|
+
const f = (t) => t > 8856e-6 ? t ** (1 / 3) : 7.787 * t + 16 / 116;
|
|
38
|
+
const x = f((r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047);
|
|
39
|
+
const y = f(r * 0.2126 + g * 0.7152 + b * 0.0722);
|
|
40
|
+
const z = f((r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883);
|
|
41
|
+
return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
|
|
42
|
+
}
|
|
43
|
+
function withLightness(hex, L) {
|
|
44
|
+
const [, A, B] = lab(hex);
|
|
45
|
+
const f = (t) => t ** 3 > 8856e-6 ? t ** 3 : (t - 16 / 116) / 7.787;
|
|
46
|
+
const fy = (L + 16) / 116;
|
|
47
|
+
const x = 0.95047 * f(A / 500 + fy);
|
|
48
|
+
const y = f(fy);
|
|
49
|
+
const z = 1.08883 * f(fy - B / 200);
|
|
50
|
+
const lin = [
|
|
51
|
+
x * 3.2406 + y * -1.5372 + z * -0.4986,
|
|
52
|
+
x * -0.9689 + y * 1.8758 + z * 0.0415,
|
|
53
|
+
x * 0.0557 + y * -0.204 + z * 1.057
|
|
54
|
+
];
|
|
55
|
+
return `#${lin.map((v) => {
|
|
56
|
+
const s = v > 31308e-7 ? 1.055 * v ** (1 / 2.4) - 0.055 : 12.92 * v;
|
|
57
|
+
return Math.round(Math.max(0, Math.min(1, s)) * 255).toString(16).padStart(2, "0");
|
|
58
|
+
}).join("")}`;
|
|
59
|
+
}
|
|
60
|
+
function deltaE2000Lab([L1, a1, b1], [L2, a2, b2]) {
|
|
61
|
+
const rad = Math.PI / 180;
|
|
62
|
+
const Cm = (Math.hypot(a1, b1) + Math.hypot(a2, b2)) / 2;
|
|
63
|
+
const G = 0.5 * (1 - Math.sqrt(Cm ** 7 / (Cm ** 7 + 25 ** 7)));
|
|
64
|
+
const a1p = (1 + G) * a1;
|
|
65
|
+
const a2p = (1 + G) * a2;
|
|
66
|
+
const C1p = Math.hypot(a1p, b1);
|
|
67
|
+
const C2p = Math.hypot(a2p, b2);
|
|
68
|
+
const hue = (ap, bp) => ap === 0 && bp === 0 ? 0 : (Math.atan2(bp, ap) / rad + 360) % 360;
|
|
69
|
+
const h1 = hue(a1p, b1);
|
|
70
|
+
const h2 = hue(a2p, b2);
|
|
71
|
+
const dL = L2 - L1;
|
|
72
|
+
const dC = C2p - C1p;
|
|
73
|
+
let dh = 0;
|
|
74
|
+
if (C1p * C2p !== 0)
|
|
75
|
+
dh = Math.abs(h2 - h1) <= 180 ? h2 - h1 : h2 - h1 > 180 ? h2 - h1 - 360 : h2 - h1 + 360;
|
|
76
|
+
const dH = 2 * Math.sqrt(C1p * C2p) * Math.sin(dh * rad / 2);
|
|
77
|
+
const Lm = (L1 + L2) / 2;
|
|
78
|
+
const Cmp = (C1p + C2p) / 2;
|
|
79
|
+
let Hm = h1 + h2;
|
|
80
|
+
if (C1p * C2p !== 0)
|
|
81
|
+
Hm = Math.abs(h1 - h2) <= 180 ? (h1 + h2) / 2 : h1 + h2 < 360 ? (h1 + h2 + 360) / 2 : (h1 + h2 - 360) / 2;
|
|
82
|
+
const T = 1 - 0.17 * Math.cos((Hm - 30) * rad) + 0.24 * Math.cos(2 * Hm * rad) + 0.32 * Math.cos((3 * Hm + 6) * rad) - 0.2 * Math.cos((4 * Hm - 63) * rad);
|
|
83
|
+
const dTheta = 30 * Math.exp(-(((Hm - 275) / 25) ** 2));
|
|
84
|
+
const Rc = 2 * Math.sqrt(Cmp ** 7 / (Cmp ** 7 + 25 ** 7));
|
|
85
|
+
const Sl = 1 + 0.015 * (Lm - 50) ** 2 / Math.sqrt(20 + (Lm - 50) ** 2);
|
|
86
|
+
const Sc = 1 + 0.045 * Cmp;
|
|
87
|
+
const Sh = 1 + 0.015 * Cmp * T;
|
|
88
|
+
const Rt = -Math.sin(2 * dTheta * rad) * Rc;
|
|
89
|
+
return Math.sqrt((dL / Sl) ** 2 + (dC / Sc) ** 2 + (dH / Sh) ** 2 + Rt * (dC / Sc) * (dH / Sh));
|
|
90
|
+
}
|
|
91
|
+
function deltaE2000(a, b) {
|
|
92
|
+
return deltaE2000Lab(lab(a), lab(b));
|
|
93
|
+
}
|
|
94
|
+
function pickPair(candidates, background) {
|
|
95
|
+
const readable = (c) => contrast(c, background) >= MIN_CONTRAST;
|
|
96
|
+
const apart = (x2, y2) => deltaE2000(x2, y2) >= MIN_DELTA_E;
|
|
97
|
+
const dir = lab(background)[0] >= 50 ? -1 : 1;
|
|
98
|
+
const readableVariant = (c) => {
|
|
99
|
+
if (readable(c)) return c;
|
|
100
|
+
const L0 = lab(c)[0];
|
|
101
|
+
for (let k = 1; k <= 100; k++) {
|
|
102
|
+
const v = withLightness(c, L0 + dir * k);
|
|
103
|
+
if (readable(v)) return v;
|
|
104
|
+
}
|
|
105
|
+
return c;
|
|
106
|
+
};
|
|
107
|
+
for (const [x2, y2] of candidates) if (readable(x2) && readable(y2) && apart(x2, y2)) return [x2, y2];
|
|
108
|
+
const variants = candidates.map(([x2, y2]) => [readableVariant(x2), readableVariant(y2)]);
|
|
109
|
+
for (const [x2, y2] of variants) if (apart(x2, y2)) return [x2, y2];
|
|
110
|
+
const [x, y] = variants[0];
|
|
111
|
+
const readableShifts = (c) => {
|
|
112
|
+
const L0 = lab(c)[0];
|
|
113
|
+
const byShift = [];
|
|
114
|
+
for (let k = -100; k <= 100; k++) {
|
|
115
|
+
if (L0 + k < 0 || L0 + k > 100) continue;
|
|
116
|
+
const v = k === 0 ? c : withLightness(c, L0 + k);
|
|
117
|
+
if (!readable(v)) continue;
|
|
118
|
+
byShift[Math.abs(k)] ??= [];
|
|
119
|
+
byShift[Math.abs(k)]?.push(v);
|
|
120
|
+
}
|
|
121
|
+
return byShift;
|
|
122
|
+
};
|
|
123
|
+
const xs = readableShifts(x);
|
|
124
|
+
const ys = readableShifts(y);
|
|
125
|
+
let best = [x, y];
|
|
126
|
+
let bestDE = deltaE2000(x, y);
|
|
127
|
+
for (let total = 1; total <= 200; total++) {
|
|
128
|
+
for (let i = 0; i <= total; i++) {
|
|
129
|
+
for (const hx of xs[i] ?? [])
|
|
130
|
+
for (const hy of ys[total - i] ?? []) {
|
|
131
|
+
const d = deltaE2000(hx, hy);
|
|
132
|
+
if (d >= MIN_DELTA_E) return [hx, hy];
|
|
133
|
+
if (d > bestDE) {
|
|
134
|
+
best = [hx, hy];
|
|
135
|
+
bestDE = d;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return best;
|
|
141
|
+
}
|
|
142
|
+
function matchupColorsSync(teamA, teamB, opts) {
|
|
143
|
+
const { league, theme, ...resolveOpts } = opts;
|
|
144
|
+
const bg = { light: hex6(theme?.light ?? BACKGROUNDS.light), dark: hex6(theme?.dark ?? BACKGROUNDS.dark) };
|
|
145
|
+
const ids = resolveSync([teamA, teamB], league, resolveOpts);
|
|
146
|
+
const rows = getLeagueSync(league).teams;
|
|
147
|
+
const [a, b] = ids.map((id) => {
|
|
148
|
+
const t = id === void 0 ? void 0 : rows.find((r) => r.team_id === id);
|
|
149
|
+
const alt = t?.color_secondary ?? null;
|
|
150
|
+
return { primary: t?.color_primary ?? alt ?? NO_COLOR, alt };
|
|
151
|
+
});
|
|
152
|
+
const candidates = [
|
|
153
|
+
[a.primary, b.primary],
|
|
154
|
+
[a.primary, b.alt],
|
|
155
|
+
[a.alt, b.primary],
|
|
156
|
+
[a.alt, b.alt]
|
|
157
|
+
].filter((p) => p[0] !== null && p[1] !== null);
|
|
158
|
+
return { light: pickPair(candidates, bg.light), dark: pickPair(candidates, bg.dark) };
|
|
159
|
+
}
|
|
160
|
+
async function matchupColors(teamA, teamB, opts) {
|
|
161
|
+
await loadLeague(opts.league);
|
|
162
|
+
return matchupColorsSync(teamA, teamB, opts);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/version.ts
|
|
166
|
+
var VERSION = "0.1.0";
|
|
167
|
+
|
|
168
|
+
// src/versions.ts
|
|
169
|
+
function versions() {
|
|
170
|
+
return { sdvplot: VERSION, index: INDEX_VERSION, manifestLastModified: MANIFEST_LAST_MODIFIED };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { VERSION, matchupColors, matchupColorsSync, rowsFrom, teams, versions };
|
|
174
|
+
//# sourceMappingURL=chunk-JJFTD4VB.js.map
|
|
175
|
+
//# sourceMappingURL=chunk-JJFTD4VB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/teams.ts","../src/rows.ts","../src/matchup-colors.ts","../src/version.ts","../src/versions.ts"],"names":["x","y"],"mappings":"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","file":"chunk-JJFTD4VB.js","sourcesContent":["import { LEAGUES, type League, type Team } from \"./data/index.js\";\nimport { loadLeague, preloadAll } from \"./index-data.js\";\n\n/** All teams for one league, or every league (in `LEAGUES` order) when omitted. */\nexport async function teams(league?: League): Promise<readonly Team[]> {\n if (league) return (await loadLeague(league)).teams;\n await preloadAll();\n return (await Promise.all(LEAGUES.map(loadLeague))).flatMap((d) => d.teams);\n}\n","import { InputError } from \"./errors.js\";\n\n/** Column form → `Row[]` (flat objects, one per index). Columns must be equal length; `{}` → `[]`. */\nexport function rowsFrom(columns: Record<string, readonly unknown[]>): Record<string, unknown>[] {\n const keys = Object.keys(columns);\n const n = keys.length ? (columns[keys[0] as string] as readonly unknown[]).length : 0;\n for (const k of keys) {\n const len = (columns[k] as readonly unknown[]).length;\n if (len !== n) throw new InputError(`rowsFrom: column \"${k}\" has length ${len}, expected ${n}`);\n }\n return Array.from({ length: n }, (_, i) => {\n const row: Record<string, unknown> = {};\n for (const k of keys) row[k] = (columns[k] as readonly unknown[])[i];\n return row;\n });\n}\n","import { contrast, hex6 } from \"./contrast.js\";\nimport { getLeagueSync, loadLeague } from \"./index-data.js\";\nimport { type ResolveOptions, type Value, resolveSync } from \"./resolve.js\";\nimport type { League } from \"./types.js\";\n\n// Port of Game on Paper's game colours (`pickGameColors`, astro/src/utils/misc.ts at b8b8eaad): its Lab\n// conversion, candidate order, thresholds and fallbacks, kept operation for operation so the pairs match\n// its output exactly (fixtures/matchup-colors).\n\nconst MIN_DELTA_E = 20;\nconst MIN_CONTRAST = 2.5;\n/** Game on Paper's page backgrounds (`GAME_BACKGROUNDS`). */\nconst BACKGROUNDS = { light: \"#ffffff\", dark: \"#181a1b\" } as const;\n/** A team with no colour gets Game on Paper's `STANDARD_THEME_COLOR`. */\nconst NO_COLOR = \"#2394fd\";\n\ntype Lab = [number, number, number];\n\n/** CIE L*a*b* (D65) of `#rrggbb`: Game on Paper's `rgb2lab`, with its rounded constants. */\nfunction lab(hex: string): Lab {\n const [r, g, b] = [1, 3, 5].map((i) => {\n const s = Number.parseInt(hex.slice(i, i + 2), 16) / 255;\n return s > 0.04045 ? ((s + 0.055) / 1.055) ** 2.4 : s / 12.92;\n }) as Lab;\n const f = (t: number) => (t > 0.008856 ? t ** (1 / 3) : 7.787 * t + 16 / 116);\n const x = f((r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047);\n const y = f(r * 0.2126 + g * 0.7152 + b * 0.0722);\n const z = f((r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883);\n return [116 * y - 16, 500 * (x - y), 200 * (y - z)];\n}\n\n/** `hex` with its L* set to `L` (a*, b* kept), clamped into sRGB: Game on Paper's `lab2rgb` + `rgbArrayToHex`. */\nfunction withLightness(hex: string, L: number): string {\n const [, A, B] = lab(hex);\n const f = (t: number) => (t ** 3 > 0.008856 ? t ** 3 : (t - 16 / 116) / 7.787);\n const fy = (L + 16) / 116;\n const x = 0.95047 * f(A / 500 + fy);\n const y = f(fy);\n const z = 1.08883 * f(fy - B / 200);\n const lin = [\n x * 3.2406 + y * -1.5372 + z * -0.4986,\n x * -0.9689 + y * 1.8758 + z * 0.0415,\n x * 0.0557 + y * -0.204 + z * 1.057,\n ];\n return `#${lin\n .map((v) => {\n const s = v > 0.0031308 ? 1.055 * v ** (1 / 2.4) - 0.055 : 12.92 * v;\n return Math.round(Math.max(0, Math.min(1, s)) * 255)\n .toString(16)\n .padStart(2, \"0\");\n })\n .join(\"\")}`;\n}\n\n/** CIEDE2000 colour difference between two L*a*b* colours (Sharma, Wu and Dalal 2005). */\nexport function deltaE2000Lab([L1, a1, b1]: Lab, [L2, a2, b2]: Lab): number {\n const rad = Math.PI / 180;\n const Cm = (Math.hypot(a1, b1) + Math.hypot(a2, b2)) / 2;\n const G = 0.5 * (1 - Math.sqrt(Cm ** 7 / (Cm ** 7 + 25 ** 7)));\n const a1p = (1 + G) * a1;\n const a2p = (1 + G) * a2;\n const C1p = Math.hypot(a1p, b1);\n const C2p = Math.hypot(a2p, b2);\n const hue = (ap: number, bp: number) => (ap === 0 && bp === 0 ? 0 : (Math.atan2(bp, ap) / rad + 360) % 360);\n const h1 = hue(a1p, b1);\n const h2 = hue(a2p, b2);\n const dL = L2 - L1;\n const dC = C2p - C1p;\n let dh = 0;\n if (C1p * C2p !== 0)\n dh = Math.abs(h2 - h1) <= 180 ? h2 - h1 : h2 - h1 > 180 ? h2 - h1 - 360 : h2 - h1 + 360;\n const dH = 2 * Math.sqrt(C1p * C2p) * Math.sin((dh * rad) / 2);\n const Lm = (L1 + L2) / 2;\n const Cmp = (C1p + C2p) / 2;\n let Hm = h1 + h2;\n if (C1p * C2p !== 0)\n Hm = Math.abs(h1 - h2) <= 180 ? (h1 + h2) / 2 : h1 + h2 < 360 ? (h1 + h2 + 360) / 2 : (h1 + h2 - 360) / 2;\n const T =\n 1 -\n 0.17 * Math.cos((Hm - 30) * rad) +\n 0.24 * Math.cos(2 * Hm * rad) +\n 0.32 * Math.cos((3 * Hm + 6) * rad) -\n 0.2 * Math.cos((4 * Hm - 63) * rad);\n const dTheta = 30 * Math.exp(-(((Hm - 275) / 25) ** 2));\n const Rc = 2 * Math.sqrt(Cmp ** 7 / (Cmp ** 7 + 25 ** 7));\n const Sl = 1 + (0.015 * (Lm - 50) ** 2) / Math.sqrt(20 + (Lm - 50) ** 2);\n const Sc = 1 + 0.045 * Cmp;\n const Sh = 1 + 0.015 * Cmp * T;\n const Rt = -Math.sin(2 * dTheta * rad) * Rc;\n return Math.sqrt((dL / Sl) ** 2 + (dC / Sc) ** 2 + (dH / Sh) ** 2 + Rt * (dC / Sc) * (dH / Sh));\n}\n\n/** CIEDE2000 between two `#rrggbb` colours, through Game on Paper's Lab conversion. */\nexport function deltaE2000(a: string, b: string): number {\n return deltaE2000Lab(lab(a), lab(b));\n}\n\n/** Game on Paper's `pickPairOn`: the first usable candidate, else L* moved until the pair reads and separates. */\nfunction pickPair(candidates: [string, string][], background: string): [string, string] {\n const readable = (c: string) => contrast(c, background) >= MIN_CONTRAST;\n const apart = (x: string, y: string) => deltaE2000(x, y) >= MIN_DELTA_E;\n // the side with room to read: darker on a light background, lighter on a dark one\n const dir = lab(background)[0] >= 50 ? -1 : 1;\n // nearest L* at which the colour reads on this background\n const readableVariant = (c: string) => {\n if (readable(c)) return c;\n const L0 = lab(c)[0];\n for (let k = 1; k <= 100; k++) {\n const v = withLightness(c, L0 + dir * k);\n if (readable(v)) return v;\n }\n return c;\n };\n\n for (const [x, y] of candidates) if (readable(x) && readable(y) && apart(x, y)) return [x, y];\n const variants = candidates.map(([x, y]): [string, string] => [readableVariant(x), readableVariant(y)]);\n for (const [x, y] of variants) if (apart(x, y)) return [x, y];\n\n // move both colours' L* within the range where each still reads, least total movement first;\n // keep the widest readable separation seen in case nothing clears\n const [x, y] = variants[0] as [string, string];\n const readableShifts = (c: string) => {\n const L0 = lab(c)[0];\n const byShift: string[][] = []; // byShift[|k|] = readable variants moved |k| in L*\n for (let k = -100; k <= 100; k++) {\n if (L0 + k < 0 || L0 + k > 100) continue;\n const v = k === 0 ? c : withLightness(c, L0 + k);\n if (!readable(v)) continue;\n byShift[Math.abs(k)] ??= [];\n byShift[Math.abs(k)]?.push(v);\n }\n return byShift;\n };\n const xs = readableShifts(x);\n const ys = readableShifts(y);\n let best: [string, string] = [x, y];\n let bestDE = deltaE2000(x, y);\n for (let total = 1; total <= 200; total++) {\n for (let i = 0; i <= total; i++) {\n for (const hx of xs[i] ?? [])\n for (const hy of ys[total - i] ?? []) {\n const d = deltaE2000(hx, hy);\n if (d >= MIN_DELTA_E) return [hx, hy];\n if (d > bestDE) {\n best = [hx, hy];\n bestDE = d;\n }\n }\n }\n }\n return best;\n}\n\n/** Options for {@link matchupColors}: the league, how to resolve the two teams, and the backgrounds. */\nexport interface MatchupColorOptions extends ResolveOptions {\n /** The league both teams belong to. */\n league: League;\n /** The background each theme's pair must read on; default `{ light: \"#ffffff\", dark: \"#181a1b\" }` (Game on Paper's pages). */\n theme?: { light?: string; dark?: string };\n}\n/** One `[teamA, teamB]` colour pair per theme, as lowercase `#rrggbb`. */\nexport interface MatchupColors {\n /** The pair for a light background. */\n light: [string, string];\n /** The pair for a dark background. */\n dark: [string, string];\n}\n\n/**\n * {@link matchupColors} once the league is loaded (`loadLeague` or `preloadAll`).\n *\n * @example\n * ```ts\n * import { loadLeague, matchupColorsSync } from \"@sportsdataverse/sdvplot\";\n *\n * await loadLeague(\"cfb\");\n * matchupColorsSync(\"Alabama\", \"Georgia\", { league: \"cfb\" });\n * ```\n */\nexport function matchupColorsSync(teamA: Value, teamB: Value, opts: MatchupColorOptions): MatchupColors {\n const { league, theme, ...resolveOpts } = opts;\n const bg = { light: hex6(theme?.light ?? BACKGROUNDS.light), dark: hex6(theme?.dark ?? BACKGROUNDS.dark) };\n const ids = resolveSync([teamA, teamB], league, resolveOpts);\n const rows = getLeagueSync(league).teams;\n const [a, b] = ids.map((id) => {\n const t = id === undefined ? undefined : rows.find((r) => r.team_id === id);\n const alt = t?.color_secondary ?? null;\n return { primary: t?.color_primary ?? alt ?? NO_COLOR, alt };\n }) as [{ primary: string; alt: string | null }, { primary: string; alt: string | null }];\n // both primaries, teamB's alternate, teamA's alternate, both alternates\n const candidates = [\n [a.primary, b.primary],\n [a.primary, b.alt],\n [a.alt, b.primary],\n [a.alt, b.alt],\n ].filter((p): p is [string, string] => p[0] !== null && p[1] !== null);\n return { light: pickPair(candidates, bg.light), dark: pickPair(candidates, bg.dark) };\n}\n\n/**\n * Two team colours that tell the teams apart on a chart: Game on Paper's \"game colours\" picker.\n *\n * @remarks\n * One pair per theme, each the first candidate whose colours are at least 20 apart in CIEDE2000 and each\n * at least 2.5:1 (WCAG) against that theme's background. Candidates, in order: both primaries, teamB's\n * secondary, teamA's secondary, both secondaries; so a team keeps its primary whenever it works, and teamA\n * (Game on Paper's home team) keeps it first. When no candidate works, an unreadable colour's L* moves just\n * far enough to read; then both colours' L* move, least total movement first, until they separate; failing\n * that, the widest readable separation found. A team with no colour gets `#2394fd`. Deterministic.\n *\n * @example\n * ```ts\n * import { matchupColors } from \"@sportsdataverse/sdvplot\";\n *\n * // two crimson teams; light: [\"#9e1b32\", \"#2c2a29\"] (Georgia's secondary), dark: [\"#ffffff\", \"#ba0c2f\"]\n * // in a page, pick the pair for the theme:\n * // const [alabama, georgia] = window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? dark : light;\n * await matchupColors(\"Alabama\", \"Georgia\", { league: \"cfb\" });\n * ```\n */\nexport async function matchupColors(\n teamA: Value,\n teamB: Value,\n opts: MatchupColorOptions,\n): Promise<MatchupColors> {\n await loadLeague(opts.league);\n return matchupColorsSync(teamA, teamB, opts);\n}\n","// Injected from package.json by tsup/vitest `define`, so changesets version bumps reach versions().\nexport const VERSION: string = __SDVPLOT_VERSION__;\n","import { INDEX_VERSION, MANIFEST_LAST_MODIFIED } from \"./data/index.js\";\nimport { VERSION } from \"./version.js\";\n\nexport function versions(): { sdvplot: string; index: string; manifestLastModified: string } {\n return { sdvplot: VERSION, index: INDEX_VERSION, manifestLastModified: MANIFEST_LAST_MODIFIED };\n}\n"]}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { archiveUrl, normSeason, getLeagueSync, resolveSync, loadLeague, VARIANTS } from './chunk-TAXO3VXH.js';
|
|
2
|
+
import { DownloadError, warn, UnresolvedTeamError, InputError } from './chunk-E7G7VSLV.js';
|
|
3
|
+
|
|
4
|
+
// src/rank.ts
|
|
5
|
+
var SOURCE_RANK = {
|
|
6
|
+
espn: 0,
|
|
7
|
+
nflverse: 1,
|
|
8
|
+
nhl: 1,
|
|
9
|
+
mlbstatic: 1,
|
|
10
|
+
fox: 1,
|
|
11
|
+
hockeytech: 2,
|
|
12
|
+
cricinfo: 2,
|
|
13
|
+
"ncaa.com": 3,
|
|
14
|
+
"nwhl.co": 4,
|
|
15
|
+
shiftstats: 4,
|
|
16
|
+
wayback: 4,
|
|
17
|
+
"aaf.com": 5,
|
|
18
|
+
"aaf-strip-crop": 6
|
|
19
|
+
};
|
|
20
|
+
var desc = (a, b) => a === b ? 0 : a === null ? 1 : b === null ? -1 : a < b ? 1 : -1;
|
|
21
|
+
function compareMarks(a, b) {
|
|
22
|
+
return a.source_rank - b.source_rank || Number(a.valid_to !== null) - Number(b.valid_to !== null) || desc(a.valid_to, b.valid_to) || desc(a.first_seen, b.first_seen) || desc(a.valid_from, b.valid_from) || (a.sha256 < b.sha256 ? -1 : a.sha256 > b.sha256 ? 1 : 0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/manifest.ts
|
|
26
|
+
var MANIFEST_URL = "https://sdv.nyc3.cdn.digitaloceanspaces.com/assets/public/manifest/marks.csv";
|
|
27
|
+
var safeArchive = (m) => /^[0-9a-f]{64}$/.test(m.sha256) && /^[a-z0-9]+$/.test(m.ext) && m.archive_url === archiveUrl(m.sha256, m.ext);
|
|
28
|
+
function parseManifestCsv(text) {
|
|
29
|
+
const src = text.replace(/^\uFEFF/, "");
|
|
30
|
+
const records = [];
|
|
31
|
+
let rec = [];
|
|
32
|
+
let cur = "";
|
|
33
|
+
let q = false;
|
|
34
|
+
const endRecord = () => {
|
|
35
|
+
rec.push(cur);
|
|
36
|
+
cur = "";
|
|
37
|
+
if (rec.length > 1 || rec[0] !== "") records.push(rec);
|
|
38
|
+
rec = [];
|
|
39
|
+
};
|
|
40
|
+
for (let i = 0; i < src.length; i++) {
|
|
41
|
+
const c = src[i];
|
|
42
|
+
if (q) {
|
|
43
|
+
if (c !== '"') cur += c;
|
|
44
|
+
else if (src[i + 1] === '"') {
|
|
45
|
+
cur += '"';
|
|
46
|
+
i++;
|
|
47
|
+
} else q = false;
|
|
48
|
+
} else if (c === '"') q = true;
|
|
49
|
+
else if (c === ",") {
|
|
50
|
+
rec.push(cur);
|
|
51
|
+
cur = "";
|
|
52
|
+
} else if (c === "\n") endRecord();
|
|
53
|
+
else if (c === "\r" && src[i + 1] === "\n") continue;
|
|
54
|
+
else cur += c;
|
|
55
|
+
}
|
|
56
|
+
if (cur !== "" || rec.length > 0) endRecord();
|
|
57
|
+
const header = records[0] ?? [];
|
|
58
|
+
return records.slice(1).map((f) => {
|
|
59
|
+
const r = {};
|
|
60
|
+
header.forEach((h, i) => {
|
|
61
|
+
r[h] = f[i] ?? "";
|
|
62
|
+
});
|
|
63
|
+
return r;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
var int = (s) => s === "" ? null : Number.parseInt(s, 10);
|
|
67
|
+
var key = (source, id) => `${source}:${id}`.trim().toLowerCase();
|
|
68
|
+
function markAliases(aliases) {
|
|
69
|
+
const by = /* @__PURE__ */ new Map();
|
|
70
|
+
for (const a of aliases) {
|
|
71
|
+
if (a.id_system !== "mark") continue;
|
|
72
|
+
const k = a.value.trim().toLowerCase();
|
|
73
|
+
const e = by.get(k) ?? {
|
|
74
|
+
teams: /* @__PURE__ */ new Set(),
|
|
75
|
+
from: null,
|
|
76
|
+
to: null,
|
|
77
|
+
anyOpenFrom: false,
|
|
78
|
+
anyOpenTo: false
|
|
79
|
+
};
|
|
80
|
+
e.teams.add(a.team_id);
|
|
81
|
+
if (a.valid_from === null) e.anyOpenFrom = true;
|
|
82
|
+
else e.from = e.from === null ? a.valid_from : Math.min(e.from, a.valid_from);
|
|
83
|
+
if (a.valid_to === null) e.anyOpenTo = true;
|
|
84
|
+
else e.to = e.to === null ? a.valid_to : Math.max(e.to, a.valid_to);
|
|
85
|
+
by.set(k, e);
|
|
86
|
+
}
|
|
87
|
+
const out = /* @__PURE__ */ new Map();
|
|
88
|
+
for (const [k, e] of by)
|
|
89
|
+
if (e.teams.size === 1)
|
|
90
|
+
out.set(k, {
|
|
91
|
+
team_id: [...e.teams][0],
|
|
92
|
+
from: e.anyOpenFrom ? null : e.from,
|
|
93
|
+
to: e.anyOpenTo ? null : e.to
|
|
94
|
+
});
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
function manifestMarks(league, rows, aliases) {
|
|
98
|
+
const ma = markAliases(aliases);
|
|
99
|
+
const out = [];
|
|
100
|
+
for (const m of rows) {
|
|
101
|
+
if (m.level !== "team" || m.league !== league || !safeArchive(m)) continue;
|
|
102
|
+
const a = ma.get(key(m.source, m.entity_id));
|
|
103
|
+
if (!a) continue;
|
|
104
|
+
const vf = int(m.valid_from);
|
|
105
|
+
const vt = int(m.valid_to);
|
|
106
|
+
out.push({
|
|
107
|
+
team_id: a.team_id,
|
|
108
|
+
mark_type: m.mark_type,
|
|
109
|
+
variant: m.variant,
|
|
110
|
+
valid_from: vf === null ? a.from : a.from === null ? vf : Math.max(vf, a.from),
|
|
111
|
+
// pl.max_horizontal (nulls ignored)
|
|
112
|
+
valid_to: vt === null ? a.to : a.to === null ? vt : Math.min(vt, a.to),
|
|
113
|
+
// pl.min_horizontal
|
|
114
|
+
source: m.source,
|
|
115
|
+
first_seen: m.first_seen,
|
|
116
|
+
sha256: m.sha256,
|
|
117
|
+
ext: m.ext,
|
|
118
|
+
width: int(m.width),
|
|
119
|
+
height: int(m.height),
|
|
120
|
+
source_rank: SOURCE_RANK[m.source] ?? 5,
|
|
121
|
+
// after height: the shard generator's JSON key order
|
|
122
|
+
archive_url: archiveUrl(m.sha256, m.ext)
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return out.sort(compareMarks);
|
|
126
|
+
}
|
|
127
|
+
var cached;
|
|
128
|
+
function resetManifestCache() {
|
|
129
|
+
cached = void 0;
|
|
130
|
+
}
|
|
131
|
+
function fetchManifest(o = {}) {
|
|
132
|
+
const f = o.fetch ?? globalThis.fetch;
|
|
133
|
+
cached ??= (async () => {
|
|
134
|
+
const r = await f(MANIFEST_URL);
|
|
135
|
+
if (!r.ok)
|
|
136
|
+
throw new DownloadError(
|
|
137
|
+
`manifest download failed: ${MANIFEST_URL} answered ${r.status}`,
|
|
138
|
+
MANIFEST_URL,
|
|
139
|
+
r.status
|
|
140
|
+
);
|
|
141
|
+
return parseManifestCsv(await r.text());
|
|
142
|
+
})().catch((e) => {
|
|
143
|
+
cached = void 0;
|
|
144
|
+
throw e;
|
|
145
|
+
});
|
|
146
|
+
return cached;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/marks.ts
|
|
150
|
+
var ro = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
151
|
+
var repr = (v) => typeof v === "string" ? `'${v}'` : String(v);
|
|
152
|
+
var covers = (lo, hi, s) => (lo === null || s >= lo) && (hi === null || s <= hi);
|
|
153
|
+
function checkMarkType(markType) {
|
|
154
|
+
if (markType !== "logo" && markType !== "wordmark")
|
|
155
|
+
throw new InputError(`markType must be "logo" or "wordmark", got ${JSON.stringify(markType)}`);
|
|
156
|
+
}
|
|
157
|
+
function checkVariant(variant, league, d) {
|
|
158
|
+
if (variant === "default" || variant === "dark") return;
|
|
159
|
+
if (VARIANTS.includes(variant)) return;
|
|
160
|
+
const known = [...new Set(d.marks.map((m) => m.variant))].sort();
|
|
161
|
+
throw new InputError(
|
|
162
|
+
`unknown variant ${JSON.stringify(variant)} for ${league}; use "default", "dark" or one of ${known.join(", ")}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
function selectMarkSync(team, league, o = {}) {
|
|
166
|
+
const markType = o.markType ?? "logo";
|
|
167
|
+
const variant = o.variant ?? "default";
|
|
168
|
+
checkMarkType(markType);
|
|
169
|
+
const s = normSeason(o.season, league);
|
|
170
|
+
const d = getLeagueSync(league);
|
|
171
|
+
checkVariant(variant, league, d);
|
|
172
|
+
const teamId = resolveSync(team, league, { season: s });
|
|
173
|
+
if (teamId === void 0) return void 0;
|
|
174
|
+
const rows = d.marks.filter((r) => r.team_id === teamId && r.mark_type === markType);
|
|
175
|
+
const side = variant === "dark" ? "dark" : "light";
|
|
176
|
+
const polarity = (v) => v === `on_${side}` || v.endsWith(`_on_${side}`);
|
|
177
|
+
const requested = (v) => v === variant;
|
|
178
|
+
const dflt = (v) => v === "default";
|
|
179
|
+
const order = side === "dark" ? [requested, polarity, dflt] : [requested, dflt, polarity];
|
|
180
|
+
for (const keep of [...order, null]) {
|
|
181
|
+
const found = keep ? rows.filter((r) => keep(r.variant)) : rows;
|
|
182
|
+
if (s !== null) {
|
|
183
|
+
const covering = found.filter((r) => covers(r.valid_from, r.valid_to, s));
|
|
184
|
+
const dated = covering.filter((r) => r.valid_from !== null || r.valid_to !== null);
|
|
185
|
+
for (const set of [dated, covering]) if (set.length) return set[0];
|
|
186
|
+
}
|
|
187
|
+
if (found.length) return found[0];
|
|
188
|
+
}
|
|
189
|
+
return void 0;
|
|
190
|
+
}
|
|
191
|
+
async function selectMark(team, league, o = {}) {
|
|
192
|
+
await loadLeague(league);
|
|
193
|
+
return selectMarkSync(team, league, o);
|
|
194
|
+
}
|
|
195
|
+
function logoUrlSync(team, league, o = {}) {
|
|
196
|
+
const markType = o.markType ?? "logo";
|
|
197
|
+
checkMarkType(markType);
|
|
198
|
+
checkVariant(o.variant ?? "default", league, getLeagueSync(league));
|
|
199
|
+
const teamId = resolveSync(team, league, ro({ season: o.season, idSystem: o.idSystem, strict: o.strict }));
|
|
200
|
+
if (teamId === void 0) return void 0;
|
|
201
|
+
const row = selectMarkSync(teamId, league, o);
|
|
202
|
+
if (row === void 0) {
|
|
203
|
+
warn(`marks:${league}:${teamId}:${markType}`, `no ${markType} archived for ${repr(team)} (${league})`);
|
|
204
|
+
return void 0;
|
|
205
|
+
}
|
|
206
|
+
return row.archive_url;
|
|
207
|
+
}
|
|
208
|
+
async function logoUrl(team, league, o = {}) {
|
|
209
|
+
await loadLeague(league);
|
|
210
|
+
return logoUrlSync(team, league, o);
|
|
211
|
+
}
|
|
212
|
+
async function marks(team, league, o = {}) {
|
|
213
|
+
const d = await loadLeague(league);
|
|
214
|
+
const teamId = resolveSync(team, league, ro({ season: o.season, idSystem: o.idSystem, strict: true }));
|
|
215
|
+
if (teamId === void 0) throw new UnresolvedTeamError(`marks() needs a team, got ${String(team)}`);
|
|
216
|
+
if (!o.full) return d.marks.filter((r) => r.team_id === teamId);
|
|
217
|
+
const fo = o.fetch === void 0 ? {} : { fetch: o.fetch };
|
|
218
|
+
return manifestMarks(league, await fetchManifest(fo), d.aliases).filter((r) => r.team_id === teamId);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export { MANIFEST_URL, compareMarks, fetchManifest, logoUrl, logoUrlSync, manifestMarks, marks, parseManifestCsv, resetManifestCache, selectMark, selectMarkSync };
|
|
222
|
+
//# sourceMappingURL=chunk-KKH6ABMA.js.map
|
|
223
|
+
//# sourceMappingURL=chunk-KKH6ABMA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rank.ts","../src/manifest.ts","../src/marks.ts"],"names":[],"mappings":";;;;AACO,IAAM,WAAA,GAAgD;AAAA,EAC3D,IAAA,EAAM,CAAA;AAAA,EACN,QAAA,EAAU,CAAA;AAAA,EACV,GAAA,EAAK,CAAA;AAAA,EACL,SAAA,EAAW,CAAA;AAAA,EACX,GAAA,EAAK,CAAA;AAAA,EACL,UAAA,EAAY,CAAA;AAAA,EACZ,QAAA,EAAU,CAAA;AAAA,EACV,UAAA,EAAY,CAAA;AAAA,EACZ,SAAA,EAAW,CAAA;AAAA,EACX,UAAA,EAAY,CAAA;AAAA,EACZ,OAAA,EAAS,CAAA;AAAA,EACT,SAAA,EAAW,CAAA;AAAA,EACX,gBAAA,EAAkB;AACpB,CAAA;AASA,IAAM,IAAA,GAAO,CAA4B,CAAA,EAAa,CAAA,KACpD,MAAM,CAAA,GAAI,CAAA,GAAI,CAAA,KAAM,IAAA,GAAO,IAAI,CAAA,KAAM,IAAA,GAAO,EAAA,GAAK,CAAA,GAAI,IAAI,CAAA,GAAI,EAAA;AAExD,SAAS,YAAA,CAAa,GAAa,CAAA,EAAqB;AAC7D,EAAA,OACE,EAAE,WAAA,GAAc,CAAA,CAAE,eAClB,MAAA,CAAO,CAAA,CAAE,aAAa,IAAI,CAAA,GAAI,MAAA,CAAO,CAAA,CAAE,aAAa,IAAI,CAAA,IACxD,KAAK,CAAA,CAAE,QAAA,EAAU,EAAE,QAAQ,CAAA,IAC3B,IAAA,CAAK,CAAA,CAAE,YAAY,CAAA,CAAE,UAAU,KAC/B,IAAA,CAAK,CAAA,CAAE,YAAY,CAAA,CAAE,UAAU,MAC9B,CAAA,CAAE,MAAA,GAAS,EAAE,MAAA,GAAS,EAAA,GAAK,EAAE,MAAA,GAAS,CAAA,CAAE,SAAS,CAAA,GAAI,CAAA,CAAA;AAE1D;;;AChCO,IAAM,YAAA,GAAe;AAoBrB,IAAM,cAAc,CAAC,CAAA,KAC1B,iBAAiB,IAAA,CAAK,CAAA,CAAE,MAAM,CAAA,IAC9B,aAAA,CAAc,KAAK,CAAA,CAAE,GAAG,KACxB,CAAA,CAAE,WAAA,KAAgB,WAAW,CAAA,CAAE,MAAA,EAAQ,EAAE,GAAG,CAAA;AAGvC,SAAS,iBAAiB,IAAA,EAA6B;AAC5D,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA;AACtC,EAAA,MAAM,UAAsB,EAAC;AAC7B,EAAA,IAAI,MAAgB,EAAC;AACrB,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,IAAI,CAAA,GAAI,KAAA;AACR,EAAA,MAAM,YAAY,MAAY;AAC5B,IAAA,GAAA,CAAI,KAAK,GAAG,CAAA;AACZ,IAAA,GAAA,GAAM,EAAA;AACN,IAAA,IAAI,GAAA,CAAI,SAAS,CAAA,IAAK,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,EAAI,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA;AACrD,IAAA,GAAA,GAAM,EAAC;AAAA,EACT,CAAA;AACA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,QAAQ,CAAA,EAAA,EAAK;AACnC,IAAA,MAAM,CAAA,GAAI,IAAI,CAAC,CAAA;AACf,IAAA,IAAI,CAAA,EAAG;AACL,MAAA,IAAI,CAAA,KAAM,KAAK,GAAA,IAAO,CAAA;AAAA,WAAA,IACb,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,KAAM,GAAA,EAAK;AAC3B,QAAA,GAAA,IAAO,GAAA;AACP,QAAA,CAAA,EAAA;AAAA,MACF,OAAO,CAAA,GAAI,KAAA;AAAA,IACb,CAAA,MAAA,IAAW,CAAA,KAAM,GAAA,EAAK,CAAA,GAAI,IAAA;AAAA,SAAA,IACjB,MAAM,GAAA,EAAK;AAClB,MAAA,GAAA,CAAI,KAAK,GAAG,CAAA;AACZ,MAAA,GAAA,GAAM,EAAA;AAAA,IACR,CAAA,MAAA,IAAW,CAAA,KAAM,IAAA,EAAM,SAAA,EAAU;AAAA,SAAA,IACxB,MAAM,IAAA,IAAQ,GAAA,CAAI,CAAA,GAAI,CAAC,MAAM,IAAA,EAAM;AAAA,SACvC,GAAA,IAAO,CAAA;AAAA,EACd;AACA,EAAA,IAAI,GAAA,KAAQ,EAAA,IAAM,GAAA,CAAI,MAAA,GAAS,GAAG,SAAA,EAAU;AAC5C,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,CAAC,CAAA,IAAK,EAAC;AAC9B,EAAA,OAAO,QAAQ,KAAA,CAAM,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM;AACjC,IAAA,MAAM,IAA4B,EAAC;AACnC,IAAA,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACvB,MAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA;AAAA,IACjB,CAAC,CAAA;AACD,IAAA,OAAO,CAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEA,IAAM,GAAA,GAAM,CAAC,CAAA,KAA8B,CAAA,KAAM,KAAK,IAAA,GAAO,MAAA,CAAO,QAAA,CAAS,CAAA,EAAG,EAAE,CAAA;AAClF,IAAM,GAAA,GAAM,CAAC,MAAA,EAAgB,EAAA,KAAuB,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,CAAG,IAAA,EAAK,CAAE,WAAA,EAAY;AAGlF,SAAS,YACd,OAAA,EAC0E;AAC1E,EAAA,MAAM,EAAA,uBAAS,GAAA,EAGb;AACF,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAI,CAAA,CAAE,cAAc,MAAA,EAAQ;AAC5B,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,IAAA,GAAO,WAAA,EAAY;AACrC,IAAA,MAAM,CAAA,GAAI,EAAA,CAAG,GAAA,CAAI,CAAC,CAAA,IAAK;AAAA,MACrB,KAAA,sBAAW,GAAA,EAAY;AAAA,MACvB,IAAA,EAAM,IAAA;AAAA,MACN,EAAA,EAAI,IAAA;AAAA,MACJ,WAAA,EAAa,KAAA;AAAA,MACb,SAAA,EAAW;AAAA,KACb;AACA,IAAA,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,OAAO,CAAA;AACrB,IAAA,IAAI,CAAA,CAAE,UAAA,KAAe,IAAA,EAAM,CAAA,CAAE,WAAA,GAAc,IAAA;AAAA,SACtC,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,IAAA,KAAS,IAAA,GAAO,CAAA,CAAE,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,UAAU,CAAA;AAC5E,IAAA,IAAI,CAAA,CAAE,QAAA,KAAa,IAAA,EAAM,CAAA,CAAE,SAAA,GAAY,IAAA;AAAA,SAClC,CAAA,CAAE,EAAA,GAAK,CAAA,CAAE,EAAA,KAAO,IAAA,GAAO,CAAA,CAAE,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,CAAA,CAAE,QAAQ,CAAA;AAClE,IAAA,EAAA,CAAG,GAAA,CAAI,GAAG,CAAC,CAAA;AAAA,EACb;AACA,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAyE;AACzF,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,EAAA;AACnB,IAAA,IAAI,CAAA,CAAE,MAAM,IAAA,KAAS,CAAA;AACnB,MAAA,GAAA,CAAI,IAAI,CAAA,EAAG;AAAA,QACT,SAAS,CAAC,GAAG,CAAA,CAAE,KAAK,EAAE,CAAC,CAAA;AAAA,QACvB,IAAA,EAAM,CAAA,CAAE,WAAA,GAAc,IAAA,GAAO,CAAA,CAAE,IAAA;AAAA,QAC/B,EAAA,EAAI,CAAA,CAAE,SAAA,GAAY,IAAA,GAAO,CAAA,CAAE;AAAA,OAC5B,CAAA;AACL,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,aAAA,CACd,MAAA,EACA,IAAA,EACA,OAAA,EACW;AACX,EAAA,MAAM,EAAA,GAAK,YAAY,OAAO,CAAA;AAC9B,EAAA,MAAM,MAAiB,EAAC;AACxB,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AACpB,IAAA,IAAI,CAAA,CAAE,UAAU,MAAA,IAAU,CAAA,CAAE,WAAW,MAAA,IAAU,CAAC,WAAA,CAAY,CAAC,CAAA,EAAG;AAClE,IAAA,MAAM,CAAA,GAAI,GAAG,GAAA,CAAI,GAAA,CAAI,EAAE,MAAA,EAAQ,CAAA,CAAE,SAAS,CAAC,CAAA;AAC3C,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,MAAM,EAAA,GAAK,GAAA,CAAI,CAAA,CAAE,UAAU,CAAA;AAC3B,IAAA,MAAM,EAAA,GAAK,GAAA,CAAI,CAAA,CAAE,QAAQ,CAAA;AACzB,IAAA,GAAA,CAAI,IAAA,CAAK;AAAA,MACP,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,WAAW,CAAA,CAAE,SAAA;AAAA,MACb,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,UAAA,EAAY,EAAA,KAAO,IAAA,GAAO,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,IAAA,KAAS,IAAA,GAAO,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,EAAE,IAAI,CAAA;AAAA;AAAA,MAC7E,QAAA,EAAU,EAAA,KAAO,IAAA,GAAO,CAAA,CAAE,EAAA,GAAK,CAAA,CAAE,EAAA,KAAO,IAAA,GAAO,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,EAAE,EAAE,CAAA;AAAA;AAAA,MACrE,QAAQ,CAAA,CAAE,MAAA;AAAA,MACV,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,QAAQ,CAAA,CAAE,MAAA;AAAA,MACV,KAAK,CAAA,CAAE,GAAA;AAAA,MACP,KAAA,EAAO,GAAA,CAAI,CAAA,CAAE,KAAK,CAAA;AAAA,MAClB,MAAA,EAAQ,GAAA,CAAI,CAAA,CAAE,MAAM,CAAA;AAAA,MACpB,WAAA,EAAa,WAAA,CAAY,CAAA,CAAE,MAAM,CAAA,IAAK,CAAA;AAAA;AAAA,MACtC,WAAA,EAAa,UAAA,CAAW,CAAA,CAAE,MAAA,EAAQ,EAAE,GAAG;AAAA,KACxC,CAAA;AAAA,EACH;AACA,EAAA,OAAO,GAAA,CAAI,KAAK,YAAY,CAAA;AAC9B;AAEA,IAAI,MAAA;AACG,SAAS,kBAAA,GAA2B;AACzC,EAAA,MAAA,GAAS,MAAA;AACX;AAEO,SAAS,aAAA,CAAc,CAAA,GAA8B,EAAC,EAA2B;AACtF,EAAA,MAAM,CAAA,GAAI,CAAA,CAAE,KAAA,IAAS,UAAA,CAAW,KAAA;AAChC,EAAA,MAAA,KAAA,CAAY,YAAY;AACtB,IAAA,MAAM,CAAA,GAAI,MAAM,CAAA,CAAE,YAAY,CAAA;AAC9B,IAAA,IAAI,CAAC,CAAA,CAAE,EAAA;AACL,MAAA,MAAM,IAAI,aAAA;AAAA,QACR,CAAA,0BAAA,EAA6B,YAAY,CAAA,UAAA,EAAa,CAAA,CAAE,MAAM,CAAA,CAAA;AAAA,QAC9D,YAAA;AAAA,QACA,CAAA,CAAE;AAAA,OACJ;AACF,IAAA,OAAO,gBAAA,CAAiB,MAAM,CAAA,CAAE,IAAA,EAAM,CAAA;AAAA,EACxC,CAAA,GAAG,CAAE,KAAA,CAAM,CAAC,CAAA,KAAe;AACzB,IAAA,MAAA,GAAS,MAAA;AACT,IAAA,MAAM,CAAA;AAAA,EACR,CAAC,CAAA;AACD,EAAA,OAAO,MAAA;AACT;;;AC9IA,IAAM,KAAK,CAAC,CAAA,KAIU,MAAA,CAAO,WAAA,CAAY,OAAO,OAAA,CAAQ,CAAC,CAAA,CAAE,MAAA,CAAO,CAAC,GAAG,CAAC,CAAA,KAAM,CAAA,KAAM,MAAS,CAAC,CAAA;AAE7F,IAAM,IAAA,GAAO,CAAC,CAAA,KAAsB,OAAO,CAAA,KAAM,WAAW,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAA,GAAM,MAAA,CAAO,CAAC,CAAA;AAE/E,IAAM,MAAA,GAAS,CAAC,EAAA,EAAmB,EAAA,EAAmB,CAAA,KAAA,CACnD,EAAA,KAAO,IAAA,IAAQ,CAAA,IAAK,EAAA,MAAQ,EAAA,KAAO,IAAA,IAAQ,CAAA,IAAK,EAAA,CAAA;AAEnD,SAAS,cAAc,QAAA,EAAwB;AAC7C,EAAA,IAAI,QAAA,KAAa,UAAU,QAAA,KAAa,UAAA;AACtC,IAAA,MAAM,IAAI,UAAA,CAAW,CAAA,2CAAA,EAA8C,KAAK,SAAA,CAAU,QAAQ,CAAC,CAAA,CAAE,CAAA;AACjG;AACA,SAAS,YAAA,CAAa,OAAA,EAAiB,MAAA,EAAgB,CAAA,EAAqB;AAC1E,EAAA,IAAI,OAAA,KAAY,SAAA,IAAa,OAAA,KAAY,MAAA,EAAQ;AACjD,EAAA,IAAK,QAAA,CAA+B,QAAA,CAAS,OAAO,CAAA,EAAG;AACvD,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,IAAI,IAAI,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,OAAO,CAAC,CAAC,EAAE,IAAA,EAAK;AAC/D,EAAA,MAAM,IAAI,UAAA;AAAA,IACR,CAAA,gBAAA,EAAmB,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA,KAAA,EAAQ,MAAM,CAAA,kCAAA,EAAqC,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,GAC/G;AACF;AAGO,SAAS,cAAA,CAAe,IAAA,EAAa,MAAA,EAAgB,CAAA,GAAmB,EAAC,EAAwB;AACtG,EAAA,MAAM,QAAA,GAAW,EAAE,QAAA,IAAY,MAAA;AAC/B,EAAA,MAAM,OAAA,GAAU,EAAE,OAAA,IAAW,SAAA;AAC7B,EAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,EAAA,MAAM,CAAA,GAAI,UAAA,CAAW,CAAA,CAAE,MAAA,EAAQ,MAAM,CAAA;AACrC,EAAA,MAAM,CAAA,GAAI,cAAc,MAAM,CAAA;AAC9B,EAAA,YAAA,CAAa,OAAA,EAAS,QAAQ,CAAC,CAAA;AAC/B,EAAA,MAAM,SAAS,WAAA,CAAY,IAAA,EAAM,QAAQ,EAAE,MAAA,EAAQ,GAAG,CAAA;AACtD,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AACjC,EAAA,MAAM,IAAA,GAAO,CAAA,CAAE,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,MAAA,IAAU,CAAA,CAAE,SAAA,KAAc,QAAQ,CAAA;AACnF,EAAA,MAAM,IAAA,GAAO,OAAA,KAAY,MAAA,GAAS,MAAA,GAAS,OAAA;AAC3C,EAAA,MAAM,QAAA,GAAW,CAAC,CAAA,KAAuB,CAAA,KAAM,CAAA,GAAA,EAAM,IAAI,CAAA,CAAA,IAAM,CAAA,CAAE,QAAA,CAAS,CAAA,IAAA,EAAO,IAAI,CAAA,CAAE,CAAA;AACvF,EAAA,MAAM,SAAA,GAAY,CAAC,CAAA,KAAuB,CAAA,KAAM,OAAA;AAChD,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAuB,CAAA,KAAM,SAAA;AAC3C,EAAA,MAAM,KAAA,GAAQ,IAAA,KAAS,MAAA,GAAS,CAAC,SAAA,EAAW,QAAA,EAAU,IAAI,CAAA,GAAI,CAAC,SAAA,EAAW,IAAA,EAAM,QAAQ,CAAA;AACxF,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,GAAG,KAAA,EAAO,IAAI,CAAA,EAAG;AACnC,IAAA,MAAM,KAAA,GAAQ,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,CAAC,MAAM,IAAA,CAAK,CAAA,CAAE,OAAO,CAAC,CAAA,GAAI,IAAA;AAC3D,IAAA,IAAI,MAAM,IAAA,EAAM;AACd,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,MAAA,CAAO,CAAA,CAAE,UAAA,EAAY,CAAA,CAAE,QAAA,EAAU,CAAC,CAAC,CAAA;AACxE,MAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,EAAE,UAAA,KAAe,IAAA,IAAQ,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AACjF,MAAA,KAAA,MAAW,GAAA,IAAO,CAAC,KAAA,EAAO,QAAQ,CAAA,MAAO,GAAA,CAAI,MAAA,EAAQ,OAAO,GAAA,CAAI,CAAC,CAAA;AAAA,IACnE;AACA,IAAA,IAAI,KAAA,CAAM,MAAA,EAAQ,OAAO,KAAA,CAAM,CAAC,CAAA;AAAA,EAClC;AACA,EAAA,OAAO,MAAA;AACT;AACA,eAAsB,UAAA,CACpB,IAAA,EACA,MAAA,EACA,CAAA,GAAmB,EAAC,EACU;AAC9B,EAAA,MAAM,WAAW,MAAM,CAAA;AACvB,EAAA,OAAO,cAAA,CAAe,IAAA,EAAM,MAAA,EAAQ,CAAC,CAAA;AACvC;AAGO,SAAS,WAAA,CAAY,IAAA,EAAa,MAAA,EAAgB,CAAA,GAAoB,EAAC,EAAuB;AACnG,EAAA,MAAM,QAAA,GAAW,EAAE,QAAA,IAAY,MAAA;AAC/B,EAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,EAAA,YAAA,CAAa,EAAE,OAAA,IAAW,SAAA,EAAW,MAAA,EAAQ,aAAA,CAAc,MAAM,CAAC,CAAA;AAClE,EAAA,MAAM,SAAS,WAAA,CAAY,IAAA,EAAM,MAAA,EAAQ,EAAA,CAAG,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,QAAA,EAAU,EAAE,QAAA,EAAU,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAA;AACzG,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AACjC,EAAA,MAAM,GAAA,GAAM,cAAA,CAAe,MAAA,EAAQ,MAAA,EAAQ,CAAC,CAAA;AAC5C,EAAA,IAAI,QAAQ,MAAA,EAAW;AACrB,IAAA,IAAA,CAAK,CAAA,MAAA,EAAS,MAAM,CAAA,CAAA,EAAI,MAAM,IAAI,QAAQ,CAAA,CAAA,EAAI,CAAA,GAAA,EAAM,QAAQ,iBAAiB,IAAA,CAAK,IAAI,CAAC,CAAA,EAAA,EAAK,MAAM,CAAA,CAAA,CAAG,CAAA;AACrG,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,GAAA,CAAI,WAAA;AACb;AAYA,eAAsB,OAAA,CACpB,IAAA,EACA,MAAA,EACA,CAAA,GAAoB,EAAC,EACQ;AAC7B,EAAA,MAAM,WAAW,MAAM,CAAA;AACvB,EAAA,OAAO,WAAA,CAAY,IAAA,EAAM,MAAA,EAAQ,CAAC,CAAA;AACpC;AASA,eAAsB,KAAA,CACpB,IAAA,EACA,MAAA,EACA,CAAA,GAAyF,EAAC,EAC7D;AAC7B,EAAA,MAAM,CAAA,GAAI,MAAM,UAAA,CAAW,MAAM,CAAA;AACjC,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,IAAA,EAAM,MAAA,EAAQ,GAAG,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,UAAU,CAAA,CAAE,QAAA,EAAU,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAA;AACrG,EAAA,IAAI,MAAA,KAAW,QAAW,MAAM,IAAI,oBAAoB,CAAA,0BAAA,EAA6B,MAAA,CAAO,IAAI,CAAC,CAAA,CAAE,CAAA;AACnG,EAAA,IAAI,CAAC,CAAA,CAAE,IAAA,EAAM,OAAO,CAAA,CAAE,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,MAAM,CAAA;AAC9D,EAAA,MAAM,EAAA,GAAK,EAAE,KAAA,KAAU,MAAA,GAAY,EAAC,GAAI,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM;AACzD,EAAA,OAAO,aAAA,CAAc,MAAA,EAAQ,MAAM,aAAA,CAAc,EAAE,CAAA,EAAG,CAAA,CAAE,OAAO,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,YAAY,MAAM,CAAA;AACrG","file":"chunk-KKH6ABMA.js","sourcesContent":["/** Source preference, best first; unknown sources rank 5. Shared by the shard generator and the lazy full-manifest path. */\nexport const SOURCE_RANK: Readonly<Record<string, number>> = {\n espn: 0,\n nflverse: 1,\n nhl: 1,\n mlbstatic: 1,\n fox: 1,\n hockeytech: 2,\n cricinfo: 2,\n \"ncaa.com\": 3,\n \"nwhl.co\": 4,\n shiftstats: 4,\n wayback: 4,\n \"aaf.com\": 5,\n \"aaf-strip-crop\": 6,\n};\n\nexport interface Rankable {\n source_rank: number;\n valid_from: number | null;\n valid_to: number | null;\n first_seen: string;\n sha256: string;\n}\nconst desc = <T extends string | number>(a: T | null, b: T | null): number =>\n a === b ? 0 : a === null ? 1 : b === null ? -1 : a < b ? 1 : -1;\n/** Python `_ranked`: source_rank asc, open-ended (valid_to null) first, valid_to desc, first_seen desc, valid_from desc, sha256 asc; nulls last. */\nexport function compareMarks(a: Rankable, b: Rankable): number {\n return (\n a.source_rank - b.source_rank ||\n Number(a.valid_to !== null) - Number(b.valid_to !== null) ||\n desc(a.valid_to, b.valid_to) ||\n desc(a.first_seen, b.first_seen) ||\n desc(a.valid_from, b.valid_from) ||\n (a.sha256 < b.sha256 ? -1 : a.sha256 > b.sha256 ? 1 : 0)\n );\n}\n","import { type Alias, type MarkRow, archiveUrl } from \"./data/index.js\";\nimport { DownloadError } from \"./errors.js\";\nimport { SOURCE_RANK, compareMarks } from \"./rank.js\";\n\nexport const MANIFEST_URL = \"https://sdv.nyc3.cdn.digitaloceanspaces.com/assets/public/manifest/marks.csv\";\n\nexport interface ManifestRow {\n level: string;\n league: string;\n entity_id: string;\n mark_type: string;\n variant: string;\n valid_from: string;\n valid_to: string;\n source: string;\n sha256: string;\n ext: string;\n width: string;\n height: string;\n archive_url: string;\n first_seen: string;\n}\n\n/** archive_url reaches the web adapters' HTML (Python drops rows failing SAFE_URL); a row must carry exactly the content-addressed URL the loader derives, or it is dropped. */\nexport const safeArchive = (m: Pick<ManifestRow, \"archive_url\" | \"sha256\" | \"ext\">): boolean =>\n /^[0-9a-f]{64}$/.test(m.sha256) &&\n /^[a-z0-9]+$/.test(m.ext) &&\n m.archive_url === archiveUrl(m.sha256, m.ext);\n\n/** RFC 4180 over the whole text (quoted commas, doubled quotes, embedded newlines; CRLF or LF); rows keyed by header name. */\nexport function parseManifestCsv(text: string): ManifestRow[] {\n const src = text.replace(/^\\uFEFF/, \"\"); // a BOM would make the first header \"\\uFEFFlevel\" and drop every row\n const records: string[][] = [];\n let rec: string[] = [];\n let cur = \"\";\n let q = false;\n const endRecord = (): void => {\n rec.push(cur);\n cur = \"\";\n if (rec.length > 1 || rec[0] !== \"\") records.push(rec);\n rec = [];\n };\n for (let i = 0; i < src.length; i++) {\n const c = src[i] as string;\n if (q) {\n if (c !== '\"') cur += c;\n else if (src[i + 1] === '\"') {\n cur += '\"';\n i++;\n } else q = false;\n } else if (c === '\"') q = true;\n else if (c === \",\") {\n rec.push(cur);\n cur = \"\";\n } else if (c === \"\\n\") endRecord();\n else if (c === \"\\r\" && src[i + 1] === \"\\n\") continue;\n else cur += c;\n }\n if (cur !== \"\" || rec.length > 0) endRecord();\n const header = records[0] ?? [];\n return records.slice(1).map((f) => {\n const r: Record<string, string> = {};\n header.forEach((h, i) => {\n r[h] = f[i] ?? \"\";\n });\n return r as unknown as ManifestRow;\n });\n}\n\nconst int = (s: string): number | null => (s === \"\" ? null : Number.parseInt(s, 10));\nconst key = (source: string, id: string): string => `${source}:${id}`.trim().toLowerCase();\n\n/** mark aliases: key → (team_id, union range), unique team mappings only. */\nexport function markAliases(\n aliases: readonly Alias[],\n): Map<string, { team_id: string; from: number | null; to: number | null }> {\n const by = new Map<\n string,\n { teams: Set<string>; from: number | null; to: number | null; anyOpenFrom: boolean; anyOpenTo: boolean }\n >();\n for (const a of aliases) {\n if (a.id_system !== \"mark\") continue;\n const k = a.value.trim().toLowerCase();\n const e = by.get(k) ?? {\n teams: new Set<string>(),\n from: null,\n to: null,\n anyOpenFrom: false,\n anyOpenTo: false,\n };\n e.teams.add(a.team_id);\n if (a.valid_from === null) e.anyOpenFrom = true;\n else e.from = e.from === null ? a.valid_from : Math.min(e.from, a.valid_from);\n if (a.valid_to === null) e.anyOpenTo = true;\n else e.to = e.to === null ? a.valid_to : Math.max(e.to, a.valid_to);\n by.set(k, e);\n }\n const out = new Map<string, { team_id: string; from: number | null; to: number | null }>();\n for (const [k, e] of by)\n if (e.teams.size === 1)\n out.set(k, {\n team_id: [...e.teams][0] as string,\n from: e.anyOpenFrom ? null : e.from,\n to: e.anyOpenTo ? null : e.to,\n });\n return out;\n}\n\n/** Alias-mapped, safe-URL-filtered, ranked marks of one league; `archive_url` is derived, never copied. Not deduped. */\nexport function manifestMarks(\n league: string,\n rows: readonly ManifestRow[],\n aliases: readonly Alias[],\n): MarkRow[] {\n const ma = markAliases(aliases);\n const out: MarkRow[] = [];\n for (const m of rows) {\n if (m.level !== \"team\" || m.league !== league || !safeArchive(m)) continue;\n const a = ma.get(key(m.source, m.entity_id));\n if (!a) continue;\n const vf = int(m.valid_from);\n const vt = int(m.valid_to);\n out.push({\n team_id: a.team_id,\n mark_type: m.mark_type as \"logo\" | \"wordmark\",\n variant: m.variant,\n valid_from: vf === null ? a.from : a.from === null ? vf : Math.max(vf, a.from), // pl.max_horizontal (nulls ignored)\n valid_to: vt === null ? a.to : a.to === null ? vt : Math.min(vt, a.to), // pl.min_horizontal\n source: m.source,\n first_seen: m.first_seen,\n sha256: m.sha256,\n ext: m.ext,\n width: int(m.width),\n height: int(m.height),\n source_rank: SOURCE_RANK[m.source] ?? 5, // after height: the shard generator's JSON key order\n archive_url: archiveUrl(m.sha256, m.ext),\n });\n }\n return out.sort(compareMarks);\n}\n\nlet cached: Promise<ManifestRow[]> | undefined;\nexport function resetManifestCache(): void {\n cached = undefined;\n}\n/** The CDN manifest, fetched once per process (a failure is not cached). */\nexport function fetchManifest(o: { fetch?: typeof fetch } = {}): Promise<ManifestRow[]> {\n const f = o.fetch ?? globalThis.fetch;\n cached ??= (async () => {\n const r = await f(MANIFEST_URL);\n if (!r.ok)\n throw new DownloadError(\n `manifest download failed: ${MANIFEST_URL} answered ${r.status}`,\n MANIFEST_URL,\n r.status,\n );\n return parseManifestCsv(await r.text());\n })().catch((e: unknown) => {\n cached = undefined;\n throw e;\n });\n return cached;\n}\n","import { VARIANTS } from \"./data/index.js\";\nimport type { League, LeagueData, MarkRow } from \"./data/index.js\";\nimport { InputError, UnresolvedTeamError, warn } from \"./errors.js\";\nimport { getLeagueSync, loadLeague } from \"./index-data.js\";\nimport { fetchManifest, manifestMarks } from \"./manifest.js\";\nimport { normSeason } from \"./normalize.js\";\nimport { type ResolveOptions, type Value, resolveSync } from \"./resolve.js\";\nimport type { IdSystem, MarkType, SeasonInput, Variant } from \"./types.js\";\n\nexport interface SelectOptions {\n season?: SeasonInput;\n variant?: Variant;\n markType?: MarkType;\n}\nexport interface LogoUrlOptions extends SelectOptions {\n idSystem?: IdSystem;\n strict?: boolean;\n}\n\n/** Drops undefined values (exactOptionalPropertyTypes). */\nconst ro = (o: {\n season?: SeasonInput;\n idSystem?: IdSystem | undefined;\n strict?: boolean | undefined;\n}): ResolveOptions => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined));\n\nconst repr = (v: Value): string => (typeof v === \"string\" ? `'${v}'` : String(v));\n\nconst covers = (lo: number | null, hi: number | null, s: number): boolean =>\n (lo === null || s >= lo) && (hi === null || s <= hi);\n\nfunction checkMarkType(markType: string): void {\n if (markType !== \"logo\" && markType !== \"wordmark\")\n throw new InputError(`markType must be \"logo\" or \"wordmark\", got ${JSON.stringify(markType)}`);\n}\nfunction checkVariant(variant: string, league: League, d: LeagueData): void {\n if (variant === \"default\" || variant === \"dark\") return;\n if ((VARIANTS as readonly string[]).includes(variant)) return;\n const known = [...new Set(d.marks.map((m) => m.variant))].sort();\n throw new InputError(\n `unknown variant ${JSON.stringify(variant)} for ${league}; use \"default\", \"dark\" or one of ${known.join(\", \")}`,\n );\n}\n\n/** Port of `select_mark` (post-preload): requested variant, then (keeping polarity) default / polarity variants, then any; within each, season-covering rows (dated before open-ended), else the best row. Rows are already ranked best-first. */\nexport function selectMarkSync(team: Value, league: League, o: SelectOptions = {}): MarkRow | undefined {\n const markType = o.markType ?? \"logo\";\n const variant = o.variant ?? \"default\";\n checkMarkType(markType);\n const s = normSeason(o.season, league);\n const d = getLeagueSync(league);\n checkVariant(variant, league, d);\n const teamId = resolveSync(team, league, { season: s });\n if (teamId === undefined) return undefined;\n const rows = d.marks.filter((r) => r.team_id === teamId && r.mark_type === markType);\n const side = variant === \"dark\" ? \"dark\" : \"light\";\n const polarity = (v: string): boolean => v === `on_${side}` || v.endsWith(`_on_${side}`);\n const requested = (v: string): boolean => v === variant;\n const dflt = (v: string): boolean => v === \"default\";\n const order = side === \"dark\" ? [requested, polarity, dflt] : [requested, dflt, polarity];\n for (const keep of [...order, null]) {\n const found = keep ? rows.filter((r) => keep(r.variant)) : rows;\n if (s !== null) {\n const covering = found.filter((r) => covers(r.valid_from, r.valid_to, s));\n const dated = covering.filter((r) => r.valid_from !== null || r.valid_to !== null);\n for (const set of [dated, covering]) if (set.length) return set[0];\n }\n if (found.length) return found[0];\n }\n return undefined;\n}\nexport async function selectMark(\n team: Value,\n league: League,\n o: SelectOptions = {},\n): Promise<MarkRow | undefined> {\n await loadLeague(league);\n return selectMarkSync(team, league, o);\n}\n\n/** Port of `logo_url` (post-preload): archive URL of the team's logo/wordmark for the season; `undefined` for an unknown team (the resolver warns) or when no mark of that type exists (one warning). */\nexport function logoUrlSync(team: Value, league: League, o: LogoUrlOptions = {}): string | undefined {\n const markType = o.markType ?? \"logo\";\n checkMarkType(markType);\n checkVariant(o.variant ?? \"default\", league, getLeagueSync(league));\n const teamId = resolveSync(team, league, ro({ season: o.season, idSystem: o.idSystem, strict: o.strict }));\n if (teamId === undefined) return undefined;\n const row = selectMarkSync(teamId, league, o);\n if (row === undefined) {\n warn(`marks:${league}:${teamId}:${markType}`, `no ${markType} archived for ${repr(team)} (${league})`);\n return undefined;\n }\n return row.archive_url;\n}\n/**\n * Archive URL of a team's logo (or wordmark, `markType`) for the season, loading the league first; `undefined` for an\n * unknown team (the resolver warns) or when no mark of that type is archived (one warning).\n *\n * @example\n * ```ts\n * import { logoUrl } from \"@sportsdataverse/sdvplot\";\n *\n * await logoUrl(\"KC\", \"nfl\", { markType: \"wordmark\" });\n * ```\n */\nexport async function logoUrl(\n team: Value,\n league: League,\n o: LogoUrlOptions = {},\n): Promise<string | undefined> {\n await loadLeague(league);\n return logoUrlSync(team, league, o);\n}\n\n/**\n * Every archived mark for one team, best first (logos and wordmarks, every variant and source).\n * Default: the committed shard (deduped, ranked rows). `full: true` fetches the CDN manifest lazily (once per process)\n * and returns every manifest row for the team, including rows the shard dedupe dropped; a failed download throws\n * `DownloadError`. Both paths filter on the team only. `fetch` overrides the global fetch for the manifest download.\n * Throws `UnresolvedTeamError` when the team is null or does not resolve (strict, as Python).\n */\nexport async function marks(\n team: Value,\n league: League,\n o: { season?: SeasonInput; idSystem?: IdSystem; full?: boolean; fetch?: typeof fetch } = {},\n): Promise<readonly MarkRow[]> {\n const d = await loadLeague(league);\n const teamId = resolveSync(team, league, ro({ season: o.season, idSystem: o.idSystem, strict: true }));\n if (teamId === undefined) throw new UnresolvedTeamError(`marks() needs a team, got ${String(team)}`);\n if (!o.full) return d.marks.filter((r) => r.team_id === teamId);\n const fo = o.fetch === undefined ? {} : { fetch: o.fetch };\n return manifestMarks(league, await fetchManifest(fo), d.aliases).filter((r) => r.team_id === teamId);\n}\n"]}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { checkHeight, checkAlpha } from './chunk-RMT2GMFH.js';
|
|
2
|
+
import { resolveSync, getLeagueSync } from './chunk-TAXO3VXH.js';
|
|
3
|
+
import { InputError, warn } from './chunk-E7G7VSLV.js';
|
|
4
|
+
|
|
5
|
+
// src/tiers.ts
|
|
6
|
+
var TIER_DESC = {
|
|
7
|
+
1: "Elite",
|
|
8
|
+
2: "Very Good",
|
|
9
|
+
3: "Medium",
|
|
10
|
+
4: "Bad",
|
|
11
|
+
5: "What are they doing?",
|
|
12
|
+
6: "",
|
|
13
|
+
7: ""
|
|
14
|
+
};
|
|
15
|
+
var TIERS_SUBTITLE = "created with the #sdvplot Tiermaker";
|
|
16
|
+
var TIER_THEMES = {
|
|
17
|
+
dark: { bg: "#1e1e1e", line: "#e0e0e0", text: "#ffffff", muted: "#8e8e93" },
|
|
18
|
+
light: { bg: "#ffffff", line: "#3a3a3c", text: "#1e1e1e", muted: "#636366" }
|
|
19
|
+
};
|
|
20
|
+
var AUTO_VARIANT = { dark: "dark", light: "default" };
|
|
21
|
+
var DEFAULT_HEIGHT = 0.1;
|
|
22
|
+
function wrapLabel(text) {
|
|
23
|
+
const out = [];
|
|
24
|
+
let line = "";
|
|
25
|
+
for (const w of text.split(/\s+/).filter(Boolean)) {
|
|
26
|
+
if (line && line.length + 1 + w.length > 14) {
|
|
27
|
+
out.push(line);
|
|
28
|
+
line = w;
|
|
29
|
+
} else line = line ? `${line} ${w}` : w;
|
|
30
|
+
}
|
|
31
|
+
if (line) out.push(line);
|
|
32
|
+
return out.join("\n");
|
|
33
|
+
}
|
|
34
|
+
var miss = (v) => v === null || v === void 0 || typeof v === "number" && Number.isNaN(v);
|
|
35
|
+
var real = (v) => typeof v === "number" && !Number.isNaN(v) || typeof v === "bigint";
|
|
36
|
+
function prepareTiers(rows, league, o = {}) {
|
|
37
|
+
const theme = o.theme ?? "dark";
|
|
38
|
+
if (!Object.hasOwn(TIER_THEMES, theme))
|
|
39
|
+
throw new InputError(`theme must be "dark" or "light", got ${String(theme)}`);
|
|
40
|
+
const height = o.height === void 0 ? DEFAULT_HEIGHT : checkHeight(o.height);
|
|
41
|
+
const alpha = checkAlpha(o.alpha ?? 0.8);
|
|
42
|
+
const tiers = rows.map((r) => r.tierNo ?? r.tier_no);
|
|
43
|
+
const teams = rows.map((r) => r.team);
|
|
44
|
+
const ranksIn = rows.map((r) => r.tierRank ?? r.tier_rank);
|
|
45
|
+
const given = !o.presort && ranksIn.some((v) => v !== void 0) ? ranksIn : void 0;
|
|
46
|
+
const all = rows.map((_, i) => i);
|
|
47
|
+
const absent = all.filter((i) => miss(tiers[i]) || given !== void 0 && miss(given[i]));
|
|
48
|
+
if (absent.length) {
|
|
49
|
+
const names = absent.map((i) => String(teams[i]));
|
|
50
|
+
const extra = names.length > 10 ? ` and ${names.length - 10} more` : "";
|
|
51
|
+
const shown = `${names.slice(0, 10).join(", ")}${extra}`;
|
|
52
|
+
warn(
|
|
53
|
+
`tiers:${league}:missing:${shown}`,
|
|
54
|
+
`skipped ${names.length} point(s) with a missing tier_no or tier_rank: ${shown}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
let idx = all.filter((i) => !absent.includes(i));
|
|
58
|
+
if (!idx.length) throw new InputError("data has no rows with a tier_no");
|
|
59
|
+
if (!idx.every((i) => real(tiers[i]) && (given === void 0 || real(given[i]))))
|
|
60
|
+
throw new InputError("tier_no and tier_rank must hold numbers (tier 1 is the top tier)");
|
|
61
|
+
const tierOf = (i) => Number(tiers[i]);
|
|
62
|
+
if (o.presort) {
|
|
63
|
+
const name = (i) => String(teams[i]);
|
|
64
|
+
const cp = (i) => Array.from(name(i), (c) => c.codePointAt(0));
|
|
65
|
+
const cmp = (a, b) => {
|
|
66
|
+
for (let k = 0; k < Math.min(a.length, b.length); k++)
|
|
67
|
+
if (a[k] !== b[k]) return a[k] - b[k];
|
|
68
|
+
return a.length - b.length;
|
|
69
|
+
};
|
|
70
|
+
idx = idx.sort(
|
|
71
|
+
(a, b) => tierOf(a) - tierOf(b) || Number(miss(teams[a])) - Number(miss(teams[b])) || cmp(cp(a), cp(b))
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const ranks = /* @__PURE__ */ new Map();
|
|
75
|
+
const seen = /* @__PURE__ */ new Map();
|
|
76
|
+
for (const i of idx) {
|
|
77
|
+
if (given) ranks.set(i, Number(given[i]));
|
|
78
|
+
else {
|
|
79
|
+
const t = tierOf(i);
|
|
80
|
+
const n = (seen.get(t) ?? 0) + 1;
|
|
81
|
+
seen.set(t, n);
|
|
82
|
+
ranks.set(i, n);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const ids = resolveSync(
|
|
86
|
+
idx.map((i) => teams[i]),
|
|
87
|
+
league
|
|
88
|
+
);
|
|
89
|
+
const kept = idx.flatMap((i, k) => {
|
|
90
|
+
const id = ids[k];
|
|
91
|
+
return id === void 0 ? [] : [[i, id]];
|
|
92
|
+
});
|
|
93
|
+
const abbr = new Map(getLeagueSync(league).teams.map((t) => [t.team_id, t.abbr]));
|
|
94
|
+
const levels = [...new Set(idx.map(tierOf))].sort((a, b) => a - b);
|
|
95
|
+
const skip = new Set(
|
|
96
|
+
o.noLineBelowTier === void 0 ? [] : typeof o.noLineBelowTier === "number" ? [o.noLineBelowTier] : o.noLineBelowTier
|
|
97
|
+
);
|
|
98
|
+
const desc = o.tierDesc ?? TIER_DESC;
|
|
99
|
+
const rs = [...ranks.values()];
|
|
100
|
+
const lo = Math.min(...rs);
|
|
101
|
+
const hi = Math.max(...rs);
|
|
102
|
+
const pad = lo === hi ? 0.5 : 0.05 * (hi - lo);
|
|
103
|
+
const first = levels[0];
|
|
104
|
+
const last = levels[levels.length - 1];
|
|
105
|
+
return {
|
|
106
|
+
x: kept.map(([i]) => ranks.get(i)),
|
|
107
|
+
y: kept.map(([i]) => tierOf(i)),
|
|
108
|
+
teamIds: kept.map(([, id]) => id),
|
|
109
|
+
labels: kept.map(([i, id]) => abbr.get(id) || String(teams[i])),
|
|
110
|
+
lines: [first - 0.5, ...levels.filter((t) => !skip.has(t)).map((t) => t + 0.5)],
|
|
111
|
+
breaks: levels,
|
|
112
|
+
breakLabels: levels.map((t) => wrapLabel(desc[t] ?? "")),
|
|
113
|
+
xlim: [lo - pad, hi + pad],
|
|
114
|
+
ylim: [first - 0.6, last + 0.6],
|
|
115
|
+
title: o.title === void 0 ? `${league.toUpperCase()} Team Tiers` : o.title ?? "",
|
|
116
|
+
subtitle: o.subtitle === void 0 ? TIERS_SUBTITLE : o.subtitle,
|
|
117
|
+
caption: o.caption ?? null,
|
|
118
|
+
height,
|
|
119
|
+
alpha,
|
|
120
|
+
variant: (o.variant ?? "auto") === "auto" ? AUTO_VARIANT[theme] : o.variant,
|
|
121
|
+
theme: TIER_THEMES[theme]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { TIERS_SUBTITLE, TIER_DESC, TIER_THEMES, prepareTiers, wrapLabel };
|
|
126
|
+
//# sourceMappingURL=chunk-NLPH2VZT.js.map
|
|
127
|
+
//# sourceMappingURL=chunk-NLPH2VZT.js.map
|