From bf235680a47733e4c452339e8c609a235cd348de Mon Sep 17 00:00:00 2001 From: Kevin Riehl Date: Wed, 3 Jun 2026 09:59:25 -0700 Subject: [PATCH] refactor: model TreeNode as a discriminated union Phase 3 (behavior-preserving): - Replace the 45-optional-field TreeNode interface with a tagged union over category: OriginNode | ExperienceNode | ProjectNode | SkillNode | EducationNode, sharing a BaseNode. Category-specific fields now live only on their member. - Modal template narrows by category (category === 'experience' && ...) instead of bare field-presence checks; equivalent at runtime since each field is exclusive to its category (proven by the union compiling against the data). - stats utils narrow correctly: aggregateSkills filters to SkillNode[] via a type predicate; countByProficiency and getPlayerClass guard on category. svelte-check: 0 errors (every data node conforms). lint/test/build clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/components/SkillTree.svelte | 14 ++--- src/lib/data.ts | 89 +++++++++++++++++------------ src/lib/utils/stats.test.ts | 4 +- src/lib/utils/stats.ts | 12 ++-- 4 files changed, 68 insertions(+), 51 deletions(-) diff --git a/src/lib/components/SkillTree.svelte b/src/lib/components/SkillTree.svelte index 635a04f..90469fc 100644 --- a/src/lib/components/SkillTree.svelte +++ b/src/lib/components/SkillTree.svelte @@ -1240,7 +1240,7 @@ {/if} - {#if selectedNode.company} + {#if selectedNode.category === 'experience' && selectedNode.company}
{selectedNode.company} {#if selectedNode.startDate} @@ -1252,7 +1252,7 @@ {/if} - {#if selectedNode.institution} + {#if selectedNode.category === 'education' && selectedNode.institution}
{selectedNode.institution} {#if selectedNode.degree} @@ -1265,7 +1265,7 @@ {/if} - {#if selectedNode.proficiency} + {#if selectedNode.category === 'skills' && selectedNode.proficiency}
{selectedNode.proficiency} - {#if selectedNode.highlights && selectedNode.highlights.length > 0} + {#if selectedNode.category === 'experience' && selectedNode.highlights && selectedNode.highlights.length > 0}