@hebcal/icalendar 5.1.1 → 6.0.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/README.md +11 -54
- package/dist/icalendar.d.ts +1 -24
- package/dist/index.mjs +53 -54
- package/dist/pkgVersion.d.ts +1 -1
- package/package.json +24 -21
- package/dist/index.cjs +0 -506
package/README.md
CHANGED
|
@@ -10,68 +10,25 @@ $ npm install @hebcal/icalendar
|
|
|
10
10
|
```javascript
|
|
11
11
|
import {HebrewCalendar, Location} from '@hebcal/core';
|
|
12
12
|
import {eventsToIcalendar} from '@hebcal/icalendar';
|
|
13
|
+
import fs from 'fs';
|
|
13
14
|
|
|
14
15
|
const options = {
|
|
15
16
|
year: 2020,
|
|
16
17
|
month: 2,
|
|
17
18
|
sedrot: true,
|
|
18
19
|
candlelighting: true,
|
|
19
|
-
location: Location.lookup('
|
|
20
|
+
location: Location.lookup('Tel Aviv'),
|
|
20
21
|
};
|
|
21
22
|
const events = HebrewCalendar.calendar(options);
|
|
22
|
-
console.log(await eventsToIcalendar(ev, options));
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Functions
|
|
26
|
-
|
|
27
|
-
<dl>
|
|
28
|
-
<dt><a href="#eventToIcal">eventToIcal(e, options)</a> ⇒ <code>string</code></dt>
|
|
29
|
-
<dd><p>Transforms a single Event into a VEVENT string</p>
|
|
30
|
-
</dd>
|
|
31
|
-
<dt><a href="#eventsToIcalendarStream">eventsToIcalendarStream(readable, events, options)</a> ⇒ <code>stream.Readable</code></dt>
|
|
32
|
-
<dd><p>Generates an RFC 2445 iCalendar stream from an array of events</p>
|
|
33
|
-
</dd>
|
|
34
|
-
<dt><a href="#eventsToIcalendar">eventsToIcalendar(events, options)</a> ⇒ <code>string</code></dt>
|
|
35
|
-
<dd><p>Renders an array of events as a full RFC 2445 iCalendar string</p>
|
|
36
|
-
</dd>
|
|
37
|
-
</dl>
|
|
38
|
-
|
|
39
|
-
<a name="eventToIcal"></a>
|
|
40
|
-
|
|
41
|
-
## eventToIcal(e, options) ⇒ <code>string</code>
|
|
42
|
-
Transforms a single Event into a VEVENT string
|
|
43
|
-
|
|
44
|
-
**Kind**: global function
|
|
45
|
-
**Returns**: <code>string</code> - multi-line result, delimited by \r\n
|
|
46
|
-
|
|
47
|
-
| Param | Type |
|
|
48
|
-
| --- | --- |
|
|
49
|
-
| e | <code>Event</code> |
|
|
50
|
-
| options | <code>HebcalOptions</code> |
|
|
51
23
|
|
|
52
|
-
|
|
24
|
+
const str = await eventsToIcalendar(events, {
|
|
25
|
+
locale: 'he',
|
|
26
|
+
...options,
|
|
27
|
+
})
|
|
53
28
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
| Param | Type |
|
|
60
|
-
| --- | --- |
|
|
61
|
-
| readable | <code>stream.Readable</code> |
|
|
62
|
-
| events | <code>Array.<Event></code> |
|
|
63
|
-
| options | <code>HebcalOptions</code> |
|
|
64
|
-
|
|
65
|
-
<a name="eventsToIcalendar"></a>
|
|
66
|
-
|
|
67
|
-
## eventsToIcalendar(events, options) ⇒ <code>string</code>
|
|
68
|
-
Renders an array of events as a full RFC 2445 iCalendar string
|
|
69
|
-
|
|
70
|
-
**Kind**: global function
|
|
71
|
-
**Returns**: <code>string</code> - multi-line result, delimited by \r\n
|
|
72
|
-
|
|
73
|
-
| Param | Type |
|
|
74
|
-
| --- | --- |
|
|
75
|
-
| events | <code>Array.<Event></code> |
|
|
76
|
-
| options | <code>HebcalOptions</code> |
|
|
29
|
+
const icalStream = fs.createWriteStream('feed.ics');
|
|
30
|
+
icalStream.write(str);
|
|
31
|
+
icalStream.close();
|
|
32
|
+
```
|
|
77
33
|
|
|
34
|
+
## [API Documentation](https://hebcal.github.io/api/icalendar/index.html)
|
package/dist/icalendar.d.ts
CHANGED
|
@@ -42,51 +42,28 @@ export declare class IcalEvent {
|
|
|
42
42
|
*/
|
|
43
43
|
constructor(ev: Event, options?: ICalOptions);
|
|
44
44
|
getAlarm(): string | null;
|
|
45
|
-
/**
|
|
46
|
-
* @return {string}
|
|
47
|
-
*/
|
|
48
45
|
getUid(): string;
|
|
49
|
-
/**
|
|
50
|
-
* @return {string[]}
|
|
51
|
-
*/
|
|
52
46
|
getLongLines(): string[];
|
|
53
|
-
/**
|
|
54
|
-
* @return {string}
|
|
55
|
-
*/
|
|
56
47
|
toString(): string;
|
|
57
48
|
/**
|
|
58
49
|
* fold lines to 75 characters
|
|
59
|
-
* @return {string[]}
|
|
60
50
|
*/
|
|
61
51
|
getLines(): string[];
|
|
62
52
|
/**
|
|
63
53
|
* fold line to 75 characters
|
|
64
|
-
* @param {string} line
|
|
65
|
-
* @return {string}
|
|
66
54
|
*/
|
|
67
55
|
static fold(line: string): string;
|
|
68
|
-
/**
|
|
69
|
-
* @param {string} str
|
|
70
|
-
* @return {string}
|
|
71
|
-
*/
|
|
72
56
|
static escape(str: string): string;
|
|
73
|
-
/**
|
|
74
|
-
* @param {Date} dt
|
|
75
|
-
* @return {string}
|
|
76
|
-
*/
|
|
77
57
|
static formatYYYYMMDD(dt: Date): string;
|
|
78
58
|
/**
|
|
79
59
|
* Returns UTC string for iCalendar
|
|
80
|
-
* @param {Date} dt
|
|
81
|
-
* @return {string}
|
|
82
60
|
*/
|
|
83
61
|
static makeDtstamp(dt: Date): string;
|
|
84
|
-
/** @return {string} */
|
|
85
62
|
static version(): string;
|
|
86
63
|
}
|
|
87
64
|
/**
|
|
88
65
|
* Transforms a single Event into a VEVENT string
|
|
89
|
-
* @
|
|
66
|
+
* @returns multi-line result, delimited by \r\n
|
|
90
67
|
*/
|
|
91
68
|
export declare function eventToIcal(ev: Event, options: ICalOptions): string;
|
|
92
69
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
/*! @hebcal/icalendar
|
|
2
|
-
import {
|
|
1
|
+
/*! @hebcal/icalendar v6.0.1 */
|
|
2
|
+
import { Locale, pad2, greg, pad4 } from '@hebcal/hdate';
|
|
3
|
+
import { flags } from '@hebcal/core';
|
|
3
4
|
import { murmur32HexSync } from 'murmurhash3';
|
|
4
|
-
import { shouldRenderBrief,
|
|
5
|
+
import { shouldRenderBrief, getEventCategories, makeAnchor, getHolidayDescription, getCalendarTitle, appendIsraelAndTracking, makeTorahMemoText } from '@hebcal/rest-api';
|
|
5
6
|
import { promises } from 'fs';
|
|
6
7
|
|
|
7
8
|
// DO NOT EDIT THIS AUTO-GENERATED FILE!
|
|
8
|
-
const version = '
|
|
9
|
+
const version = '6.0.1';
|
|
9
10
|
|
|
10
11
|
const vtimezoneCache = new Map();
|
|
11
12
|
const CATEGORY = {
|
|
@@ -48,8 +49,11 @@ function appendTrackingToUrl(url, options) {
|
|
|
48
49
|
}
|
|
49
50
|
const encoder = new TextEncoder();
|
|
50
51
|
const char74re = /(.{1,74})/g;
|
|
51
|
-
const DAILY_LEARNING = flags.DAILY_LEARNING |
|
|
52
|
-
flags.
|
|
52
|
+
const DAILY_LEARNING = flags.DAILY_LEARNING |
|
|
53
|
+
flags.DAF_YOMI |
|
|
54
|
+
flags.MISHNA_YOMI |
|
|
55
|
+
flags.YERUSHALMI_YOMI |
|
|
56
|
+
flags.NACH_YOMI;
|
|
53
57
|
/**
|
|
54
58
|
* Represents an RFC 2445 iCalendar VEVENT
|
|
55
59
|
*/
|
|
@@ -69,10 +73,12 @@ class IcalEvent {
|
|
|
69
73
|
else if (typeof opts.sequence === 'number') {
|
|
70
74
|
this.sequence = opts.sequence;
|
|
71
75
|
}
|
|
72
|
-
const timed = this.timed = Boolean(ev.eventTime);
|
|
76
|
+
const timed = (this.timed = Boolean(ev.eventTime));
|
|
73
77
|
const locale = opts.locale;
|
|
74
78
|
const location = opts.location;
|
|
75
|
-
let subj = shouldRenderBrief(ev)
|
|
79
|
+
let subj = shouldRenderBrief(ev)
|
|
80
|
+
? ev.renderBrief(locale)
|
|
81
|
+
: ev.render(locale);
|
|
76
82
|
const mask = ev.getFlags();
|
|
77
83
|
if (ev.locationName) {
|
|
78
84
|
this.locationName = ev.locationName;
|
|
@@ -80,7 +86,7 @@ class IcalEvent {
|
|
|
80
86
|
else if (timed && location) {
|
|
81
87
|
this.locationName = location.getShortName();
|
|
82
88
|
}
|
|
83
|
-
else if (
|
|
89
|
+
else if (mask & DAILY_LEARNING && ev.category) {
|
|
84
90
|
this.locationName = Locale.gettext(ev.category, locale);
|
|
85
91
|
}
|
|
86
92
|
const date = IcalEvent.formatYYYYMMDD(ev.getDate().greg());
|
|
@@ -129,7 +135,8 @@ class IcalEvent {
|
|
|
129
135
|
}
|
|
130
136
|
}
|
|
131
137
|
this.subj = subj;
|
|
132
|
-
this.category =
|
|
138
|
+
this.category =
|
|
139
|
+
ev.category || CATEGORY[(_a = getEventCategories(ev)) === null || _a === void 0 ? void 0 : _a[0]];
|
|
133
140
|
}
|
|
134
141
|
getAlarm() {
|
|
135
142
|
const ev = this.ev;
|
|
@@ -157,9 +164,6 @@ class IcalEvent {
|
|
|
157
164
|
}
|
|
158
165
|
return null;
|
|
159
166
|
}
|
|
160
|
-
/**
|
|
161
|
-
* @return {string}
|
|
162
|
-
*/
|
|
163
167
|
getUid() {
|
|
164
168
|
if (this.ev.uid) {
|
|
165
169
|
return this.ev.uid;
|
|
@@ -178,9 +182,6 @@ class IcalEvent {
|
|
|
178
182
|
}
|
|
179
183
|
return uid;
|
|
180
184
|
}
|
|
181
|
-
/**
|
|
182
|
-
* @return {string[]}
|
|
183
|
-
*/
|
|
184
185
|
getLongLines() {
|
|
185
186
|
if (this.lines)
|
|
186
187
|
return this.lines;
|
|
@@ -189,17 +190,16 @@ class IcalEvent {
|
|
|
189
190
|
if (this.sequence) {
|
|
190
191
|
categoryLine.unshift(`SEQUENCE:${this.sequence}`);
|
|
191
192
|
}
|
|
192
|
-
const arr = this.lines = [
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
].concat(categoryLine).concat([
|
|
193
|
+
const arr = (this.lines = ['BEGIN:VEVENT', `DTSTAMP:${this.dtstamp}`]
|
|
194
|
+
.concat(categoryLine)
|
|
195
|
+
.concat([
|
|
196
196
|
`SUMMARY:${this.subj}`,
|
|
197
197
|
`DTSTART${this.dtargs}:${this.startDate}`,
|
|
198
198
|
`DTEND${this.dtargs}:${this.endDate}`,
|
|
199
199
|
`UID:${uid}`,
|
|
200
200
|
`TRANSP:${this.transp}`,
|
|
201
201
|
`X-MICROSOFT-CDO-BUSYSTATUS:${this.busyStatus}`,
|
|
202
|
-
]);
|
|
202
|
+
]));
|
|
203
203
|
if (!this.timed) {
|
|
204
204
|
arr.push('X-MICROSOFT-CDO-ALLDAYEVENT:TRUE');
|
|
205
205
|
}
|
|
@@ -233,23 +233,17 @@ class IcalEvent {
|
|
|
233
233
|
arr.push('END:VEVENT');
|
|
234
234
|
return arr;
|
|
235
235
|
}
|
|
236
|
-
/**
|
|
237
|
-
* @return {string}
|
|
238
|
-
*/
|
|
239
236
|
toString() {
|
|
240
237
|
return this.getLines().join('\r\n');
|
|
241
238
|
}
|
|
242
239
|
/**
|
|
243
240
|
* fold lines to 75 characters
|
|
244
|
-
* @return {string[]}
|
|
245
241
|
*/
|
|
246
242
|
getLines() {
|
|
247
243
|
return this.getLongLines().map(IcalEvent.fold);
|
|
248
244
|
}
|
|
249
245
|
/**
|
|
250
246
|
* fold line to 75 characters
|
|
251
|
-
* @param {string} line
|
|
252
|
-
* @return {string}
|
|
253
247
|
*/
|
|
254
248
|
static fold(line) {
|
|
255
249
|
let isASCII = true;
|
|
@@ -292,10 +286,6 @@ class IcalEvent {
|
|
|
292
286
|
}
|
|
293
287
|
return result + current;
|
|
294
288
|
}
|
|
295
|
-
/**
|
|
296
|
-
* @param {string} str
|
|
297
|
-
* @return {string}
|
|
298
|
-
*/
|
|
299
289
|
static escape(str) {
|
|
300
290
|
if (str.indexOf(',') !== -1) {
|
|
301
291
|
str = str.replace(/,/g, '\\,');
|
|
@@ -305,46 +295,45 @@ class IcalEvent {
|
|
|
305
295
|
}
|
|
306
296
|
return str;
|
|
307
297
|
}
|
|
308
|
-
/**
|
|
309
|
-
* @param {Date} dt
|
|
310
|
-
* @return {string}
|
|
311
|
-
*/
|
|
312
298
|
static formatYYYYMMDD(dt) {
|
|
313
|
-
return pad4(dt.getFullYear()) +
|
|
314
|
-
pad2(dt.getMonth() + 1) + pad2(dt.getDate());
|
|
299
|
+
return (pad4(dt.getFullYear()) + pad2(dt.getMonth() + 1) + pad2(dt.getDate()));
|
|
315
300
|
}
|
|
316
301
|
/**
|
|
317
302
|
* Returns UTC string for iCalendar
|
|
318
|
-
* @param {Date} dt
|
|
319
|
-
* @return {string}
|
|
320
303
|
*/
|
|
321
304
|
static makeDtstamp(dt) {
|
|
322
305
|
const s = dt.toISOString();
|
|
323
|
-
return s.slice(0, 4) +
|
|
324
|
-
s.slice(
|
|
306
|
+
return (s.slice(0, 4) +
|
|
307
|
+
s.slice(5, 7) +
|
|
308
|
+
s.slice(8, 13) +
|
|
309
|
+
s.slice(14, 16) +
|
|
310
|
+
s.slice(17, 19) +
|
|
311
|
+
'Z');
|
|
325
312
|
}
|
|
326
|
-
/** @return {string} */
|
|
327
313
|
static version() {
|
|
328
314
|
return version;
|
|
329
315
|
}
|
|
330
316
|
}
|
|
331
317
|
/**
|
|
332
318
|
* Transforms a single Event into a VEVENT string
|
|
333
|
-
* @
|
|
319
|
+
* @returns multi-line result, delimited by \r\n
|
|
334
320
|
*/
|
|
335
321
|
function eventToIcal(ev, options) {
|
|
336
322
|
const ical = new IcalEvent(ev, options);
|
|
337
323
|
return ical.toString();
|
|
338
324
|
}
|
|
339
325
|
const torahMemoCache = new Map();
|
|
340
|
-
const HOLIDAY_IGNORE_MASK = DAILY_LEARNING |
|
|
341
|
-
flags.
|
|
326
|
+
const HOLIDAY_IGNORE_MASK = DAILY_LEARNING |
|
|
327
|
+
flags.OMER_COUNT |
|
|
328
|
+
flags.SHABBAT_MEVARCHIM |
|
|
329
|
+
flags.MOLAD |
|
|
330
|
+
flags.USER_EVENT |
|
|
342
331
|
flags.HEBREW_DATE;
|
|
343
332
|
/**
|
|
344
333
|
* @private
|
|
345
334
|
*/
|
|
346
335
|
function makeTorahMemo(ev, il) {
|
|
347
|
-
if (
|
|
336
|
+
if (ev.getFlags() & HOLIDAY_IGNORE_MASK || ev.eventTime) {
|
|
348
337
|
return '';
|
|
349
338
|
}
|
|
350
339
|
const hd = ev.getDate();
|
|
@@ -375,8 +364,16 @@ function createMemo(ev, options) {
|
|
|
375
364
|
const mask = ev.getFlags();
|
|
376
365
|
if (mask & flags.OMER_COUNT) {
|
|
377
366
|
const omerEv = ev;
|
|
378
|
-
const sefira = [
|
|
379
|
-
|
|
367
|
+
const sefira = [
|
|
368
|
+
omerEv.sefira('en'),
|
|
369
|
+
omerEv.sefira('he'),
|
|
370
|
+
omerEv.sefira('translit'),
|
|
371
|
+
].join('\\n');
|
|
372
|
+
return (omerEv.getTodayIs('en') +
|
|
373
|
+
'\\n\\n' +
|
|
374
|
+
omerEv.getTodayIs('he') +
|
|
375
|
+
'\\n\\n' +
|
|
376
|
+
sefira);
|
|
380
377
|
}
|
|
381
378
|
const url = appendTrackingToUrl(ev.url(), options);
|
|
382
379
|
const torahMemo = makeTorahMemo(ev, options.il);
|
|
@@ -415,7 +412,7 @@ async function eventsToIcalendar(events, options) {
|
|
|
415
412
|
if (!opts.title) {
|
|
416
413
|
opts.title = getCalendarTitle(events, opts);
|
|
417
414
|
}
|
|
418
|
-
const icals = events.map(
|
|
415
|
+
const icals = events.map(ev => new IcalEvent(ev, opts));
|
|
419
416
|
return icalEventsToString(icals, opts);
|
|
420
417
|
}
|
|
421
418
|
/**
|
|
@@ -432,11 +429,13 @@ async function icalEventsToString(icals, options) {
|
|
|
432
429
|
const opts = Object.assign({}, options);
|
|
433
430
|
opts.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
434
431
|
const title = opts.title ? IcalEvent.escape(opts.title) : 'Untitled';
|
|
435
|
-
const caldesc = opts.caldesc
|
|
436
|
-
opts.
|
|
437
|
-
|
|
438
|
-
'
|
|
439
|
-
|
|
432
|
+
const caldesc = opts.caldesc
|
|
433
|
+
? IcalEvent.escape(opts.caldesc)
|
|
434
|
+
: opts.yahrzeit
|
|
435
|
+
? 'Yahrzeits + Anniversaries from www.hebcal.com'
|
|
436
|
+
: 'Jewish Holidays from www.hebcal.com';
|
|
437
|
+
const prodid = opts.prodid ||
|
|
438
|
+
`-//hebcal.com/NONSGML Hebcal Calendar v1${version}//${uclang}`;
|
|
440
439
|
const preamble = [
|
|
441
440
|
'BEGIN:VCALENDAR',
|
|
442
441
|
'VERSION:2.0',
|
package/dist/pkgVersion.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "
|
|
1
|
+
export declare const version = "6.0.1";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hebcal/icalendar",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"author": "Michael J. Radwin (https://github.com/mjradwin)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ical",
|
|
@@ -9,15 +9,16 @@
|
|
|
9
9
|
"hebcal"
|
|
10
10
|
],
|
|
11
11
|
"description": "Jewish holidays and Hebrew calendar as iCalendar RFC 2445",
|
|
12
|
-
"main": "dist/index.cjs",
|
|
13
12
|
"module": "dist/index.mjs",
|
|
14
13
|
"type": "module",
|
|
15
14
|
"exports": {
|
|
16
15
|
"import": "./dist/index.mjs",
|
|
17
|
-
"require": "./dist/index.cjs",
|
|
18
16
|
"types": "./dist/icalendar.d.ts"
|
|
19
17
|
},
|
|
20
18
|
"typings": "dist/icalendar.d.ts",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">= 18.0.0"
|
|
21
|
+
},
|
|
21
22
|
"files": [
|
|
22
23
|
"dist"
|
|
23
24
|
],
|
|
@@ -29,10 +30,11 @@
|
|
|
29
30
|
"url": "https://github.com/hebcal/hebcal-icalendar/issues"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@hebcal/core": "^5.
|
|
33
|
-
"@hebcal/
|
|
33
|
+
"@hebcal/core": "^5.8.0",
|
|
34
|
+
"@hebcal/hdate": "^0.12.0",
|
|
35
|
+
"@hebcal/rest-api": "^5.2.0",
|
|
34
36
|
"murmurhash3": "^0.5.0",
|
|
35
|
-
"tslib": "^2.
|
|
37
|
+
"tslib": "^2.8.1"
|
|
36
38
|
},
|
|
37
39
|
"scripts": {
|
|
38
40
|
"build:rollup": "rollup -c",
|
|
@@ -40,27 +42,28 @@
|
|
|
40
42
|
"build": "npm run build:version && npm run build:rollup",
|
|
41
43
|
"prepare": "npm run build",
|
|
42
44
|
"pretest": "npm run build",
|
|
43
|
-
"
|
|
45
|
+
"docs": "typedoc",
|
|
44
46
|
"coverage": "jest --coverage",
|
|
45
|
-
"test": "jest"
|
|
47
|
+
"test": "jest",
|
|
48
|
+
"lint": "gts lint",
|
|
49
|
+
"clean": "gts clean",
|
|
50
|
+
"compile": "tsc",
|
|
51
|
+
"fix": "gts fix"
|
|
46
52
|
},
|
|
47
53
|
"license": "BSD-2-Clause",
|
|
48
54
|
"devDependencies": {
|
|
49
|
-
"@babel/preset-env": "^7.
|
|
50
|
-
"@babel/preset-typescript": "^7.
|
|
51
|
-
"@hebcal/learning": "^5.
|
|
52
|
-
"@rollup/plugin-commonjs": "^
|
|
55
|
+
"@babel/preset-env": "^7.26.0",
|
|
56
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
57
|
+
"@hebcal/learning": "^5.1.2",
|
|
58
|
+
"@rollup/plugin-commonjs": "^28.0.1",
|
|
53
59
|
"@rollup/plugin-json": "^6.1.0",
|
|
54
|
-
"@rollup/plugin-typescript": "^
|
|
55
|
-
"@types/jest": "^29.5.
|
|
56
|
-
"
|
|
57
|
-
"eslint-config-google": "^0.14.0",
|
|
60
|
+
"@rollup/plugin-typescript": "^12.1.1",
|
|
61
|
+
"@types/jest": "^29.5.14",
|
|
62
|
+
"@types/node": "22.9.0",
|
|
58
63
|
"gts": "^5.3.1",
|
|
59
64
|
"jest": "^29.7.0",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"ts-jest": "^29.1.5",
|
|
64
|
-
"typescript": "^5.5.3"
|
|
65
|
+
"rollup": "^4.25.0",
|
|
66
|
+
"typedoc": "^0.26.11",
|
|
67
|
+
"typescript": "^5.6.3"
|
|
65
68
|
}
|
|
66
69
|
}
|
package/dist/index.cjs
DELETED
|
@@ -1,506 +0,0 @@
|
|
|
1
|
-
/*! @hebcal/icalendar v5.1.1 */
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
var core = require('@hebcal/core');
|
|
5
|
-
var murmurhash3 = require('murmurhash3');
|
|
6
|
-
var restApi = require('@hebcal/rest-api');
|
|
7
|
-
var fs = require('fs');
|
|
8
|
-
|
|
9
|
-
// DO NOT EDIT THIS AUTO-GENERATED FILE!
|
|
10
|
-
const version = '5.1.1';
|
|
11
|
-
|
|
12
|
-
const vtimezoneCache = new Map();
|
|
13
|
-
const CATEGORY = {
|
|
14
|
-
candles: 'Holiday',
|
|
15
|
-
dafyomi: 'Daf Yomi',
|
|
16
|
-
mishnayomi: 'Mishna Yomi',
|
|
17
|
-
nachyomi: 'Nach Yomi',
|
|
18
|
-
yerushalmi: 'Yerushalmi Yomi',
|
|
19
|
-
havdalah: 'Holiday',
|
|
20
|
-
hebdate: null,
|
|
21
|
-
holiday: 'Holiday',
|
|
22
|
-
mevarchim: null,
|
|
23
|
-
molad: null,
|
|
24
|
-
omer: null,
|
|
25
|
-
parashat: 'Parsha',
|
|
26
|
-
roshchodesh: 'Holiday',
|
|
27
|
-
user: 'Personal',
|
|
28
|
-
zmanim: null,
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* @private
|
|
32
|
-
*/
|
|
33
|
-
function addOptional(arr, key, val) {
|
|
34
|
-
if (val) {
|
|
35
|
-
const str = IcalEvent.escape(val);
|
|
36
|
-
arr.push(key + ':' + str);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* @private
|
|
41
|
-
*/
|
|
42
|
-
function appendTrackingToUrl(url, options) {
|
|
43
|
-
if (!url) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
const utmSource = options.utmSource || 'js';
|
|
47
|
-
const utmMedium = options.utmMedium || 'icalendar';
|
|
48
|
-
const utmCampaign = options.utmCampaign;
|
|
49
|
-
return restApi.appendIsraelAndTracking(url, options.il, utmSource, utmMedium, utmCampaign);
|
|
50
|
-
}
|
|
51
|
-
const encoder = new TextEncoder();
|
|
52
|
-
const char74re = /(.{1,74})/g;
|
|
53
|
-
const DAILY_LEARNING = core.flags.DAILY_LEARNING | core.flags.DAF_YOMI |
|
|
54
|
-
core.flags.MISHNA_YOMI | core.flags.YERUSHALMI_YOMI | core.flags.NACH_YOMI;
|
|
55
|
-
/**
|
|
56
|
-
* Represents an RFC 2445 iCalendar VEVENT
|
|
57
|
-
*/
|
|
58
|
-
class IcalEvent {
|
|
59
|
-
/**
|
|
60
|
-
* Builds an IcalEvent object from a Hebcal Event
|
|
61
|
-
*/
|
|
62
|
-
constructor(ev, options = {}) {
|
|
63
|
-
var _a;
|
|
64
|
-
this.ev = ev;
|
|
65
|
-
const opts = Object.assign({}, options);
|
|
66
|
-
this.options = opts;
|
|
67
|
-
this.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
68
|
-
if (typeof ev.sequence === 'number') {
|
|
69
|
-
this.sequence = ev.sequence;
|
|
70
|
-
}
|
|
71
|
-
else if (typeof opts.sequence === 'number') {
|
|
72
|
-
this.sequence = opts.sequence;
|
|
73
|
-
}
|
|
74
|
-
const timed = this.timed = Boolean(ev.eventTime);
|
|
75
|
-
const locale = opts.locale;
|
|
76
|
-
const location = opts.location;
|
|
77
|
-
let subj = restApi.shouldRenderBrief(ev) ? ev.renderBrief(locale) : ev.render(locale);
|
|
78
|
-
const mask = ev.getFlags();
|
|
79
|
-
if (ev.locationName) {
|
|
80
|
-
this.locationName = ev.locationName;
|
|
81
|
-
}
|
|
82
|
-
else if (timed && location) {
|
|
83
|
-
this.locationName = location.getShortName();
|
|
84
|
-
}
|
|
85
|
-
else if ((mask & DAILY_LEARNING) && ev.category) {
|
|
86
|
-
this.locationName = core.Locale.gettext(ev.category, locale);
|
|
87
|
-
}
|
|
88
|
-
const date = IcalEvent.formatYYYYMMDD(ev.getDate().greg());
|
|
89
|
-
this.startDate = this.isoDateOnly = date;
|
|
90
|
-
this.dtargs = '';
|
|
91
|
-
this.transp = 'TRANSPARENT';
|
|
92
|
-
this.busyStatus = 'FREE';
|
|
93
|
-
if (timed) {
|
|
94
|
-
let [hour, minute] = ev.eventTimeStr.split(':');
|
|
95
|
-
hour = +hour;
|
|
96
|
-
minute = +minute;
|
|
97
|
-
this.startDate += 'T' + restApi.pad2(hour) + restApi.pad2(minute) + '00';
|
|
98
|
-
this.endDate = this.startDate;
|
|
99
|
-
if (location === null || location === void 0 ? void 0 : location.getTzid()) {
|
|
100
|
-
this.dtargs = `;TZID=${location.getTzid()}`;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
this.endDate = IcalEvent.formatYYYYMMDD(ev.getDate().next().greg());
|
|
105
|
-
// for all-day untimed, use DTEND;VALUE=DATE intsead of DURATION:P1D.
|
|
106
|
-
// It's more compatible with everthing except ancient versions of
|
|
107
|
-
// Lotus Notes circa 2004
|
|
108
|
-
this.dtargs = ';VALUE=DATE';
|
|
109
|
-
if (mask & core.flags.CHAG) {
|
|
110
|
-
this.transp = 'OPAQUE';
|
|
111
|
-
this.busyStatus = 'OOF';
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (opts.emoji) {
|
|
115
|
-
const prefix = ev.getEmoji();
|
|
116
|
-
if (prefix) {
|
|
117
|
-
if (mask & core.flags.OMER_COUNT) {
|
|
118
|
-
subj = subj + ' ' + prefix;
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
subj = prefix + ' ' + subj;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// make subject safe for iCalendar
|
|
126
|
-
subj = IcalEvent.escape(subj);
|
|
127
|
-
if (opts.appendHebrewToSubject) {
|
|
128
|
-
const hebrew = ev.renderBrief('he');
|
|
129
|
-
if (hebrew) {
|
|
130
|
-
subj += ` / ${hebrew}`;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
this.subj = subj;
|
|
134
|
-
this.category = ev.category || CATEGORY[(_a = restApi.getEventCategories(ev)) === null || _a === void 0 ? void 0 : _a[0]];
|
|
135
|
-
}
|
|
136
|
-
getAlarm() {
|
|
137
|
-
const ev = this.ev;
|
|
138
|
-
const mask = ev.getFlags();
|
|
139
|
-
const evAlarm = ev.alarm;
|
|
140
|
-
if (typeof evAlarm === 'string') {
|
|
141
|
-
return 'TRIGGER:' + evAlarm;
|
|
142
|
-
}
|
|
143
|
-
else if (typeof evAlarm === 'boolean' && !evAlarm) {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
else if (core.greg.isDate(evAlarm)) {
|
|
147
|
-
const alarmDt = evAlarm;
|
|
148
|
-
alarmDt.setSeconds(0);
|
|
149
|
-
return 'TRIGGER;VALUE=DATE-TIME:' + IcalEvent.makeDtstamp(alarmDt);
|
|
150
|
-
}
|
|
151
|
-
else if (mask & core.flags.OMER_COUNT) {
|
|
152
|
-
return 'TRIGGER:-P0DT3H30M0S'; // 8:30pm Omer alarm evening before
|
|
153
|
-
}
|
|
154
|
-
else if (mask & core.flags.USER_EVENT) {
|
|
155
|
-
return 'TRIGGER:-P0DT12H0M0S'; // noon the day before
|
|
156
|
-
}
|
|
157
|
-
else if (this.timed && ev.getDesc().startsWith('Candle lighting')) {
|
|
158
|
-
return 'TRIGGER:-P0DT0H10M0S';
|
|
159
|
-
}
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* @return {string}
|
|
164
|
-
*/
|
|
165
|
-
getUid() {
|
|
166
|
-
if (this.ev.uid) {
|
|
167
|
-
return this.ev.uid;
|
|
168
|
-
}
|
|
169
|
-
const options = this.options;
|
|
170
|
-
const digest = murmurhash3.murmur32HexSync(this.ev.getDesc());
|
|
171
|
-
let uid = `hebcal-${this.isoDateOnly}-${digest}`;
|
|
172
|
-
const loc = options.location;
|
|
173
|
-
if (this.timed && loc) {
|
|
174
|
-
if (loc.getGeoId()) {
|
|
175
|
-
uid += `-${loc.getGeoId()}`;
|
|
176
|
-
}
|
|
177
|
-
else if (loc.getName()) {
|
|
178
|
-
uid += '-' + restApi.makeAnchor(loc.getName());
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return uid;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* @return {string[]}
|
|
185
|
-
*/
|
|
186
|
-
getLongLines() {
|
|
187
|
-
if (this.lines)
|
|
188
|
-
return this.lines;
|
|
189
|
-
const categoryLine = this.category ? [`CATEGORIES:${this.category}`] : [];
|
|
190
|
-
const uid = this.getUid();
|
|
191
|
-
if (this.sequence) {
|
|
192
|
-
categoryLine.unshift(`SEQUENCE:${this.sequence}`);
|
|
193
|
-
}
|
|
194
|
-
const arr = this.lines = [
|
|
195
|
-
'BEGIN:VEVENT',
|
|
196
|
-
`DTSTAMP:${this.dtstamp}`,
|
|
197
|
-
].concat(categoryLine).concat([
|
|
198
|
-
`SUMMARY:${this.subj}`,
|
|
199
|
-
`DTSTART${this.dtargs}:${this.startDate}`,
|
|
200
|
-
`DTEND${this.dtargs}:${this.endDate}`,
|
|
201
|
-
`UID:${uid}`,
|
|
202
|
-
`TRANSP:${this.transp}`,
|
|
203
|
-
`X-MICROSOFT-CDO-BUSYSTATUS:${this.busyStatus}`,
|
|
204
|
-
]);
|
|
205
|
-
if (!this.timed) {
|
|
206
|
-
arr.push('X-MICROSOFT-CDO-ALLDAYEVENT:TRUE');
|
|
207
|
-
}
|
|
208
|
-
const ev = this.ev;
|
|
209
|
-
const mask = ev.getFlags();
|
|
210
|
-
const isUserEvent = Boolean(mask & core.flags.USER_EVENT);
|
|
211
|
-
if (!isUserEvent) {
|
|
212
|
-
arr.push('CLASS:PUBLIC');
|
|
213
|
-
}
|
|
214
|
-
const options = this.options;
|
|
215
|
-
// create memo (holiday descr, Torah, etc)
|
|
216
|
-
const memo = createMemo(ev, options);
|
|
217
|
-
addOptional(arr, 'DESCRIPTION', memo);
|
|
218
|
-
addOptional(arr, 'LOCATION', this.locationName);
|
|
219
|
-
const loc = options.location;
|
|
220
|
-
if (this.timed && loc) {
|
|
221
|
-
arr.push('GEO:' + loc.getLatitude() + ';' + loc.getLongitude());
|
|
222
|
-
}
|
|
223
|
-
// In addition to the URL being part of the DESCRIPTION field,
|
|
224
|
-
// should we also generate an RFC 5545 URL property?
|
|
225
|
-
if (options.url) {
|
|
226
|
-
const url = ev.url();
|
|
227
|
-
if (url) {
|
|
228
|
-
arr.push('URL:' + appendTrackingToUrl(url, options));
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const trigger = this.getAlarm();
|
|
232
|
-
if (trigger) {
|
|
233
|
-
arr.push('BEGIN:VALARM', 'ACTION:DISPLAY', 'DESCRIPTION:Event reminder', `${trigger}`, 'END:VALARM');
|
|
234
|
-
}
|
|
235
|
-
arr.push('END:VEVENT');
|
|
236
|
-
return arr;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* @return {string}
|
|
240
|
-
*/
|
|
241
|
-
toString() {
|
|
242
|
-
return this.getLines().join('\r\n');
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* fold lines to 75 characters
|
|
246
|
-
* @return {string[]}
|
|
247
|
-
*/
|
|
248
|
-
getLines() {
|
|
249
|
-
return this.getLongLines().map(IcalEvent.fold);
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* fold line to 75 characters
|
|
253
|
-
* @param {string} line
|
|
254
|
-
* @return {string}
|
|
255
|
-
*/
|
|
256
|
-
static fold(line) {
|
|
257
|
-
let isASCII = true;
|
|
258
|
-
for (let i = 0; i < line.length; i++) {
|
|
259
|
-
if (line.charCodeAt(i) > 255) {
|
|
260
|
-
isASCII = false;
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
if (isASCII) {
|
|
265
|
-
if (line.length <= 74) {
|
|
266
|
-
return line;
|
|
267
|
-
}
|
|
268
|
-
const matches = line.match(char74re);
|
|
269
|
-
return matches.join('\r\n ');
|
|
270
|
-
}
|
|
271
|
-
if (encoder.encode(line).length <= 74) {
|
|
272
|
-
return line;
|
|
273
|
-
}
|
|
274
|
-
// iterate unicode character by character, making sure
|
|
275
|
-
// that adding a new character would keep the line <= 75 octets
|
|
276
|
-
let result = '';
|
|
277
|
-
let current = '';
|
|
278
|
-
let len = 0;
|
|
279
|
-
for (let i = 0; i < line.length; i++) {
|
|
280
|
-
const char = line[i];
|
|
281
|
-
const octets = char.charCodeAt(0) < 256 ? 1 : encoder.encode(char).length;
|
|
282
|
-
const newlen = len + octets;
|
|
283
|
-
if (newlen < 75) {
|
|
284
|
-
current += char;
|
|
285
|
-
len = newlen;
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
288
|
-
result += current + '\r\n ';
|
|
289
|
-
line = line.substring(i);
|
|
290
|
-
current = '';
|
|
291
|
-
len = 0;
|
|
292
|
-
i = -1;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return result + current;
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* @param {string} str
|
|
299
|
-
* @return {string}
|
|
300
|
-
*/
|
|
301
|
-
static escape(str) {
|
|
302
|
-
if (str.indexOf(',') !== -1) {
|
|
303
|
-
str = str.replace(/,/g, '\\,');
|
|
304
|
-
}
|
|
305
|
-
if (str.indexOf(';') !== -1) {
|
|
306
|
-
str = str.replace(/;/g, '\\;');
|
|
307
|
-
}
|
|
308
|
-
return str;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* @param {Date} dt
|
|
312
|
-
* @return {string}
|
|
313
|
-
*/
|
|
314
|
-
static formatYYYYMMDD(dt) {
|
|
315
|
-
return restApi.pad4(dt.getFullYear()) +
|
|
316
|
-
restApi.pad2(dt.getMonth() + 1) + restApi.pad2(dt.getDate());
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Returns UTC string for iCalendar
|
|
320
|
-
* @param {Date} dt
|
|
321
|
-
* @return {string}
|
|
322
|
-
*/
|
|
323
|
-
static makeDtstamp(dt) {
|
|
324
|
-
const s = dt.toISOString();
|
|
325
|
-
return s.slice(0, 4) + s.slice(5, 7) + s.slice(8, 13) +
|
|
326
|
-
s.slice(14, 16) + s.slice(17, 19) + 'Z';
|
|
327
|
-
}
|
|
328
|
-
/** @return {string} */
|
|
329
|
-
static version() {
|
|
330
|
-
return version;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
* Transforms a single Event into a VEVENT string
|
|
335
|
-
* @return {string} multi-line result, delimited by \r\n
|
|
336
|
-
*/
|
|
337
|
-
function eventToIcal(ev, options) {
|
|
338
|
-
const ical = new IcalEvent(ev, options);
|
|
339
|
-
return ical.toString();
|
|
340
|
-
}
|
|
341
|
-
const torahMemoCache = new Map();
|
|
342
|
-
const HOLIDAY_IGNORE_MASK = DAILY_LEARNING | core.flags.OMER_COUNT |
|
|
343
|
-
core.flags.SHABBAT_MEVARCHIM | core.flags.MOLAD | core.flags.USER_EVENT |
|
|
344
|
-
core.flags.HEBREW_DATE;
|
|
345
|
-
/**
|
|
346
|
-
* @private
|
|
347
|
-
*/
|
|
348
|
-
function makeTorahMemo(ev, il) {
|
|
349
|
-
if ((ev.getFlags() & HOLIDAY_IGNORE_MASK) || ev.eventTime) {
|
|
350
|
-
return '';
|
|
351
|
-
}
|
|
352
|
-
const hd = ev.getDate();
|
|
353
|
-
const yy = hd.getFullYear();
|
|
354
|
-
const mm = hd.getMonth();
|
|
355
|
-
const dd = hd.getDate();
|
|
356
|
-
const key = [yy, mm, dd, il ? '1' : '0', ev.getDesc()].join('-');
|
|
357
|
-
let memo = torahMemoCache.get(key);
|
|
358
|
-
if (typeof memo === 'string') {
|
|
359
|
-
return memo;
|
|
360
|
-
}
|
|
361
|
-
memo = restApi.makeTorahMemoText(ev, il).replace(/\n/g, '\\n');
|
|
362
|
-
torahMemoCache.set(key, memo);
|
|
363
|
-
return memo;
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* @private
|
|
367
|
-
*/
|
|
368
|
-
function createMemo(ev, options) {
|
|
369
|
-
let memo = ev.memo;
|
|
370
|
-
if (typeof memo === 'string' && memo.length && memo.indexOf('\n') !== -1) {
|
|
371
|
-
memo = memo.replace(/\n/g, '\\n');
|
|
372
|
-
}
|
|
373
|
-
const desc = ev.getDesc();
|
|
374
|
-
if (desc === 'Havdalah' || desc === 'Candle lighting') {
|
|
375
|
-
return memo || '';
|
|
376
|
-
}
|
|
377
|
-
const mask = ev.getFlags();
|
|
378
|
-
if (mask & core.flags.OMER_COUNT) {
|
|
379
|
-
const omerEv = ev;
|
|
380
|
-
const sefira = [omerEv.sefira('en'), omerEv.sefira('he'), omerEv.sefira('translit')].join('\\n');
|
|
381
|
-
return omerEv.getTodayIs('en') + '\\n\\n' + omerEv.getTodayIs('he') + '\\n\\n' + sefira;
|
|
382
|
-
}
|
|
383
|
-
const url = appendTrackingToUrl(ev.url(), options);
|
|
384
|
-
const torahMemo = makeTorahMemo(ev, options.il);
|
|
385
|
-
if (!memo) {
|
|
386
|
-
if (typeof ev.linkedEvent !== 'undefined') {
|
|
387
|
-
memo = ev.linkedEvent.render(options.locale);
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
memo = restApi.getHolidayDescription(ev);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
if (torahMemo) {
|
|
394
|
-
if (memo.length) {
|
|
395
|
-
memo += '\\n\\n';
|
|
396
|
-
}
|
|
397
|
-
memo += torahMemo;
|
|
398
|
-
}
|
|
399
|
-
if (url) {
|
|
400
|
-
if (memo.length) {
|
|
401
|
-
memo += '\\n\\n';
|
|
402
|
-
}
|
|
403
|
-
memo += url;
|
|
404
|
-
}
|
|
405
|
-
return memo;
|
|
406
|
-
}
|
|
407
|
-
/**
|
|
408
|
-
* Generates an RFC 2445 iCalendar string from an array of events
|
|
409
|
-
*/
|
|
410
|
-
async function eventsToIcalendar(events, options) {
|
|
411
|
-
if (!events.length)
|
|
412
|
-
throw new RangeError('Events can not be empty');
|
|
413
|
-
if (!options)
|
|
414
|
-
throw new TypeError('Invalid options object');
|
|
415
|
-
const opts = Object.assign({}, options);
|
|
416
|
-
opts.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
417
|
-
if (!opts.title) {
|
|
418
|
-
opts.title = restApi.getCalendarTitle(events, opts);
|
|
419
|
-
}
|
|
420
|
-
const icals = events.map((ev) => new IcalEvent(ev, opts));
|
|
421
|
-
return icalEventsToString(icals, opts);
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Generates an RFC 2445 iCalendar string from an array of IcalEvents
|
|
425
|
-
*/
|
|
426
|
-
async function icalEventsToString(icals, options) {
|
|
427
|
-
if (!icals.length)
|
|
428
|
-
throw new RangeError('Events can not be empty');
|
|
429
|
-
if (!options)
|
|
430
|
-
throw new TypeError('Invalid options object');
|
|
431
|
-
const stream = [];
|
|
432
|
-
const locale = options.locale || core.Locale.getLocaleName();
|
|
433
|
-
const uclang = locale.toUpperCase();
|
|
434
|
-
const opts = Object.assign({}, options);
|
|
435
|
-
opts.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
436
|
-
const title = opts.title ? IcalEvent.escape(opts.title) : 'Untitled';
|
|
437
|
-
const caldesc = opts.caldesc ? IcalEvent.escape(opts.caldesc) :
|
|
438
|
-
opts.yahrzeit ?
|
|
439
|
-
'Yahrzeits + Anniversaries from www.hebcal.com' :
|
|
440
|
-
'Jewish Holidays from www.hebcal.com';
|
|
441
|
-
const prodid = opts.prodid || `-//hebcal.com/NONSGML Hebcal Calendar v1${version}//${uclang}`;
|
|
442
|
-
const preamble = [
|
|
443
|
-
'BEGIN:VCALENDAR',
|
|
444
|
-
'VERSION:2.0',
|
|
445
|
-
`PRODID:${prodid}`,
|
|
446
|
-
'CALSCALE:GREGORIAN',
|
|
447
|
-
'METHOD:PUBLISH',
|
|
448
|
-
'X-LOTUS-CHARSET:UTF-8',
|
|
449
|
-
];
|
|
450
|
-
if (opts.publishedTTL !== false) {
|
|
451
|
-
const publishedTTL = opts.publishedTTL || 'PT7D';
|
|
452
|
-
preamble.push(`X-PUBLISHED-TTL:${publishedTTL}`);
|
|
453
|
-
}
|
|
454
|
-
preamble.push(`X-WR-CALNAME:${title}`);
|
|
455
|
-
preamble.push(`X-WR-CALDESC:${caldesc}`);
|
|
456
|
-
for (const line of preamble.map(IcalEvent.fold)) {
|
|
457
|
-
stream.push(line);
|
|
458
|
-
stream.push('\r\n');
|
|
459
|
-
}
|
|
460
|
-
if (opts.relcalid) {
|
|
461
|
-
stream.push(IcalEvent.fold(`X-WR-RELCALID:${opts.relcalid}`));
|
|
462
|
-
stream.push('\r\n');
|
|
463
|
-
}
|
|
464
|
-
if (opts.calendarColor) {
|
|
465
|
-
stream.push(`X-APPLE-CALENDAR-COLOR:${opts.calendarColor}\r\n`);
|
|
466
|
-
}
|
|
467
|
-
const location = opts.location;
|
|
468
|
-
const tzid = location === null || location === void 0 ? void 0 : location.getTzid();
|
|
469
|
-
if (tzid) {
|
|
470
|
-
stream.push(`X-WR-TIMEZONE;VALUE=TEXT:${tzid}\r\n`);
|
|
471
|
-
const vtz = vtimezoneCache.get(tzid);
|
|
472
|
-
if (typeof vtz === 'string') {
|
|
473
|
-
stream.push(vtz);
|
|
474
|
-
stream.push('\r\n');
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
477
|
-
const vtimezoneFilename = `./zoneinfo/${tzid}.ics`;
|
|
478
|
-
try {
|
|
479
|
-
const vtimezoneIcs = await fs.promises.readFile(vtimezoneFilename, 'utf-8');
|
|
480
|
-
const lines = vtimezoneIcs.split('\r\n');
|
|
481
|
-
// ignore first 3 and last 1 lines
|
|
482
|
-
const str = lines.slice(3, lines.length - 2).join('\r\n');
|
|
483
|
-
stream.push(str);
|
|
484
|
-
stream.push('\r\n');
|
|
485
|
-
vtimezoneCache.set(tzid, str);
|
|
486
|
-
}
|
|
487
|
-
catch (error) {
|
|
488
|
-
// ignore failure when no timezone definition to read
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
for (const ical of icals) {
|
|
493
|
-
const lines = ical.getLines();
|
|
494
|
-
for (const line of lines) {
|
|
495
|
-
stream.push(line);
|
|
496
|
-
stream.push('\r\n');
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
stream.push('END:VCALENDAR\r\n');
|
|
500
|
-
return stream.join('');
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
exports.IcalEvent = IcalEvent;
|
|
504
|
-
exports.eventToIcal = eventToIcal;
|
|
505
|
-
exports.eventsToIcalendar = eventsToIcalendar;
|
|
506
|
-
exports.icalEventsToString = icalEventsToString;
|