iamcal 3.1.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/component.d.ts +2 -1
- package/lib/component.d.ts.map +1 -1
- package/lib/component.js +14 -16
- package/lib/components/CalendarEvent.d.ts +34 -8
- package/lib/components/CalendarEvent.d.ts.map +1 -1
- package/lib/components/CalendarEvent.js +67 -8
- package/lib/date.d.ts +41 -3
- package/lib/date.d.ts.map +1 -1
- package/lib/date.js +75 -7
- package/lib/duration.d.ts +106 -0
- package/lib/duration.d.ts.map +1 -0
- package/lib/duration.js +277 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/property/Property.d.ts +24 -2
- package/lib/property/Property.d.ts.map +1 -1
- package/lib/property/Property.js +71 -4
- package/lib/property/validate.js +2 -2
- package/package.json +1 -1
- package/src/component.ts +15 -23
- package/src/components/CalendarEvent.ts +73 -9
- package/src/date.ts +96 -13
- package/src/duration.ts +329 -0
- package/src/index.ts +1 -0
- package/src/property/Property.ts +80 -5
- package/src/property/validate.ts +1 -1
package/lib/property/validate.js
CHANGED
|
@@ -126,7 +126,7 @@ function validateDateTime(value) {
|
|
|
126
126
|
(0, date_1.parseDateTimeString)(value);
|
|
127
127
|
}
|
|
128
128
|
catch {
|
|
129
|
-
throw new PropertyValidationError(`${value} does not match pattern for
|
|
129
|
+
throw new PropertyValidationError(`${value} does not match pattern for DATE-TIME`);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
@@ -314,4 +314,4 @@ function validateProperty(property) {
|
|
|
314
314
|
validateValue(property.value, valueType);
|
|
315
315
|
}
|
|
316
316
|
/* eslint-enable jsdoc/require-description-complete-sentence */
|
|
317
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
317
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJvcGVydHkvdmFsaWRhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBNEJBLHdDQUtDO0FBT0QsMENBS0M7QUFPRCxrRUFRQztBQU9ELG9DQVFDO0FBT0QsNENBUUM7QUFPRCw0Q0FLQztBQU9ELHNDQUtDO0FBT0QsMENBS0M7QUFPRCx3Q0FLQztBQVFELHdEQUVDO0FBT0Qsb0NBS0M7QUFPRCxvQ0FLQztBQU9ELGtDQVFDO0FBT0QsOENBS0M7QUFRRCxzQ0FnREM7QUFPRCxrREFLQztBQW9CRCw0Q0FzQkM7QUFyVEQsa0NBQThEO0FBQzlELHNEQUF1QztBQUN2QywwQ0FBZ0Q7QUFFaEQsbUNBQXFFO0FBQ3JFLDJDQUF3RTtBQUV4RSw2RUFBNkU7QUFDN0UsTUFBYSx1QkFBd0IsU0FBUSxLQUFLO0lBQzlDLFlBQVksT0FBZTtRQUN2QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDZCxJQUFJLENBQUMsSUFBSSxHQUFHLHlCQUF5QixDQUFBO0lBQ3pDLENBQUM7Q0FDSjtBQUxELDBEQUtDO0FBRUQsMEVBQTBFO0FBQzFFLE1BQWEsb0JBQXFCLFNBQVEsS0FBSztJQUMzQyxZQUFZLE9BQWU7UUFDdkIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ2QsSUFBSSxDQUFDLElBQUksR0FBRyxzQkFBc0IsQ0FBQTtJQUN0QyxDQUFDO0NBQ0o7QUFMRCxvREFLQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixjQUFjLENBQUMsS0FBYTtJQUN4QyxJQUFJLENBQUMsSUFBQSw2QkFBa0IsRUFBQyxRQUFRLENBQUMsZUFBZSxFQUFFLEtBQUssQ0FBQztRQUNwRCxNQUFNLElBQUksdUJBQXVCLENBQzdCLEdBQUcsS0FBSyxvQ0FBb0MsQ0FDL0MsQ0FBQTtBQUNULENBQUM7QUFFRDs7OztHQUlHO0FBQ0gs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
|
package/package.json
CHANGED
package/src/component.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { CalendarDateOrTime } from './date'
|
|
1
|
+
import { CalendarDateOrTime, isCalendarDateOrTime } from './date'
|
|
2
|
+
import { CalendarDuration } from './duration'
|
|
2
3
|
import { Property } from './property/Property'
|
|
3
4
|
import type { AllowedPropertyName, KnownPropertyName } from './property/names'
|
|
4
5
|
import {
|
|
@@ -83,33 +84,24 @@ export class Component {
|
|
|
83
84
|
return null
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
setProperty(name: string, value: string | CalendarDateOrTime): this {
|
|
87
|
+
setProperty(name: string, value: string | CalendarDateOrTime | CalendarDuration): this {
|
|
87
88
|
for (const property of this.properties) {
|
|
88
89
|
if (property.name !== name) continue
|
|
89
|
-
|
|
90
|
-
if (typeof value === 'string') {
|
|
91
|
-
property.value = value
|
|
92
|
-
return this
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const dateProperty = Property.fromDate(name, value)
|
|
96
|
-
|
|
97
|
-
// Update value type
|
|
98
|
-
if (dateProperty.getValueType() === 'DATE')
|
|
99
|
-
property.setValueType('DATE')
|
|
100
|
-
else property.removeValueType()
|
|
101
|
-
|
|
102
|
-
// Update value
|
|
103
|
-
property.value = dateProperty.value
|
|
104
|
-
|
|
90
|
+
property.setValue(value)
|
|
105
91
|
return this
|
|
106
92
|
}
|
|
107
93
|
// Property is new
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
)
|
|
94
|
+
let property: Property
|
|
95
|
+
|
|
96
|
+
if (typeof value === 'string') {
|
|
97
|
+
property = new Property(name, value)
|
|
98
|
+
} else if (isCalendarDateOrTime(value)) {
|
|
99
|
+
property = Property.fromDate(name, value)
|
|
100
|
+
} else {
|
|
101
|
+
property = Property.fromDuration(name, value)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.properties.push(property)
|
|
113
105
|
return this
|
|
114
106
|
}
|
|
115
107
|
|
|
@@ -6,9 +6,22 @@ import {
|
|
|
6
6
|
parseDateProperty,
|
|
7
7
|
toDateTimeString,
|
|
8
8
|
} from '../date'
|
|
9
|
+
import { CalendarDuration } from '../duration'
|
|
9
10
|
import { KnownPropertyName } from '../property/names'
|
|
10
11
|
import { PropertyValidationError } from '../property/validate'
|
|
11
12
|
|
|
13
|
+
export const DEFAULT_EVENT_DURATION_DATE_TIME: CalendarDuration = new CalendarDuration('PT0S')
|
|
14
|
+
export const DEFAULT_EVENT_DURATION_DATE: CalendarDuration = new CalendarDuration('P1D')
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the default event duration for an event without an end nor duration.
|
|
18
|
+
* @param isFullDay Whether the event is a full day event.
|
|
19
|
+
* @returns `DEFAULT_EVENT_DURATION_DATE` for full day events, `DEFAULT_EVENT_DURATION_DATE_TIME` for other events.
|
|
20
|
+
*/
|
|
21
|
+
export function getDefaultEventDuration(isFullDay: boolean): CalendarDuration {
|
|
22
|
+
return isFullDay ? DEFAULT_EVENT_DURATION_DATE : DEFAULT_EVENT_DURATION_DATE_TIME
|
|
23
|
+
}
|
|
24
|
+
|
|
12
25
|
/**
|
|
13
26
|
* Represents a VEVENT component, representing an event in a calendar.
|
|
14
27
|
*/
|
|
@@ -138,10 +151,36 @@ export class CalendarEvent extends Component {
|
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
/**
|
|
141
|
-
*
|
|
154
|
+
* Check if this event is a full day event.
|
|
155
|
+
* @returns `true` if the event is a full day event, `false` if not.
|
|
156
|
+
*/
|
|
157
|
+
isFullDay(): boolean {
|
|
158
|
+
return this.getStart().isFullDay()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get the non-inclusive end of the event, implies value from duration if unset.
|
|
142
163
|
* @returns The end date of the event as a {@link CalendarDateOrTime} or `undefined` if not set.
|
|
143
164
|
*/
|
|
144
|
-
getEnd(): CalendarDateOrTime
|
|
165
|
+
getEnd(): CalendarDateOrTime {
|
|
166
|
+
const explicit = this.getExplicitEnd()
|
|
167
|
+
if (explicit) return explicit
|
|
168
|
+
|
|
169
|
+
// Calculate end from start and duration
|
|
170
|
+
const start = this.getStart()
|
|
171
|
+
let duration = this.getExplicitDuration()
|
|
172
|
+
if (!duration) {
|
|
173
|
+
duration = getDefaultEventDuration(this.isFullDay())
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return start.offset(duration)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get the DTEND property of the event, representing the non-inclusive end of the event.
|
|
181
|
+
* @returns The end date of the event as a {@link CalendarDateOrTime} or `undefined` if not set.
|
|
182
|
+
*/
|
|
183
|
+
getExplicitEnd(): CalendarDateOrTime | undefined {
|
|
145
184
|
const property = this.getProperty('DTEND')
|
|
146
185
|
if (!property) return
|
|
147
186
|
return parseDateProperty(property)
|
|
@@ -178,25 +217,49 @@ export class CalendarEvent extends Component {
|
|
|
178
217
|
}
|
|
179
218
|
|
|
180
219
|
/**
|
|
181
|
-
* Get the duration of the event
|
|
182
|
-
* @returns The duration of the event
|
|
220
|
+
* Get the duration of the event, implies value from end or default if unset.
|
|
221
|
+
* @returns The duration of the event as a {@link CalendarDuration}.
|
|
183
222
|
*/
|
|
184
|
-
getDuration():
|
|
185
|
-
|
|
223
|
+
getDuration(): CalendarDuration {
|
|
224
|
+
const explicit = this.getExplicitDuration()
|
|
225
|
+
if (explicit) return explicit
|
|
226
|
+
|
|
227
|
+
// Calculate duration from start and end
|
|
228
|
+
const start = this.getStart()
|
|
229
|
+
const end = this.getExplicitEnd()
|
|
230
|
+
if (!end) {
|
|
231
|
+
return getDefaultEventDuration(this.isFullDay())
|
|
232
|
+
}
|
|
233
|
+
return CalendarDuration.fromDifference(start, end)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get the DURATION property of the event.
|
|
238
|
+
* @returns The duration of the event as a {@link CalendarDuration}, or `undefined` if not set.
|
|
239
|
+
*/
|
|
240
|
+
getExplicitDuration(): CalendarDuration | undefined {
|
|
241
|
+
const property = this.getProperty('DURATION')?.value
|
|
242
|
+
if (property == undefined) return undefined
|
|
186
243
|
}
|
|
187
244
|
|
|
188
245
|
/**
|
|
189
246
|
* Set the duration of the event.
|
|
190
247
|
*
|
|
191
|
-
* Will remove '
|
|
192
|
-
*
|
|
248
|
+
* Will remove 'DTEND' if present.
|
|
249
|
+
*
|
|
250
|
+
* If DTSTART is of type DATE the duration will be floored to the nearest day.
|
|
251
|
+
* @param value The duration of the event as a {@link CalendarDuration} duration string.
|
|
193
252
|
* @returns The CalendarEvent instance for chaining.
|
|
194
253
|
* @example
|
|
195
254
|
* // Set duration to 1 hour and 30 minutes.
|
|
196
255
|
* event.setDuration(`PT1H30M`)
|
|
197
256
|
*/
|
|
198
|
-
setDuration(value: string): this {
|
|
257
|
+
setDuration(value: string | CalendarDuration): this {
|
|
199
258
|
this.removeEnd()
|
|
259
|
+
if (typeof value === 'string')
|
|
260
|
+
value = new CalendarDuration(value)
|
|
261
|
+
if (this.getStart().isFullDay())
|
|
262
|
+
value = value.floor('D')
|
|
200
263
|
return this.setProperty('DURATION', value)
|
|
201
264
|
}
|
|
202
265
|
|
|
@@ -242,3 +305,4 @@ export class CalendarEvent extends Component {
|
|
|
242
305
|
this.removePropertiesWithName('GEO')
|
|
243
306
|
}
|
|
244
307
|
}
|
|
308
|
+
|
package/src/date.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import * as patterns from './patterns'
|
|
2
2
|
import { Property } from './property/Property'
|
|
3
|
+
import { CalendarDuration } from './duration'
|
|
3
4
|
|
|
4
5
|
export const ONE_SECOND_MS = 1000
|
|
5
6
|
export const ONE_MINUTE_MS = 60 * ONE_SECOND_MS
|
|
6
7
|
export const ONE_HOUR_MS = 60 * ONE_MINUTE_MS
|
|
7
8
|
export const ONE_DAY_MS = 24 * ONE_HOUR_MS
|
|
9
|
+
export const ONE_WEEK_MS = 7 * ONE_DAY_MS
|
|
10
|
+
|
|
11
|
+
export const ONE_MINUTE_SECONDS = 60
|
|
12
|
+
export const ONE_HOUR_SECONDS = 60 * ONE_MINUTE_SECONDS
|
|
13
|
+
export const ONE_DAY_SECONDS = 24 * ONE_HOUR_SECONDS
|
|
14
|
+
export const ONE_WEEK_SECONDS = 7 * ONE_DAY_SECONDS
|
|
8
15
|
|
|
9
16
|
export interface CalendarDateOrTime {
|
|
10
17
|
/**
|
|
@@ -24,7 +31,14 @@ export interface CalendarDateOrTime {
|
|
|
24
31
|
* Check if this date represents a full day, as opposed to a date-time.
|
|
25
32
|
* @returns `true` if this object is a {@link CalendarDate}.
|
|
26
33
|
*/
|
|
27
|
-
isFullDay():
|
|
34
|
+
isFullDay(): this is CalendarDate
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get a new time offset by a duration.
|
|
38
|
+
* @param duration The duration to offset the time by.
|
|
39
|
+
* @returns A new {@link CalendarDateOrTime} of the same type.
|
|
40
|
+
*/
|
|
41
|
+
offset(duration: CalendarDuration): CalendarDateOrTime
|
|
28
42
|
}
|
|
29
43
|
|
|
30
44
|
/**
|
|
@@ -36,10 +50,10 @@ export class CalendarDate implements CalendarDateOrTime {
|
|
|
36
50
|
|
|
37
51
|
constructor(date: Date | string | CalendarDateOrTime) {
|
|
38
52
|
if (typeof date === 'object') {
|
|
39
|
-
if (
|
|
40
|
-
this.date = date
|
|
53
|
+
if (isDateObject(date)) {
|
|
54
|
+
this.date = date
|
|
41
55
|
} else {
|
|
42
|
-
this.date = (date
|
|
56
|
+
this.date = (date).getDate()
|
|
43
57
|
}
|
|
44
58
|
} else {
|
|
45
59
|
try {
|
|
@@ -64,9 +78,30 @@ export class CalendarDate implements CalendarDateOrTime {
|
|
|
64
78
|
return new Date(this.date)
|
|
65
79
|
}
|
|
66
80
|
|
|
67
|
-
isFullDay():
|
|
81
|
+
isFullDay(): this is CalendarDate {
|
|
68
82
|
return true
|
|
69
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get a new date offset by a duration.
|
|
87
|
+
* @param duration The duration to offset the date by.
|
|
88
|
+
* @returns A new {@link CalendarDate} offset by the duration.
|
|
89
|
+
*/
|
|
90
|
+
offset(duration: CalendarDuration): CalendarDate {
|
|
91
|
+
const offsetMs = duration.floor('D').inMilliseconds()
|
|
92
|
+
const ms = this.getDate().getTime()
|
|
93
|
+
const time = new Date(ms + offsetMs)
|
|
94
|
+
return new CalendarDate(time)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
[Symbol.toPrimitive](hint: string): number | string | null {
|
|
98
|
+
if (hint === 'string') {
|
|
99
|
+
return this.getValue()
|
|
100
|
+
} else if (hint === 'number') {
|
|
101
|
+
return this.date.getTime()
|
|
102
|
+
}
|
|
103
|
+
return null
|
|
104
|
+
}
|
|
70
105
|
}
|
|
71
106
|
|
|
72
107
|
export class CalendarDateTime implements CalendarDateOrTime {
|
|
@@ -74,10 +109,10 @@ export class CalendarDateTime implements CalendarDateOrTime {
|
|
|
74
109
|
|
|
75
110
|
constructor(date: Date | string | CalendarDateOrTime) {
|
|
76
111
|
if (typeof date === 'object') {
|
|
77
|
-
if (
|
|
78
|
-
this.date = date
|
|
112
|
+
if (isDateObject(date)) {
|
|
113
|
+
this.date = date
|
|
79
114
|
} else {
|
|
80
|
-
this.date = (date
|
|
115
|
+
this.date = (date).getDate()
|
|
81
116
|
}
|
|
82
117
|
} else {
|
|
83
118
|
try {
|
|
@@ -100,9 +135,57 @@ export class CalendarDateTime implements CalendarDateOrTime {
|
|
|
100
135
|
return new Date(this.date)
|
|
101
136
|
}
|
|
102
137
|
|
|
103
|
-
isFullDay():
|
|
138
|
+
isFullDay(): this is CalendarDate {
|
|
104
139
|
return false
|
|
105
140
|
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get a new time offset by a duration.
|
|
144
|
+
* @param duration The duration to offset the time by.
|
|
145
|
+
* @returns A new {@link CalendarDateTime} offset by the duration.
|
|
146
|
+
*/
|
|
147
|
+
offset(duration: CalendarDuration): CalendarDateTime {
|
|
148
|
+
const offsetMs = duration.inMilliseconds()
|
|
149
|
+
const ms = this.getDate().getTime()
|
|
150
|
+
const time = new Date(ms + offsetMs)
|
|
151
|
+
return new CalendarDateTime(time)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
[Symbol.toPrimitive](hint: string): number | string | null {
|
|
155
|
+
if (hint === 'string') {
|
|
156
|
+
return this.getValue()
|
|
157
|
+
} else if (hint === 'number') {
|
|
158
|
+
return this.date.getTime()
|
|
159
|
+
}
|
|
160
|
+
return null
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Check if an object is a JavaScript `Date`.
|
|
166
|
+
* @param maybeDate The object to check.
|
|
167
|
+
* @returns `true` if the object is a `Date`, `false` otherwise.
|
|
168
|
+
*/
|
|
169
|
+
export function isDateObject(maybeDate: unknown): maybeDate is Date {
|
|
170
|
+
return Object.prototype.toString.call(maybeDate) === '[object Date]'
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Check if an object is a `CalendarDateOrTime`.
|
|
175
|
+
* @param maybeDate The object to check.
|
|
176
|
+
* @returns `true` if the object is a `CalendarDateOrTime`, `false` otherwise.
|
|
177
|
+
*/
|
|
178
|
+
export function isCalendarDateOrTime(
|
|
179
|
+
maybeDate: unknown
|
|
180
|
+
): maybeDate is CalendarDateOrTime {
|
|
181
|
+
return (
|
|
182
|
+
maybeDate != null &&
|
|
183
|
+
typeof maybeDate === "object" &&
|
|
184
|
+
typeof (maybeDate as CalendarDateOrTime).getValue === "function" &&
|
|
185
|
+
typeof (maybeDate as CalendarDateOrTime).getDate === "function" &&
|
|
186
|
+
typeof (maybeDate as CalendarDateOrTime).isFullDay === "function" &&
|
|
187
|
+
typeof (maybeDate as CalendarDateOrTime).offset === "function"
|
|
188
|
+
)
|
|
106
189
|
}
|
|
107
190
|
|
|
108
191
|
/**
|
|
@@ -370,10 +453,10 @@ export function convertDate(
|
|
|
370
453
|
date: Date | CalendarDateOrTime,
|
|
371
454
|
fullDay: boolean = false
|
|
372
455
|
): CalendarDateOrTime {
|
|
373
|
-
if (
|
|
374
|
-
if (fullDay) return new CalendarDate(date
|
|
375
|
-
else return new CalendarDateTime(date
|
|
456
|
+
if (isDateObject(date)) {
|
|
457
|
+
if (fullDay) return new CalendarDate(date)
|
|
458
|
+
else return new CalendarDateTime(date)
|
|
376
459
|
} else {
|
|
377
|
-
return date
|
|
460
|
+
return date
|
|
378
461
|
}
|
|
379
462
|
}
|