@hebcal/icalendar 6.3.6 → 6.3.8
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/foldLine.d.ts +1 -0
- package/dist/foldLine.js +51 -0
- package/dist/icalendar.js +27 -54
- package/dist/pkgVersion.d.ts +1 -1
- package/dist/pkgVersion.js +2 -2
- package/package.json +10 -10
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function foldLine(line: string): string;
|
package/dist/foldLine.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*! @hebcal/icalendar v6.3.8 */
|
|
2
|
+
import { Buffer } from 'node:buffer';
|
|
3
|
+
|
|
4
|
+
let foldSegmenter;
|
|
5
|
+
const char74re = /.{1,74}/g;
|
|
6
|
+
function foldLine(line) {
|
|
7
|
+
const lineBytes = Buffer.byteLength(line);
|
|
8
|
+
if (lineBytes <= 74) {
|
|
9
|
+
return line;
|
|
10
|
+
}
|
|
11
|
+
if (lineBytes === line.length) {
|
|
12
|
+
// All-ASCII fast path: every UTF-16 unit encodes to one UTF-8 byte
|
|
13
|
+
// iff the string is pure ASCII, so we can split by JS chars.
|
|
14
|
+
return line.match(char74re).join('\r\n ');
|
|
15
|
+
}
|
|
16
|
+
// Walk grapheme clusters so we never split a multi-octet UTF-8
|
|
17
|
+
// sequence (or a combining/ZWJ/regional-indicator cluster) across
|
|
18
|
+
// a fold boundary. Reuse a single Segmenter to avoid per-call
|
|
19
|
+
// construction cost.
|
|
20
|
+
if (!foldSegmenter) {
|
|
21
|
+
foldSegmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
|
|
22
|
+
}
|
|
23
|
+
const parts = [];
|
|
24
|
+
let chunkStart = 0;
|
|
25
|
+
let len = 0;
|
|
26
|
+
for (const { segment, index } of foldSegmenter.segment(line)) {
|
|
27
|
+
const cp = segment.codePointAt(0);
|
|
28
|
+
// Most segments are a single code point; compute UTF-8 length
|
|
29
|
+
// arithmetically and skip the Buffer.byteLength call.
|
|
30
|
+
const cpUnits = cp >= 0x10000 ? 2 : 1;
|
|
31
|
+
let octets;
|
|
32
|
+
if (segment.length === cpUnits) {
|
|
33
|
+
octets = cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
octets = Buffer.byteLength(segment);
|
|
37
|
+
}
|
|
38
|
+
if (len + octets >= 75) {
|
|
39
|
+
parts.push(line.slice(chunkStart, index));
|
|
40
|
+
chunkStart = index;
|
|
41
|
+
len = octets;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
len += octets;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
parts.push(line.slice(chunkStart));
|
|
48
|
+
return parts.join('\r\n ');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { foldLine };
|
package/dist/icalendar.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @hebcal/icalendar v6.3.
|
|
1
|
+
/*! @hebcal/icalendar v6.3.8 */
|
|
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';
|
|
@@ -10,6 +10,7 @@ import { appendIsraelAndTracking } from '@hebcal/rest-api/dist/esm/url';
|
|
|
10
10
|
import { makeAnchor } from '@hebcal/rest-api/dist/esm/makeAnchor';
|
|
11
11
|
import { promises } from 'node:fs';
|
|
12
12
|
import { version } from './pkgVersion.js';
|
|
13
|
+
import { foldLine } from './foldLine.js';
|
|
13
14
|
|
|
14
15
|
const vtimezoneCache = new Map();
|
|
15
16
|
const CATEGORY = {
|
|
@@ -56,8 +57,6 @@ function appendTrackingToUrl(url, options) {
|
|
|
56
57
|
const utmCampaign = options.utmCampaign;
|
|
57
58
|
return appendIsraelAndTracking(url, options.il, utmSource, utmMedium, utmCampaign);
|
|
58
59
|
}
|
|
59
|
-
const encoder = new TextEncoder();
|
|
60
|
-
const char74re = /(.{1,74})/g;
|
|
61
60
|
const DAILY_LEARNING = flags.DAILY_LEARNING |
|
|
62
61
|
flags.DAF_YOMI |
|
|
63
62
|
flags.MISHNA_YOMI |
|
|
@@ -67,13 +66,27 @@ const DAILY_LEARNING = flags.DAILY_LEARNING |
|
|
|
67
66
|
* Represents an RFC 2445 iCalendar VEVENT
|
|
68
67
|
*/
|
|
69
68
|
class IcalEvent {
|
|
69
|
+
ev;
|
|
70
|
+
options;
|
|
71
|
+
dtstamp;
|
|
72
|
+
sequence;
|
|
73
|
+
timed;
|
|
74
|
+
locationName;
|
|
75
|
+
startDate;
|
|
76
|
+
isoDateOnly;
|
|
77
|
+
dtargs;
|
|
78
|
+
transp;
|
|
79
|
+
busyStatus;
|
|
80
|
+
endDate;
|
|
81
|
+
subj;
|
|
82
|
+
category;
|
|
83
|
+
lines;
|
|
70
84
|
/**
|
|
71
85
|
* Builds an IcalEvent object from a Hebcal Event
|
|
72
86
|
*/
|
|
73
87
|
constructor(ev, options = {}) {
|
|
74
|
-
var _a;
|
|
75
88
|
this.ev = ev;
|
|
76
|
-
const opts =
|
|
89
|
+
const opts = { ...options };
|
|
77
90
|
this.options = opts;
|
|
78
91
|
this.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
79
92
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -112,7 +125,7 @@ class IcalEvent {
|
|
|
112
125
|
minute = +minute;
|
|
113
126
|
this.startDate += 'T' + pad2(hour) + pad2(minute) + '00';
|
|
114
127
|
this.endDate = this.startDate;
|
|
115
|
-
if (location
|
|
128
|
+
if (location?.getTzid()) {
|
|
116
129
|
this.dtargs = `;TZID=${location.getTzid()}`;
|
|
117
130
|
}
|
|
118
131
|
}
|
|
@@ -147,7 +160,7 @@ class IcalEvent {
|
|
|
147
160
|
}
|
|
148
161
|
}
|
|
149
162
|
this.subj = subj;
|
|
150
|
-
this.category = ev0.category || CATEGORY[
|
|
163
|
+
this.category = ev0.category || CATEGORY[getEventCategories(ev)?.[0]];
|
|
151
164
|
}
|
|
152
165
|
getAlarm() {
|
|
153
166
|
const ev = this.ev;
|
|
@@ -252,51 +265,13 @@ class IcalEvent {
|
|
|
252
265
|
* fold lines to 75 characters
|
|
253
266
|
*/
|
|
254
267
|
getLines() {
|
|
255
|
-
return this.getLongLines().map(
|
|
268
|
+
return this.getLongLines().map(foldLine);
|
|
256
269
|
}
|
|
257
270
|
/**
|
|
258
271
|
* fold line to 75 characters
|
|
259
272
|
*/
|
|
260
273
|
static fold(line) {
|
|
261
|
-
|
|
262
|
-
for (let i = 0; i < line.length; i++) {
|
|
263
|
-
if (line.codePointAt(i) > 255) {
|
|
264
|
-
isASCII = false;
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
if (isASCII) {
|
|
269
|
-
if (line.length <= 74) {
|
|
270
|
-
return line;
|
|
271
|
-
}
|
|
272
|
-
const matches = line.match(char74re);
|
|
273
|
-
return matches.join('\r\n ');
|
|
274
|
-
}
|
|
275
|
-
if (encoder.encode(line).length <= 74) {
|
|
276
|
-
return line;
|
|
277
|
-
}
|
|
278
|
-
// iterate unicode character by character, making sure
|
|
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);
|
|
283
|
-
let result = '';
|
|
284
|
-
let current = '';
|
|
285
|
-
let len = 0;
|
|
286
|
-
for (const ch of chars) {
|
|
287
|
-
const octets = ch.codePointAt(0) < 256 ? 1 : encoder.encode(ch).length;
|
|
288
|
-
const newlen = len + octets;
|
|
289
|
-
if (newlen < 75) {
|
|
290
|
-
current += ch;
|
|
291
|
-
len = newlen;
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
result += current + '\r\n ';
|
|
295
|
-
current = ch;
|
|
296
|
-
len = octets;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return result + current;
|
|
274
|
+
return foldLine(line);
|
|
300
275
|
}
|
|
301
276
|
static escape(str) {
|
|
302
277
|
if (str.includes(',')) {
|
|
@@ -424,7 +399,7 @@ async function eventsToIcalendar(events, options) {
|
|
|
424
399
|
throw new RangeError('Events can not be empty');
|
|
425
400
|
if (!options)
|
|
426
401
|
throw new TypeError('Invalid options object');
|
|
427
|
-
const opts =
|
|
402
|
+
const opts = { ...options };
|
|
428
403
|
opts.dtstamp = opts.dtstamp || IcalEvent.makeDtstamp(new Date());
|
|
429
404
|
if (!opts.title) {
|
|
430
405
|
opts.title = getCalendarTitle(events, opts);
|
|
@@ -455,7 +430,7 @@ async function getVtimezone(tzid) {
|
|
|
455
430
|
vtimezoneCache.set(tzid, str);
|
|
456
431
|
return str;
|
|
457
432
|
}
|
|
458
|
-
catch
|
|
433
|
+
catch {
|
|
459
434
|
// ignore failure when no timezone definition to read
|
|
460
435
|
return undefined;
|
|
461
436
|
}
|
|
@@ -465,9 +440,7 @@ function makeIcalPreamble(opts) {
|
|
|
465
440
|
const lang = locale.length === 2 ? locale : localeMap[locale] || 'en';
|
|
466
441
|
const uclang = lang.toUpperCase();
|
|
467
442
|
const title = opts.title ? IcalEvent.escape(opts.title) : 'Untitled';
|
|
468
|
-
const caldesc = opts.caldesc
|
|
469
|
-
? IcalEvent.escape(opts.caldesc)
|
|
470
|
-
: undefined;
|
|
443
|
+
const caldesc = opts.caldesc ? IcalEvent.escape(opts.caldesc) : undefined;
|
|
471
444
|
const prodid = opts.prodid ||
|
|
472
445
|
`-//hebcal.com/NONSGML Hebcal Calendar v1${version}//${uclang}`;
|
|
473
446
|
const preamble = [
|
|
@@ -506,12 +479,12 @@ async function icalEventsToString(icals, options) {
|
|
|
506
479
|
throw new TypeError('Invalid options object');
|
|
507
480
|
const stream = [];
|
|
508
481
|
const preamble = makeIcalPreamble(options);
|
|
509
|
-
for (const line of preamble.map(
|
|
482
|
+
for (const line of preamble.map(foldLine)) {
|
|
510
483
|
stream.push(line);
|
|
511
484
|
stream.push('\r\n');
|
|
512
485
|
}
|
|
513
486
|
const location = options.location;
|
|
514
|
-
const tzid = location
|
|
487
|
+
const tzid = location?.getTzid();
|
|
515
488
|
if (tzid) {
|
|
516
489
|
stream.push(`X-WR-TIMEZONE;VALUE=TEXT:${tzid}\r\n`);
|
|
517
490
|
const vtz = await getVtimezone(tzid);
|
package/dist/pkgVersion.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "6.3.
|
|
1
|
+
export declare const version = "6.3.8";
|
package/dist/pkgVersion.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hebcal/icalendar",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.8",
|
|
4
4
|
"author": "Michael J. Radwin (https://github.com/mjradwin)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ical",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://hebcal.github.io/api/icalendar/",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@hebcal/core": "^6.
|
|
34
|
-
"@hebcal/hdate": "^0.
|
|
35
|
-
"@hebcal/rest-api": "^6.4.
|
|
33
|
+
"@hebcal/core": "^6.3.3",
|
|
34
|
+
"@hebcal/hdate": "^0.22.2",
|
|
35
|
+
"@hebcal/rest-api": "^6.4.7",
|
|
36
36
|
"murmurhash3": "^0.5.0",
|
|
37
37
|
"tslib": "^2.8.1"
|
|
38
38
|
},
|
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
},
|
|
51
51
|
"license": "BSD-2-Clause",
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@hebcal/learning": "^6.
|
|
53
|
+
"@hebcal/learning": "^6.8.0",
|
|
54
54
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
55
|
-
"@types/node": "25.
|
|
55
|
+
"@types/node": "25.6.0",
|
|
56
56
|
"gts": "^7.0.0",
|
|
57
|
-
"rollup": "^4.
|
|
58
|
-
"typedoc": "^0.28.
|
|
59
|
-
"typescript": "^
|
|
60
|
-
"vitest": "^4.
|
|
57
|
+
"rollup": "^4.60.2",
|
|
58
|
+
"typedoc": "^0.28.19",
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"vitest": "^4.1.5"
|
|
61
61
|
}
|
|
62
62
|
}
|