courseModel.js Core logic
Course normalization and edge extraction. Called once per course when the catalog loads. Transforms raw JSON from the catalog scraper into the internal Course shape used by all other modules.
Parent
Called by
PlannerContext.jsx (once at startup, for every course)
Imports
constants.js (SUBJECT_PALETTE)
The normalization transform
flowchart LR
RAW["Raw catalog JSON\n{id, subject, number,\ntitle, credits, prereqs,\nterms, nuPath, ...}"]
NORM["normalizeCourse()"]
OUT["Internal Course object\n{id, subject, number, classId,\ntitle, description,\ncredits, shMin, shMax,\nprereqs, coreqs,\nofferedFall/Spring/SumA/SumB,\nnuPath, color, edges}"]
RAW --> NORM --> OUT
Exported functions
normalizeCourse(raw) → Course
Converts a raw catalog entry to the internal shape:
- id:
subject + numberwith no space (e.g."CS3500") - classId:
parseInt(number)for numeric comparisons - shMin / shMax: parsed from variable-credit ranges like "1-4 credits"
- offeredFall/Spring/SumA/SumB: derived from Banner term codes via
getOfferedFromTerms() - color: deterministic hex color from
subjectColor(subject) - edges: extracted prerequisite/corequisite edges via
extractEdges()
Returns: Course object in internal format
extractEdges(courseId, prereqs, coreqs) → Edge[]
Walks the prereq and coreq trees recursively. At each leaf node (
{ subject, classId }), emits one edge. Edges are used to draw SVG lines in RelationLines and list relationships in InfoPanel.
Returns: Edge[] — each is
{ from: string, to: string, type: "prerequisite"|"corequisite" }subjectColor(subject) → string
Deterministic color hash. Sums the char codes of the subject string, then indexes into
SUBJECT_PALETTE (25 CSS hex colors). Same subject always gets the same color across sessions and builds. Used for the left-edge stripe on CourseCard.
Returns: CSS hex color string, e.g. "#4a90d9"
getOfferedFromTerms(terms) → string[]
Maps Banner term codes to offering labels. Banner codes end in:
10 = fall, 30 = spring, 40 = Summer I (sumA), 60 = Summer II (sumB).
Deduplicates and returns a subset of ["fall","spring","sumA","sumB"].
Returns: string[] — offering type labels
Internal Course schema
{
"id": "CS3500", // canonical key, no space
"subject": "CS",
"number": "3500",
"classId": 3500, // parseInt(number)
"title": "Object-Oriented Design",
"description": "...",
"credits": 4,
"shMin": 4, // same as credits if not variable
"shMax": 4, // shMin !== shMax → variable credit
"prereqs": { // recursive AND/OR tree, or null
"type": "or",
"courses": [
{ "subject": "CS", "classId": 2510 },
{ "subject": "CS", "classId": 2511 }
]
},
"coreqs": null,
"terms": ["202510", "202530"], // Banner term codes
"offeredFall": true,
"offeredSpring": true,
"offeredSumA": false,
"offeredSumB": false,
"nuPath": ["AD"],
"color": "#4a90d9", // from subjectColor()
"edges": [ // from extractEdges()
{ "from": "CS3500", "to": "CS2510", "type": "prerequisite" }
]
}