CourseKitStarPlan
Room & Instructor Extractors
Pull structured room and instructor metadata out of free-form iCal LOCATION and DESCRIPTION fields
StarPlan VEVENTs encode rooms in LOCATION and instructors in DESCRIPTION as free-form text. These extractors apply configurable regex patterns to produce structured records you can store. Defaults match HFU conventions; pass a config to support other institutions.
extractRoom
import { extractRoom, type ExtractedRoom } from '@hfu.digital/coursekit-starplan';
const room = extractRoom('A1.0.1');
// → { name: 'A1.0.1', building: 'A1', floor: '0', isOnline: false }
const online = extractRoom('Online (Zoom)');
// → { name: 'Online (Zoom)', building: null, floor: null, isOnline: true }
const unknown = extractRoom('Aula');
// → { name: 'Aula', building: null, floor: null, isOnline: false }
const missing = extractRoom('');
// → nullRoomExtractorConfig
| Option | Type | Default | Description |
|---|---|---|---|
pattern | RegExp | /^([A-Za-z]+\d*)\.(\d+)\.\d+/ | Captures building (group 1) and floor (group 2). Default matches HFU's A1.0.1 pattern. |
onlineKeywords | string[] | ['online', 'zoom', 'teams', 'virtuell', 'virtual', 'webex'] | Lowercased substrings that flag a location as online/virtual |
ExtractedRoom
interface ExtractedRoom {
name: string; // Original LOCATION (trimmed)
building: string | null; // Uppercased capture group 1, or null
floor: string | null; // Capture group 2, or null
isOnline: boolean; // True if any onlineKeyword matched
}extractInstructor
import { extractInstructor } from '@hfu.digital/coursekit-starplan';
const name = extractInstructor('Dozent: Prof. Dr. Mustermann\nRaum: A1.0.1');
// → 'Prof. Dr. Mustermann'
const none = extractInstructor('Praktikum');
// → nullInstructorExtractorConfig
| Option | Type | Default | Description |
|---|---|---|---|
patterns | RegExp[] | German + English defaults | Patterns whose first capture group is the instructor name. Tried in order; first match wins. |
minNameLength | number | 3 | Reject captures shorter than this |
maxNameLength | number | 100 | Reject captures longer than this |
Default patterns (in order):
/Dozent(?:in)?:\s*(.+?)(?:\n|$)/i
/Instructor:\s*(.+?)(?:\n|$)/i
/Lehrer(?:in)?:\s*(.+?)(?:\n|$)/i
/Prof\.?\s*(?:Dr\.?\s*)?(.+?)(?:\n|$)/iCaptures containing @ are rejected (avoids matching email addresses).
Notes
- Both extractors fall back to
nullrather than throwing — handle the null case explicitly when persisting. - For multi-instructor support, run
extractInstructorwith custom patterns or split the description yourself before passing it in. - Building names are uppercased; floor strings are returned as-is (so
'A1.05.10'→building: 'A1', floor: '05').