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