/* * Why use YAML + Zod setup instead of plain ol' JSON data files? * * - YAML is way easier to write — no quotes, commas, or braces everywhere * - Zod validates data at build time (catches typos and missing fields early) * - Built-in validation for emails, URLs, etc. * - Easy data transformation (like resolving asset paths for Vite) * * Yeah, it's a bit more setup, but the DX improvement is totally worth it. * */ import z from "zod"; import { resolveStaticImg, slugify } from "$lib/utils"; import DEVS from "./devs.yaml"; import SOCIALS from "./socials.yaml"; const teamModules = import.meta.glob("./team/*.{yaml,yml}", { eager: true }); const TEAM_FILES = Object.entries(teamModules).reduce( (acc, [path, mod]) => { const year = path.match(/(\d{4})\.(yaml|yml)$/)?.[1]; if (year && mod !== null && typeof mod === "object" && "default" in mod) { acc[year] = mod.default; } return acc; }, {} as Record, ); const LinkSchema = z.object({ platform: z.string(), url: z.url(), }); const MemberSchema = z.object({ name: z.string(), links: z.array(LinkSchema).default([]), }); const createTeamSchema = (year: string) => { const CoreMemberSchema = MemberSchema.extend({ title: z.string(), avatar: z.string().transform(av => resolveStaticImg(`leads/${year}/${av}`)), }); const GroupSchema = z .object({ name: z.string(), leads: z.array( MemberSchema.extend({ avatar: z.string().transform(av => resolveStaticImg(`leads/${year}/${av}`)), }), ), }) .transform(group => ({ ...group, id: slugify(group.name), })); return z.object({ core: z.array(CoreMemberSchema), groups: z.array(GroupSchema), }); }; const SocialsSchema = z.array( z.object({ platform: z.string(), url: z.url(), }), ); const RoleEnum = z.enum(["Project Lead", "Co-Lead", "Backend", "Frontend", "Documentation"]); const DevSchema = z.array( MemberSchema.extend({ avatar: z .string() .transform(av => resolveStaticImg(av)) .optional(), roles: z.array(RoleEnum), }), ); export const DEV_DATA = DevSchema.parse(DEVS); export type TDevData = z.infer; export const TEAM_DATA_BY_YEAR = Object.entries(TEAM_FILES).reduce( (acc, [year, data]) => { const TeamSchema = createTeamSchema(year); acc[year] = TeamSchema.parse(data); return acc; }, {} as Record>>, ); export type TTeamData = z.infer>; export const SOCIALS_DATA = SocialsSchema.parse(SOCIALS); export type TSocialsData = z.infer;