ical-generator 3.5.2-develop.1 → 3.5.2-develop.3
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/package.json +10 -9
- package/src/alarm.ts +623 -0
- package/src/attendee.ts +614 -0
- package/src/calendar.ts +864 -0
- package/src/category.ts +98 -0
- package/src/event.ts +1669 -0
- package/src/index.ts +118 -0
- package/src/tools.ts +402 -0
- package/src/types.ts +111 -0
package/src/calendar.ts
ADDED
|
@@ -0,0 +1,864 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
addOrGetCustomAttributes,
|
|
5
|
+
checkEnum,
|
|
6
|
+
foldLines,
|
|
7
|
+
generateCustomAttributes,
|
|
8
|
+
isMomentDuration,
|
|
9
|
+
toDurationString
|
|
10
|
+
} from './tools';
|
|
11
|
+
import ICalEvent, {ICalEventData, ICalEventJSONData} from './event';
|
|
12
|
+
import {writeFile, writeFileSync, promises as fsPromises} from 'fs';
|
|
13
|
+
import {ServerResponse} from 'http';
|
|
14
|
+
import { ICalMomentDurationStub, ICalTimezone } from './types';
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export interface ICalCalendarData {
|
|
18
|
+
prodId?: ICalCalendarProdIdData | string;
|
|
19
|
+
method?: ICalCalendarMethod | null;
|
|
20
|
+
name?: string | null;
|
|
21
|
+
description?: string | null;
|
|
22
|
+
timezone?: ICalTimezone | string | null;
|
|
23
|
+
source?: string | null;
|
|
24
|
+
url?: string | null;
|
|
25
|
+
scale?: string | null;
|
|
26
|
+
ttl?: number | ICalMomentDurationStub | null;
|
|
27
|
+
events?: (ICalEvent | ICalEventData)[];
|
|
28
|
+
x?: {key: string, value: string}[] | [string, string][] | Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface ICalCalendarInternalData {
|
|
32
|
+
prodId: string;
|
|
33
|
+
method: ICalCalendarMethod | null;
|
|
34
|
+
name: string | null;
|
|
35
|
+
description: string | null;
|
|
36
|
+
timezone: ICalTimezone | null;
|
|
37
|
+
source: string | null;
|
|
38
|
+
url: string | null;
|
|
39
|
+
scale: string | null;
|
|
40
|
+
ttl: number | null;
|
|
41
|
+
events: ICalEvent[];
|
|
42
|
+
x: [string, string][];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ICalCalendarJSONData {
|
|
46
|
+
prodId: string;
|
|
47
|
+
method: ICalCalendarMethod | null;
|
|
48
|
+
name: string | null;
|
|
49
|
+
description: string | null;
|
|
50
|
+
timezone: string | null;
|
|
51
|
+
source: string | null;
|
|
52
|
+
url: string | null;
|
|
53
|
+
scale: string | null;
|
|
54
|
+
ttl: number | null;
|
|
55
|
+
events: ICalEventJSONData[];
|
|
56
|
+
x: {key: string, value: string}[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ICalCalendarProdIdData {
|
|
60
|
+
company: string;
|
|
61
|
+
product: string;
|
|
62
|
+
language?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export enum ICalCalendarMethod {
|
|
66
|
+
PUBLISH = 'PUBLISH',
|
|
67
|
+
REQUEST = 'REQUEST',
|
|
68
|
+
REPLY = 'REPLY',
|
|
69
|
+
ADD = 'ADD',
|
|
70
|
+
CANCEL = 'CANCEL',
|
|
71
|
+
REFRESH = 'REFRESH',
|
|
72
|
+
COUNTER = 'COUNTER',
|
|
73
|
+
DECLINECOUNTER = 'DECLINECOUNTER'
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Usually you get an `ICalCalendar` object like this:
|
|
79
|
+
* ```javascript
|
|
80
|
+
* import ical from 'ical-generator';
|
|
81
|
+
* const calendar = ical();
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* But you can also use the constructor directly like this:
|
|
85
|
+
* ```javascript
|
|
86
|
+
* import {ICalCalendar} from 'ical-generator';
|
|
87
|
+
* const calendar = new ICalCalendar();
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export default class ICalCalendar {
|
|
91
|
+
private readonly data: ICalCalendarInternalData;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* You can pass options to setup your calendar or use setters to do this.
|
|
95
|
+
*
|
|
96
|
+
* ```javascript
|
|
97
|
+
* * import ical from 'ical-generator';
|
|
98
|
+
*
|
|
99
|
+
* // or use require:
|
|
100
|
+
* // const ical = require('ical-generator');
|
|
101
|
+
*
|
|
102
|
+
*
|
|
103
|
+
* const cal = ical({name: 'my first iCal'});
|
|
104
|
+
*
|
|
105
|
+
* // is the same as
|
|
106
|
+
*
|
|
107
|
+
* const cal = ical().name('my first iCal');
|
|
108
|
+
*
|
|
109
|
+
* // is the same as
|
|
110
|
+
*
|
|
111
|
+
* const cal = ical();
|
|
112
|
+
* cal.name('sebbo.net');
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @param data Calendar data
|
|
116
|
+
*/
|
|
117
|
+
constructor(data: ICalCalendarData = {}) {
|
|
118
|
+
this.data = {
|
|
119
|
+
prodId: '//sebbo.net//ical-generator//EN',
|
|
120
|
+
method: null,
|
|
121
|
+
name: null,
|
|
122
|
+
description: null,
|
|
123
|
+
timezone: null,
|
|
124
|
+
source: null,
|
|
125
|
+
url: null,
|
|
126
|
+
scale: null,
|
|
127
|
+
ttl: null,
|
|
128
|
+
events: [],
|
|
129
|
+
x: []
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
data.prodId !== undefined && this.prodId(data.prodId);
|
|
133
|
+
data.method !== undefined && this.method(data.method);
|
|
134
|
+
data.name !== undefined && this.name(data.name);
|
|
135
|
+
data.description !== undefined && this.description(data.description);
|
|
136
|
+
data.timezone !== undefined && this.timezone(data.timezone);
|
|
137
|
+
data.source !== undefined && this.source(data.source);
|
|
138
|
+
data.url !== undefined && this.url(data.url);
|
|
139
|
+
data.scale !== undefined && this.scale(data.scale);
|
|
140
|
+
data.ttl !== undefined && this.ttl(data.ttl);
|
|
141
|
+
data.events !== undefined && this.events(data.events);
|
|
142
|
+
data.x !== undefined && this.x(data.x);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get your feed's prodid. Will always return a string.
|
|
148
|
+
* @since 0.2.0
|
|
149
|
+
*/
|
|
150
|
+
prodId(): string;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Set your feed's prodid. `prodid` can be either a
|
|
154
|
+
* string like `//sebbo.net//ical-generator//EN` or a
|
|
155
|
+
* valid [[`ICalCalendarProdIdData`]] object. `language`
|
|
156
|
+
* is optional and defaults to `EN`.
|
|
157
|
+
*
|
|
158
|
+
* ```javascript
|
|
159
|
+
* cal.prodId({
|
|
160
|
+
* company: 'My Company',
|
|
161
|
+
* product: 'My Product',
|
|
162
|
+
* language: 'EN' // optional, defaults to EN
|
|
163
|
+
* });
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* @since 0.2.0
|
|
167
|
+
*/
|
|
168
|
+
prodId(prodId: ICalCalendarProdIdData | string): this;
|
|
169
|
+
prodId(prodId?: ICalCalendarProdIdData | string): this | string {
|
|
170
|
+
if (!prodId) {
|
|
171
|
+
return this.data.prodId;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const prodIdRegEx = /^\/\/(.+)\/\/(.+)\/\/([A-Z]{1,4})$/;
|
|
175
|
+
|
|
176
|
+
if (typeof prodId === 'string' && prodIdRegEx.test(prodId)) {
|
|
177
|
+
this.data.prodId = prodId;
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
180
|
+
if (typeof prodId === 'string') {
|
|
181
|
+
throw new Error(
|
|
182
|
+
'`prodId` isn\'t formated correctly. See https://sebbo2002.github.io/ical-generator/develop/reference/'+
|
|
183
|
+
'classes/ICalCalendar.html#prodId'
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (typeof prodId !== 'object') {
|
|
188
|
+
throw new Error('`prodid` needs to be a valid formed string or an object!');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!prodId.company) {
|
|
192
|
+
throw new Error('`prodid.company` is a mandatory item!');
|
|
193
|
+
}
|
|
194
|
+
if (!prodId.product) {
|
|
195
|
+
throw new Error('`prodid.product` is a mandatory item!');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const language = (prodId.language || 'EN').toUpperCase();
|
|
199
|
+
this.data.prodId = '//' + prodId.company + '//' + prodId.product + '//' + language;
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get the feed method attribute.
|
|
206
|
+
* See [[`ICalCalendarMethod`]] for possible results.
|
|
207
|
+
*
|
|
208
|
+
* @since 0.2.8
|
|
209
|
+
*/
|
|
210
|
+
method(): ICalCalendarMethod | null;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Set the feed method attribute.
|
|
214
|
+
* See [[`ICalCalendarMethod`]] for available options.
|
|
215
|
+
*
|
|
216
|
+
* #### Typescript Example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* import {ICalCalendarMethod} from 'ical-generator';
|
|
219
|
+
* calendar.method(ICalCalendarMethod.PUBLISH);
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* @since 0.2.8
|
|
223
|
+
*/
|
|
224
|
+
method(method: ICalCalendarMethod | null): this;
|
|
225
|
+
method(method?: ICalCalendarMethod | null): this | ICalCalendarMethod | null {
|
|
226
|
+
if (method === undefined) {
|
|
227
|
+
return this.data.method;
|
|
228
|
+
}
|
|
229
|
+
if (!method) {
|
|
230
|
+
this.data.method = null;
|
|
231
|
+
return this;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.data.method = checkEnum(ICalCalendarMethod, method) as ICalCalendarMethod;
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get your feed's name
|
|
241
|
+
* @since 0.2.0
|
|
242
|
+
*/
|
|
243
|
+
name(): string | null;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Set your feed's name. Is used to fill `NAME`
|
|
247
|
+
* and `X-WR-CALNAME` in your iCal file.
|
|
248
|
+
*
|
|
249
|
+
* @since 0.2.0
|
|
250
|
+
*/
|
|
251
|
+
name(name: string | null): this;
|
|
252
|
+
name(name?: string | null): this | string | null {
|
|
253
|
+
if (name === undefined) {
|
|
254
|
+
return this.data.name;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.data.name = name ? String(name) : null;
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get your feed's description
|
|
264
|
+
* @since 0.2.7
|
|
265
|
+
*/
|
|
266
|
+
description(): string | null;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Set your feed's description
|
|
270
|
+
* @since 0.2.7
|
|
271
|
+
*/
|
|
272
|
+
description(description: string | null): this;
|
|
273
|
+
description(description?: string | null): this | string | null {
|
|
274
|
+
if (description === undefined) {
|
|
275
|
+
return this.data.description;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
this.data.description = description ? String(description) : null;
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get the current calendar timezone
|
|
285
|
+
* @since 0.2.0
|
|
286
|
+
*/
|
|
287
|
+
timezone(): string | null;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Use this method to set your feed's timezone. Is used
|
|
291
|
+
* to fill `TIMEZONE-ID` and `X-WR-TIMEZONE` in your iCal export.
|
|
292
|
+
* Please not that all date values are treaded differently, if
|
|
293
|
+
* a timezone was set. See [[`formatDate`]] for details. If no
|
|
294
|
+
* time zone is specified, all information is output as UTC.
|
|
295
|
+
*
|
|
296
|
+
* ```javascript
|
|
297
|
+
* cal.timezone('America/New_York');
|
|
298
|
+
* ```
|
|
299
|
+
*
|
|
300
|
+
* @see https://github.com/sebbo2002/ical-generator#-date-time--timezones
|
|
301
|
+
* @since 0.2.0
|
|
302
|
+
*/
|
|
303
|
+
timezone(timezone: string | null): this;
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Sets the time zone to be used in this calendar file for all times of all
|
|
307
|
+
* events. Please note that if the time zone is set, ical-generator assumes
|
|
308
|
+
* that all times are already in the correct time zone. Alternatively, a
|
|
309
|
+
* `moment-timezone` or a Luxon object can be passed with `setZone`,
|
|
310
|
+
* ical-generator will then set the time zone itself.
|
|
311
|
+
*
|
|
312
|
+
* For the best support of time zones, a VTimezone entry in the calendar is
|
|
313
|
+
* recommended, which informs the client about the corresponding time zones
|
|
314
|
+
* (daylight saving time, deviation from UTC, etc.). `ical-generator` itself
|
|
315
|
+
* does not have a time zone database, so an external generator is needed here.
|
|
316
|
+
*
|
|
317
|
+
* A VTimezone generator is a function that takes a time zone as a string and
|
|
318
|
+
* returns a VTimezone component according to the ical standard. For example,
|
|
319
|
+
* ical-timezones can be used for this:
|
|
320
|
+
*
|
|
321
|
+
* ```typescript
|
|
322
|
+
* import ical from 'ical-generator';
|
|
323
|
+
* import {getVtimezoneComponent} from '@touch4it/ical-timezones';
|
|
324
|
+
*
|
|
325
|
+
* const cal = new ICalCalendar();
|
|
326
|
+
* cal.timezone({
|
|
327
|
+
* name: 'FOO',
|
|
328
|
+
* generator: getVtimezoneComponent
|
|
329
|
+
* });
|
|
330
|
+
* cal.createEvent({
|
|
331
|
+
* start: new Date(),
|
|
332
|
+
* timezone: 'Europe/London'
|
|
333
|
+
* });
|
|
334
|
+
* ```
|
|
335
|
+
*
|
|
336
|
+
* @see https://github.com/sebbo2002/ical-generator#-date-time--timezones
|
|
337
|
+
* @since 2.0.0
|
|
338
|
+
*/
|
|
339
|
+
timezone(timezone: ICalTimezone | string | null): this;
|
|
340
|
+
timezone(timezone?: ICalTimezone | string | null): this | string | null {
|
|
341
|
+
if (timezone === undefined) {
|
|
342
|
+
return this.data.timezone?.name || null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if(timezone === 'UTC') {
|
|
346
|
+
this.data.timezone = null;
|
|
347
|
+
}
|
|
348
|
+
else if(typeof timezone === 'string') {
|
|
349
|
+
this.data.timezone = {name: timezone};
|
|
350
|
+
}
|
|
351
|
+
else if(timezone === null) {
|
|
352
|
+
this.data.timezone = null;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
this.data.timezone = timezone;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Get current value of the `SOURCE` attribute.
|
|
364
|
+
* @since 2.2.0-develop.1
|
|
365
|
+
*/
|
|
366
|
+
source(): string | null;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Use this method to set your feed's `SOURCE` attribute.
|
|
370
|
+
* This tells the client where to refresh your feed.
|
|
371
|
+
*
|
|
372
|
+
* ```javascript
|
|
373
|
+
* cal.source('http://example.com/my/original_source.ical');
|
|
374
|
+
* ```
|
|
375
|
+
*
|
|
376
|
+
* @since 2.2.0-develop.1
|
|
377
|
+
*/
|
|
378
|
+
source(source: string | null): this;
|
|
379
|
+
source(source?: string | null): this | string | null {
|
|
380
|
+
if (source === undefined) {
|
|
381
|
+
return this.data.source;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
this.data.source = source || null;
|
|
385
|
+
return this;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get your feed's URL
|
|
391
|
+
* @since 0.2.5
|
|
392
|
+
*/
|
|
393
|
+
url(): string | null;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Set your feed's URL
|
|
397
|
+
*
|
|
398
|
+
* ```javascript
|
|
399
|
+
* calendar.url('http://example.com/my/feed.ical');
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* @since 0.2.5
|
|
403
|
+
*/
|
|
404
|
+
url(url: string | null): this;
|
|
405
|
+
url(url?: string | null): this | string | null {
|
|
406
|
+
if (url === undefined) {
|
|
407
|
+
return this.data.url;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
this.data.url = url || null;
|
|
411
|
+
return this;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Get current value of the `CALSCALE` attribute. It will
|
|
417
|
+
* return `null` if no value was set. The iCal standard
|
|
418
|
+
* specifies this as `GREGORIAN` if no value is present.
|
|
419
|
+
*
|
|
420
|
+
* @since 1.8.0
|
|
421
|
+
*/
|
|
422
|
+
scale(): string | null;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Use this method to set your feed's `CALSCALE` attribute. There is no
|
|
426
|
+
* default value for this property and it will not appear in your iCal
|
|
427
|
+
* file unless set. The iCal standard specifies this as `GREGORIAN` if
|
|
428
|
+
* no value is present.
|
|
429
|
+
*
|
|
430
|
+
* ```javascript
|
|
431
|
+
* cal.scale('gregorian');
|
|
432
|
+
* ```
|
|
433
|
+
*
|
|
434
|
+
* @since 1.8.0
|
|
435
|
+
*/
|
|
436
|
+
scale(scale: string | null): this;
|
|
437
|
+
scale(scale?: string | null): this | string | null {
|
|
438
|
+
if (scale === undefined) {
|
|
439
|
+
return this.data.scale;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (scale === null) {
|
|
443
|
+
this.data.scale = null;
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
this.data.scale = scale.toUpperCase();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return this;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Get the current ttl duration in seconds
|
|
455
|
+
* @since 0.2.5
|
|
456
|
+
*/
|
|
457
|
+
ttl(): number | null;
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Use this method to set your feed's time to live
|
|
461
|
+
* (in seconds). Is used to fill `REFRESH-INTERVAL` and
|
|
462
|
+
* `X-PUBLISHED-TTL` in your iCal.
|
|
463
|
+
*
|
|
464
|
+
* ```javascript
|
|
465
|
+
* const cal = ical().ttl(60 * 60 * 24); // 1 day
|
|
466
|
+
* ```
|
|
467
|
+
*
|
|
468
|
+
* You can also pass a moment.js duration object. Zero, null
|
|
469
|
+
* or negative numbers will reset the `ttl` attribute.
|
|
470
|
+
*
|
|
471
|
+
* @since 0.2.5
|
|
472
|
+
*/
|
|
473
|
+
ttl(ttl: number | ICalMomentDurationStub | null): this;
|
|
474
|
+
ttl(ttl?: number | ICalMomentDurationStub | null): this | number | null {
|
|
475
|
+
if (ttl === undefined) {
|
|
476
|
+
return this.data.ttl;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (isMomentDuration(ttl)) {
|
|
480
|
+
this.data.ttl = ttl.asSeconds();
|
|
481
|
+
}
|
|
482
|
+
else if (ttl && ttl > 0) {
|
|
483
|
+
this.data.ttl = ttl;
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
this.data.ttl = null;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return this;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Creates a new [[`ICalEvent`]] and returns it. Use options to prefill the event's attributes.
|
|
495
|
+
* Calling this method without options will create an empty event.
|
|
496
|
+
*
|
|
497
|
+
* ```javascript
|
|
498
|
+
* import ical from 'ical-generator';
|
|
499
|
+
*
|
|
500
|
+
* // or use require:
|
|
501
|
+
* // const ical = require('ical-generator');
|
|
502
|
+
*
|
|
503
|
+
* const cal = ical();
|
|
504
|
+
* const event = cal.createEvent({summary: 'My Event'});
|
|
505
|
+
*
|
|
506
|
+
* // overwrite event summary
|
|
507
|
+
* event.summary('Your Event');
|
|
508
|
+
* ```
|
|
509
|
+
*
|
|
510
|
+
* @since 0.2.0
|
|
511
|
+
*/
|
|
512
|
+
createEvent(data: ICalEvent | ICalEventData): ICalEvent {
|
|
513
|
+
const event = data instanceof ICalEvent ? data : new ICalEvent(data, this);
|
|
514
|
+
this.data.events.push(event);
|
|
515
|
+
return event;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Returns all events of this calendar.
|
|
521
|
+
*
|
|
522
|
+
* ```javascript
|
|
523
|
+
* const cal = ical();
|
|
524
|
+
*
|
|
525
|
+
* cal.events([
|
|
526
|
+
* {
|
|
527
|
+
* start: new Date(),
|
|
528
|
+
* end: new Date(new Date().getTime() + 3600000),
|
|
529
|
+
* summary: 'Example Event',
|
|
530
|
+
* description: 'It works ;)',
|
|
531
|
+
* url: 'http://sebbo.net/'
|
|
532
|
+
* }
|
|
533
|
+
* ]);
|
|
534
|
+
*
|
|
535
|
+
* cal.events(); // --> [ICalEvent]
|
|
536
|
+
* ```
|
|
537
|
+
*
|
|
538
|
+
* @since 0.2.0
|
|
539
|
+
*/
|
|
540
|
+
events(): ICalEvent[];
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Add multiple events to your calendar.
|
|
544
|
+
*
|
|
545
|
+
* ```javascript
|
|
546
|
+
* const cal = ical();
|
|
547
|
+
*
|
|
548
|
+
* cal.events([
|
|
549
|
+
* {
|
|
550
|
+
* start: new Date(),
|
|
551
|
+
* end: new Date(new Date().getTime() + 3600000),
|
|
552
|
+
* summary: 'Example Event',
|
|
553
|
+
* description: 'It works ;)',
|
|
554
|
+
* url: 'http://sebbo.net/'
|
|
555
|
+
* }
|
|
556
|
+
* ]);
|
|
557
|
+
*
|
|
558
|
+
* cal.events(); // --> [ICalEvent]
|
|
559
|
+
* ```
|
|
560
|
+
*
|
|
561
|
+
* @since 0.2.0
|
|
562
|
+
*/
|
|
563
|
+
events(events: (ICalEvent | ICalEventData)[]): this;
|
|
564
|
+
events(events?: (ICalEvent | ICalEventData)[]): this | ICalEvent[] {
|
|
565
|
+
if (!events) {
|
|
566
|
+
return this.data.events;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
events.forEach((e: ICalEvent | ICalEventData) => this.createEvent(e));
|
|
570
|
+
return this;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Remove all events from the calendar without
|
|
576
|
+
* touching any other data like name or prodId.
|
|
577
|
+
*
|
|
578
|
+
* @since 2.0.0-develop.1
|
|
579
|
+
*/
|
|
580
|
+
clear(): this {
|
|
581
|
+
this.data.events = [];
|
|
582
|
+
return this;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Save ical file using [`fs/promises`](https://nodejs.org/api/fs.html#fs_fspromises_writefile_file_data_options).
|
|
588
|
+
* Only works in node.js environments.
|
|
589
|
+
*
|
|
590
|
+
* ```javascript
|
|
591
|
+
* await calendar.save('./calendar.ical');
|
|
592
|
+
* ```
|
|
593
|
+
*/
|
|
594
|
+
save(path: string): Promise<void>;
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Save ical file with [`fs.writeFile`](http://nodejs.org/api/fs.html#fs_fs_writefile_filename_data_options_callback).
|
|
598
|
+
* Only works in node.js environments.
|
|
599
|
+
*
|
|
600
|
+
* ```javascript
|
|
601
|
+
* calendar.save('./calendar.ical', err => {
|
|
602
|
+
* console.log(err);
|
|
603
|
+
* });
|
|
604
|
+
* ```
|
|
605
|
+
*/
|
|
606
|
+
save(path: string, cb?: (err: NodeJS.ErrnoException | null) => void): this;
|
|
607
|
+
save(path: string, cb?: (err: NodeJS.ErrnoException | null) => void): this | Promise<void> {
|
|
608
|
+
if (cb) {
|
|
609
|
+
writeFile(path, this.toString(), cb);
|
|
610
|
+
return this;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return fsPromises.writeFile(path, this.toString());
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Save Calendar to disk synchronously using
|
|
619
|
+
* [fs.writeFileSync](http://nodejs.org/api/fs.html#fs_fs_writefilesync_filename_data_options).
|
|
620
|
+
* Only works in node.js environments.
|
|
621
|
+
*
|
|
622
|
+
* ```javascript
|
|
623
|
+
* calendar.saveSync('./calendar.ical');
|
|
624
|
+
* ```
|
|
625
|
+
*/
|
|
626
|
+
saveSync(path: string): this {
|
|
627
|
+
writeFileSync(path, this.toString());
|
|
628
|
+
return this;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Send calendar to the user when using HTTP using the passed `ServerResponse` object.
|
|
634
|
+
* Use second parameter `filename` to change the filename, which defaults to `'calendar.ics'`.
|
|
635
|
+
*
|
|
636
|
+
* @param response HTTP Response object which is used to send the calendar
|
|
637
|
+
* @param [filename = 'calendar.ics'] Filename of the calendar file
|
|
638
|
+
*/
|
|
639
|
+
serve(response: ServerResponse, filename = 'calendar.ics'): this {
|
|
640
|
+
response.writeHead(200, {
|
|
641
|
+
'Content-Type': 'text/calendar; charset=utf-8',
|
|
642
|
+
'Content-Disposition': `attachment; filename="${filename}"`
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
response.end(this.toString());
|
|
646
|
+
return this;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Generates a blob to use for downloads or to generate a download URL.
|
|
652
|
+
* Only supported in browsers supporting the Blob API.
|
|
653
|
+
*
|
|
654
|
+
* Unfortunately, because node.js has no Blob implementation (they have Buffer
|
|
655
|
+
* instead), this method is currently untested. Sorry Dave…
|
|
656
|
+
*
|
|
657
|
+
* @since 1.9.0
|
|
658
|
+
*/
|
|
659
|
+
toBlob(): Blob {
|
|
660
|
+
return new Blob([this.toString()], {type: 'text/calendar'});
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Returns a URL to download the ical file. Uses the Blob object internally,
|
|
666
|
+
* so it's only supported in browsers supporting the Blob API.
|
|
667
|
+
*
|
|
668
|
+
* Unfortunately, because node.js has no Blob implementation (they have Buffer
|
|
669
|
+
* instead), this can't be tested right now. Sorry Dave…
|
|
670
|
+
*
|
|
671
|
+
* @since 1.9.0
|
|
672
|
+
*/
|
|
673
|
+
toURL(): string {
|
|
674
|
+
return URL.createObjectURL(this.toBlob());
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Set X-* attributes. Woun't filter double attributes,
|
|
680
|
+
* which are also added by another method (e.g. busystatus),
|
|
681
|
+
* so these attributes may be inserted twice.
|
|
682
|
+
*
|
|
683
|
+
* ```javascript
|
|
684
|
+
* calendar.x([
|
|
685
|
+
* {
|
|
686
|
+
* key: "X-MY-CUSTOM-ATTR",
|
|
687
|
+
* value: "1337!"
|
|
688
|
+
* }
|
|
689
|
+
* ]);
|
|
690
|
+
*
|
|
691
|
+
* calendar.x([
|
|
692
|
+
* ["X-MY-CUSTOM-ATTR", "1337!"]
|
|
693
|
+
* ]);
|
|
694
|
+
*
|
|
695
|
+
* calendar.x({
|
|
696
|
+
* "X-MY-CUSTOM-ATTR": "1337!"
|
|
697
|
+
* });
|
|
698
|
+
* ```
|
|
699
|
+
*
|
|
700
|
+
* @since 1.9.0
|
|
701
|
+
*/
|
|
702
|
+
x (keyOrArray: {key: string, value: string}[] | [string, string][] | Record<string, string>): this;
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Set a X-* attribute. Woun't filter double attributes,
|
|
706
|
+
* which are also added by another method (e.g. busystatus),
|
|
707
|
+
* so these attributes may be inserted twice.
|
|
708
|
+
*
|
|
709
|
+
* ```javascript
|
|
710
|
+
* calendar.x("X-MY-CUSTOM-ATTR", "1337!");
|
|
711
|
+
* ```
|
|
712
|
+
*
|
|
713
|
+
* @since 1.9.0
|
|
714
|
+
*/
|
|
715
|
+
x (keyOrArray: string, value: string): this;
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Get all custom X-* attributes.
|
|
719
|
+
* @since 1.9.0
|
|
720
|
+
*/
|
|
721
|
+
x (): {key: string, value: string}[];
|
|
722
|
+
x (keyOrArray?: {key: string, value: string}[] | [string, string][] | Record<string, string> | string, value?: string): this | void | ({key: string, value: string})[] {
|
|
723
|
+
if(keyOrArray === undefined) {
|
|
724
|
+
return addOrGetCustomAttributes (this.data);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if(typeof keyOrArray === 'string' && typeof value === 'string') {
|
|
728
|
+
addOrGetCustomAttributes (this.data, keyOrArray, value);
|
|
729
|
+
}
|
|
730
|
+
else if(typeof keyOrArray === 'object') {
|
|
731
|
+
addOrGetCustomAttributes (this.data, keyOrArray);
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
throw new Error('Either key or value is not a string!');
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return this;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Return a shallow copy of the calendar's options for JSON stringification.
|
|
743
|
+
* Third party objects like moment.js values or RRule objects are stringified
|
|
744
|
+
* as well. Can be used for persistence.
|
|
745
|
+
*
|
|
746
|
+
* ```javascript
|
|
747
|
+
* const cal = ical();
|
|
748
|
+
* const json = JSON.stringify(cal);
|
|
749
|
+
*
|
|
750
|
+
* // later: restore calendar data
|
|
751
|
+
* cal = ical(JSON.parse(json));
|
|
752
|
+
* ```
|
|
753
|
+
*
|
|
754
|
+
* @since 0.2.4
|
|
755
|
+
*/
|
|
756
|
+
toJSON(): ICalCalendarJSONData {
|
|
757
|
+
return Object.assign({}, this.data, {
|
|
758
|
+
timezone: this.timezone(),
|
|
759
|
+
events: this.data.events.map(event => event.toJSON()),
|
|
760
|
+
x: this.x()
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Get the number of events added to your calendar
|
|
767
|
+
*/
|
|
768
|
+
length(): number {
|
|
769
|
+
return this.data.events.length;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Return generated calendar as a string.
|
|
775
|
+
*
|
|
776
|
+
* ```javascript
|
|
777
|
+
* const cal = ical();
|
|
778
|
+
* console.log(cal.toString()); // → BEGIN:VCALENDAR…
|
|
779
|
+
* ```
|
|
780
|
+
*/
|
|
781
|
+
toString(): string {
|
|
782
|
+
let g = '';
|
|
783
|
+
|
|
784
|
+
// VCALENDAR and VERSION
|
|
785
|
+
g = 'BEGIN:VCALENDAR\r\nVERSION:2.0\r\n';
|
|
786
|
+
|
|
787
|
+
// PRODID
|
|
788
|
+
g += 'PRODID:-' + this.data.prodId + '\r\n';
|
|
789
|
+
|
|
790
|
+
// URL
|
|
791
|
+
if (this.data.url) {
|
|
792
|
+
g += 'URL:' + this.data.url + '\r\n';
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// SOURCE
|
|
796
|
+
if (this.data.source) {
|
|
797
|
+
g += 'SOURCE;VALUE=URI:' + this.data.source + '\r\n';
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// CALSCALE
|
|
801
|
+
if (this.data.scale) {
|
|
802
|
+
g += 'CALSCALE:' + this.data.scale + '\r\n';
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// METHOD
|
|
806
|
+
if (this.data.method) {
|
|
807
|
+
g += 'METHOD:' + this.data.method + '\r\n';
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// NAME
|
|
811
|
+
if (this.data.name) {
|
|
812
|
+
g += 'NAME:' + this.data.name + '\r\n';
|
|
813
|
+
g += 'X-WR-CALNAME:' + this.data.name + '\r\n';
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Description
|
|
817
|
+
if (this.data.description) {
|
|
818
|
+
g += 'X-WR-CALDESC:' + this.data.description + '\r\n';
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// Timezone
|
|
822
|
+
if(this.data.timezone?.generator) {
|
|
823
|
+
const timezones = [...new Set([
|
|
824
|
+
this.timezone(),
|
|
825
|
+
...this.data.events.map(event => event.timezone())
|
|
826
|
+
])].filter(tz => tz !== null && !tz.startsWith('/')) as string[];
|
|
827
|
+
|
|
828
|
+
timezones.forEach(tz => {
|
|
829
|
+
if(!this.data.timezone?.generator) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
const s = this.data.timezone.generator(tz);
|
|
834
|
+
if(!s) {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
g += s.replace(/\r\n/g, '\n')
|
|
839
|
+
.replace(/\n/g, '\r\n')
|
|
840
|
+
.trim() + '\r\n';
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
if (this.data.timezone?.name) {
|
|
844
|
+
g += 'TIMEZONE-ID:' + this.data.timezone.name + '\r\n';
|
|
845
|
+
g += 'X-WR-TIMEZONE:' + this.data.timezone.name + '\r\n';
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// TTL
|
|
849
|
+
if (this.data.ttl) {
|
|
850
|
+
g += 'REFRESH-INTERVAL;VALUE=DURATION:' + toDurationString(this.data.ttl) + '\r\n';
|
|
851
|
+
g += 'X-PUBLISHED-TTL:' + toDurationString(this.data.ttl) + '\r\n';
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Events
|
|
855
|
+
this.data.events.forEach(event => g += event.toString());
|
|
856
|
+
|
|
857
|
+
// CUSTOM X ATTRIBUTES
|
|
858
|
+
g += generateCustomAttributes(this.data);
|
|
859
|
+
|
|
860
|
+
g += 'END:VCALENDAR';
|
|
861
|
+
|
|
862
|
+
return foldLines(g);
|
|
863
|
+
}
|
|
864
|
+
}
|