@hebcal/icalendar 6.3.3 → 6.3.5
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/dist/{index.js → icalendar.js} +75 -67
- package/dist/pkgVersion.d.ts +1 -1
- package/dist/pkgVersion.js +5 -0
- package/package.json +11 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/icalendar v6.3.
|
|
1
|
+
/*! @hebcal/icalendar v6.3.5 */
|
|
2
2
|
import { flags } from '@hebcal/core/dist/esm/event';
|
|
3
3
|
import { Locale } from '@hebcal/core/dist/esm/locale';
|
|
4
4
|
import { murmur32HexSync } from 'murmurhash3';
|
|
@@ -8,10 +8,8 @@ import { getHolidayDescription } from '@hebcal/rest-api/dist/esm/holiday';
|
|
|
8
8
|
import { makeTorahMemoText } from '@hebcal/rest-api/dist/esm/memo';
|
|
9
9
|
import { appendIsraelAndTracking } from '@hebcal/rest-api/dist/esm/url';
|
|
10
10
|
import { makeAnchor } from '@hebcal/rest-api/dist/esm/makeAnchor';
|
|
11
|
-
import { promises } from 'fs';
|
|
12
|
-
|
|
13
|
-
// DO NOT EDIT THIS AUTO-GENERATED FILE!
|
|
14
|
-
const version = '6.3.3';
|
|
11
|
+
import { promises } from 'node:fs';
|
|
12
|
+
import { version } from './pkgVersion.js';
|
|
15
13
|
|
|
16
14
|
const vtimezoneCache = new Map();
|
|
17
15
|
const CATEGORY = {
|
|
@@ -78,6 +76,7 @@ class IcalEvent {
|
|
|
78
76
|
const opts = Object.assign({}, options);
|
|
79
77
|
this.options = opts;
|
|
80
78
|
this.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
80
|
const ev0 = ev;
|
|
82
81
|
if (typeof ev0.sequence === 'number') {
|
|
83
82
|
this.sequence = ev0.sequence;
|
|
@@ -261,7 +260,7 @@ class IcalEvent {
|
|
|
261
260
|
static fold(line) {
|
|
262
261
|
let isASCII = true;
|
|
263
262
|
for (let i = 0; i < line.length; i++) {
|
|
264
|
-
if (line.
|
|
263
|
+
if (line.codePointAt(i) > 255) {
|
|
265
264
|
isASCII = false;
|
|
266
265
|
break;
|
|
267
266
|
}
|
|
@@ -278,33 +277,33 @@ class IcalEvent {
|
|
|
278
277
|
}
|
|
279
278
|
// iterate unicode character by character, making sure
|
|
280
279
|
// that adding a new character would keep the line <= 75 octets
|
|
280
|
+
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
|
|
281
|
+
const segments = segmenter.segment(line);
|
|
282
|
+
const chars = Array.from(segments, s => s.segment);
|
|
281
283
|
let result = '';
|
|
282
284
|
let current = '';
|
|
283
285
|
let len = 0;
|
|
284
|
-
for (
|
|
285
|
-
const
|
|
286
|
-
const octets = char.charCodeAt(0) < 256 ? 1 : encoder.encode(char).length;
|
|
286
|
+
for (const ch of chars) {
|
|
287
|
+
const octets = ch.codePointAt(0) < 256 ? 1 : encoder.encode(ch).length;
|
|
287
288
|
const newlen = len + octets;
|
|
288
289
|
if (newlen < 75) {
|
|
289
|
-
current +=
|
|
290
|
+
current += ch;
|
|
290
291
|
len = newlen;
|
|
291
292
|
}
|
|
292
293
|
else {
|
|
293
294
|
result += current + '\r\n ';
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
len = 0;
|
|
297
|
-
i = -1;
|
|
295
|
+
current = ch;
|
|
296
|
+
len = octets;
|
|
298
297
|
}
|
|
299
298
|
}
|
|
300
299
|
return result + current;
|
|
301
300
|
}
|
|
302
301
|
static escape(str) {
|
|
303
|
-
if (str.
|
|
304
|
-
str = str.
|
|
302
|
+
if (str.includes(',')) {
|
|
303
|
+
str = str.replaceAll(',', String.raw `\,`);
|
|
305
304
|
}
|
|
306
|
-
if (str.
|
|
307
|
-
str = str.
|
|
305
|
+
if (str.includes(';')) {
|
|
306
|
+
str = str.replaceAll(';', String.raw `\;`);
|
|
308
307
|
}
|
|
309
308
|
return str;
|
|
310
309
|
}
|
|
@@ -342,10 +341,13 @@ const HOLIDAY_IGNORE_MASK = DAILY_LEARNING |
|
|
|
342
341
|
flags.MOLAD |
|
|
343
342
|
flags.USER_EVENT |
|
|
344
343
|
flags.HEBREW_DATE;
|
|
344
|
+
const ESC_NEWLINE = String.raw `\n`;
|
|
345
|
+
const DBL_NEWLINE = ESC_NEWLINE + ESC_NEWLINE;
|
|
345
346
|
/**
|
|
346
347
|
* @private
|
|
347
348
|
*/
|
|
348
349
|
function makeTorahMemo(ev, il) {
|
|
350
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
349
351
|
if (ev.getFlags() & HOLIDAY_IGNORE_MASK || ev.eventTime) {
|
|
350
352
|
return '';
|
|
351
353
|
}
|
|
@@ -358,7 +360,7 @@ function makeTorahMemo(ev, il) {
|
|
|
358
360
|
if (typeof memo === 'string') {
|
|
359
361
|
return memo;
|
|
360
362
|
}
|
|
361
|
-
memo = makeTorahMemoText(ev, il).
|
|
363
|
+
memo = makeTorahMemoText(ev, il).replaceAll('\n', ESC_NEWLINE);
|
|
362
364
|
torahMemoCache.set(key, memo);
|
|
363
365
|
return memo;
|
|
364
366
|
}
|
|
@@ -367,8 +369,8 @@ function makeTorahMemo(ev, il) {
|
|
|
367
369
|
*/
|
|
368
370
|
function createMemo(ev, options) {
|
|
369
371
|
let memo = ev.memo || '';
|
|
370
|
-
if (memo.length && memo.
|
|
371
|
-
memo = memo.
|
|
372
|
+
if (memo.length && memo.includes('\n')) {
|
|
373
|
+
memo = memo.replaceAll('\n', ESC_NEWLINE);
|
|
372
374
|
}
|
|
373
375
|
const desc = ev.getDesc();
|
|
374
376
|
if (desc === 'Havdalah' || desc === 'Candle lighting') {
|
|
@@ -381,33 +383,34 @@ function createMemo(ev, options) {
|
|
|
381
383
|
omerEv.sefira('en'),
|
|
382
384
|
omerEv.sefira('he'),
|
|
383
385
|
omerEv.sefira('translit'),
|
|
384
|
-
].join(
|
|
386
|
+
].join(ESC_NEWLINE);
|
|
385
387
|
return (omerEv.getTodayIs('en') +
|
|
386
|
-
|
|
388
|
+
DBL_NEWLINE +
|
|
387
389
|
omerEv.getTodayIs('he') +
|
|
388
|
-
|
|
390
|
+
DBL_NEWLINE +
|
|
389
391
|
sefira);
|
|
390
392
|
}
|
|
391
393
|
if (!memo) {
|
|
392
394
|
memo = getHolidayDescription(ev);
|
|
393
395
|
}
|
|
394
396
|
if (!memo) {
|
|
397
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
395
398
|
const linkEv = ev.linkedEvent;
|
|
396
|
-
if (
|
|
399
|
+
if (linkEv && linkEv.getDesc() !== ev.getDesc()) {
|
|
397
400
|
memo = linkEv.render(options.locale);
|
|
398
401
|
}
|
|
399
402
|
}
|
|
400
403
|
const torahMemo = makeTorahMemo(ev, options.il);
|
|
401
404
|
if (torahMemo) {
|
|
402
405
|
if (memo.length) {
|
|
403
|
-
memo +=
|
|
406
|
+
memo += DBL_NEWLINE;
|
|
404
407
|
}
|
|
405
408
|
memo += torahMemo;
|
|
406
409
|
}
|
|
407
410
|
const url = appendTrackingToUrl(ev.url(), options);
|
|
408
411
|
if (url) {
|
|
409
412
|
if (memo.length) {
|
|
410
|
-
memo +=
|
|
413
|
+
memo += DBL_NEWLINE;
|
|
411
414
|
}
|
|
412
415
|
memo += url;
|
|
413
416
|
}
|
|
@@ -438,20 +441,29 @@ const localeMap = {
|
|
|
438
441
|
ashkenazi: 'en',
|
|
439
442
|
ashkenazi_romanian: 'ro',
|
|
440
443
|
};
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
444
|
+
async function getVtimezone(tzid) {
|
|
445
|
+
const vtz = vtimezoneCache.get(tzid);
|
|
446
|
+
if (typeof vtz === 'string') {
|
|
447
|
+
return vtz;
|
|
448
|
+
}
|
|
449
|
+
const filename = `./zoneinfo/${tzid}.ics`;
|
|
450
|
+
try {
|
|
451
|
+
const contents = await promises.readFile(filename, 'utf-8');
|
|
452
|
+
const lines = contents.split('\r\n');
|
|
453
|
+
// ignore first 3 and last 1 lines
|
|
454
|
+
const str = lines.slice(3, lines.length - 2).join('\r\n');
|
|
455
|
+
vtimezoneCache.set(tzid, str);
|
|
456
|
+
return str;
|
|
457
|
+
}
|
|
458
|
+
catch (_a) {
|
|
459
|
+
// ignore failure when no timezone definition to read
|
|
460
|
+
return undefined;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function makeIcalPreamble(opts) {
|
|
464
|
+
const locale = opts.locale || 'en';
|
|
451
465
|
const lang = locale.length === 2 ? locale : localeMap[locale] || 'en';
|
|
452
466
|
const uclang = lang.toUpperCase();
|
|
453
|
-
const opts = Object.assign({}, options);
|
|
454
|
-
opts.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
455
467
|
const title = opts.title ? IcalEvent.escape(opts.title) : 'Untitled';
|
|
456
468
|
const caldesc = opts.caldesc
|
|
457
469
|
? IcalEvent.escape(opts.caldesc)
|
|
@@ -470,46 +482,42 @@ async function icalEventsToString(icals, options) {
|
|
|
470
482
|
];
|
|
471
483
|
if (opts.publishedTTL !== false) {
|
|
472
484
|
const publishedTTL = opts.publishedTTL || 'P7D';
|
|
473
|
-
preamble.push(`REFRESH-INTERVAL;VALUE=DURATION:${publishedTTL}`);
|
|
474
|
-
preamble.push(`X-PUBLISHED-TTL:${publishedTTL}`);
|
|
485
|
+
preamble.push(`REFRESH-INTERVAL;VALUE=DURATION:${publishedTTL}`, `X-PUBLISHED-TTL:${publishedTTL}`);
|
|
475
486
|
}
|
|
476
|
-
preamble.push(`X-WR-CALNAME:${title}`);
|
|
477
|
-
|
|
487
|
+
preamble.push(`X-WR-CALNAME:${title}`, `X-WR-CALDESC:${caldesc}`);
|
|
488
|
+
const relcalid = opts.relcalid;
|
|
489
|
+
if (relcalid) {
|
|
490
|
+
preamble.push(`X-WR-RELCALID:${relcalid}`);
|
|
491
|
+
}
|
|
492
|
+
const calendarColor = opts.calendarColor;
|
|
493
|
+
if (calendarColor) {
|
|
494
|
+
preamble.push(`X-APPLE-CALENDAR-COLOR:${calendarColor}`);
|
|
495
|
+
}
|
|
496
|
+
return preamble;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Generates an RFC 2445 iCalendar string from an array of IcalEvents
|
|
500
|
+
*/
|
|
501
|
+
async function icalEventsToString(icals, options) {
|
|
502
|
+
if (!icals.length)
|
|
503
|
+
throw new RangeError('Events can not be empty');
|
|
504
|
+
if (!options)
|
|
505
|
+
throw new TypeError('Invalid options object');
|
|
506
|
+
const stream = [];
|
|
507
|
+
const preamble = makeIcalPreamble(options);
|
|
478
508
|
for (const line of preamble.map(IcalEvent.fold)) {
|
|
479
509
|
stream.push(line);
|
|
480
510
|
stream.push('\r\n');
|
|
481
511
|
}
|
|
482
|
-
|
|
483
|
-
stream.push(IcalEvent.fold(`X-WR-RELCALID:${opts.relcalid}`));
|
|
484
|
-
stream.push('\r\n');
|
|
485
|
-
}
|
|
486
|
-
if (opts.calendarColor) {
|
|
487
|
-
stream.push(`X-APPLE-CALENDAR-COLOR:${opts.calendarColor}\r\n`);
|
|
488
|
-
}
|
|
489
|
-
const location = opts.location;
|
|
512
|
+
const location = options.location;
|
|
490
513
|
const tzid = location === null || location === void 0 ? void 0 : location.getTzid();
|
|
491
514
|
if (tzid) {
|
|
492
515
|
stream.push(`X-WR-TIMEZONE;VALUE=TEXT:${tzid}\r\n`);
|
|
493
|
-
const vtz =
|
|
516
|
+
const vtz = await getVtimezone(tzid);
|
|
494
517
|
if (typeof vtz === 'string') {
|
|
495
518
|
stream.push(vtz);
|
|
496
519
|
stream.push('\r\n');
|
|
497
520
|
}
|
|
498
|
-
else {
|
|
499
|
-
const vtimezoneFilename = `./zoneinfo/${tzid}.ics`;
|
|
500
|
-
try {
|
|
501
|
-
const vtimezoneIcs = await promises.readFile(vtimezoneFilename, 'utf-8');
|
|
502
|
-
const lines = vtimezoneIcs.split('\r\n');
|
|
503
|
-
// ignore first 3 and last 1 lines
|
|
504
|
-
const str = lines.slice(3, lines.length - 2).join('\r\n');
|
|
505
|
-
stream.push(str);
|
|
506
|
-
stream.push('\r\n');
|
|
507
|
-
vtimezoneCache.set(tzid, str);
|
|
508
|
-
}
|
|
509
|
-
catch (error) {
|
|
510
|
-
// ignore failure when no timezone definition to read
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
521
|
}
|
|
514
522
|
for (const ical of icals) {
|
|
515
523
|
const lines = ical.getLines();
|
package/dist/pkgVersion.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "6.3.
|
|
1
|
+
export declare const version = "6.3.5";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hebcal/icalendar",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.5",
|
|
4
4
|
"author": "Michael J. Radwin (https://github.com/mjradwin)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ical",
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
],
|
|
11
11
|
"description": "Jewish holidays and Hebrew calendar as iCalendar RFC 2445",
|
|
12
12
|
"type": "module",
|
|
13
|
-
"module": "./dist/
|
|
13
|
+
"module": "./dist/icalendar.js",
|
|
14
14
|
"typings": "./dist/icalendar.d.ts",
|
|
15
15
|
"exports": {
|
|
16
|
-
".": "./dist/
|
|
16
|
+
".": "./dist/icalendar.js"
|
|
17
17
|
},
|
|
18
18
|
"engines": {
|
|
19
|
-
"node": ">=
|
|
19
|
+
"node": ">= 20"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"dist"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://hebcal.github.io/api/icalendar/",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@hebcal/core": "^6.0.
|
|
33
|
+
"@hebcal/core": "^6.0.8",
|
|
34
34
|
"@hebcal/hdate": "^0.21.1",
|
|
35
35
|
"@hebcal/rest-api": "^6.4.0",
|
|
36
36
|
"murmurhash3": "^0.5.0",
|
|
@@ -40,7 +40,6 @@
|
|
|
40
40
|
"build:rollup": "rollup -c",
|
|
41
41
|
"build:version": "node ./version.cjs package.json src/pkgVersion.ts",
|
|
42
42
|
"build": "npm run build:version && npm run build:rollup",
|
|
43
|
-
"prepare": "npm run build",
|
|
44
43
|
"pretest": "npm run build",
|
|
45
44
|
"docs": "typedoc",
|
|
46
45
|
"test": "vitest",
|
|
@@ -51,13 +50,13 @@
|
|
|
51
50
|
},
|
|
52
51
|
"license": "BSD-2-Clause",
|
|
53
52
|
"devDependencies": {
|
|
54
|
-
"@hebcal/learning": "^6.6.
|
|
53
|
+
"@hebcal/learning": "^6.6.1",
|
|
55
54
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
56
|
-
"@types/node": "
|
|
57
|
-
"gts": "^
|
|
58
|
-
"rollup": "^4.
|
|
59
|
-
"typedoc": "^0.28.
|
|
55
|
+
"@types/node": "25.0.10",
|
|
56
|
+
"gts": "^7.0.0",
|
|
57
|
+
"rollup": "^4.56.0",
|
|
58
|
+
"typedoc": "^0.28.16",
|
|
60
59
|
"typescript": "^5.9.3",
|
|
61
|
-
"vitest": "^4.0.
|
|
60
|
+
"vitest": "^4.0.18"
|
|
62
61
|
}
|
|
63
62
|
}
|