Architecture#
Source layout#
All of the plugin’s logic lives under src/:
File |
Responsibility |
|---|---|
|
Plugin entry point: loads settings, registers the sidebar/month views, the editor suggest, the live preview extension, and the post-processor; adds the Open calendar in sidebar, Open calendar in a new tab, and Refresh calendars commands. |
|
Shared types: |
|
Default settings and the settings UI. |
|
Looks up the current Obsidian UI language via the official
|
|
A minimal read-only CalDAV client: calendar discovery
( |
|
An iCalendar (RFC 5545) parser extracting |
|
Expands a |
|
Resolves an account’s configured time zone (an IANA zone name via
|
|
|
|
Triggers on |
|
Reads a note’s |
|
Scans the vault for |
|
Builds the |
|
The inline event chip, and the click-to-open detail popup (a
manually positioned floating panel, closed on outside click or
Esc). The lookup is scoped to the |
|
A CodeMirror 6 |
|
A Markdown post-processor that does the same replacement for Reading
view, by scanning rendered text nodes directly - |
|
The sidebar agenda list: a fixed 30-day window of |
|
The full-tab month grid view (same |
|
The year/month picker opened from the month view’s heading, with a click-to-edit year field. |
Data flow#
settingsTab.ts --> CalDavAccount[] (server URL, credentials, calendars)
|
v
caldav/client.ts --> PROPFIND/REPORT over requestUrl
| (discovery + event fetch)
v
caldav/ics.ts --> parses each VEVENT into a CalDavEvent
|
v
caldav/recurrence.ts --> expands RRULE occurrences on demand
|
v
caldav/store.ts --> merged, cached, scoped CalDavEvent[]
|
+--> editorSuggest/*.ts --> autocomplete while typing
|
+--> render/livePreview.ts --> widget/chip (Live Preview)
|
+--> render/postProcessor.ts --> widget/chip (Reading view)
| |
| v
| render/eventChip.ts + eventCard.ts --> click-to-open detail popup
|
+--> view/AgendaItemView.ts / vue/AgendaView.vue --> sidebar list
|
+--> view/MonthItemView.ts / vue/MonthView.vue --> month grid
notes/noteEvents.ts (vault-wide frontmatter scan) --> NoteEvent[]
|
+--> (merged into a CalendarListItem[] alongside CalDavEvent[],
inside AgendaItemView.ts/MonthItemView.ts, right before
the sidebar list / month grid above render - nothing else
in this diagram ever sees a NoteEvent)
Reference syntax#
{{hrcal:<accountId>:<calendarName>:date:YYYY-MM-DD}} renders as a date
widget; {{hrcal:<accountId>:<calendarName>:event:<uid>}} renders as an
event chip. Both are normally inserted by the staged {{hrcal: editor
suggest, but either can be typed by hand too — an unresolvable reference
renders as a faded, dashed chip (or, for a date whose account/calendar
doesn’t match a registered one, a warning inside the widget) instead of
failing silently.
Both kinds are always scoped by the accountId/calendarName named
directly in the reference - note frontmatter (harang-account/
harang-calendar, see Usage) plays no role here any more.
accountId is the account’s stable internal id rather than its display
name, generated once when the account is created and never changing, so
renaming an account in Settings does not affect references inserted after
this id-based scheme took effect; calendarName is still the calendar’s
display name, so a calendar rename can still break existing references, the
same as before this change. There is no id-or-name fallback, so a reference
written before this change — using the account’s old name-based segment —
will no longer resolve and needs to be deleted and re-inserted via the
{{hrcal: editor suggest.
Note events (harang-date/harang-repeat/harang-time)#
Unrelated to the reference syntax above: a note carrying harang-date
frontmatter (see Usage) becomes a NoteEvent and shows up as an
item in the sidebar agenda list and month grid only - never in a
{{hrcal:...}} date widget or as an event chip, and never written to or
read from a CalDAV server. harang-repeat reuses the same rrule
package as caldav/recurrence.ts, but with its own from-scratch
expansion logic (see notes/noteEvents.ts above) rather than sharing
that module’s function directly, since a note event has no time-of-day at
all by default and needs consistently UTC-midnight-anchored date math
throughout to avoid the local/UTC all-day mismatch this project has hit
(and fixed) several times elsewhere. harang-time layers an optional
HH:MM-HH:MM display range on top of that all-day date math - it only
affects how a NoteEvent is labeled and sorted alongside timed CalDAV
events, not the (still UTC-midnight-anchored) date expansion itself.
No runtime dependencies beyond rrule#
Beyond what Obsidian itself provides (the obsidian package, CodeMirror
6, Vue 3) and the rrule package for
recurrence expansion, the plugin has no runtime dependencies — the CalDAV
client and iCalendar parser are both hand-written rather than pulled in
from npm, keeping the bundle small and avoiding exposure to a third-party
HTTP/XML parsing library’s own vulnerabilities.