ical-generator 8.1.2-develop.8 → 9.0.0-develop.1

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/src/alarm.ts CHANGED
@@ -1,92 +1,102 @@
1
1
  'use strict';
2
2
 
3
3
  import type ICalEvent from './event.ts';
4
+
5
+ import ICalAttendee, { type ICalAttendeeData } from './attendee.ts';
4
6
  import {
5
7
  addOrGetCustomAttributes,
6
- formatDate,
8
+ checkDate,
9
+ checkNameAndMail,
7
10
  escape,
11
+ formatDate,
8
12
  generateCustomAttributes,
9
- checkDate,
10
13
  toDurationString,
11
14
  toJSON,
12
- checkNameAndMail
13
15
  } from './tools.ts';
14
16
  import { type ICalDateTimeValue } from './types.ts';
15
- import ICalAttendee, { type ICalAttendeeData } from './attendee.ts';
16
-
17
17
 
18
18
  export enum ICalAlarmType {
19
- display = 'display',
20
19
  audio = 'audio',
21
- email = 'email'
20
+ display = 'display',
21
+ email = 'email',
22
22
  }
23
23
 
24
24
  export const ICalAlarmRelatesTo = {
25
25
  end: 'END',
26
- start: 'START'
26
+ start: 'START',
27
27
  } as const;
28
28
 
29
- export type ICalAlarmRelatesTo = typeof ICalAlarmRelatesTo[keyof typeof ICalAlarmRelatesTo];
30
-
31
- export type ICalAlarmTypeValue = keyof ICalAlarmType;
32
-
33
- export interface ICalAttachment {
34
- uri: string;
35
- mime: string | null;
36
- }
37
-
38
- export type ICalAlarmData = ICalAlarmBaseData |
39
- ICalAlarmTriggerData |
40
- ICalAlarmTriggerAfterData |
41
- ICalAlarmTriggerBeforeData;
42
-
43
- export type ICalAlarmTriggerData = ICalAlarmBaseData & { trigger: number | ICalDateTimeValue };
44
- export type ICalAlarmTriggerAfterData = ICalAlarmBaseData & { triggerAfter: number | ICalDateTimeValue };
45
- export type ICalAlarmTriggerBeforeData = ICalAlarmBaseData & { triggerBefore: number | ICalDateTimeValue };
46
-
47
29
  export interface ICalAlarmBaseData {
48
- type?: ICalAlarmType;
30
+ attach?: ICalAttachment | null | string;
31
+ attendees?: ICalAttendee[] | ICalAttendeeData[];
32
+ description?: null | string;
49
33
  relatesTo?: ICalAlarmRelatesTo | null;
50
34
  repeat?: ICalAlarmRepeatData | null;
51
- attach?: string | ICalAttachment | null;
52
- description?: string | null;
53
- summary?: string | null;
54
- attendees?: ICalAttendee[] | ICalAttendeeData[];
55
- x?: {key: string, value: string}[] | [string, string][] | Record<string, string>;
35
+ summary?: null | string;
36
+ type?: ICalAlarmType;
37
+ x?:
38
+ | [string, string][]
39
+ | Record<string, string>
40
+ | { key: string; value: string }[];
41
+ }
42
+
43
+ export type ICalAlarmData =
44
+ | ICalAlarmBaseData
45
+ | ICalAlarmTriggerAfterData
46
+ | ICalAlarmTriggerBeforeData
47
+ | ICalAlarmTriggerData;
48
+
49
+ export interface ICalAlarmJSONData {
50
+ attach: ICalAttachment | null;
51
+ attendees: ICalAttendee[];
52
+ description: null | string;
53
+ interval: null | number;
54
+ relatesTo: ICalAlarmRelatesTo | null;
55
+ repeat: ICalAlarmRepeatData | null;
56
+ summary: null | string;
57
+ trigger: number | string;
58
+ type: ICalAlarmType;
59
+ x: { key: string; value: string }[];
56
60
  }
57
61
 
62
+ export type ICalAlarmRelatesTo =
63
+ (typeof ICalAlarmRelatesTo)[keyof typeof ICalAlarmRelatesTo];
64
+
58
65
  export interface ICalAlarmRepeatData {
59
- times: number;
60
66
  interval: number;
67
+ times: number;
68
+ }
69
+ export type ICalAlarmTriggerAfterData = ICalAlarmBaseData & {
70
+ triggerAfter: ICalDateTimeValue | number;
71
+ };
72
+ export type ICalAlarmTriggerBeforeData = ICalAlarmBaseData & {
73
+ triggerBefore: ICalDateTimeValue | number;
74
+ };
75
+
76
+ export type ICalAlarmTriggerData = ICalAlarmBaseData & {
77
+ trigger: ICalDateTimeValue | number;
78
+ };
79
+
80
+ export type ICalAlarmTypeValue = keyof ICalAlarmType;
81
+
82
+ export interface ICalAttachment {
83
+ mime: null | string;
84
+ uri: string;
61
85
  }
62
86
 
63
87
  interface ICalInternalAlarmData {
64
- type: ICalAlarmType;
65
- trigger: ICalDateTimeValue | number;
66
- relatesTo: ICalAlarmRelatesTo | null;
67
- repeat: ICalAlarmRepeatData | null;
68
- interval: number | null;
69
88
  attach: ICalAttachment | null;
70
- description: string | null;
71
- summary: string | null;
72
89
  attendees: ICalAttendee[];
73
- x: [string, string][];
74
- }
75
-
76
- export interface ICalAlarmJSONData {
77
- type: ICalAlarmType;
78
- trigger: string | number;
90
+ description: null | string;
91
+ interval: null | number;
79
92
  relatesTo: ICalAlarmRelatesTo | null;
80
93
  repeat: ICalAlarmRepeatData | null;
81
- interval: number | null;
82
- attach: ICalAttachment | null;
83
- description: string | null;
84
- summary: string | null;
85
- attendees: ICalAttendee[];
86
- x: {key: string, value: string}[];
94
+ summary: null | string;
95
+ trigger: ICalDateTimeValue | number;
96
+ type: ICalAlarmType;
97
+ x: [string, string][];
87
98
  }
88
99
 
89
-
90
100
  /**
91
101
  * Usually you get an {@link ICalAlarm} object like this:
92
102
  *
@@ -116,18 +126,18 @@ export default class ICalAlarm {
116
126
  * @param data Alarm Data
117
127
  * @param event Reference to ICalEvent object
118
128
  */
119
- constructor (data: ICalAlarmData, event: ICalEvent) {
129
+ constructor(data: ICalAlarmData, event: ICalEvent) {
120
130
  this.data = {
121
- type: ICalAlarmType.display,
122
- trigger: -600,
123
- relatesTo: null,
124
- repeat: null,
125
- interval: null,
126
131
  attach: null,
132
+ attendees: [],
127
133
  description: null,
134
+ interval: null,
135
+ relatesTo: null,
136
+ repeat: null,
128
137
  summary: null,
129
- attendees: [],
130
- x: []
138
+ trigger: -600,
139
+ type: ICalAlarmType.display,
140
+ x: [],
131
141
  };
132
142
 
133
143
  this.event = event;
@@ -136,9 +146,12 @@ export default class ICalAlarm {
136
146
  }
137
147
 
138
148
  if (data.type !== undefined) this.type(data.type);
139
- if ('trigger' in data && data.trigger !== undefined) this.trigger(data.trigger);
140
- if ('triggerBefore' in data && data.triggerBefore !== undefined) this.triggerBefore(data.triggerBefore);
141
- if ('triggerAfter' in data && data.triggerAfter !== undefined) this.triggerAfter(data.triggerAfter);
149
+ if ('trigger' in data && data.trigger !== undefined)
150
+ this.trigger(data.trigger);
151
+ if ('triggerBefore' in data && data.triggerBefore !== undefined)
152
+ this.triggerBefore(data.triggerBefore);
153
+ if ('triggerAfter' in data && data.triggerAfter !== undefined)
154
+ this.triggerAfter(data.triggerAfter);
142
155
  if (data.repeat) this.repeat(data.repeat);
143
156
  if (data.attach !== undefined) this.attach(data.attach);
144
157
  if (data.description !== undefined) this.description(data.description);
@@ -147,83 +160,149 @@ export default class ICalAlarm {
147
160
  if (data.x !== undefined) this.x(data.x);
148
161
  }
149
162
 
150
-
151
163
  /**
152
- * Get the alarm type
164
+ * Get Attachment
153
165
  * @since 0.2.1
154
166
  */
155
- type (type: ICalAlarmType): this;
156
-
167
+ attach(): null | { mime: null | string; uri: string };
157
168
  /**
158
- * Set the alarm type. See {@link ICalAlarmType}
159
- * for available status options.
169
+ * Set Alarm attachment. Used to set the alarm sound
170
+ * if alarm type is audio. Defaults to "Basso".
171
+ *
172
+ * ```javascript
173
+ * const cal = ical();
174
+ * const event = cal.createEvent();
175
+ *
176
+ * event.createAlarm({
177
+ * attach: 'https://example.com/notification.aud'
178
+ * });
179
+ *
180
+ * // OR
181
+ *
182
+ * event.createAlarm({
183
+ * attach: {
184
+ * uri: 'https://example.com/notification.aud',
185
+ * mime: 'audio/basic'
186
+ * }
187
+ * });
188
+ * ```
189
+ *
160
190
  * @since 0.2.1
161
191
  */
162
- type (): ICalAlarmType;
163
- type (type?: ICalAlarmType): this | ICalAlarmType {
164
- if (type === undefined) {
165
- return this.data.type;
192
+ attach(
193
+ attachment: null | string | { mime?: null | string; uri: string },
194
+ ): this;
195
+ attach(
196
+ attachment?: null | string | { mime?: null | string; uri: string },
197
+ ): null | this | { mime: null | string; uri: string } {
198
+ if (attachment === undefined) {
199
+ return this.data.attach;
166
200
  }
167
- if (!type || !Object.keys(ICalAlarmType).includes(type)) {
168
- throw new Error('`type` is not correct, must be either `display` or `audio`!');
201
+ if (!attachment) {
202
+ this.data.attach = null;
203
+ return this;
169
204
  }
170
205
 
171
- this.data.type = type;
206
+ let _attach = null;
207
+ if (typeof attachment === 'string') {
208
+ _attach = {
209
+ mime: null,
210
+ uri: attachment,
211
+ };
212
+ } else if (typeof attachment === 'object') {
213
+ _attach = {
214
+ mime: attachment.mime || null,
215
+ uri: attachment.uri,
216
+ };
217
+ } else {
218
+ throw new Error(
219
+ '`attachment` needs to be a valid formed string or an object. See https://sebbo2002.github.io/' +
220
+ 'ical-generator/develop/reference/classes/ICalAlarm.html#attach',
221
+ );
222
+ }
223
+
224
+ if (!_attach.uri) {
225
+ throw new Error('`attach.uri` is empty!');
226
+ }
227
+
228
+ this.data.attach = {
229
+ mime: _attach.mime,
230
+ uri: _attach.uri,
231
+ };
172
232
  return this;
173
233
  }
174
234
 
175
-
176
235
  /**
177
- * Get the trigger time for the alarm. Can either
178
- * be a date and time value ({@link ICalDateTimeValue}) or
179
- * a number, which will represent the seconds between
180
- * alarm and event start. The number is negative, if the
181
- * alarm is triggered after the event started.
236
+ * Get all attendees
237
+ * @since 7.0.0
238
+ */
239
+ attendees(): ICalAttendee[];
240
+ /**
241
+ * Add multiple attendees to your event
182
242
  *
183
- * @since 0.2.1
243
+ * @since 7.0.0
184
244
  */
185
- trigger (): number | ICalDateTimeValue;
245
+ attendees(attendees: (ICalAttendee | ICalAttendeeData | string)[]): this;
246
+ attendees(
247
+ attendees?: (ICalAttendee | ICalAttendeeData | string)[],
248
+ ): ICalAttendee[] | this {
249
+ if (!attendees) {
250
+ return this.data.attendees;
251
+ }
252
+
253
+ attendees.forEach((attendee) => this.createAttendee(attendee));
254
+ return this;
255
+ }
186
256
 
187
257
  /**
188
- * Use this method to set the alarm time.
189
- *
190
- * ```javascript
191
- * const cal = ical();
192
- * const event = cal.createEvent();
193
- * const alarm = cal.createAlarm();
194
- *
195
- * alarm.trigger(600); // -> 10 minutes before event starts
196
- * alarm.trigger(new Date()); // -> now
197
- * ```
198
- *
199
- * You can use any supported date object, see
200
- * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
201
- * for details about supported values and timezone handling.
258
+ * Creates a new {@link ICalAttendee} and returns it. Use options to prefill
259
+ * the attendee's attributes. Calling this method without options will create
260
+ * an empty attendee.
202
261
  *
203
- * @since 0.2.1
262
+ * @since 7.0.0
204
263
  */
205
- trigger (trigger: number | ICalDateTimeValue | Date): this;
206
- trigger (trigger?: number | ICalDateTimeValue | Date): this | number | ICalDateTimeValue {
207
-
208
- // Getter
209
- if (trigger === undefined && typeof this.data.trigger === 'number') {
210
- return -1 * this.data.trigger;
264
+ createAttendee(
265
+ data: ICalAttendee | ICalAttendeeData | string,
266
+ ): ICalAttendee {
267
+ if (data instanceof ICalAttendee) {
268
+ this.data.attendees.push(data);
269
+ return data;
211
270
  }
212
- if (trigger === undefined) {
213
- return this.data.trigger;
271
+ if (typeof data === 'string') {
272
+ data = { email: data, ...checkNameAndMail('data', data) };
214
273
  }
215
274
 
216
- // Setter
217
- if (typeof trigger === 'number' && isFinite(trigger)) {
218
- this.data.trigger = -1 * trigger;
219
- }
220
- else if(!trigger || typeof trigger === 'number') {
221
- throw new Error('`trigger` is not correct, must be a finite number or a supported date!');
275
+ const attendee = new ICalAttendee(data, this);
276
+ this.data.attendees.push(attendee);
277
+ return attendee;
278
+ }
279
+
280
+ /**
281
+ * Get the alarm description. Used to set the alarm message
282
+ * if alarm type is `display`. If the alarm type is `email`, it's
283
+ * used to set the email body. Defaults to the event's summary.
284
+ *
285
+ * @since 0.2.1
286
+ */
287
+ description(): null | string;
288
+ /**
289
+ * Set the alarm description. Used to set the alarm message
290
+ * if alarm type is `display`. If the alarm type is `email`, it's
291
+ * used to set the email body. Defaults to the event's summary.
292
+ *
293
+ * @since 0.2.1
294
+ */
295
+ description(description: null | string): this;
296
+ description(description?: null | string): null | string | this {
297
+ if (description === undefined) {
298
+ return this.data.description;
222
299
  }
223
- else {
224
- this.data.trigger = checkDate(trigger, 'trigger');
300
+ if (!description) {
301
+ this.data.description = null;
302
+ return this;
225
303
  }
226
304
 
305
+ this.data.description = description;
227
306
  return this;
228
307
  }
229
308
 
@@ -232,34 +311,35 @@ export default class ICalAlarm {
232
311
  * Can be either `START` or `END`. If the value is
233
312
  * `START` the alarm is triggerd relative to the event start time.
234
313
  * If the value is `END` the alarm is triggerd relative to the event end time
235
- *
314
+ *
236
315
  * @since 4.0.1
237
316
  */
238
317
  relatesTo(): ICalAlarmRelatesTo | null;
239
-
240
318
  /**
241
319
  * Use this method to set to which time alarm trigger relates to.
242
320
  * Works only if trigger is a `number`
243
- *
321
+ *
244
322
  * ```javascript
245
323
  * const cal = ical();
246
324
  * const event = cal.createEvent();
247
325
  * const alarm = cal.createAlarm();
248
326
  *
249
327
  * alarm.trigger(600); // -> 10 minutes before event starts
250
- *
328
+ *
251
329
  * alarm.relatesTo('START'); // -> 10 minutes before event starts
252
330
  * alarm.relatesTo('END'); // -> 10 minutes before event ends
253
- *
331
+ *
254
332
  * alarm.trigger(-600); // -> 10 minutes after event starts
255
- *
333
+ *
256
334
  * alarm.relatesTo('START'); // -> 10 minutes after event starts
257
335
  * alarm.relatesTo('END'); // -> 10 minutes after event ends
258
336
  * ```
259
337
  * @since 4.0.1
260
338
  */
261
339
  relatesTo(relatesTo: ICalAlarmRelatesTo | null): this;
262
- relatesTo(relatesTo?: ICalAlarmRelatesTo | null): this | ICalAlarmRelatesTo | null {
340
+ relatesTo(
341
+ relatesTo?: ICalAlarmRelatesTo | null,
342
+ ): ICalAlarmRelatesTo | null | this {
263
343
  if (relatesTo === undefined) {
264
344
  return this.data.relatesTo;
265
345
  }
@@ -269,321 +349,378 @@ export default class ICalAlarm {
269
349
  }
270
350
 
271
351
  if (!Object.values(ICalAlarmRelatesTo).includes(relatesTo)) {
272
- throw new Error('`relatesTo` is not correct, must be either `START` or `END`!');
352
+ throw new Error(
353
+ '`relatesTo` is not correct, must be either `START` or `END`!',
354
+ );
273
355
  }
274
356
 
275
357
  this.data.relatesTo = relatesTo;
276
358
  return this;
277
359
  }
278
360
 
279
-
280
361
  /**
281
- * Get the trigger time for the alarm. Can either
282
- * be a date and time value ({@link ICalDateTimeValue}) or
283
- * a number, which will represent the seconds between
284
- * alarm and event start. The number is negative, if the
285
- * alarm is triggered before the event started.
286
- *
362
+ * Get Alarm Repetitions
287
363
  * @since 0.2.1
288
364
  */
289
- triggerAfter (): number | ICalDateTimeValue;
290
-
365
+ repeat(): ICalAlarmRepeatData | null;
291
366
  /**
292
- * Use this method to set the alarm time. Unlike `trigger`, this time
293
- * the alarm takes place after the event has started.
367
+ * Set Alarm Repetitions. Use this to repeat the alarm.
294
368
  *
295
369
  * ```javascript
296
370
  * const cal = ical();
297
371
  * const event = cal.createEvent();
298
- * const alarm = cal.createAlarm();
299
372
  *
300
- * alarm.trigger(600); // -> 10 minutes after event starts
373
+ * // repeat the alarm 4 times every 5 minutes…
374
+ * cal.createAlarm({
375
+ * repeat: {
376
+ * times: 4,
377
+ * interval: 300
378
+ * }
379
+ * });
301
380
  * ```
302
381
  *
303
- * You can use any supported date object, see
304
- * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
305
- * for details about supported values and timezone handling.
306
- *
307
382
  * @since 0.2.1
308
383
  */
309
- triggerAfter (trigger: number | ICalDateTimeValue): this;
310
- triggerAfter (trigger?: number | ICalDateTimeValue): this | number | ICalDateTimeValue {
311
- if (trigger === undefined) {
312
- return this.data.trigger;
384
+ repeat(repeat: ICalAlarmRepeatData | null): this;
385
+ repeat(
386
+ repeat?: ICalAlarmRepeatData | null,
387
+ ): ICalAlarmRepeatData | null | this {
388
+ if (repeat === undefined) {
389
+ return this.data.repeat;
390
+ }
391
+ if (!repeat) {
392
+ this.data.repeat = null;
393
+ return this;
313
394
  }
314
395
 
315
- return this.trigger(typeof trigger === 'number' ? -1 * trigger : trigger);
316
- }
317
-
318
-
319
- /**
320
- * Get the trigger time for the alarm. Can either
321
- * be a date and time value ({@link ICalDateTimeValue}) or
322
- * a number, which will represent the seconds between
323
- * alarm and event start. The number is negative, if the
324
- * alarm is triggered after the event started.
325
- *
326
- * @since 0.2.1
327
- * @see {@link trigger}
328
- * @see {@link triggerAfter}
329
- */
330
- triggerBefore (trigger: number | ICalDateTimeValue): this;
396
+ if (typeof repeat !== 'object') {
397
+ throw new Error('`repeat` is not correct, must be an object!');
398
+ }
399
+ if (typeof repeat.times !== 'number' || !isFinite(repeat.times)) {
400
+ throw new Error('`repeat.times` is not correct, must be numeric!');
401
+ }
402
+ if (typeof repeat.interval !== 'number' || !isFinite(repeat.interval)) {
403
+ throw new Error(
404
+ '`repeat.interval` is not correct, must be numeric!',
405
+ );
406
+ }
407
+
408
+ this.data.repeat = repeat;
409
+ return this;
410
+ }
331
411
 
332
412
  /**
333
- * Use this method to set the alarm time.
334
- *
335
- * ```javascript
336
- * const cal = ical();
337
- * const event = cal.createEvent();
338
- * const alarm = cal.createAlarm();
339
- *
340
- * alarm.trigger(600); // -> 10 minutes before event starts
341
- * alarm.trigger(new Date()); // -> now
342
- * ```
413
+ * Get the alarm summary. Used to set the email subject
414
+ * if alarm type is `email`. Defaults to the event's summary.
343
415
  *
344
- * You can use any supported date object, see
345
- * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
346
- * for details about supported values and timezone handling.
416
+ * @since 7.0.0
417
+ */
418
+ summary(): null | string;
419
+ /**
420
+ * Set the alarm summary. Used to set the email subject
421
+ * if alarm type is display. Defaults to the event's summary.
347
422
  *
348
423
  * @since 0.2.1
349
- * @see {@link trigger}
350
- * @see {@link triggerAfter}
351
424
  */
352
- triggerBefore (): number | ICalDateTimeValue;
353
- triggerBefore (trigger?: number | ICalDateTimeValue): this | number | ICalDateTimeValue {
354
- if(trigger === undefined) {
355
- return this.trigger();
425
+ summary(summary: null | string): this;
426
+ summary(summary?: null | string): null | string | this {
427
+ if (summary === undefined) {
428
+ return this.data.summary;
429
+ }
430
+ if (!summary) {
431
+ this.data.summary = null;
432
+ return this;
356
433
  }
357
434
 
358
- return this.trigger(trigger);
435
+ this.data.summary = summary;
436
+ return this;
359
437
  }
360
438
 
361
-
362
439
  /**
363
- * Get Alarm Repetitions
364
- * @since 0.2.1
440
+ * Return a shallow copy of the alarm's options for JSON stringification.
441
+ * Third party objects like moment.js values are stringified as well. Can
442
+ * be used for persistence.
443
+ *
444
+ * @since 0.2.4
365
445
  */
366
- repeat(): ICalAlarmRepeatData | null;
367
-
446
+ toJSON(): ICalAlarmJSONData {
447
+ const trigger = this.trigger();
448
+ return Object.assign({}, this.data, {
449
+ trigger: typeof trigger === 'number' ? trigger : toJSON(trigger),
450
+ x: this.x(),
451
+ });
452
+ }
368
453
  /**
369
- * Set Alarm Repetitions. Use this to repeat the alarm.
454
+ * Return generated event as a string.
370
455
  *
371
456
  * ```javascript
372
- * const cal = ical();
373
- * const event = cal.createEvent();
374
- *
375
- * // repeat the alarm 4 times every 5 minutes…
376
- * cal.createAlarm({
377
- * repeat: {
378
- * times: 4,
379
- * interval: 300
380
- * }
381
- * });
457
+ * const alarm = event.createAlarm();
458
+ * console.log(alarm.toString()); // → BEGIN:VALARM…
382
459
  * ```
383
- *
384
- * @since 0.2.1
385
460
  */
386
- repeat(repeat: ICalAlarmRepeatData | null): this;
387
- repeat (repeat?: ICalAlarmRepeatData | null): this | ICalAlarmRepeatData | null {
388
- if (repeat === undefined) {
389
- return this.data.repeat;
461
+ toString(): string {
462
+ let g = 'BEGIN:VALARM\r\n';
463
+
464
+ // ACTION
465
+ g += 'ACTION:' + this.data.type.toUpperCase() + '\r\n';
466
+
467
+ if (
468
+ typeof this.data.trigger === 'number' &&
469
+ this.data.relatesTo === null
470
+ ) {
471
+ if (this.data.trigger > 0) {
472
+ g +=
473
+ 'TRIGGER;RELATED=END:' +
474
+ toDurationString(this.data.trigger) +
475
+ '\r\n';
476
+ } else {
477
+ g += 'TRIGGER:' + toDurationString(this.data.trigger) + '\r\n';
478
+ }
479
+ } else if (typeof this.data.trigger === 'number') {
480
+ g +=
481
+ 'TRIGGER;RELATED=' +
482
+ this.data.relatesTo?.toUpperCase() +
483
+ ':' +
484
+ toDurationString(this.data.trigger) +
485
+ '\r\n';
486
+ } else {
487
+ g +=
488
+ 'TRIGGER;VALUE=DATE-TIME:' +
489
+ formatDate(this.event.timezone(), this.data.trigger) +
490
+ '\r\n';
390
491
  }
391
- if (!repeat) {
392
- this.data.repeat = null;
393
- return this;
492
+
493
+ // REPEAT
494
+ if (this.data.repeat) {
495
+ if (!this.data.repeat.times) {
496
+ throw new Error(
497
+ 'No value for `repeat.times` in ICalAlarm given, but required for `interval`!',
498
+ );
499
+ }
500
+ if (!this.data.repeat.interval) {
501
+ throw new Error(
502
+ 'No value for `repeat.interval` in ICalAlarm given, but required for `repeat`!',
503
+ );
504
+ }
505
+
506
+ g += 'REPEAT:' + this.data.repeat.times + '\r\n';
507
+ g +=
508
+ 'DURATION:' +
509
+ toDurationString(this.data.repeat.interval) +
510
+ '\r\n';
394
511
  }
395
512
 
396
- if (typeof repeat !== 'object') {
397
- throw new Error('`repeat` is not correct, must be an object!');
513
+ // ATTACH
514
+ if (
515
+ this.data.type === 'audio' &&
516
+ this.data.attach &&
517
+ this.data.attach.mime
518
+ ) {
519
+ g +=
520
+ 'ATTACH;FMTTYPE=' +
521
+ escape(this.data.attach.mime, false) +
522
+ ':' +
523
+ escape(this.data.attach.uri, false) +
524
+ '\r\n';
525
+ } else if (this.data.type === 'audio' && this.data.attach) {
526
+ g +=
527
+ 'ATTACH;VALUE=URI:' +
528
+ escape(this.data.attach.uri, false) +
529
+ '\r\n';
530
+ } else if (this.data.type === 'audio') {
531
+ g += 'ATTACH;VALUE=URI:Basso\r\n';
398
532
  }
399
- if (typeof repeat.times !== 'number' || !isFinite(repeat.times)) {
400
- throw new Error('`repeat.times` is not correct, must be numeric!');
533
+
534
+ // DESCRIPTION
535
+ if (this.data.type !== 'audio' && this.data.description) {
536
+ g += 'DESCRIPTION:' + escape(this.data.description, false) + '\r\n';
537
+ } else if (this.data.type !== 'audio') {
538
+ g += 'DESCRIPTION:' + escape(this.event.summary(), false) + '\r\n';
401
539
  }
402
- if (typeof repeat.interval !== 'number' || !isFinite(repeat.interval)) {
403
- throw new Error('`repeat.interval` is not correct, must be numeric!');
540
+
541
+ // SUMMARY
542
+ if (this.data.type === 'email' && this.data.summary) {
543
+ g += 'SUMMARY:' + escape(this.data.summary, false) + '\r\n';
544
+ } else if (this.data.type === 'email') {
545
+ g += 'SUMMARY:' + escape(this.event.summary(), false) + '\r\n';
404
546
  }
405
547
 
406
- this.data.repeat = repeat;
407
- return this;
408
- }
548
+ // ATTENDEES
549
+ if (this.data.type === 'email') {
550
+ this.data.attendees.forEach((attendee) => {
551
+ g += attendee.toString();
552
+ });
553
+ }
409
554
 
555
+ // CUSTOM X ATTRIBUTES
556
+ g += generateCustomAttributes(this.data);
557
+
558
+ g += 'END:VALARM\r\n';
559
+ return g;
560
+ }
410
561
 
411
562
  /**
412
- * Get Attachment
563
+ * Get the trigger time for the alarm. Can either
564
+ * be a date and time value ({@link ICalDateTimeValue}) or
565
+ * a number, which will represent the seconds between
566
+ * alarm and event start. The number is negative, if the
567
+ * alarm is triggered after the event started.
568
+ *
413
569
  * @since 0.2.1
414
570
  */
415
- attach (): {uri: string, mime: string | null} | null;
416
-
571
+ trigger(): ICalDateTimeValue | number;
417
572
  /**
418
- * Set Alarm attachment. Used to set the alarm sound
419
- * if alarm type is audio. Defaults to "Basso".
573
+ * Use this method to set the alarm time.
420
574
  *
421
575
  * ```javascript
422
576
  * const cal = ical();
423
577
  * const event = cal.createEvent();
578
+ * const alarm = cal.createAlarm();
424
579
  *
425
- * event.createAlarm({
426
- * attach: 'https://example.com/notification.aud'
427
- * });
428
- *
429
- * // OR
430
- *
431
- * event.createAlarm({
432
- * attach: {
433
- * uri: 'https://example.com/notification.aud',
434
- * mime: 'audio/basic'
435
- * }
436
- * });
580
+ * alarm.trigger(600); // -> 10 minutes before event starts
581
+ * alarm.trigger(new Date()); // -> now
437
582
  * ```
438
583
  *
584
+ * You can use any supported date object, see
585
+ * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
586
+ * for details about supported values and timezone handling.
587
+ *
439
588
  * @since 0.2.1
440
589
  */
441
- attach (attachment: {uri: string, mime?: string | null} | string | null): this;
442
- attach (attachment?: {uri: string, mime?: string | null} | string | null): this | {uri: string, mime: string | null} | null {
443
- if (attachment === undefined) {
444
- return this.data.attach;
590
+ trigger(trigger: Date | ICalDateTimeValue | number): this;
591
+ trigger(
592
+ trigger?: Date | ICalDateTimeValue | number,
593
+ ): ICalDateTimeValue | number | this {
594
+ // Getter
595
+ if (trigger === undefined && typeof this.data.trigger === 'number') {
596
+ return -1 * this.data.trigger;
445
597
  }
446
- if (!attachment) {
447
- this.data.attach = null;
448
- return this;
598
+ if (trigger === undefined) {
599
+ return this.data.trigger;
449
600
  }
450
601
 
451
- let _attach = null;
452
- if (typeof attachment === 'string') {
453
- _attach = {
454
- uri: attachment,
455
- mime: null
456
- };
457
- }
458
- else if (typeof attachment === 'object') {
459
- _attach = {
460
- uri: attachment.uri,
461
- mime: attachment.mime || null
462
- };
463
- }
464
- else {
602
+ // Setter
603
+ if (typeof trigger === 'number' && isFinite(trigger)) {
604
+ this.data.trigger = -1 * trigger;
605
+ } else if (!trigger || typeof trigger === 'number') {
465
606
  throw new Error(
466
- '`attachment` needs to be a valid formed string or an object. See https://sebbo2002.github.io/' +
467
- 'ical-generator/develop/reference/classes/ICalAlarm.html#attach'
607
+ '`trigger` is not correct, must be a finite number or a supported date!',
468
608
  );
609
+ } else {
610
+ this.data.trigger = checkDate(trigger, 'trigger');
469
611
  }
470
612
 
471
- if (!_attach.uri) {
472
- throw new Error('`attach.uri` is empty!');
473
- }
474
-
475
- this.data.attach = {
476
- uri: _attach.uri,
477
- mime: _attach.mime
478
- };
479
613
  return this;
480
614
  }
481
615
 
482
-
483
616
  /**
484
- * Get the alarm description. Used to set the alarm message
485
- * if alarm type is `display`. If the alarm type is `email`, it's
486
- * used to set the email body. Defaults to the event's summary.
617
+ * Get the trigger time for the alarm. Can either
618
+ * be a date and time value ({@link ICalDateTimeValue}) or
619
+ * a number, which will represent the seconds between
620
+ * alarm and event start. The number is negative, if the
621
+ * alarm is triggered before the event started.
487
622
  *
488
623
  * @since 0.2.1
489
624
  */
490
- description (): string | null;
491
-
625
+ triggerAfter(): ICalDateTimeValue | number;
492
626
  /**
493
- * Set the alarm description. Used to set the alarm message
494
- * if alarm type is `display`. If the alarm type is `email`, it's
495
- * used to set the email body. Defaults to the event's summary.
627
+ * Use this method to set the alarm time. Unlike `trigger`, this time
628
+ * the alarm takes place after the event has started.
629
+ *
630
+ * ```javascript
631
+ * const cal = ical();
632
+ * const event = cal.createEvent();
633
+ * const alarm = cal.createAlarm();
634
+ *
635
+ * alarm.trigger(600); // -> 10 minutes after event starts
636
+ * ```
637
+ *
638
+ * You can use any supported date object, see
639
+ * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
640
+ * for details about supported values and timezone handling.
496
641
  *
497
642
  * @since 0.2.1
498
643
  */
499
- description (description: string | null): this;
500
- description (description?: string | null): this | string | null {
501
- if (description === undefined) {
502
- return this.data.description;
503
- }
504
- if (!description) {
505
- this.data.description = null;
506
- return this;
644
+ triggerAfter(trigger: ICalDateTimeValue | number): this;
645
+ triggerAfter(
646
+ trigger?: ICalDateTimeValue | number,
647
+ ): ICalDateTimeValue | number | this {
648
+ if (trigger === undefined) {
649
+ return this.data.trigger;
507
650
  }
508
651
 
509
- this.data.description = description;
510
- return this;
652
+ return this.trigger(
653
+ typeof trigger === 'number' ? -1 * trigger : trigger,
654
+ );
511
655
  }
512
656
 
513
-
514
657
  /**
515
- * Get the alarm summary. Used to set the email subject
516
- * if alarm type is `email`. Defaults to the event's summary.
517
- *
518
- * @since 7.0.0
519
- */
520
- summary (): string | null;
521
-
522
- /**
523
- * Set the alarm summary. Used to set the email subject
524
- * if alarm type is display. Defaults to the event's summary.
658
+ * Get the trigger time for the alarm. Can either
659
+ * be a date and time value ({@link ICalDateTimeValue}) or
660
+ * a number, which will represent the seconds between
661
+ * alarm and event start. The number is negative, if the
662
+ * alarm is triggered after the event started.
525
663
  *
526
664
  * @since 0.2.1
665
+ * @see {@link trigger}
666
+ * @see {@link triggerAfter}
527
667
  */
528
- summary (summary: string | null): this;
529
- summary (summary?: string | null): this | string | null {
530
- if (summary === undefined) {
531
- return this.data.summary;
532
- }
533
- if (!summary) {
534
- this.data.summary = null;
535
- return this;
536
- }
537
-
538
- this.data.summary = summary;
539
- return this;
540
- }
541
-
542
-
668
+ triggerBefore(trigger: ICalDateTimeValue | number): this;
543
669
  /**
544
- * Creates a new {@link ICalAttendee} and returns it. Use options to prefill
545
- * the attendee's attributes. Calling this method without options will create
546
- * an empty attendee.
670
+ * Use this method to set the alarm time.
547
671
  *
548
- * @since 7.0.0
672
+ * ```javascript
673
+ * const cal = ical();
674
+ * const event = cal.createEvent();
675
+ * const alarm = cal.createAlarm();
676
+ *
677
+ * alarm.trigger(600); // -> 10 minutes before event starts
678
+ * alarm.trigger(new Date()); // -> now
679
+ * ```
680
+ *
681
+ * You can use any supported date object, see
682
+ * [readme](https://github.com/sebbo2002/ical-generator#-date-time--timezones)
683
+ * for details about supported values and timezone handling.
684
+ *
685
+ * @since 0.2.1
686
+ * @see {@link trigger}
687
+ * @see {@link triggerAfter}
549
688
  */
550
- createAttendee(data: ICalAttendee | ICalAttendeeData | string): ICalAttendee {
551
- if (data instanceof ICalAttendee) {
552
- this.data.attendees.push(data);
553
- return data;
554
- }
555
- if (typeof data === 'string') {
556
- data = { email: data, ...checkNameAndMail('data', data) };
689
+ triggerBefore(): ICalDateTimeValue | number;
690
+ triggerBefore(
691
+ trigger?: ICalDateTimeValue | number,
692
+ ): ICalDateTimeValue | number | this {
693
+ if (trigger === undefined) {
694
+ return this.trigger();
557
695
  }
558
696
 
559
- const attendee = new ICalAttendee(data, this);
560
- this.data.attendees.push(attendee);
561
- return attendee;
697
+ return this.trigger(trigger);
562
698
  }
563
-
564
-
565
699
  /**
566
- * Get all attendees
567
- * @since 7.0.0
700
+ * Get the alarm type
701
+ * @since 0.2.1
568
702
  */
569
- attendees(): ICalAttendee[];
570
-
703
+ type(type: ICalAlarmType): this;
571
704
  /**
572
- * Add multiple attendees to your event
573
- *
574
- * @since 7.0.0
705
+ * Set the alarm type. See {@link ICalAlarmType}
706
+ * for available status options.
707
+ * @since 0.2.1
575
708
  */
576
- attendees(attendees: (ICalAttendee | ICalAttendeeData | string)[]): this;
577
- attendees(attendees?: (ICalAttendee | ICalAttendeeData | string)[]): this | ICalAttendee[] {
578
- if (!attendees) {
579
- return this.data.attendees;
709
+ type(): ICalAlarmType;
710
+ type(type?: ICalAlarmType): ICalAlarmType | this {
711
+ if (type === undefined) {
712
+ return this.data.type;
713
+ }
714
+ if (!type || !Object.keys(ICalAlarmType).includes(type)) {
715
+ throw new Error(
716
+ '`type` is not correct, must be either `display` or `audio`!',
717
+ );
580
718
  }
581
719
 
582
- attendees.forEach(attendee => this.createAttendee(attendee));
720
+ this.data.type = type;
583
721
  return this;
584
722
  }
585
723
 
586
-
587
724
  /**
588
725
  * Set X-* attributes. Woun't filter double attributes,
589
726
  * which are also added by another method (e.g. type),
@@ -608,8 +745,12 @@ export default class ICalAlarm {
608
745
  *
609
746
  * @since 1.9.0
610
747
  */
611
- x (keyOrArray: {key: string, value: string}[] | [string, string][] | Record<string, string>): this;
612
-
748
+ x(
749
+ keyOrArray:
750
+ | [string, string][]
751
+ | Record<string, string>
752
+ | { key: string; value: string }[],
753
+ ): this;
613
754
  /**
614
755
  * Set a X-* attribute. Woun't filter double attributes,
615
756
  * which are also added by another method (e.g. type),
@@ -621,128 +762,32 @@ export default class ICalAlarm {
621
762
  *
622
763
  * @since 1.9.0
623
764
  */
624
- x (keyOrArray: string, value: string): this;
625
-
765
+ x(keyOrArray: string, value: string): this;
626
766
  /**
627
767
  * Get all custom X-* attributes.
628
768
  * @since 1.9.0
629
769
  */
630
- x (): {key: string, value: string}[];
631
- x (keyOrArray?: ({key: string, value: string})[] | [string, string][] | Record<string, string> | string, value?: string): this | void | ({key: string, value: string})[] {
632
- if(keyOrArray === undefined) {
633
- return addOrGetCustomAttributes (this.data);
634
- }
635
-
636
- if(typeof keyOrArray === 'string' && typeof value === 'string') {
637
- addOrGetCustomAttributes (this.data, keyOrArray, value);
638
- }
639
- else if(typeof keyOrArray === 'object') {
640
- addOrGetCustomAttributes (this.data, keyOrArray);
641
- }
642
- else {
770
+ x(): { key: string; value: string }[];
771
+ x(
772
+ keyOrArray?:
773
+ | [string, string][]
774
+ | Record<string, string>
775
+ | string
776
+ | { key: string; value: string }[],
777
+ value?: string,
778
+ ): this | void | { key: string; value: string }[] {
779
+ if (keyOrArray === undefined) {
780
+ return addOrGetCustomAttributes(this.data);
781
+ }
782
+
783
+ if (typeof keyOrArray === 'string' && typeof value === 'string') {
784
+ addOrGetCustomAttributes(this.data, keyOrArray, value);
785
+ } else if (typeof keyOrArray === 'object') {
786
+ addOrGetCustomAttributes(this.data, keyOrArray);
787
+ } else {
643
788
  throw new Error('Either key or value is not a string!');
644
789
  }
645
790
 
646
791
  return this;
647
792
  }
648
-
649
-
650
- /**
651
- * Return a shallow copy of the alarm's options for JSON stringification.
652
- * Third party objects like moment.js values are stringified as well. Can
653
- * be used for persistence.
654
- *
655
- * @since 0.2.4
656
- */
657
- toJSON (): ICalAlarmJSONData {
658
- const trigger = this.trigger();
659
- return Object.assign({}, this.data, {
660
- trigger: typeof trigger === 'number' ? trigger : toJSON(trigger),
661
- x: this.x()
662
- });
663
- }
664
-
665
-
666
- /**
667
- * Return generated event as a string.
668
- *
669
- * ```javascript
670
- * const alarm = event.createAlarm();
671
- * console.log(alarm.toString()); // → BEGIN:VALARM…
672
- * ```
673
- */
674
- toString (): string {
675
- let g = 'BEGIN:VALARM\r\n';
676
-
677
- // ACTION
678
- g += 'ACTION:' + this.data.type.toUpperCase() + '\r\n';
679
-
680
- if (typeof this.data.trigger === 'number' && this.data.relatesTo === null) {
681
- if (this.data.trigger > 0) {
682
- g += 'TRIGGER;RELATED=END:' + toDurationString(this.data.trigger) + '\r\n';
683
- }
684
- else {
685
- g += 'TRIGGER:' + toDurationString(this.data.trigger) + '\r\n';
686
- }
687
- }
688
- else if (typeof this.data.trigger === 'number') {
689
- g += 'TRIGGER;RELATED=' + this.data.relatesTo?.toUpperCase() + ':' + toDurationString(this.data.trigger) + '\r\n';
690
- }
691
- else {
692
- g += 'TRIGGER;VALUE=DATE-TIME:' + formatDate(this.event.timezone(), this.data.trigger) + '\r\n';
693
- }
694
-
695
- // REPEAT
696
- if (this.data.repeat) {
697
- if (!this.data.repeat.times) {
698
- throw new Error('No value for `repeat.times` in ICalAlarm given, but required for `interval`!');
699
- }
700
- if (!this.data.repeat.interval) {
701
- throw new Error('No value for `repeat.interval` in ICalAlarm given, but required for `repeat`!');
702
- }
703
-
704
- g += 'REPEAT:' + this.data.repeat.times + '\r\n';
705
- g += 'DURATION:' + toDurationString(this.data.repeat.interval) + '\r\n';
706
- }
707
-
708
- // ATTACH
709
- if (this.data.type === 'audio' && this.data.attach && this.data.attach.mime) {
710
- g += 'ATTACH;FMTTYPE=' + escape(this.data.attach.mime, false) + ':' + escape(this.data.attach.uri, false) + '\r\n';
711
- }
712
- else if (this.data.type === 'audio' && this.data.attach) {
713
- g += 'ATTACH;VALUE=URI:' + escape(this.data.attach.uri, false) + '\r\n';
714
- }
715
- else if (this.data.type === 'audio') {
716
- g += 'ATTACH;VALUE=URI:Basso\r\n';
717
- }
718
-
719
- // DESCRIPTION
720
- if (this.data.type !== 'audio' && this.data.description) {
721
- g += 'DESCRIPTION:' + escape(this.data.description, false) + '\r\n';
722
- }
723
- else if (this.data.type !== 'audio') {
724
- g += 'DESCRIPTION:' + escape(this.event.summary(), false) + '\r\n';
725
- }
726
-
727
- // SUMMARY
728
- if (this.data.type === 'email' && this.data.summary) {
729
- g += 'SUMMARY:' + escape(this.data.summary, false) + '\r\n';
730
- }
731
- else if (this.data.type === 'email') {
732
- g += 'SUMMARY:' + escape(this.event.summary(), false) + '\r\n';
733
- }
734
-
735
- // ATTENDEES
736
- if (this.data.type === 'email') {
737
- this.data.attendees.forEach(attendee => {
738
- g += attendee.toString();
739
- });
740
- }
741
-
742
- // CUSTOM X ATTRIBUTES
743
- g += generateCustomAttributes(this.data);
744
-
745
- g += 'END:VALARM\r\n';
746
- return g;
747
- }
748
793
  }