From a84e69b8c830f7efb49ba03520fdd1186ef81a70 Mon Sep 17 00:00:00 2001
From: Schreipfelerer <Schreipfelerer@gmail.com>
Date: Thu, 15 May 2025 17:21:51 +0200
Subject: [PATCH] stop compiler form crying

---
 src/index.ts         | 19 ++++++++-------
 src/lib/parsing.ts   | 58 +++++++++++++++++++++++++++++++++++++-------
 src/lib/rendering.ts | 24 +++++++++---------
 3 files changed, 72 insertions(+), 29 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index dec2453..6763d36 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -14,6 +14,7 @@ import {
     renderTranscriptPageHtml,
 } from "./lib/rendering";
 import { generateAttendancePage } from "./lib/attendance";
+// @ts-ignore
 import bootstrap from "bootstrap/dist/css/bootstrap.min.css";
 
 async function main() {
@@ -87,27 +88,27 @@ async function run(inputDir: string, outputDir: string, options: CliOptions) {
         }
     }
 
-    const allMeta = [
-        ...parseResults.map((res) => res.data),
+    const allMeta: { meta: FinishedTranscriptMeta }[] = [
+        ...parseResults.map((res) => res.data!),
         ...oldTranscripts.map((t) => ({ meta: t })),
-    ]
+    ];
+
+    allMeta
         .sort((a, b) => b.meta.date.localeCompare(a.meta.date))
         .map((res) => ({
             ...res,
             meta: {
                 ...res.meta,
                 resolutions: res.meta.resolutions?.sort((a, b) => {
-                    const tOrder = { P: 0, F: 1, B: 2 };
+                    const tOrder = { P: 0, F: 1, B: 2, U: undefined };
 
                     function getNum(x: Resolution) {
-                        return parseInt(
-                            x.number.match(/\d+\.(\d+)[PBF]?/)?.[1],
-                            10,
-                        );
+                        const match = /\d+\.(\d+)[PBF]?/.exec(x.number);
+                        return match ? parseInt(match[1], 10) : NaN;
                     }
 
                     function getType(x: Resolution) {
-                        return x.number.match(/\d+\.\d+([PBF]?)/)?.[1];
+                        return x.number.match(/\d+\.\d+([PBF]?)/)?.[1] ?? "U";
                     }
 
                     // This works because `0` and `NaN` are falsy. :)
diff --git a/src/lib/parsing.ts b/src/lib/parsing.ts
index cdae812..384cfb3 100644
--- a/src/lib/parsing.ts
+++ b/src/lib/parsing.ts
@@ -63,9 +63,9 @@ export function parseOld(
 ): FinishedTranscriptMeta[] {
     return old.map((t) => ({
         // Fallback for some options:
-        spec_version: -1, // PDFs
-        no_link: false,
         ...t,
+        spec_version: t.spec_version ?? -1, // PDFs
+        no_link: t.no_link ?? false,
         // Reformat resolutions
         resolutions: t.resolutions?.map((r) => {
             let accepted = r.accepted;
@@ -86,10 +86,9 @@ export function parseOld(
                 }
             }
             return {
+                ...r,
                 html: `<span>${markdownParser.utils.escapeHtml(r.text)}</span>`,
-                text: r.text,
                 accepted,
-                ...r,
             };
         }),
     }));
@@ -106,6 +105,38 @@ function _endBlock(ast, start, level, close) {
     throw new TypeError(`Encountered open without close: '${close}'`);
 }
 
+function _popKey<T>(
+    map: Map<string, string>,
+    key: string,
+    ok: (val: string) => T,
+    onMissing: string,
+    extraCheck?: (val: string) => boolean,
+): T;
+
+function _popKey<T>(
+    map: Map<string, string>,
+    key: string,
+    ok: (val: string) => T,
+    onMissing?: undefined,
+    extraCheck?: (val: string) => boolean,
+): T | undefined;
+
+function _popKey(
+    map: Map<string, string>,
+    key: string,
+    ok: undefined,
+    onMissing: string,
+    extraCheck?: (val: string) => boolean,
+): string;
+
+function _popKey(
+    map: Map<string, string>,
+    key: string,
+    ok?: undefined,
+    onMissing?: undefined,
+    extraCheck?: (val: string) => boolean,
+): string | undefined;
+
 function _popKey<T>(
     map: Map<string, string>,
     key: string,
@@ -304,6 +335,7 @@ export interface Resolution {
               abstention: number;
           };
     relevant?: { till?: Date | null; reason?: string };
+    no_link?: boolean;
 }
 
 export interface Todo {
@@ -348,7 +380,7 @@ function _extractMainClass(token: Token) {
     return [...token.type.matchAll(/^container_(\S+)_open$/g)]?.[0]?.[1];
 }
 
-function _extractBase(tokens: [Token], mainClass?: string) {
+function _extractBase(tokens: Token[], mainClass?: string) {
     if (tokens.length < 1) {
         throw TypeError(
             "Parsing this requires an inline span with at least one child",
@@ -366,7 +398,11 @@ function _extractBase(tokens: [Token], mainClass?: string) {
     }
 
     const spanAttributes = new Map(tokens[0].attrs);
-    const html = markdownParser.renderer.render(tokens, { breaks: false });
+    const html = markdownParser.renderer.render(
+        tokens,
+        { breaks: false },
+        undefined,
+    );
     // See comment in uresolution
     const text = tokens
         .filter((t) => t.type == "text" || t.type == "inline")
@@ -390,8 +426,12 @@ function _extractBase(tokens: [Token], mainClass?: string) {
     };
 }
 
-function tryExtractCards(tokens: [Token], sharedState, mainClass): Token {
-    let rendered = undefined;
+function tryExtractCards(
+    tokens: Token[],
+    sharedState,
+    mainClass,
+): Token | undefined {
+    let rendered: undefined | string = undefined;
 
     const base = _extractBase(tokens, mainClass);
 
@@ -567,7 +607,7 @@ function tryExtractResolution(base, date): Resolution | null {
         throw new TypeError("Auslaufgrund impliziert Auslaufdatum.");
     }
 
-    if (till instanceof Date && isNaN(till)) {
+    if (till instanceof Date && isNaN(till?.valueOf())) {
         throw new TypeError(
             "Auslaufdatum muss ein gültiges Datum oder `forever` sein.",
         );
diff --git a/src/lib/rendering.ts b/src/lib/rendering.ts
index e134bb1..9e63f59 100644
--- a/src/lib/rendering.ts
+++ b/src/lib/rendering.ts
@@ -24,17 +24,17 @@ export function renderResolutionToHtml(resolution: Resolution): string {
         <div class="row align-items-center">
             <div class="col">
                 <span class="p-1 border-bottom border-success border-2">
-                    Ja: ${resolution.votes.yes}
+                    Ja: ${resolution.votes!.yes}
                 </span>
             </div>
             <div class="col">
                 <span class="p-1 border-bottom border-danger border-2">
-                    Nein: ${resolution.votes.no}
+                    Nein: ${resolution.votes!.no}
                 </span>
             </div>
             <div class="col">
                 <span class="p-1 border-bottom border-info border-2">
-                    Enthaltung: ${resolution.votes.abstention}
+                    Enthaltung: ${resolution.votes!.abstention}
                 </span>
             </div>
         </div>
@@ -391,14 +391,14 @@ export function generateResolutionsHtml(
                   .map((t) => {
                       const transcriptFilename = !t.no_link
                           ? getTranscriptFilename(t)
-                          : null;
+                          : undefined;
                       const resolutions = t.resolutions ?? [];
 
                       return resolutions.map((r) =>
                           generateResolutionRowHtml(
                               r,
-                              transcriptFilename,
                               t.date,
+                              transcriptFilename,
                               modifiedBy.get(r.number),
                               revokedBy.get(r.number),
                           ),
@@ -416,20 +416,22 @@ export function generateResolutionsHtml(
 
 function generateResolutionRowHtml(
     resolution: Resolution,
-    transcriptFileName?: string,
     date: string,
+    transcriptFileName?: string,
     modifiedBy?: Resolution[],
     revokedBy?: Resolution[],
 ): string {
     function samePageResolutionLink(other: Resolution | string) {
-        const number = other?.number ?? other;
-        // TODO: check if link exists.
+        const number = typeof other === "string" ? other : other.number;
         const link = `<a href=${"#" + number}>${number}</a>`;
         return typeof other === "string" || other.isActive !== false
             ? link
             : `<del>${link}</del>`;
     }
-    function linkResolutions(name: string, others: Resolution[] | string[]) {
+    function linkResolutions(
+        name: string,
+        others: Resolution[] | string[] | undefined,
+    ) {
         function genInnerHTML(name: string, others: Resolution[] | string[]) {
             return `<strong>${name}:</strong> ${others.map(samePageResolutionLink).join(", ")}`;
         }
@@ -439,7 +441,7 @@ function generateResolutionRowHtml(
     }
 
     let linkedNumber =
-        transcriptFileName !== null
+        transcriptFileName !== undefined
             ? `<a href="../protokolle/${transcriptFileName}/#${resolution.number}">${resolution.number}</a>`
             : `${resolution.number}`;
 
@@ -453,7 +455,7 @@ function generateResolutionRowHtml(
         votes = Object.keys(resolution.votes)
             .map(
                 (r) =>
-                    `${r === "abstention" ? "Enth." : r}: ${resolution.votes[r]}`,
+                    `${r === "abstention" ? "Enth." : r}: ${resolution.votes![r]}`,
             )
             .join("<br>");
     } else {
-- 
GitLab