1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! # JSCalendar
//!
//! The RFC 8984 conversion: the decoded calendar as a JSCalendar `Group`, and
//! back.
//!
//! [`Ical::to_jscalendar`] writes the decoded model as the JSON object a JMAP
//! calendar server exchanges; [`Ical::from_jscalendar`] reads one back,
//! borrowing the JSON tree's strings where it can. There is no JSCalendar model
//! in this crate: a Group is a plain [`serde_json::Value`], and iCalendar stays
//! the one decoded model, exactly as [`jcal`](crate::jcal) leaves it.
//!
//! ## A re-modelling, not a re-encoding
//!
//! jCal spells the same model in JSON. JSCalendar is a different model: a
//! `VCALENDAR` is a Group of Events and Tasks (RFC 8984 2.1, 2.2, 5.3), a
//! `DTEND` is a duration, an `ATTENDEE` line is a Participant object, a `VALARM`
//! is an Alert, and an overriding `VEVENT` is not a component at all but a patch
//! inside the series it overrides. The conversion rules are those of
//! [draft-ietf-calext-jscalendar-icalendar](https://datatracker.ietf.org/doc/draft-ietf-calext-jscalendar-icalendar/),
//! read against the published RFC 8984 rather than its successor: where the
//! draft names a member only JSCalendar 2.0 has, this crate writes RFC 8984's
//! (`recurrenceRules` rather than `recurrenceRule`, `sendTo` and `replyTo`
//! rather than `calendarAddress`).
//!
//! ## Nothing is dropped
//!
//! Both directions are lossless through an escape hatch, and only a non-object
//! root can fail the import. Exporting, a property or component with no
//! JSCalendar counterpart is kept whole in the object's `iCalendar` member, in
//! jCal syntax, and a parameter left over after a property converts is kept in
//! that member's `convertedProperties` record (draft 5.1.1). The same record
//! names the property a member came from wherever more than one could have, so
//! `updated` knows whether it was a `DTSTAMP` or a `LAST-MODIFIED`.
//!
//! Importing, the mirror hatch applies: a member with no iCalendar counterpart
//! becomes a `JSPROP` property holding its JSON, located by a `JSPTR` parameter
//! (draft 4.1.2, 4.2.2), and a collection key that was not simply the element's
//! position is carried on a `JSID` parameter so it survives the next conversion.
//!
//! ## What normalises
//!
//! Three things do not survive a round trip unchanged, and none of them is
//! recoverable from the JSON alone.
//!
//! An `RRULE`'s `UNTIL` is stated in UTC whenever `DTSTART` is, but RFC 8984
//! states it in the object's own time zone. Shifting between the two needs the
//! time-zone database, which this crate does not carry, so the wall-clock digits
//! are carried across unshifted: exact for a floating or UTC object, and off by
//! that zone's offset for any other. The whole of [`timezone`](crate::timezone)
//! is available to a caller that wants to shift it from the calendar's own
//! `VTIMEZONE`.
//!
//! A `DTEND` becomes a duration, so an event that ended in another time zone
//! than it started in comes back with the start's zone on both ends.
//!
//! Ordering inside a component is lost, since a JSCalendar object is a set of
//! members rather than a list of lines. Byte fidelity is the syntax tree's job;
//! JSCalendar is a projection of the decoded model, one further removed than
//! jCal is.
use ;
use ;
use Value;
use crateIcal;
/// What a JSCalendar value cannot be read as.
///
/// Only the shape of the document is refused; everything inside it is read
/// liberally, so this is a short list on purpose.