import type { H3Event } from 'h3' interface SelectValue { value: string } interface FileValue { url: string visible_name: string } export interface CvRow { id: number From: string | null To: string | null Type: SelectValue | null Institution: string | null Area: string | null area_german?: string | null Place: SelectValue | null Grade: string | null file?: FileValue[] | null urls?: string | null } export function cvTable(event: H3Event): string { const { baserowCvTableId } = useRuntimeConfig(event) if (!baserowCvTableId) { throw createError({ statusCode: 500, statusMessage: 'NUXT_BASEROW_CV_TABLE_ID is not set' }) } return baserowCvTableId } /** Baserow hands out file URLs with its internal protocol (http); serve them from the configured Baserow URL instead */ function fileUrl(url: string, baserowUrl: string): string { const { pathname } = new URL(url) return new URL(pathname, baserowUrl).href } function toCvLink(line: string): CvLink | null { // "https://…", or "Label https://…" for custom link text const match = line.match(/^(.*?)[\s:|–-]*(https?:\/\/\S+)$/) if (!match) return null let url: URL try { url = new URL(match[2]!) } catch { return null } const path = url.pathname.replace(/\/+$/, '') const kind = url.hostname === 'github.com' ? 'github' : 'web' const fallback = kind === 'github' ? path.slice(1) : url.hostname + path return { label: match[1]!.trim() || fallback, url: url.href, kind } } /** One URL per line; a blank line starts a new group */ function toCvLinks(text: string | null | undefined): CvLink[][] { return (text ?? '') .split(/\n\s*\n/) .map(block => block.split('\n').map(line => toCvLink(line.trim())).filter((link): link is CvLink => !!link)) .filter(group => group.length) } export function toCvEntry(row: CvRow, baserowUrl: string): CvEntry | null { if (!row.From) return null return { id: row.id, from: row.From, to: row.To || null, type: (row.Type?.value as CvType | undefined) ?? null, institution: (row.Institution ?? '').trim(), area: (row.Area ?? '').trim(), areaGerman: (row.area_german ?? '').trim(), place: row.Place?.value ?? null, grade: row.Grade ?? null, files: (row.file ?? []).map(file => ({ name: file.visible_name, url: fileUrl(file.url, baserowUrl) })), links: toCvLinks(row.urls) } }