Parsing goes through icalendar's low-level parser, which keeps properties in order and keeps repeated ones. Writing is ours: that crate's writer escapes a whole property value as text, so CATEGORIES:Work,Personal would go out as one category named "Work,Personal" to every other client. Anything the model does not interpret is carried rather than dropped -- X-MOZ-LASTACK, X-EVOLUTION-ALARM-UID, ACKNOWLEDGED, the X-MICROSOFT-CDO set, unrecognised ATTENDEE parameters, and whole VTODO/VJOURNAL components. A calendar has several clients writing to it and this one is not the authority on which properties matter. VTIMEZONE is modelled properly, and TZID is stored exactly as written: Exchange names its zones "Pacific Standard Time", which no IANA lookup resolves, and normalising at parse time would make the document unrepresentable. Mapping to a real zone belongs at the point of use. Tested against a golden corpus captured from the live Baikal (seven producing clients over five years) and a published Outlook feed, scrubbed of private content with the structure left byte-for-byte. Eight hand-written fixtures cover what neither server had: DURATION, floating times, RDATE, DST boundaries, leap day, and the full escape set. The contract is that parse -> write -> parse is stable, plus a check that no property name loses occurrences across the trip, since a parser that dropped ATTENDEE entirely would round-trip perfectly and still be wrong.
41 lines
1.4 KiB
TOML
41 lines
1.4 KiB
TOML
[package]
|
|
name = "runway-core"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
description = "Pure calendar domain: RFC 5545 model, iCalendar round-trip, recurrence expansion."
|
|
|
|
[features]
|
|
default = ["model"]
|
|
# Types only. Wasm-safe, dependency-light: this is all the frontend needs.
|
|
model = []
|
|
# iCalendar parsing/serialisation. Server and CLI only.
|
|
ical = ["dep:icalendar"]
|
|
# RRULE expansion. Server and CLI only.
|
|
recurrence = ["dep:rrule", "dep:chrono-tz"]
|
|
|
|
[dependencies]
|
|
chrono = { workspace = true }
|
|
serde = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
uuid = { workspace = true }
|
|
chrono-tz = { workspace = true, optional = true }
|
|
icalendar = { workspace = true, optional = true }
|
|
rrule = { workspace = true, optional = true }
|
|
|
|
# On wasm there is no OS entropy source, so uuid needs to be pointed at the
|
|
# browser's crypto API explicitly. Without this the frontend cannot compile the
|
|
# shared model at all -- worth catching in CI, not at deploy time.
|
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
|
uuid = { workspace = true, features = ["js"] }
|
|
|
|
[dev-dependencies]
|
|
serde_json = { workspace = true }
|
|
pretty_assertions = { workspace = true }
|
|
# Turns the optional features on for the test build only, so `cargo test` covers
|
|
# the iCalendar layer without the frontend's default build ever pulling it in.
|
|
runway-core = { path = ".", features = ["ical"] }
|
|
|
|
[lints]
|
|
workspace = true
|