From 975cea84e3f8ba1c77aca06b55058487df1f21d4 Mon Sep 17 00:00:00 2001 From: Amruth Pillai Date: Sat, 4 Jul 2026 21:29:44 +0200 Subject: [PATCH] refactor(web): finding 5 - replace ts-pattern matchers with data maps Replace getItemTitle/getItemSubtitle exhaustive ts-pattern matchers with TITLE_FIELD/SUBTITLE_FIELD lookup maps + special-case branches for summary and cover-letter. Adds a shared truncateHtml helper. Removes ts-pattern import. Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa --- .../-sidebar/left/sections/custom.tsx | 146 +++++++++--------- 1 file changed, 77 insertions(+), 69 deletions(-) diff --git a/apps/web/src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx b/apps/web/src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx index 77a83f847..eda684e30 100644 --- a/apps/web/src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx +++ b/apps/web/src/routes/builder/$resumeId/-sidebar/left/sections/custom.tsx @@ -15,7 +15,6 @@ import { TrashSimpleIcon, } from "@phosphor-icons/react"; import { AnimatePresence, Reorder } from "motion/react"; -import { match } from "ts-pattern"; import { Badge } from "@reactive-resume/ui/components/badge"; import { DropdownMenu, @@ -39,78 +38,87 @@ import { getSectionTitle } from "@/libs/resume/section"; import { SectionBase } from "../shared/section-base"; import { SectionAddItemButton, SectionItem } from "../shared/section-item"; +// ponytail: data maps replace ts-pattern exhaustive matchers — same coverage, no runtime dependency +const TITLE_FIELD: Partial> = { + profiles: "network", + experience: "company", + education: "school", + projects: "name", + skills: "name", + languages: "language", + interests: "name", + awards: "title", + certifications: "title", + publications: "title", + volunteer: "organization", + references: "name", +}; + +const SUBTITLE_FIELD: Partial> = { + profiles: "username", + experience: "position", + education: "degree", + projects: "period", + skills: "proficiency", + languages: "fluency", + awards: "awarder", + certifications: "issuer", + publications: "publisher", + volunteer: "period", +}; + +function truncateHtml(html: string, max = 50): string { + const stripped = stripHtml(html); + return stripped.length > max ? `${stripped.slice(0, max)}...` : stripped; +} + function getItemTitle(type: CustomSectionType, item: CustomSectionItemType): string { - return match(type) - .with("summary", () => { - if ("content" in item) { - const stripped = stripHtml(item.content); - return stripped.length > 50 - ? `${stripped.slice(0, 50)}...` - : stripped || - t({ - comment: "Fallback title for a custom summary item in resume builder when content is empty", - message: "Summary", - }); - } - return t({ - comment: "Fallback title for a custom summary item in resume builder when content is unavailable", - message: "Summary", - }); - }) - .with("profiles", () => ("network" in item ? item.network : "")) - .with("experience", () => ("company" in item ? item.company : "")) - .with("education", () => ("school" in item ? item.school : "")) - .with("projects", () => ("name" in item ? item.name : "")) - .with("skills", () => ("name" in item ? item.name : "")) - .with("languages", () => ("language" in item ? item.language : "")) - .with("interests", () => ("name" in item ? item.name : "")) - .with("awards", () => ("title" in item ? item.title : "")) - .with("certifications", () => ("title" in item ? item.title : "")) - .with("publications", () => ("title" in item ? item.title : "")) - .with("volunteer", () => ("organization" in item ? item.organization : "")) - .with("references", () => ("name" in item ? item.name : "")) - .with("cover-letter", () => { - if ("recipient" in item) { - const stripped = stripHtml(item.recipient); - return stripped.length > 50 - ? `${stripped.slice(0, 50)}...` - : stripped || - t({ - comment: "Fallback title for a custom cover letter item in resume builder when recipient is empty", - message: "Cover Letter", - }); - } - return t({ - comment: "Fallback title for a custom cover letter item in resume builder when recipient is unavailable", - message: "Cover Letter", - }); - }) - .exhaustive(); + if (type === "summary") { + if ("content" in item) { + return ( + truncateHtml(item.content) || + t({ + comment: "Fallback title for a custom summary item in resume builder when content is empty", + message: "Summary", + }) + ); + } + return t({ + comment: "Fallback title for a custom summary item in resume builder when content is unavailable", + message: "Summary", + }); + } + if (type === "cover-letter") { + if ("recipient" in item) { + return ( + truncateHtml(item.recipient) || + t({ + comment: "Fallback title for a custom cover letter item in resume builder when recipient is empty", + message: "Cover Letter", + }) + ); + } + return t({ + comment: "Fallback title for a custom cover letter item in resume builder when recipient is unavailable", + message: "Cover Letter", + }); + } + const field = TITLE_FIELD[type]; + return field && field in item ? String((item as Record)[field]) : ""; } function getItemSubtitle(type: CustomSectionType, item: CustomSectionItemType): string | undefined { - return match(type) - .with("summary", () => undefined) - .with("profiles", () => ("username" in item ? item.username : undefined)) - .with("experience", () => ("position" in item ? item.position : undefined)) - .with("education", () => ("degree" in item ? item.degree : undefined)) - .with("projects", () => ("period" in item ? item.period : undefined)) - .with("skills", () => ("proficiency" in item ? item.proficiency : undefined)) - .with("languages", () => ("fluency" in item ? item.fluency : undefined)) - .with("interests", () => undefined) - .with("awards", () => ("awarder" in item ? item.awarder : undefined)) - .with("certifications", () => ("issuer" in item ? item.issuer : undefined)) - .with("publications", () => ("publisher" in item ? item.publisher : undefined)) - .with("volunteer", () => ("period" in item ? item.period : undefined)) - .with("references", () => undefined) - .with("cover-letter", () => { - if ("content" in item) { - const stripped = stripHtml(item.content); - return stripped.length > 50 ? `${stripped.slice(0, 50)}...` : stripped || undefined; - } - return undefined; - }) - .exhaustive(); + if (type === "cover-letter") { + if ("content" in item) { + const result = truncateHtml(item.content); + return result || undefined; + } + return undefined; + } + const field = SUBTITLE_FIELD[type]; + if (!field || !(field in item)) return undefined; + const value = (item as Record)[field]; + return typeof value === "string" ? value || undefined : undefined; } export function CustomSectionBuilder() {