Skip to the content

Capsid menu

app/lib/cv/types.ts

169 lines and 0 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.

Functions

None: it only declares types or values.

Imports

It imports no other module of this repo. Imported by app/db/cv.ts.

Source

/**
 * The shapes of the CV's source entries: what a file in content/cv/ states (docs/CV.md), before
 * app/lib/cv/entries.mjs resolves it into the entries every surface renders. Types only. The checks that hold
 * a file to them are in app/lib/cv/validate.mjs.
 *
 * PRIVACY (Capsid dustinedwards/decisions.md, PROTECTED): no student is named anywhere in the CV files. Mentoring is a count by
 * cohort, year, level and program; students appear only inside the published author lists of papers. No phone,
 * room, email or home location, and no private community groups.
 *
 * AREAS are the site's four research areas, and each tag must be defensible from the entry itself.
 * Where it is not, the list is empty rather than guessed.
 */

export type CvArea = "retroviruses" | "bacteriophages" | "science-education" | "ai";

export type CvType =
  | "appointment"
  | "education"
  | "publication"
  | "grant"
  | "award"
  | "talk"
  | "course"
  | "mentoring"
  | "service"
  | "development";

export type CvRole =
  | "first-author"
  | "senior-author"
  | "co-author"
  | "recipient"
  | "speaker"
  | "instructor"
  | "mentor"
  | "chair"
  | "organizer"
  | "member"
  | "editor"
  | "reviewer"
  | "judge"
  | "advisor"
  | "volunteer"
  | "consultant"
  | "participant";

export type CvLink = { label: string; href: string };

/**
 * `year` is when it started; `endYear` is when it ended, "present" while it continues, or absent for
 * a single year. A null year is an undated line (a membership, a canceled meeting): it matches no year
 * range and sorts last.
 */
type Dated = { year: number | null; endYear?: number | "present" };

type Tagged = { areas: CvArea[]; role: CvRole | null; links?: CvLink[] };

/** A paper the site has a record for: everything but the DOI comes from its file in content/publications/. */
type CvPaperRef = { type: "publication"; doi: string };

/** A paper with no site record, cited as the CV cites it. */
type CvPaperInline = Dated &
  Tagged & {
    type: "publication";
    title: string;
    authors: string[];
    journal: string;
    volume?: string;
    issue?: string;
    pages?: string;
  };

type CvAppointment = Dated &
  Tagged & {
    type: "appointment";
    section: "Positions" | "Administrative and leadership";
    title: string;
    org: string;
    detail?: string;
    /** Duties, grouped as the CV groups them. */
    duties?: { heading: string; items: string[] }[];
    /**
     * A current leadership title the site states beside the role (the headship): in the Person record's job
     * title, on the About page and on the CV's header. Other leadership entries stay on the CV alone.
     */
    headline?: boolean;
  };

type CvEducation = Dated &
  Tagged & { type: "education"; title: string; org: string; detail?: string };

type CvGrant = Dated &
  Tagged & {
    type: "grant";
    /** US dollars, as the CV states them. */
    amount: number;
    title: string;
    funder?: string;
    /** "with a student researcher" and the like; never a name. */
    note?: string;
  };

type CvAward = Dated & Tagged & { type: "award"; title: string; org?: string; place?: string };

type CvTalk = Dated &
  Tagged & {
    type: "talk";
    title: string;
    /** As the CV lists them; the co-presenters are faculty colleagues. */
    presenters: string[];
    venue: string;
  };

type CvCourse = Dated &
  Tagged & { type: "course"; code: string; title: string; org: string; term: string };

type CvMentoring = Dated &
  Tagged & {
    type: "mentoring";
    section: string;
    count: number;
    /** Students, or awards the mentored students won. Only students add to the students total. */
    unit: "students" | "awards";
    level: string;
    program: string;
    org: string;
    detail?: string;
    /** One cohort or academic year, so the count belongs to `year` alone and can be charted by year. */
    cohort: boolean;
  };

type CvService = Dated &
  Tagged & {
    type: "service";
    section:
      | "Department"
      | "College"
      | "University"
      | "Professional"
      | "Community"
      | "Compensated professional consulting"
      | "Professional memberships";
    title: string;
    org?: string;
    place?: string;
  };

type CvDevelopment = Dated & Tagged & { type: "development"; title: string; org?: string; place?: string };

export type CvSourceEntry =
  | CvPaperRef
  | CvPaperInline
  | CvAppointment
  | CvEducation
  | CvGrant
  | CvAward
  | CvTalk
  | CvCourse
  | CvMentoring
  | CvService
  | CvDevelopment;

/** The people the CV is about, as content/cv/profile.md states them. */
/** What the profile states. The person's title is not stated: it is derived (CvPersonView). */
export type CvPerson = {
  name: string;
  degree: string;
  /** The field he works in, "Virologist": the second half of the one-line role. */
  discipline: string;
  department: string;
  org: string;
};

/** The CV's own totals for presentations; only invited talks where Dustin leads are entries. */
export type CvPresentations = { international: number; national: number; from: number; to: number };

/** What the files hold, assembled in the order of CV_FILES (app/lib/cv/parse.mjs): one flat entry list. */
export type CvSource = {
  edition: string;
  person: CvPerson;
  presentations: CvPresentations;
  entries: CvSourceEntry[];
};

/**
 * What one file becomes, as D1's `cv.record` holds it and as the save, the sync and the build write it:
 * the profile's facts, or a section's entries with their type stated.
 */
export type CvFileRecord =
  | { slug: "profile"; type: "profile"; edition: string; person: CvPerson; presentations: CvPresentations }
  | { slug: string; type: CvType; entries: CvSourceEntry[] };