@johnmorrisdotca/kyogijo-stadiums 0.0.0-stage → 0.4.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.
Files changed (321) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE.md +293 -0
  4. package/README.md +600 -2
  5. package/dist/annotate.d.ts +47 -0
  6. package/dist/annotate.js +349 -0
  7. package/dist/atlas-entry.d.ts +4 -0
  8. package/dist/atlas-entry.js +3 -0
  9. package/dist/atlas.d.ts +131 -0
  10. package/dist/atlas.js +149 -0
  11. package/dist/background.d.ts +56 -0
  12. package/dist/background.js +127 -0
  13. package/dist/ballpark.d.ts +48 -0
  14. package/dist/ballpark.js +129 -0
  15. package/dist/canvas-entry.d.ts +2 -0
  16. package/dist/canvas-entry.js +2 -0
  17. package/dist/canvas.d.ts +85 -0
  18. package/dist/canvas.js +279 -0
  19. package/dist/charts-entry.d.ts +10 -0
  20. package/dist/charts-entry.js +8 -0
  21. package/dist/charts.baseball.d.ts +30 -0
  22. package/dist/charts.baseball.js +152 -0
  23. package/dist/charts.curling.d.ts +52 -0
  24. package/dist/charts.curling.js +196 -0
  25. package/dist/charts.d.ts +172 -0
  26. package/dist/charts.js +508 -0
  27. package/dist/charts.network.d.ts +66 -0
  28. package/dist/charts.network.js +64 -0
  29. package/dist/charts.soccer.d.ts +43 -0
  30. package/dist/charts.soccer.js +191 -0
  31. package/dist/charts.types.d.ts +396 -0
  32. package/dist/charts.types.js +1 -0
  33. package/dist/colour.d.ts +29 -0
  34. package/dist/colour.js +97 -0
  35. package/dist/common.d.ts +14 -0
  36. package/dist/common.js +32 -0
  37. package/dist/court.d.ts +89 -0
  38. package/dist/court.js +248 -0
  39. package/dist/courts.style.d.ts +20 -0
  40. package/dist/courts.style.js +54 -0
  41. package/dist/cricket.board.d.ts +18 -0
  42. package/dist/cricket.board.js +67 -0
  43. package/dist/curling.board.d.ts +24 -0
  44. package/dist/curling.board.js +147 -0
  45. package/dist/d3-entry.d.ts +3 -0
  46. package/dist/d3-entry.js +2 -0
  47. package/dist/d3.d.ts +45 -0
  48. package/dist/d3.js +56 -0
  49. package/dist/draw.d.ts +52 -0
  50. package/dist/draw.js +705 -0
  51. package/dist/element-define.d.ts +2 -0
  52. package/dist/element-define.js +4 -0
  53. package/dist/element-entry.d.ts +1 -0
  54. package/dist/element-entry.js +2 -0
  55. package/dist/element.d.ts +39 -0
  56. package/dist/element.js +321 -0
  57. package/dist/eras-entry.d.ts +2 -0
  58. package/dist/eras-entry.js +2 -0
  59. package/dist/eras.d.ts +204 -0
  60. package/dist/eras.js +396 -0
  61. package/dist/events-entry.d.ts +3 -0
  62. package/dist/events-entry.js +3 -0
  63. package/dist/events.d.ts +54 -0
  64. package/dist/events.data.d.ts +59 -0
  65. package/dist/events.data.js +297 -0
  66. package/dist/events.js +127 -0
  67. package/dist/features.d.ts +31 -0
  68. package/dist/features.js +284 -0
  69. package/dist/field.score.d.ts +5 -0
  70. package/dist/field.score.js +33 -0
  71. package/dist/fields/afl.d.ts +11 -0
  72. package/dist/fields/afl.js +103 -0
  73. package/dist/fields/cricket.d.ts +9 -0
  74. package/dist/fields/cricket.js +81 -0
  75. package/dist/fields/fieldhockey.d.ts +6 -0
  76. package/dist/fields/fieldhockey.js +81 -0
  77. package/dist/fields/gaelic.d.ts +10 -0
  78. package/dist/fields/gaelic.js +86 -0
  79. package/dist/fields/handball.d.ts +6 -0
  80. package/dist/fields/handball.js +85 -0
  81. package/dist/fields/lacrosse.d.ts +17 -0
  82. package/dist/fields/lacrosse.js +169 -0
  83. package/dist/fields/rugby.d.ts +10 -0
  84. package/dist/fields/rugby.js +130 -0
  85. package/dist/fields.d.ts +12 -0
  86. package/dist/fields.js +44 -0
  87. package/dist/fields.kit.d.ts +63 -0
  88. package/dist/fields.kit.js +108 -0
  89. package/dist/fields.style.d.ts +4 -0
  90. package/dist/fields.style.js +19 -0
  91. package/dist/fields.types.d.ts +155 -0
  92. package/dist/fields.types.js +1 -0
  93. package/dist/format.d.ts +10 -0
  94. package/dist/format.js +28 -0
  95. package/dist/formations.d.ts +18 -0
  96. package/dist/formations.js +211 -0
  97. package/dist/frames-entry.d.ts +8 -0
  98. package/dist/frames-entry.js +7 -0
  99. package/dist/frames.d.ts +199 -0
  100. package/dist/frames.js +271 -0
  101. package/dist/frames.providers.d.ts +16 -0
  102. package/dist/frames.providers.js +302 -0
  103. package/dist/geojson-entry.d.ts +2 -0
  104. package/dist/geojson-entry.js +2 -0
  105. package/dist/geojson.d.ts +79 -0
  106. package/dist/geojson.js +147 -0
  107. package/dist/geometry-entry.d.ts +7 -0
  108. package/dist/geometry-entry.js +5 -0
  109. package/dist/geometry.d.ts +295 -0
  110. package/dist/geometry.js +361 -0
  111. package/dist/grounds-entry.d.ts +4 -0
  112. package/dist/grounds-entry.js +3 -0
  113. package/dist/grounds.d.ts +134 -0
  114. package/dist/grounds.data.d.ts +2 -0
  115. package/dist/grounds.data.js +1849 -0
  116. package/dist/grounds.js +74 -0
  117. package/dist/heat.colour.d.ts +37 -0
  118. package/dist/heat.colour.js +54 -0
  119. package/dist/heat.d.ts +43 -0
  120. package/dist/heat.js +614 -0
  121. package/dist/heat.stats.d.ts +123 -0
  122. package/dist/heat.stats.js +413 -0
  123. package/dist/heat.types.d.ts +145 -0
  124. package/dist/heat.types.js +1 -0
  125. package/dist/heat.zones.d.ts +54 -0
  126. package/dist/heat.zones.js +424 -0
  127. package/dist/homeside.d.ts +16 -0
  128. package/dist/homeside.js +43 -0
  129. package/dist/index.d.ts +47 -0
  130. package/dist/index.js +29 -0
  131. package/dist/layers-entry.d.ts +19 -0
  132. package/dist/layers-entry.js +11 -0
  133. package/dist/layers.d.ts +41 -0
  134. package/dist/layers.env.d.ts +72 -0
  135. package/dist/layers.env.js +79 -0
  136. package/dist/layers.js +533 -0
  137. package/dist/layers.marks.d.ts +45 -0
  138. package/dist/layers.marks.js +168 -0
  139. package/dist/layers.types.d.ts +226 -0
  140. package/dist/layers.types.js +1 -0
  141. package/dist/layout.d.ts +97 -0
  142. package/dist/layout.js +381 -0
  143. package/dist/layout.style.d.ts +6 -0
  144. package/dist/layout.style.js +17 -0
  145. package/dist/layouts-entry.d.ts +5 -0
  146. package/dist/layouts-entry.js +4 -0
  147. package/dist/leagues/aussie.d.ts +57 -0
  148. package/dist/leagues/aussie.js +36 -0
  149. package/dist/leagues/baseball.d.ts +58 -0
  150. package/dist/leagues/baseball.js +171 -0
  151. package/dist/leagues/basketball.d.ts +67 -0
  152. package/dist/leagues/basketball.js +128 -0
  153. package/dist/leagues/courts.d.ts +212 -0
  154. package/dist/leagues/courts.js +114 -0
  155. package/dist/leagues/cricket.d.ts +45 -0
  156. package/dist/leagues/cricket.js +34 -0
  157. package/dist/leagues/curling.d.ts +64 -0
  158. package/dist/leagues/curling.js +53 -0
  159. package/dist/leagues/fieldhockey.d.ts +48 -0
  160. package/dist/leagues/fieldhockey.js +29 -0
  161. package/dist/leagues/fields.d.ts +10 -0
  162. package/dist/leagues/fields.js +6 -0
  163. package/dist/leagues/football.d.ts +8 -0
  164. package/dist/leagues/football.js +82 -0
  165. package/dist/leagues/gaelic.d.ts +50 -0
  166. package/dist/leagues/gaelic.js +29 -0
  167. package/dist/leagues/handball.d.ts +45 -0
  168. package/dist/leagues/handball.js +32 -0
  169. package/dist/leagues/hockey.d.ts +63 -0
  170. package/dist/leagues/hockey.js +166 -0
  171. package/dist/leagues/lacrosse.d.ts +103 -0
  172. package/dist/leagues/lacrosse.js +175 -0
  173. package/dist/leagues/rugby.d.ts +59 -0
  174. package/dist/leagues/rugby.js +72 -0
  175. package/dist/leagues/sources.d.ts +18 -0
  176. package/dist/leagues/sources.js +95 -0
  177. package/dist/leagues/types.d.ts +43 -0
  178. package/dist/leagues/types.js +5 -0
  179. package/dist/leagues-entry.d.ts +23 -0
  180. package/dist/leagues-entry.js +15 -0
  181. package/dist/leagues.d.ts +172 -0
  182. package/dist/leagues.js +462 -0
  183. package/dist/look.d.ts +50 -0
  184. package/dist/look.js +186 -0
  185. package/dist/mark.d.ts +35 -0
  186. package/dist/mark.js +59 -0
  187. package/dist/mount-entry.d.ts +2 -0
  188. package/dist/mount-entry.js +2 -0
  189. package/dist/mount.d.ts +63 -0
  190. package/dist/mount.js +167 -0
  191. package/dist/mow.d.ts +36 -0
  192. package/dist/mow.js +111 -0
  193. package/dist/names.d.ts +77 -0
  194. package/dist/names.js +97 -0
  195. package/dist/outline.d.ts +25 -0
  196. package/dist/outline.js +112 -0
  197. package/dist/parks-entry.d.ts +4 -0
  198. package/dist/parks-entry.js +3 -0
  199. package/dist/parks.d.ts +200 -0
  200. package/dist/parks.data.d.ts +2 -0
  201. package/dist/parks.data.js +4489 -0
  202. package/dist/parks.js +92 -0
  203. package/dist/plot-entry.d.ts +2 -0
  204. package/dist/plot-entry.js +2 -0
  205. package/dist/plot.d.ts +74 -0
  206. package/dist/plot.js +68 -0
  207. package/dist/png-entry.d.ts +2 -0
  208. package/dist/png-entry.js +2 -0
  209. package/dist/png.d.ts +26 -0
  210. package/dist/png.js +46 -0
  211. package/dist/ranges.d.ts +33 -0
  212. package/dist/ranges.js +178 -0
  213. package/dist/ranges.names.d.ts +31 -0
  214. package/dist/ranges.names.js +65 -0
  215. package/dist/react-entry.d.ts +2 -0
  216. package/dist/react-entry.js +2 -0
  217. package/dist/react.d.ts +53 -0
  218. package/dist/react.js +58 -0
  219. package/dist/replay-entry.d.ts +5 -0
  220. package/dist/replay-entry.js +4 -0
  221. package/dist/replay.control.d.ts +47 -0
  222. package/dist/replay.control.js +184 -0
  223. package/dist/replay.d.ts +170 -0
  224. package/dist/replay.dom.d.ts +21 -0
  225. package/dist/replay.dom.js +388 -0
  226. package/dist/replay.js +579 -0
  227. package/dist/replay.types.d.ts +152 -0
  228. package/dist/replay.types.js +1 -0
  229. package/dist/restyle.d.ts +21 -0
  230. package/dist/restyle.js +70 -0
  231. package/dist/road.d.ts +26 -0
  232. package/dist/road.draw.d.ts +6 -0
  233. package/dist/road.draw.js +269 -0
  234. package/dist/road.js +59 -0
  235. package/dist/road.model.d.ts +63 -0
  236. package/dist/road.model.js +215 -0
  237. package/dist/road.style.d.ts +7 -0
  238. package/dist/road.style.js +26 -0
  239. package/dist/road.types.d.ts +122 -0
  240. package/dist/road.types.js +1 -0
  241. package/dist/scene-entry.d.ts +7 -0
  242. package/dist/scene-entry.js +5 -0
  243. package/dist/scene.css.d.ts +44 -0
  244. package/dist/scene.css.js +296 -0
  245. package/dist/scene.d.ts +27 -0
  246. package/dist/scene.fit.d.ts +12 -0
  247. package/dist/scene.fit.js +18 -0
  248. package/dist/scene.flat.d.ts +38 -0
  249. package/dist/scene.flat.js +167 -0
  250. package/dist/scene.js +420 -0
  251. package/dist/scene.path.d.ts +40 -0
  252. package/dist/scene.path.js +357 -0
  253. package/dist/scene.types.d.ts +172 -0
  254. package/dist/scene.types.js +1 -0
  255. package/dist/scene.xml.d.ts +31 -0
  256. package/dist/scene.xml.js +81 -0
  257. package/dist/score.d.ts +70 -0
  258. package/dist/score.js +212 -0
  259. package/dist/sets.board.d.ts +22 -0
  260. package/dist/sets.board.js +89 -0
  261. package/dist/sheet.d.ts +18 -0
  262. package/dist/sheet.js +38 -0
  263. package/dist/special.d.ts +44 -0
  264. package/dist/special.js +204 -0
  265. package/dist/special.style.d.ts +8 -0
  266. package/dist/special.style.js +36 -0
  267. package/dist/strings.d.ts +581 -0
  268. package/dist/strings.js +411 -0
  269. package/dist/style.d.ts +35 -0
  270. package/dist/style.js +177 -0
  271. package/dist/surfaces/baseball.d.ts +33 -0
  272. package/dist/surfaces/baseball.js +208 -0
  273. package/dist/surfaces/baseball.walls.d.ts +16 -0
  274. package/dist/surfaces/baseball.walls.js +150 -0
  275. package/dist/surfaces/basketball.d.ts +8 -0
  276. package/dist/surfaces/basketball.js +199 -0
  277. package/dist/surfaces/curling.d.ts +23 -0
  278. package/dist/surfaces/curling.js +128 -0
  279. package/dist/surfaces/field.d.ts +12 -0
  280. package/dist/surfaces/field.js +163 -0
  281. package/dist/surfaces/football.d.ts +12 -0
  282. package/dist/surfaces/football.js +208 -0
  283. package/dist/surfaces/hockey.d.ts +10 -0
  284. package/dist/surfaces/hockey.js +166 -0
  285. package/dist/surfaces/net.d.ts +7 -0
  286. package/dist/surfaces/net.js +151 -0
  287. package/dist/surfaces/soccer-providers.d.ts +124 -0
  288. package/dist/surfaces/soccer-providers.js +334 -0
  289. package/dist/surfaces/soccer-spec.d.ts +138 -0
  290. package/dist/surfaces/soccer-spec.js +175 -0
  291. package/dist/surfaces/soccer.d.ts +25 -0
  292. package/dist/surfaces/soccer.js +270 -0
  293. package/dist/surfaces/surface.d.ts +180 -0
  294. package/dist/surfaces/surface.js +49 -0
  295. package/dist/team.common.d.ts +75 -0
  296. package/dist/team.common.js +97 -0
  297. package/dist/team.formation.d.ts +24 -0
  298. package/dist/team.formation.js +121 -0
  299. package/dist/team.geometry.d.ts +66 -0
  300. package/dist/team.geometry.js +304 -0
  301. package/dist/team.layers.d.ts +16 -0
  302. package/dist/team.layers.js +32 -0
  303. package/dist/team.motion.d.ts +9 -0
  304. package/dist/team.motion.js +325 -0
  305. package/dist/team.network.d.ts +43 -0
  306. package/dist/team.network.js +215 -0
  307. package/dist/team.shape.d.ts +12 -0
  308. package/dist/team.shape.js +217 -0
  309. package/dist/team.types.d.ts +189 -0
  310. package/dist/team.types.js +1 -0
  311. package/dist/text.d.ts +31 -0
  312. package/dist/text.js +88 -0
  313. package/dist/themes.d.ts +14 -0
  314. package/dist/themes.js +24 -0
  315. package/dist/types.d.ts +565 -0
  316. package/dist/types.js +1 -0
  317. package/dist/units.d.ts +45 -0
  318. package/dist/units.js +90 -0
  319. package/dist/version.d.ts +2 -0
  320. package/dist/version.js +2 -0
  321. package/package.json +234 -4
@@ -0,0 +1,63 @@
1
+ import { type KyogijoWords } from "./strings.ts";
2
+ import type { RoadDecided, RoadFinalist, RoadOptions, RoadTotals } from "./road.types.ts";
3
+ import type { Language, Team } from "./types.ts";
4
+ /** Who won a match, from the finalist's side. `unknown` when the score is not a pair of numbers. */
5
+ export type Result = "win" | "loss" | "draw" | "unknown";
6
+ /** A match as it is drawn: the two scores written, who won, and how it was decided. */
7
+ export interface MatchView {
8
+ /** The round's key; empty for a match of the group stage. */
9
+ round: string;
10
+ opponent: Team;
11
+ /** The finalist's score and the opponent's, written. For a score that is one text that could not be split, `whole` is that text and the two are empty. */
12
+ mine: string;
13
+ theirs: string;
14
+ whole?: string;
15
+ result: Result;
16
+ decided: RoadDecided;
17
+ pens?: [string, string];
18
+ /** The words that replace the usual ones under the score, or undefined. */
19
+ note?: string;
20
+ /** Whether the usual words (FT, AET, the shoot-out) are written: always for a knockout match, only when asked for a group match. */
21
+ says: boolean;
22
+ homeFirst?: boolean;
23
+ }
24
+ /** The chart's data, ready to draw. */
25
+ export interface Model {
26
+ language: Language;
27
+ words: KyogijoWords;
28
+ finalists: [Team, Team];
29
+ /** The matches of the group stage, for each finalist. */
30
+ group: [MatchView[], MatchView[]];
31
+ /** The knockout matches for each finalist, by round key. */
32
+ path: [Map<string, MatchView>, Map<string, MatchView>];
33
+ /** The rounds, the earliest first. */
34
+ rounds: string[];
35
+ /** The final, if played: the scores of the first finalist and the second. */
36
+ final?: MatchView;
37
+ label(key: string): string;
38
+ groupLabel: string;
39
+ title: string;
40
+ subtitle: string | undefined;
41
+ }
42
+ /** A number from a number or from text that is one, else undefined. */
43
+ export declare function numeric(value: unknown): number | undefined;
44
+ /** The rounds of two paths, the earliest first: a round both have is once, and a round only one has stays after the round before it. */
45
+ export declare function mergeRounds(paths: readonly (readonly string[])[]): string[];
46
+ /** Read and check what `roadToFinal` was given. */
47
+ export declare function readModel(finalists: readonly RoadFinalist[], options: RoadOptions): Model;
48
+ /** The words under a score: FT, AET or the shoot-out (the first side's numbers first), a note in their place, or nothing. */
49
+ export declare function decidedWords(view: MatchView, w: KyogijoWords["road"], mineFirst: boolean): string;
50
+ /** The score of a match as one text, the first side's first. */
51
+ export declare function scoreText(view: MatchView, mineFirst?: boolean): string;
52
+ /** The abbreviation written under a mark: the team's own, else made from its name. */
53
+ export declare function codeOf(team: Team): string;
54
+ /** The numbers behind the chart. */
55
+ export declare function totalsOf(model: Model): RoadTotals;
56
+ /** The chart's accessible name. */
57
+ export declare function nameOf(model: Model): string;
58
+ /** What the chart shows, in a sentence or two. */
59
+ export declare function summaryOf(model: Model): string;
60
+ /** One HTML table with a row for every match: the group stage, the knockout rounds in order, and the final. */
61
+ export declare function tableOf(model: Model, options?: {
62
+ className?: string;
63
+ }): string;
@@ -0,0 +1,215 @@
1
+ // The road chart's data, read and checked: the scores split into the two sides, who won each match, the words under each score, the rounds in the order played, and
2
+ // the sentences and the table that say the same in words. Nothing here draws.
3
+ import { esc } from "./format.js";
4
+ import { safeClass } from "./common.js";
5
+ import { KYOGIJO_STRINGS, fill } from "./strings.js";
6
+ import { abbreviate } from "./text.js";
7
+ const own = (object, key) => object !== undefined && Object.prototype.hasOwnProperty.call(object, key);
8
+ /** A number from a number or from text that is one, else undefined. */
9
+ export function numeric(value) {
10
+ if (typeof value === "number")
11
+ return Number.isFinite(value) ? value : undefined;
12
+ if (typeof value === "string" && /^\s*-?\d+(?:\.\d+)?\s*$/.test(value))
13
+ return Number(value);
14
+ return undefined;
15
+ }
16
+ const written = (value) => (value === undefined || value === null ? "" : String(value).trim());
17
+ /** The two sides of a score. */
18
+ function split(score) {
19
+ if (Array.isArray(score) && score.length === 2)
20
+ return { mine: written(score[0]), theirs: written(score[1]) };
21
+ const text = written(score);
22
+ const parts = /^(\S+?)\s*[-–—:]\s*(\S+)$/.exec(text);
23
+ if (parts !== null)
24
+ return { mine: parts[1], theirs: parts[2] };
25
+ return { mine: "", theirs: "", whole: text };
26
+ }
27
+ function resultOf(mine, theirs, pens) {
28
+ const a = numeric(mine);
29
+ const b = numeric(theirs);
30
+ if (a === undefined || b === undefined)
31
+ return "unknown";
32
+ if (a !== b)
33
+ return a > b ? "win" : "loss";
34
+ const p = pens === undefined ? undefined : [numeric(pens[0]), numeric(pens[1])];
35
+ if (p !== undefined && p[0] !== undefined && p[1] !== undefined && p[0] !== p[1])
36
+ return p[0] > p[1] ? "win" : "loss";
37
+ return "draw";
38
+ }
39
+ function pensOf(value) {
40
+ return Array.isArray(value) && value.length === 2 && written(value[0]) !== "" && written(value[1]) !== "" ? [written(value[0]), written(value[1])] : undefined;
41
+ }
42
+ function viewOf(m, opponent, round, knockout) {
43
+ const { mine, theirs, whole } = split(m.score);
44
+ const pens = pensOf(m.pens);
45
+ const decided = m.decidedBy === "aet" || m.decidedBy === "pens" || m.decidedBy === "ft" ? m.decidedBy : pens !== undefined ? "pens" : "ft";
46
+ const note = typeof m.note === "string" ? m.note.trim() : undefined;
47
+ return {
48
+ round,
49
+ opponent,
50
+ mine,
51
+ theirs,
52
+ ...(whole === undefined ? {} : { whole }),
53
+ result: resultOf(mine, theirs, pens),
54
+ decided,
55
+ ...(pens === undefined ? {} : { pens }),
56
+ ...(note === undefined ? {} : { note }),
57
+ says: knockout || m.decidedBy !== undefined || pens !== undefined,
58
+ ...("homeFirst" in m && typeof m.homeFirst === "boolean" ? { homeFirst: m.homeFirst } : {}),
59
+ };
60
+ }
61
+ /** The rounds of two paths, the earliest first: a round both have is once, and a round only one has stays after the round before it. */
62
+ export function mergeRounds(paths) {
63
+ const out = [];
64
+ for (const path of paths) {
65
+ let at = 0;
66
+ for (const key of path) {
67
+ const found = out.indexOf(key);
68
+ if (found >= 0)
69
+ at = found + 1;
70
+ else {
71
+ out.splice(at, 0, key);
72
+ at += 1;
73
+ }
74
+ }
75
+ }
76
+ return out;
77
+ }
78
+ const isTeam = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.name === "string";
79
+ /** Read and check what `roadToFinal` was given. */
80
+ export function readModel(finalists, options) {
81
+ if (!Array.isArray(finalists) || finalists.length !== 2)
82
+ throw new TypeError("roadToFinal takes the two finalists as a list of two teams, each with a path");
83
+ const language = options.language === "ja" ? "ja" : "en";
84
+ const words = KYOGIJO_STRINGS[language];
85
+ const w = words.road;
86
+ const teams = finalists;
87
+ for (const [i, f] of teams.entries()) {
88
+ if (!isTeam(f))
89
+ throw new TypeError(`Finalist ${i + 1} is a team with a name`);
90
+ if (!Array.isArray(f.path))
91
+ throw new TypeError(`Finalist ${i + 1} (${f.name}) needs a path: the list of its matches before the final`);
92
+ if (f.group !== undefined && !Array.isArray(f.group))
93
+ throw new TypeError(`The group of ${f.name} is a list of matches`);
94
+ for (const m of [...f.path, ...(f.group ?? [])]) {
95
+ if (typeof m !== "object" || m === null || !isTeam(m.opponent) || m.score === undefined || m.score === null)
96
+ throw new TypeError(`Every match of ${f.name} has an opponent (a team with a name) and a score`);
97
+ }
98
+ for (const m of f.path)
99
+ if (typeof m.round !== "string" || m.round.trim() === "")
100
+ throw new TypeError(`Every match of the path of ${f.name} has a round`);
101
+ }
102
+ const path = teams.map((f) => {
103
+ const map = new Map();
104
+ for (const m of f.path)
105
+ map.set(m.round.trim(), viewOf(m, m.opponent, m.round.trim(), true));
106
+ return map;
107
+ });
108
+ const group = teams.map((f) => (f.group ?? []).map((m) => viewOf(m, m.opponent, "", false)));
109
+ const rounds = mergeRounds(teams.map((f) => f.path.map((m) => m.round.trim())));
110
+ const labels = options.labels;
111
+ const model = {
112
+ language,
113
+ words,
114
+ finalists: teams,
115
+ group,
116
+ path,
117
+ rounds,
118
+ label: (key) => (own(labels, key) && typeof labels?.[key] === "string" ? labels[key] : own(w.rounds, key) ? w.rounds[key] : key),
119
+ groupLabel: typeof options.groupLabel === "string" && options.groupLabel.trim() !== "" ? options.groupLabel.trim() : w.group,
120
+ title: typeof options.title === "string" && options.title.trim() !== "" ? options.title.trim() : w.title,
121
+ subtitle: typeof options.subtitle === "string" && options.subtitle.trim() !== "" ? options.subtitle.trim() : typeof options.title === "string" && options.title.trim() !== "" ? w.title : undefined,
122
+ };
123
+ if (options.final !== undefined) {
124
+ if (typeof options.final !== "object" || options.final === null || options.final.score === undefined || options.final.score === null)
125
+ throw new TypeError("The final is { score }: the first finalist's score first");
126
+ model.final = viewOf(options.final, teams[1], "final", true);
127
+ }
128
+ return model;
129
+ }
130
+ /** The words under a score: FT, AET or the shoot-out (the first side's numbers first), a note in their place, or nothing. */
131
+ export function decidedWords(view, w, mineFirst) {
132
+ if (view.note !== undefined)
133
+ return view.note;
134
+ if (!view.says)
135
+ return "";
136
+ if (view.decided === "aet")
137
+ return w.aet;
138
+ if (view.decided === "pens" && view.pens !== undefined)
139
+ return fill(w.pens, mineFirst ? { a: view.pens[0], b: view.pens[1] } : { a: view.pens[1], b: view.pens[0] });
140
+ return view.decided === "pens" ? w.aet : w.ft;
141
+ }
142
+ /** The score of a match as one text, the first side's first. */
143
+ export function scoreText(view, mineFirst = true) {
144
+ if (view.whole !== undefined)
145
+ return view.whole;
146
+ return mineFirst ? `${view.mine}-${view.theirs}` : `${view.theirs}-${view.mine}`;
147
+ }
148
+ /** The abbreviation written under a mark: the team's own, else made from its name. */
149
+ export function codeOf(team) {
150
+ return (typeof team.abbr === "string" && team.abbr.trim() !== "" ? team.abbr.trim() : abbreviate(String(team.name ?? ""))).slice(0, 5).toLocaleUpperCase("en");
151
+ }
152
+ function record(f, group, path) {
153
+ const all = [...group, ...path.values()];
154
+ let scored = 0;
155
+ let conceded = 0;
156
+ for (const v of all) {
157
+ const a = numeric(v.mine);
158
+ const b = numeric(v.theirs);
159
+ if (a !== undefined && b !== undefined) {
160
+ scored += a;
161
+ conceded += b;
162
+ }
163
+ }
164
+ return { name: f.name, matches: all.length, won: all.filter((v) => v.result === "win").length, drawn: all.filter((v) => v.result === "draw").length, lost: all.filter((v) => v.result === "loss").length, scored, conceded };
165
+ }
166
+ /** The numbers behind the chart. */
167
+ export function totalsOf(model) {
168
+ const [a, b] = model.finalists;
169
+ const final = model.final;
170
+ const champion = final === undefined || final.result === "unknown" || final.result === "draw" ? null : final.result === "win" ? a.name : b.name;
171
+ return { finalists: [record(a, model.group[0], model.path[0]), record(b, model.group[1], model.path[1])], rounds: [...model.rounds], played: final !== undefined, champion };
172
+ }
173
+ /** The chart's accessible name. */
174
+ export function nameOf(model) {
175
+ const heading = [model.title, model.subtitle].filter((part) => part !== undefined).join(model.words.said.sep);
176
+ return fill(model.words.road.name, { a: model.finalists[0].name, b: model.finalists[1].name, title: heading });
177
+ }
178
+ /** What the chart shows, in a sentence or two. */
179
+ export function summaryOf(model) {
180
+ const w = model.words.road;
181
+ const [a, b] = model.finalists;
182
+ const t = totalsOf(model);
183
+ const parts = [fill(w.summary, { a: a.name, b: b.name, an: t.finalists[0].matches, bn: t.finalists[1].matches })];
184
+ const final = model.final;
185
+ if (final === undefined)
186
+ parts.push(w.toPlay);
187
+ else {
188
+ parts.push(fill(w.final, { a: a.name, b: b.name, score: scoreText(final), how: decidedWords(final, w, true) || w.ft }));
189
+ if (t.champion !== null)
190
+ parts.push(fill(w.champion, { name: t.champion }));
191
+ }
192
+ return parts.join(model.words.said.gap);
193
+ }
194
+ /** One HTML table with a row for every match: the group stage, the knockout rounds in order, and the final. */
195
+ export function tableOf(model, options = {}) {
196
+ const w = model.words.road;
197
+ const cls = safeClass(options.className) || "ky-table";
198
+ const [a, b] = model.finalists;
199
+ const result = (r) => (r === "win" ? w.won : r === "loss" ? w.lost : r === "draw" ? w.drew : "");
200
+ const row = (team, round, v) => `<tr><th scope="row">${esc(team.name)}</th><td>${esc(round)}</td><td>${esc(v.opponent.name)}</td><td>${esc(scoreText(v))}</td><td>${esc(decidedWords(v, w, true))}</td><td>${esc(result(v.result))}</td></tr>`;
201
+ const rows = [];
202
+ for (const [i, team] of [a, b].entries()) {
203
+ for (const v of model.group[i])
204
+ rows.push(row(team, model.groupLabel, v));
205
+ for (const key of model.rounds) {
206
+ const v = model.path[i].get(key);
207
+ if (v !== undefined)
208
+ rows.push(row(team, model.label(key), v));
209
+ }
210
+ }
211
+ if (model.final !== undefined)
212
+ rows.push(row(a, model.label("final"), { ...model.final, opponent: b }));
213
+ const head = [w.tableTeam, w.tableRound, w.tableOpponent, w.tableScore, w.tableDecided, w.tableResult].map((name) => `<th scope="col">${esc(name)}</th>`).join("");
214
+ return `<table class="${cls}" data-kind="road"><caption>${esc(fill(w.caption, { a: a.name, b: b.name }))}</caption><thead><tr>${head}</tr></thead><tbody>${rows.join("")}</tbody></table>`;
215
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The rules of the road-to-the-final chart (`roadToFinal`): the ground, the ink and the quiet ink in light and dark, the panel behind a round's name, the road down the
3
+ * middle, and the classes of the title, the names, the scores and the small words under them. The colours are custom properties on the chart (`--ky-road-bg`,
4
+ * `--ky-road-ink`, `--ky-road-muted`, `--ky-road-panel`, `--ky-road-spine`, `--ky-road-left`, `--ky-road-right`), so a page can set them. A chart writes these rules in,
5
+ * with the round mark's (`KYOGIJO_MARK_STYLE`); `KYOGIJO_STYLE` has them for a page that draws with `style: "none"`.
6
+ */
7
+ export declare const KYOGIJO_ROAD_STYLE: string;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The rules of the road-to-the-final chart (`roadToFinal`): the ground, the ink and the quiet ink in light and dark, the panel behind a round's name, the road down the
3
+ * middle, and the classes of the title, the names, the scores and the small words under them. The colours are custom properties on the chart (`--ky-road-bg`,
4
+ * `--ky-road-ink`, `--ky-road-muted`, `--ky-road-panel`, `--ky-road-spine`, `--ky-road-left`, `--ky-road-right`), so a page can set them. A chart writes these rules in,
5
+ * with the round mark's (`KYOGIJO_MARK_STYLE`); `KYOGIJO_STYLE` has them for a page that draws with `style: "none"`.
6
+ */
7
+ export const KYOGIJO_ROAD_STYLE = `
8
+ :where(.kyogijo-road){--ky-road-bg:#f6f4ee;--ky-road-ink:#1d2421;--ky-road-muted:#5a655f;--ky-road-panel:#e7e3d6;--ky-road-spine:#c4bfae;--ky-road-left:#2f6db0;--ky-road-right:#b5452c;--ky-road-plain:#8b948f;--ky-mark-ring:#fff;--ky-mark-edge:rgba(0,0,0,.3);--ky-mark-plain:#fff;--ky-font:system-ui,-apple-system,"Segoe UI","Hiragino Sans","Noto Sans JP",sans-serif;display:block;width:100%;height:auto;font-family:var(--ky-font)}
9
+ @media (prefers-color-scheme:dark){:where(html:not([data-theme=light]) .kyogijo-road:not([data-theme=light])){--ky-road-bg:#131716;--ky-road-ink:#ece8dc;--ky-road-muted:#a9b2ac;--ky-road-panel:#252b28;--ky-road-spine:#3d4541;--ky-road-left:#6aa9f0;--ky-road-right:#f59a5b;--ky-mark-ring:#e9ece6;--ky-mark-edge:rgba(0,0,0,.6);--ky-mark-plain:#2a302d}}
10
+ :where(html[data-theme=dark] .kyogijo-road,.kyogijo-road[data-theme=dark]){--ky-road-bg:#131716;--ky-road-ink:#ece8dc;--ky-road-muted:#a9b2ac;--ky-road-panel:#252b28;--ky-road-spine:#3d4541;--ky-road-left:#6aa9f0;--ky-road-right:#f59a5b;--ky-mark-ring:#e9ece6;--ky-mark-edge:rgba(0,0,0,.6);--ky-mark-plain:#2a302d}
11
+ .kyogijo-road .ky-r-bg{fill:var(--ky-road-bg)}
12
+ .kyogijo-road text{font-family:var(--ky-font);font-variant-numeric:tabular-nums}
13
+ .kyogijo-road .ky-r-t{fill:var(--ky-road-ink);font-weight:800}
14
+ .kyogijo-road .ky-r-s,.kyogijo-road .ky-r-e{fill:var(--ky-road-muted);font-weight:600}
15
+ .kyogijo-road .ky-r-name{fill:var(--ky-road-ink);font-weight:800}
16
+ .kyogijo-road .ky-r-panel{fill:var(--ky-road-panel)}
17
+ .kyogijo-road .ky-r-lab{fill:var(--ky-road-ink);font-weight:700}
18
+ .kyogijo-road .ky-r-spine{stroke:var(--ky-road-spine);fill:none;stroke-linecap:round}
19
+ .kyogijo-road .ky-r-n{fill:var(--ky-road-ink);font-weight:800}
20
+ .kyogijo-road .ky-r-n.ky-r-low,.kyogijo-road .ky-r-dash{fill:var(--ky-road-muted);font-weight:700}
21
+ .kyogijo-road .ky-r-sub,.kyogijo-road .ky-r-code{fill:var(--ky-road-muted);font-weight:700}
22
+ .kyogijo-road .ky-r-vs{fill:var(--ky-road-muted);font-weight:700}
23
+ .kyogijo-road .ky-r-dim{opacity:.5}
24
+ .kyogijo-road .ky-r-left{--c:var(--ky-road-left)}
25
+ .kyogijo-road .ky-r-right{--c:var(--ky-road-right)}
26
+ .kyogijo-road .ky-r-plain{--c:var(--ky-road-plain)}`.trim();
@@ -0,0 +1,122 @@
1
+ import type { Language, Team } from "./types.ts";
2
+ /** A match's score from the finalist's side: `[for, against]` (numbers, or text such as a series' `4`), or one text, `"4-2"`, that is split at its dash. */
3
+ export type RoadScore = readonly [number | string, number | string] | string;
4
+ /** How a match was decided: `ft` (full time, the default), `aet` (after extra time) or `pens` (a shoot-out after extra time). */
5
+ export type RoadDecided = "ft" | "aet" | "pens";
6
+ /** One match on a finalist's way. */
7
+ export interface RoadMatch {
8
+ /** The round, as a key. `round-of-32`, `round-of-16`, `quarter-final` and `semi-final` have words in English and Japanese; any other key is written as it is, or as `options.labels` names it. */
9
+ round: string;
10
+ /** The team it played: its name, abbreviation, `logo` (the flag or the crest) and `color`. */
11
+ opponent: Team;
12
+ /** The score, the finalist's first: `[2, 1]` is a 2-1 win. */
13
+ score: RoadScore;
14
+ /** How it was decided: `ft` by default, or `pens` when `pens` is given. Written under the score: FT, AET, or the shoot-out. */
15
+ decidedBy?: RoadDecided;
16
+ /** The shoot-out, the finalist's first: `[4, 3]`. */
17
+ pens?: readonly [number | string, number | string];
18
+ /** The order of the pair, left to right: `true` the finalist first, `false` its opponent first. By default the finalist is at the outer edge of its side, so that the two paths mirror each other. */
19
+ homeFirst?: boolean;
20
+ /** Words to write under the score in place of FT, AET or the shoot-out (`Game 6`, `OT`). An empty text writes nothing. */
21
+ note?: string;
22
+ }
23
+ /** One match of the group stage: as a knockout match, without a round. */
24
+ export type RoadGroupMatch = Omit<RoadMatch, "round"> & {
25
+ round?: string;
26
+ };
27
+ /** A finalist: a team and the matches it played on the way, the earliest first. */
28
+ export interface RoadFinalist extends Team {
29
+ /** The knockout matches before the final, the earliest first. */
30
+ path: readonly RoadMatch[];
31
+ /** The group stage, in the order played. A row of small marks, codes and scores at the foot. */
32
+ group?: readonly RoadGroupMatch[];
33
+ }
34
+ /** The final, when it has been played. */
35
+ export interface RoadFinal {
36
+ /** The score, the first finalist's first. */
37
+ score: RoadScore;
38
+ decidedBy?: RoadDecided;
39
+ /** The shoot-out, the first finalist's first. */
40
+ pens?: readonly [number | string, number | string];
41
+ note?: string;
42
+ }
43
+ /** The sizes of the chart: `card` 1080 by 1350 (a tall post), `square` 1080 by 1080, `wide` 1200 by 675 (the finalists at the two ends) and `phone` 390 wide and as tall as it needs. */
44
+ export type RoadSize = "card" | "square" | "wide" | "phone";
45
+ /** What `roadToFinal` takes besides the finalists. */
46
+ export interface RoadOptions {
47
+ /** The words of the chart: its title, the rounds' names, how a match was decided and the table. English by default. */
48
+ language?: Language;
49
+ /** A prefix for the ids inside the drawing. Made from the chart when missing, so that two charts on a page do not share ids. */
50
+ id?: string;
51
+ /** The tournament, set large at the top. "Road to the final" when missing. */
52
+ title?: string;
53
+ /** The line under it. "Road to the final" when a `title` is given. */
54
+ subtitle?: string;
55
+ /** The final, if it has been played: its score is written between the two big marks, the winner is brighter, and the table has a row for it. */
56
+ final?: RoadFinal;
57
+ /** The names of the rounds, by key, over the package's own words. Any key a match uses may be named here: `{ "first-round": "First round" }`. */
58
+ labels?: Readonly<Record<string, string>>;
59
+ /** The group stage's name, over the package's own. */
60
+ groupLabel?: string;
61
+ /** `card` (the default), `square`, `wide` or `phone`. */
62
+ size?: RoadSize;
63
+ /** `light` or `dark` to force one; `auto` (the default) follows the device and the page. */
64
+ theme?: "auto" | "light" | "dark";
65
+ /** Who is brighter: `auto` (the default) the side that won each match, `none` nobody. */
66
+ winner?: "auto" | "none";
67
+ /** Write the opponent's three-letter code under its mark. On by default. */
68
+ codes?: boolean;
69
+ /** A line at the foot: a source, a credit, "Made-up results". */
70
+ endnote?: string;
71
+ /** A class for the root. */
72
+ className?: string;
73
+ /** `none` leaves the stylesheet to the page (`KYOGIJO_STYLE` has every rule). */
74
+ style?: "embed" | "none";
75
+ }
76
+ /** One finalist's record on the way. */
77
+ export interface RoadRecord {
78
+ name: string;
79
+ /** Matches played in the group and the knockout rounds (not the final), and how many it won, drew and lost. */
80
+ matches: number;
81
+ won: number;
82
+ drawn: number;
83
+ lost: number;
84
+ /** The goals it scored and let in over the matches whose score is a pair of numbers. */
85
+ scored: number;
86
+ conceded: number;
87
+ }
88
+ /** The numbers behind a road chart. */
89
+ export interface RoadTotals {
90
+ finalists: [RoadRecord, RoadRecord];
91
+ /** The rounds of the chart, the earliest first, as keys. */
92
+ rounds: string[];
93
+ /** The final has a score. */
94
+ played: boolean;
95
+ /** The winner of the final, or null when it has not been played or is level. */
96
+ champion: string | null;
97
+ }
98
+ /** The size in pixels a size draws at, and what it is for. */
99
+ export interface RoadSizeInfo {
100
+ readonly width: number;
101
+ /** `undefined` for a size that is as tall as the rounds need. */
102
+ readonly height: number | undefined;
103
+ readonly about: string;
104
+ }
105
+ /** What `roadToFinal` gives back. */
106
+ export interface RoadChart {
107
+ /** The options the chart was made with, with the finalists: pass changes to `draw`. */
108
+ options: RoadOptions;
109
+ /** The chart's accessible name, in the chart's language. */
110
+ title: string;
111
+ /** What the chart shows, in a sentence or two, for a caption. */
112
+ summary: string;
113
+ /** The numbers behind it. */
114
+ totals: RoadTotals;
115
+ /** The drawing as an SVG string. `extra` is laid over the options (`size`, `theme`, `language`, `labels`, `final`...). */
116
+ draw(extra?: Partial<RoadOptions>): string;
117
+ /** One HTML table with a row for every match: the table that stands for the drawing for a screen reader. */
118
+ table(options?: {
119
+ className?: string;
120
+ language?: Language;
121
+ }): string;
122
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export { sceneFromSvg, sceneOf } from "./scene.ts";
2
+ export { sceneToSvg } from "./scene.flat.ts";
3
+ export type { FlatOptions } from "./scene.flat.ts";
4
+ export { pathCommands } from "./scene.path.ts";
5
+ export { parseSvg, writeSvg } from "./scene.xml.ts";
6
+ export type { SvgNode } from "./scene.xml.ts";
7
+ export type { Matrix, Paint, PathCommand, Scene, SceneBase, SceneCircle, SceneClip, SceneEllipse, SceneGradient, SceneImage, SceneItem, SceneLine, SceneOptions, ScenePath, ScenePattern, ScenePoly, SceneRect, SceneShape, SceneSource, SceneStyle, SceneText } from "./scene.types.ts";
@@ -0,0 +1,5 @@
1
+ // A drawing as plain data: the shapes it is painted with, in order, their colours worked out for light or dark; and the SVG that needs no stylesheet.
2
+ export { sceneFromSvg, sceneOf } from "./scene.js";
3
+ export { sceneToSvg } from "./scene.flat.js";
4
+ export { pathCommands } from "./scene.path.js";
5
+ export { parseSvg, writeSvg } from "./scene.xml.js";
@@ -0,0 +1,44 @@
1
+ /** An element as the selectors see it. */
2
+ export interface CssNode {
3
+ name: string;
4
+ attrs: Readonly<Record<string, string>>;
5
+ parent?: CssNode;
6
+ }
7
+ interface Simple {
8
+ tag?: string;
9
+ classes: string[];
10
+ attrs: {
11
+ name: string;
12
+ value?: string;
13
+ }[];
14
+ where: Complex[][];
15
+ not: Complex[][];
16
+ }
17
+ /** Compounds from the leftmost to the rightmost, with the combinator that joins each to the one before. */
18
+ type Complex = {
19
+ combinator: " " | ">" | "";
20
+ simple: Simple;
21
+ }[];
22
+ interface Rule {
23
+ selector: Complex;
24
+ specificity: number;
25
+ order: number;
26
+ declarations: [string, string][];
27
+ }
28
+ /** A stylesheet's rules for one theme: those under `prefers-color-scheme` are in when the theme is that one, and the other media are out. */
29
+ export interface Stylesheet {
30
+ rules: Rule[];
31
+ }
32
+ /** Read a stylesheet. `theme` decides which `@media (prefers-color-scheme:…)` blocks count. */
33
+ export declare function parseStylesheet(css: string, theme: "light" | "dark", into?: Stylesheet): Stylesheet;
34
+ /** The declarations that apply to an element, lowest priority first (by weight, then by order). */
35
+ export declare function matched(sheet: Stylesheet, node: CssNode): [string, string][];
36
+ /** The declarations of a `style` attribute. */
37
+ export declare const inlineStyle: (text: string | undefined) => [string, string][];
38
+ /** Replace every `var(--name, fallback)` in a value. A name with no value and no fallback makes the whole value `undefined` (the property is not set). */
39
+ export declare function substitute(value: string, vars: Readonly<Record<string, string>>, depth?: number): string | undefined;
40
+ /** A value with its lengths worked out: `px` dropped, `em` multiplied by the font size, and every `calc()` replaced by its number. */
41
+ export declare function evaluate(value: string, fontSize: number): string;
42
+ /** A length or a number as a number of user units: `3`, `3px`, `.14em` (of the font size), and `calc()` of a product, sum or difference of those. */
43
+ export declare function lengthOf(value: string | undefined, fontSize: number): number | undefined;
44
+ export {};