ical-generator 3.5.1 → 3.5.2-develop.2

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 CHANGED
@@ -14,34 +14,35 @@
14
14
  "@semantic-release/git": "^10.0.1",
15
15
  "@semantic-release/npm": "^9.0.1",
16
16
  "@touch4it/ical-timezones": "^1.8.1",
17
- "@types/luxon": "^2.4.0",
17
+ "@types/luxon": "^3.0.1",
18
18
  "@types/mocha": "^9.1.1",
19
- "@types/node": "^18.0.3",
20
- "@typescript-eslint/eslint-plugin": "^5.30.5",
21
- "@typescript-eslint/parser": "^5.30.5",
22
- "dayjs": "^1.11.3",
23
- "eslint": "^8.19.0",
24
- "eslint-plugin-jsonc": "^2.3.1",
19
+ "@types/node": "^18.7.16",
20
+ "@typescript-eslint/eslint-plugin": "^5.36.2",
21
+ "@typescript-eslint/parser": "^5.36.2",
22
+ "dayjs": "^1.11.5",
23
+ "eslint": "^8.23.0",
24
+ "eslint-plugin-jsonc": "^2.4.0",
25
25
  "license-checker": "^25.0.1",
26
- "luxon": "^2.5.0",
26
+ "luxon": "^3.0.3",
27
27
  "mocha": "^10.0.0",
28
28
  "mochawesome": "^7.1.3",
29
29
  "moment": "^2.29.4",
30
- "moment-timezone": "^0.5.34",
30
+ "moment-timezone": "^0.5.37",
31
31
  "nyc": "^15.1.0",
32
- "portfinder": "^1.0.28",
32
+ "portfinder": "^1.0.32",
33
33
  "rrule": "^2.7.1",
34
- "semantic-release": "^19.0.3",
34
+ "semantic-release": "^19.0.5",
35
35
  "semantic-release-license": "^1.0.2",
36
36
  "source-map-support": "^0.5.21",
37
- "ts-node": "^10.8.2",
38
- "typedoc": "^0.23.5",
39
- "typescript": "^4.7.4"
37
+ "ts-node": "^10.9.1",
38
+ "typedoc": "^0.23.14",
39
+ "typescript": "^4.8.3"
40
40
  },
41
41
  "engines": {
42
42
  "node": ">=12.0.0"
43
43
  },
44
44
  "files": [
45
+ "/src",
45
46
  "/dist"
46
47
  ],
47
48
  "homepage": "https://github.com/sebbo2002/ical-generator",
@@ -119,5 +120,5 @@
119
120
  "start": "node ./dist/bin/start.js",
120
121
  "test": "mocha"
121
122
  },
122
- "version": "3.5.1"
123
+ "version": "3.5.2-develop.2"
123
124
  }
package/src/alarm.ts ADDED
@@ -0,0 +1,623 @@
1
+ 'use strict';
2
+
3
+ import ICalEvent from './event';
4
+ import {
5
+ addOrGetCustomAttributes,
6
+ formatDate,
7
+ escape,
8
+ generateCustomAttributes,
9
+ checkDate,
10
+ toDurationString,
11
+ toJSON
12
+ } from './tools';
13
+ import {ICalDateTimeValue} from './types';
14
+
15
+
16
+ export enum ICalAlarmType {
17
+ display = 'display',
18
+ audio = 'audio'
19
+ }
20
+
21
+ export type ICalAlarmTypeValue = keyof ICalAlarmType;
22
+
23
+ export interface ICalAttachment {
24
+ uri: string;
25
+ mime: string | null;
26
+ }
27
+
28
+ export interface ICalAlarmData {
29
+ type?: ICalAlarmType | null;
30
+ trigger?: number | ICalDateTimeValue | null;
31
+ triggerBefore?: number | ICalDateTimeValue | null;
32
+ triggerAfter?: number | ICalDateTimeValue | null;
33
+ repeat?: number | null;
34
+ interval?: number | null;
35
+ attach?: string | ICalAttachment | null;
36
+ description?: string | null;
37
+ x?: {key: string, value: string}[] | [string, string][] | Record<string, string>;
38
+ }
39
+
40
+ interface ICalInternalAlarmData {
41
+ type: ICalAlarmType | null;
42
+ trigger: ICalDateTimeValue | number | null;
43
+ repeat: number | null;
44
+ interval: number | null;
45
+ attach: ICalAttachment | null;
46
+ description: string | null;
47
+ x: [string, string][];
48
+ }
49
+
50
+ export interface ICalAlarmJSONData {
51
+ type: ICalAlarmType | null;
52
+ trigger: string | number | null;
53
+ repeat: number | null;
54
+ interval: number | null;
55
+ attach: ICalAttachment | null;
56
+ description: string | null;
57
+ x: {key: string, value: string}[];
58
+ }
59
+
60
+
61
+ /**
62
+ * Usually you get an `ICalAlarm` object like this:
63
+ *
64
+ * ```javascript
65
+ * import ical from 'ical-generator';
66
+ * const calendar = ical();
67
+ * const event = calendar.createEvent();
68
+ * const alarm = event.createAlarm();
69
+ * ```
70
+ *
71
+ * You can also use the [[`ICalAlarm`]] object directly:
72
+ *
73
+ * ```javascript
74
+ * import ical, {ICalAlarm} from 'ical-generator';
75
+ * const alarm = new ICalAlarm();
76
+ * event.alarms([alarm]);
77
+ * ```
78
+ */
79
+ export default class ICalAlarm {
80
+ private readonly data: ICalInternalAlarmData;
81
+ private readonly event: ICalEvent;
82
+
83
+ /**
84
+ * Constructor of [[`ICalAttendee`]]. The event reference is required
85
+ * to query the calendar's timezone and summary when required.
86
+ *
87
+ * @param data Alarm Data
88
+ * @param calendar Reference to ICalEvent object
89
+ */
90
+ constructor (data: ICalAlarmData, event: ICalEvent) {
91
+ this.data = {
92
+ type: null,
93
+ trigger: null,
94
+ repeat: null,
95
+ interval: null,
96
+ attach: null,
97
+ description: null,
98
+ x: []
99
+ };
100
+
101
+ this.event = event;
102
+ if (!event) {
103
+ throw new Error('`event` option required!');
104
+ }
105
+
106
+ data.type !== undefined && this.type(data.type);
107
+ data.trigger !== undefined && this.trigger(data.trigger);
108
+ data.triggerBefore !== undefined && this.triggerBefore(data.triggerBefore);
109
+ data.triggerAfter !== undefined && this.triggerAfter(data.triggerAfter);
110
+ data.repeat !== undefined && this.repeat(data.repeat);
111
+ data.interval !== undefined && this.interval(data.interval);
112
+ data.attach !== undefined && this.attach(data.attach);
113
+ data.description !== undefined && this.description(data.description);
114
+ data.x !== undefined && this.x(data.x);
115
+ }
116
+
117
+
118
+ /**
119
+ * Get the alarm type
120
+ * @since 0.2.1
121
+ */
122
+ type (type: ICalAlarmType | null): this;
123
+
124
+ /**
125
+ * Set the alarm type. See [[`ICalAlarmType`]]
126
+ * for available status options.
127
+ * @since 0.2.1
128
+ */
129
+ type (): ICalAlarmType | null;
130
+ type (type?: ICalAlarmType | null): this | ICalAlarmType | null {
131
+ if (type === undefined) {
132
+ return this.data.type;
133
+ }
134
+ if (!type) {
135
+ this.data.type = null;
136
+ return this;
137
+ }
138
+
139
+ if (!Object.keys(ICalAlarmType).includes(type)) {
140
+ throw new Error('`type` is not correct, must be either `display` or `audio`!');
141
+ }
142
+
143
+ this.data.type = type;
144
+ return this;
145
+ }
146
+
147
+
148
+ /**
149
+ * Get the trigger time for the alarm. Can either
150
+ * be a date and time value ([[`ICalDateTimeValue`]]) or
151
+ * a number, which will represent the seconds between
152
+ * alarm and event start. The number is negative, if the
153
+ * alarm is triggered after the event started.
154
+ *
155
+ * @since 0.2.1
156
+ */
157
+ trigger (): number | ICalDateTimeValue | null;
158
+
159
+ /**
160
+ * Use this method to set the alarm time.
161
+ *
162
+ * ```javascript
163
+ * const cal = ical();
164
+ * const event = cal.createEvent();
165
+ * const alarm = cal.createAlarm();
166
+ *
167
+ * alarm.trigger(600); // -> 10 minutes before event starts
168
+ * alarm.trigger(new Date()); // -> now
169
+ * ```
170
+ *
171
+ * You can use any supported date object, see
172
+ * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
173
+ * for details about supported values and timezone handling.
174
+ *
175
+ * @since 0.2.1
176
+ */
177
+ trigger (trigger: number | ICalDateTimeValue | Date | null): this;
178
+ trigger (trigger?: number | ICalDateTimeValue | Date | null): this | number | ICalDateTimeValue | null {
179
+
180
+ // Getter
181
+ if (trigger === undefined && typeof this.data.trigger === 'number') {
182
+ return -1 * this.data.trigger;
183
+ }
184
+ if (trigger === undefined && this.data.trigger) {
185
+ return this.data.trigger;
186
+ }
187
+ if (trigger === undefined) {
188
+ return null;
189
+ }
190
+
191
+ // Setter
192
+ if (!trigger) {
193
+ this.data.trigger = null;
194
+ }
195
+ else if (typeof trigger === 'number' && isFinite(trigger)) {
196
+ this.data.trigger = -1 * trigger;
197
+ }
198
+ else if(typeof trigger === 'number') {
199
+ throw new Error('`trigger` is not correct, must be a finite number or a supported date!');
200
+ }
201
+ else {
202
+ this.data.trigger = checkDate(trigger, 'trigger');
203
+ }
204
+
205
+ return this;
206
+ }
207
+
208
+
209
+ /**
210
+ * Get the trigger time for the alarm. Can either
211
+ * be a date and time value ([[`ICalDateTimeValue`]]) or
212
+ * a number, which will represent the seconds between
213
+ * alarm and event start. The number is negative, if the
214
+ * alarm is triggered before the event started.
215
+ *
216
+ * @since 0.2.1
217
+ */
218
+ triggerAfter (): number | ICalDateTimeValue | null;
219
+
220
+ /**
221
+ * Use this method to set the alarm time. Unlike `trigger`, this time
222
+ * the alarm takes place after the event has started.
223
+ *
224
+ * ```javascript
225
+ * const cal = ical();
226
+ * const event = cal.createEvent();
227
+ * const alarm = cal.createAlarm();
228
+ *
229
+ * alarm.trigger(600); // -> 10 minutes after event starts
230
+ * ```
231
+ *
232
+ * You can use any supported date object, see
233
+ * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
234
+ * for details about supported values and timezone handling.
235
+ *
236
+ * @since 0.2.1
237
+ */
238
+ triggerAfter (trigger: number | ICalDateTimeValue | null): this;
239
+ triggerAfter (trigger?: number | ICalDateTimeValue | null): this | number | ICalDateTimeValue | null {
240
+ if (trigger === undefined) {
241
+ return this.data.trigger;
242
+ }
243
+
244
+ return this.trigger(typeof trigger === 'number' ? -1 * trigger : trigger);
245
+ }
246
+
247
+
248
+ /**
249
+ * Get the trigger time for the alarm. Can either
250
+ * be a date and time value ([[`ICalDateTimeValue`]]) or
251
+ * a number, which will represent the seconds between
252
+ * alarm and event start. The number is negative, if the
253
+ * alarm is triggered after the event started.
254
+ *
255
+ * @since 0.2.1
256
+ * @alias trigger
257
+ */
258
+ triggerBefore (trigger: number | ICalDateTimeValue | null): this;
259
+
260
+ /**
261
+ * Use this method to set the alarm time.
262
+ *
263
+ * ```javascript
264
+ * const cal = ical();
265
+ * const event = cal.createEvent();
266
+ * const alarm = cal.createAlarm();
267
+ *
268
+ * alarm.trigger(600); // -> 10 minutes before event starts
269
+ * alarm.trigger(new Date()); // -> now
270
+ * ```
271
+ *
272
+ * You can use any supported date object, see
273
+ * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
274
+ * for details about supported values and timezone handling.
275
+ *
276
+ * @since 0.2.1
277
+ * @alias trigger
278
+ */
279
+ triggerBefore (): number | ICalDateTimeValue | null;
280
+ triggerBefore (trigger?: number | ICalDateTimeValue | null): this | number | ICalDateTimeValue | null {
281
+ if(trigger === undefined) {
282
+ return this.trigger();
283
+ }
284
+
285
+ return this.trigger(trigger);
286
+ }
287
+
288
+
289
+ /**
290
+ * Get Alarm Repetitions
291
+ * @since 0.2.1
292
+ */
293
+ repeat(): number | null;
294
+
295
+ /**
296
+ * Set Alarm Repetitions. Use this to repeat the alarm.
297
+ *
298
+ * ```javascript
299
+ * const cal = ical();
300
+ * const event = cal.createEvent();
301
+ *
302
+ * // repeat the alarm 4 times every 5 minutes…
303
+ * cal.createAlarm({
304
+ * repeat: 4,
305
+ * interval: 300
306
+ * });
307
+ * ```
308
+ *
309
+ * @since 0.2.1
310
+ */
311
+ repeat(repeat: number | null): this;
312
+ repeat (repeat?: number | null): this | number | null {
313
+ if (repeat === undefined) {
314
+ return this.data.repeat;
315
+ }
316
+ if (!repeat) {
317
+ this.data.repeat = null;
318
+ return this;
319
+ }
320
+
321
+ if (typeof repeat !== 'number' || !isFinite(repeat)) {
322
+ throw new Error('`repeat` is not correct, must be numeric!');
323
+ }
324
+
325
+ this.data.repeat = repeat;
326
+ return this;
327
+ }
328
+
329
+
330
+ /**
331
+ * Get Repeat Interval
332
+ * @since 0.2.1
333
+ */
334
+ interval (interval: number | null): this;
335
+
336
+ /**
337
+ * Set Repeat Interval
338
+ *
339
+ * ```javascript
340
+ * const cal = ical();
341
+ * const event = cal.createEvent();
342
+ *
343
+ * // repeat the alarm 4 times every 5 minutes…
344
+ * cal.createAlarm({
345
+ * repeat: 4,
346
+ * interval: 300
347
+ * });
348
+ * ```
349
+ *
350
+ * @since 0.2.1
351
+ */
352
+ interval(): number | null;
353
+ interval (interval?: number | null): this | number | null {
354
+ if (interval === undefined) {
355
+ return this.data.interval || null;
356
+ }
357
+ if (!interval) {
358
+ this.data.interval = null;
359
+ return this;
360
+ }
361
+
362
+ if (typeof interval !== 'number' || !isFinite(interval)) {
363
+ throw new Error('`interval` is not correct, must be numeric!');
364
+ }
365
+
366
+ this.data.interval = interval;
367
+ return this;
368
+ }
369
+
370
+
371
+ /**
372
+ * Get Attachment
373
+ * @since 0.2.1
374
+ */
375
+ attach (): {uri: string, mime: string | null} | null;
376
+
377
+ /**
378
+ * Set Alarm attachment. Used to set the alarm sound
379
+ * if alarm type is audio. Defaults to "Basso".
380
+ *
381
+ * ```javascript
382
+ * const cal = ical();
383
+ * const event = cal.createEvent();
384
+ *
385
+ * event.createAlarm({
386
+ * attach: 'https://example.com/notification.aud'
387
+ * });
388
+ *
389
+ * // OR
390
+ *
391
+ * event.createAlarm({
392
+ * attach: {
393
+ * uri: 'https://example.com/notification.aud',
394
+ * mime: 'audio/basic'
395
+ * }
396
+ * });
397
+ * ```
398
+ *
399
+ * @since 0.2.1
400
+ */
401
+ attach (attachment: {uri: string, mime?: string | null} | string | null): this;
402
+ attach (attachment?: {uri: string, mime?: string | null} | string | null): this | {uri: string, mime: string | null} | null {
403
+ if (attachment === undefined) {
404
+ return this.data.attach;
405
+ }
406
+ if (!attachment) {
407
+ this.data.attach = null;
408
+ return this;
409
+ }
410
+
411
+ let _attach = null;
412
+ if (typeof attachment === 'string') {
413
+ _attach = {
414
+ uri: attachment,
415
+ mime: null
416
+ };
417
+ }
418
+ else if (typeof attachment === 'object') {
419
+ _attach = {
420
+ uri: attachment.uri,
421
+ mime: attachment.mime || null
422
+ };
423
+ }
424
+ else {
425
+ throw new Error(
426
+ '`attachment` needs to be a valid formed string or an object. See https://sebbo2002.github.io/' +
427
+ 'ical-generator/develop/reference/classes/ICalAlarm.html#attach'
428
+ );
429
+ }
430
+
431
+ if (!_attach.uri) {
432
+ throw new Error('`attach.uri` is empty!');
433
+ }
434
+
435
+ this.data.attach = {
436
+ uri: _attach.uri,
437
+ mime: _attach.mime
438
+ };
439
+ return this;
440
+ }
441
+
442
+
443
+ /**
444
+ * Get the alarm description. Used to set the alarm message
445
+ * if alarm type is display. Defaults to the event's summary.
446
+ *
447
+ * @since 0.2.1
448
+ */
449
+ description (): string | null;
450
+
451
+ /**
452
+ * Set the alarm description. Used to set the alarm message
453
+ * if alarm type is display. Defaults to the event's summary.
454
+ *
455
+ * @since 0.2.1
456
+ */
457
+ description (description: string | null): this;
458
+ description (description?: string | null): this | string | null {
459
+ if (description === undefined) {
460
+ return this.data.description;
461
+ }
462
+ if (!description) {
463
+ this.data.description = null;
464
+ return this;
465
+ }
466
+
467
+ this.data.description = description;
468
+ return this;
469
+ }
470
+
471
+
472
+ /**
473
+ * Set X-* attributes. Woun't filter double attributes,
474
+ * which are also added by another method (e.g. type),
475
+ * so these attributes may be inserted twice.
476
+ *
477
+ * ```javascript
478
+ * alarm.x([
479
+ * {
480
+ * key: "X-MY-CUSTOM-ATTR",
481
+ * value: "1337!"
482
+ * }
483
+ * ]);
484
+ *
485
+ * alarm.x([
486
+ * ["X-MY-CUSTOM-ATTR", "1337!"]
487
+ * ]);
488
+ *
489
+ * alarm.x({
490
+ * "X-MY-CUSTOM-ATTR": "1337!"
491
+ * });
492
+ * ```
493
+ *
494
+ * @since 1.9.0
495
+ */
496
+ x (keyOrArray: {key: string, value: string}[] | [string, string][] | Record<string, string>): this;
497
+
498
+ /**
499
+ * Set a X-* attribute. Woun't filter double attributes,
500
+ * which are also added by another method (e.g. type),
501
+ * so these attributes may be inserted twice.
502
+ *
503
+ * ```javascript
504
+ * alarm.x("X-MY-CUSTOM-ATTR", "1337!");
505
+ * ```
506
+ *
507
+ * @since 1.9.0
508
+ */
509
+ x (keyOrArray: string, value: string): this;
510
+
511
+ /**
512
+ * Get all custom X-* attributes.
513
+ * @since 1.9.0
514
+ */
515
+ x (): {key: string, value: string}[];
516
+ x (keyOrArray?: ({key: string, value: string})[] | [string, string][] | Record<string, string> | string, value?: string): this | void | ({key: string, value: string})[] {
517
+ if(keyOrArray === undefined) {
518
+ return addOrGetCustomAttributes (this.data);
519
+ }
520
+
521
+ if(typeof keyOrArray === 'string' && typeof value === 'string') {
522
+ addOrGetCustomAttributes (this.data, keyOrArray, value);
523
+ }
524
+ else if(typeof keyOrArray === 'object') {
525
+ addOrGetCustomAttributes (this.data, keyOrArray);
526
+ }
527
+ else {
528
+ throw new Error('Either key or value is not a string!');
529
+ }
530
+
531
+ return this;
532
+ }
533
+
534
+
535
+ /**
536
+ * Return a shallow copy of the alarm's options for JSON stringification.
537
+ * Third party objects like moment.js values are stringified as well. Can
538
+ * be used for persistence.
539
+ *
540
+ * @since 0.2.4
541
+ */
542
+ toJSON (): ICalAlarmJSONData {
543
+ const trigger = this.trigger();
544
+ return Object.assign({}, this.data, {
545
+ trigger: typeof trigger === 'number' ? trigger : toJSON(trigger),
546
+ x: this.x()
547
+ });
548
+ }
549
+
550
+
551
+ /**
552
+ * Return generated event as a string.
553
+ *
554
+ * ```javascript
555
+ * const alarm = event.createAlarm();
556
+ * console.log(alarm.toString()); // → BEGIN:VALARM…
557
+ * ```
558
+ */
559
+ toString (): string {
560
+ let g = 'BEGIN:VALARM\r\n';
561
+
562
+ if (!this.data.type) {
563
+ throw new Error('No value for `type` in ICalAlarm given!');
564
+ }
565
+ if (!this.data.trigger) {
566
+ throw new Error('No value for `trigger` in ICalAlarm given!');
567
+ }
568
+
569
+ // ACTION
570
+ g += 'ACTION:' + this.data.type.toUpperCase() + '\r\n';
571
+
572
+ if (typeof this.data.trigger === 'number' && this.data.trigger > 0) {
573
+ g += 'TRIGGER;RELATED=END:' + toDurationString(this.data.trigger) + '\r\n';
574
+ }
575
+ else if (typeof this.data.trigger === 'number') {
576
+ g += 'TRIGGER:' + toDurationString(this.data.trigger) + '\r\n';
577
+ }
578
+ else {
579
+ g += 'TRIGGER;VALUE=DATE-TIME:' + formatDate(this.event.timezone(), this.data.trigger) + '\r\n';
580
+ }
581
+
582
+ // REPEAT
583
+ if (this.data.repeat && !this.data.interval) {
584
+ throw new Error('No value for `interval` in ICalAlarm given, but required for `repeat`!');
585
+ }
586
+ if (this.data.repeat) {
587
+ g += 'REPEAT:' + this.data.repeat + '\r\n';
588
+ }
589
+
590
+ // INTERVAL
591
+ if (this.data.interval && !this.data.repeat) {
592
+ throw new Error('No value for `repeat` in ICalAlarm given, but required for `interval`!');
593
+ }
594
+ if (this.data.interval) {
595
+ g += 'DURATION:' + toDurationString(this.data.interval) + '\r\n';
596
+ }
597
+
598
+ // ATTACH
599
+ if (this.data.type === 'audio' && this.data.attach && this.data.attach.mime) {
600
+ g += 'ATTACH;FMTTYPE=' + escape(this.data.attach.mime, false) + ':' + escape(this.data.attach.uri, false) + '\r\n';
601
+ }
602
+ else if (this.data.type === 'audio' && this.data.attach) {
603
+ g += 'ATTACH;VALUE=URI:' + escape(this.data.attach.uri, false) + '\r\n';
604
+ }
605
+ else if (this.data.type === 'audio') {
606
+ g += 'ATTACH;VALUE=URI:Basso\r\n';
607
+ }
608
+
609
+ // DESCRIPTION
610
+ if (this.data.type === 'display' && this.data.description) {
611
+ g += 'DESCRIPTION:' + escape(this.data.description, false) + '\r\n';
612
+ }
613
+ else if (this.data.type === 'display') {
614
+ g += 'DESCRIPTION:' + escape(this.event.summary(), false) + '\r\n';
615
+ }
616
+
617
+ // CUSTOM X ATTRIBUTES
618
+ g += generateCustomAttributes(this.data);
619
+
620
+ g += 'END:VALARM\r\n';
621
+ return g;
622
+ }
623
+ }