ical-generator 8.1.2-develop.9 → 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/README.md +13 -19
- package/dist/index.cjs +7 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1329 -1329
- package/dist/index.d.ts +1329 -1329
- package/dist/index.js +17 -17
- package/dist/index.js.map +1 -1
- package/package.json +126 -122
- package/src/alarm.ts +499 -454
- package/src/attendee.ts +364 -345
- package/src/calendar.ts +422 -439
- package/src/category.ts +5 -14
- package/src/event.ts +1293 -1118
- package/src/index.ts +19 -25
- package/src/tools.ts +348 -258
- package/src/types.ts +86 -75
package/src/tools.ts
CHANGED
|
@@ -8,172 +8,54 @@ import {
|
|
|
8
8
|
type ICalMomentStub,
|
|
9
9
|
type ICalMomentTimezoneStub,
|
|
10
10
|
type ICalOrganizer,
|
|
11
|
-
type ICalRRuleStub
|
|
11
|
+
type ICalRRuleStub,
|
|
12
12
|
} from './types.ts';
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
s += 'T' + m.getHours().toString().padStart(2, '0') +
|
|
43
|
-
m.getMinutes().toString().padStart(2, '0') +
|
|
44
|
-
m.getSeconds().toString().padStart(2, '0');
|
|
45
|
-
|
|
46
|
-
return s;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
s += 'T' + m.getUTCHours().toString().padStart(2, '0') +
|
|
50
|
-
m.getUTCMinutes().toString().padStart(2, '0') +
|
|
51
|
-
m.getUTCSeconds().toString().padStart(2, '0') +
|
|
52
|
-
(floating ? '' : 'Z');
|
|
53
|
-
|
|
54
|
-
return s;
|
|
55
|
-
}
|
|
56
|
-
else if(isMoment(d)) {
|
|
57
|
-
// @see https://momentjs.com/timezone/docs/#/using-timezones/parsing-in-zone/
|
|
58
|
-
const m = timezone
|
|
59
|
-
? (isMomentTZ(d) && !d.tz() ? d.clone().tz(timezone) : d)
|
|
60
|
-
: (floating || (dateonly && isMomentTZ(d) && d.tz()) ? d : d.utc());
|
|
61
|
-
|
|
62
|
-
return m.format('YYYYMMDD') + (!dateonly ? (
|
|
63
|
-
'T' + m.format('HHmmss') + (floating || timezone ? '' : 'Z')
|
|
64
|
-
) : '');
|
|
65
|
-
}
|
|
66
|
-
else if(isLuxonDate(d)) {
|
|
67
|
-
const m = timezone
|
|
68
|
-
? d.setZone(timezone)
|
|
69
|
-
: (floating || (dateonly && d.zone.type !== 'system') ? d : d.setZone('utc'));
|
|
70
|
-
|
|
71
|
-
return m.toFormat('yyyyLLdd') + (!dateonly ? (
|
|
72
|
-
'T' + m.toFormat('HHmmss') + (floating || timezone ? '' : 'Z')
|
|
73
|
-
) : '');
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// @see https://day.js.org/docs/en/plugin/utc
|
|
77
|
-
|
|
78
|
-
let m = d;
|
|
79
|
-
if(timezone) {
|
|
80
|
-
m = typeof d.tz === 'function' ? d.tz(timezone) : d;
|
|
81
|
-
}
|
|
82
|
-
else if(floating) {
|
|
83
|
-
// m = d;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
else if (typeof d.utc === 'function') {
|
|
87
|
-
m = d.utc();
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
throw new Error('Unable to convert dayjs object to UTC value: UTC plugin is not available!');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return m.format('YYYYMMDD') + (!dateonly ? (
|
|
94
|
-
'T' + m.format('HHmmss') + (floating || timezone ? '' : 'Z')
|
|
95
|
-
) : '');
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Converts a valid date/time object supported by this library to a string.
|
|
101
|
-
* For information about this format, see RFC 5545, section 3.3.5
|
|
102
|
-
* https://tools.ietf.org/html/rfc5545#section-3.3.5
|
|
103
|
-
*/
|
|
104
|
-
export function formatDateTZ (timezone: string | null, property: string, date: ICalDateTimeValue | Date | string, eventData?: {floating?: boolean | null, timezone?: string | null}): string {
|
|
105
|
-
let tzParam = '';
|
|
106
|
-
let floating = eventData?.floating || false;
|
|
107
|
-
|
|
108
|
-
if (eventData?.timezone) {
|
|
109
|
-
tzParam = ';TZID=' + eventData.timezone;
|
|
110
|
-
|
|
111
|
-
// This isn't a 'floating' event because it has a timezone;
|
|
112
|
-
// but we use it to omit the 'Z' UTC specifier in formatDate()
|
|
113
|
-
floating = true;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return property + tzParam + ':' + formatDate(timezone, date, false, floating);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Escapes special characters in the given string
|
|
121
|
-
*/
|
|
122
|
-
export function escape (str: string | unknown, inQuotes: boolean): string {
|
|
123
|
-
return String(str).replace(inQuotes ? /[\\"]/g : /[\\;,]/g, function (match) {
|
|
124
|
-
return '\\' + match;
|
|
125
|
-
}).replace(/(?:\r\n|\r|\n)/g, '\\n');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Trim line length of given string
|
|
130
|
-
*/
|
|
131
|
-
export function foldLines (input: string): string {
|
|
132
|
-
return input.split('\r\n').map(function (line) {
|
|
133
|
-
let result = '';
|
|
134
|
-
let c = 0;
|
|
135
|
-
for (let i = 0; i < line.length; i++) {
|
|
136
|
-
let ch = line.charAt(i);
|
|
137
|
-
|
|
138
|
-
// surrogate pair, see https://mathiasbynens.be/notes/javascript-encoding#surrogate-pairs
|
|
139
|
-
if (ch >= '\ud800' && ch <= '\udbff') {
|
|
140
|
-
ch += line.charAt(++i);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// TextEncoder is available in browsers and node.js >= 11.0.0
|
|
144
|
-
const charsize = new TextEncoder().encode(ch).length;
|
|
145
|
-
c += charsize;
|
|
146
|
-
if (c > 74) {
|
|
147
|
-
result += '\r\n ';
|
|
148
|
-
c = charsize;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
result += ch;
|
|
152
|
-
}
|
|
153
|
-
return result;
|
|
154
|
-
}).join('\r\n');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function addOrGetCustomAttributes (data: {x: [string, string][]}, keyOrArray: ({key: string, value: string})[] | [string, string][] | Record<string, string>): void;
|
|
158
|
-
export function addOrGetCustomAttributes (data: {x: [string, string][]}, keyOrArray: string, value: string): void;
|
|
159
|
-
export function addOrGetCustomAttributes (data: {x: [string, string][]}): ({key: string, value: string})[];
|
|
160
|
-
export function addOrGetCustomAttributes (data: {x: [string, string][]}, keyOrArray?: ({key: string, value: string})[] | [string, string][] | Record<string, string> | string | undefined, value?: string | undefined): void | ({key: string, value: string})[] {
|
|
14
|
+
export function addOrGetCustomAttributes(
|
|
15
|
+
data: { x: [string, string][] },
|
|
16
|
+
keyOrArray:
|
|
17
|
+
| [string, string][]
|
|
18
|
+
| Record<string, string>
|
|
19
|
+
| { key: string; value: string }[],
|
|
20
|
+
): void;
|
|
21
|
+
|
|
22
|
+
export function addOrGetCustomAttributes(
|
|
23
|
+
data: { x: [string, string][] },
|
|
24
|
+
keyOrArray: string,
|
|
25
|
+
value: string,
|
|
26
|
+
): void;
|
|
27
|
+
|
|
28
|
+
export function addOrGetCustomAttributes(data: {
|
|
29
|
+
x: [string, string][];
|
|
30
|
+
}): { key: string; value: string }[];
|
|
31
|
+
|
|
32
|
+
export function addOrGetCustomAttributes(
|
|
33
|
+
data: { x: [string, string][] },
|
|
34
|
+
keyOrArray?:
|
|
35
|
+
| [string, string][]
|
|
36
|
+
| Record<string, string>
|
|
37
|
+
| string
|
|
38
|
+
| undefined
|
|
39
|
+
| { key: string; value: string }[],
|
|
40
|
+
value?: string | undefined,
|
|
41
|
+
): void | { key: string; value: string }[] {
|
|
161
42
|
if (Array.isArray(keyOrArray)) {
|
|
162
|
-
data.x = keyOrArray.map(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
43
|
+
data.x = keyOrArray.map(
|
|
44
|
+
(o: [string, string] | { key: string; value: string }) => {
|
|
45
|
+
if (Array.isArray(o)) {
|
|
46
|
+
return o;
|
|
47
|
+
}
|
|
48
|
+
if (typeof o.key !== 'string' || typeof o.value !== 'string') {
|
|
49
|
+
throw new Error('Either key or value is not a string!');
|
|
50
|
+
}
|
|
51
|
+
if (o.key.substr(0, 2) !== 'X-') {
|
|
52
|
+
throw new Error('Key has to start with `X-`!');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return [o.key, o.value] as [string, string];
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
} else if (typeof keyOrArray === 'object') {
|
|
177
59
|
data.x = Object.entries(keyOrArray).map(([key, value]) => {
|
|
178
60
|
if (typeof key !== 'string' || typeof value !== 'string') {
|
|
179
61
|
throw new Error('Either key or value is not a string!');
|
|
@@ -184,29 +66,70 @@ export function addOrGetCustomAttributes (data: {x: [string, string][]}, keyOrAr
|
|
|
184
66
|
|
|
185
67
|
return [key, value];
|
|
186
68
|
});
|
|
187
|
-
}
|
|
188
|
-
else if (typeof keyOrArray === 'string' && typeof value === 'string') {
|
|
69
|
+
} else if (typeof keyOrArray === 'string' && typeof value === 'string') {
|
|
189
70
|
if (keyOrArray.substr(0, 2) !== 'X-') {
|
|
190
71
|
throw new Error('Key has to start with `X-`!');
|
|
191
72
|
}
|
|
192
73
|
|
|
193
74
|
data.x.push([keyOrArray, value]);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return data.x.map(a => ({
|
|
75
|
+
} else {
|
|
76
|
+
return data.x.map((a) => ({
|
|
197
77
|
key: a[0],
|
|
198
|
-
value: a[1]
|
|
78
|
+
value: a[1],
|
|
199
79
|
}));
|
|
200
80
|
}
|
|
201
81
|
}
|
|
202
82
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Checks if the given input is a valid date and
|
|
85
|
+
* returns the internal representation (= moment object)
|
|
86
|
+
*/
|
|
87
|
+
export function checkDate(
|
|
88
|
+
value: ICalDateTimeValue,
|
|
89
|
+
attribute: string,
|
|
90
|
+
): ICalDateTimeValue {
|
|
91
|
+
// Date & String
|
|
92
|
+
if (
|
|
93
|
+
(value instanceof Date && isNaN(value.getTime())) ||
|
|
94
|
+
(typeof value === 'string' && isNaN(new Date(value).getTime()))
|
|
95
|
+
) {
|
|
96
|
+
throw new Error(`\`${attribute}\` has to be a valid date!`);
|
|
97
|
+
}
|
|
98
|
+
if (value instanceof Date || typeof value === 'string') {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Luxon
|
|
103
|
+
if (isLuxonDate(value) && value.isValid === true) {
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Moment / Moment Timezone
|
|
108
|
+
if ((isMoment(value) || isDayjs(value)) && value.isValid()) {
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw new Error(`\`${attribute}\` has to be a valid date!`);
|
|
208
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Checks if the given string `value` is a
|
|
116
|
+
* valid one for the type `type`
|
|
117
|
+
*/
|
|
118
|
+
export function checkEnum(
|
|
119
|
+
type: Record<string, string>,
|
|
120
|
+
value: unknown,
|
|
121
|
+
): unknown {
|
|
122
|
+
const allowedValues = Object.values(type);
|
|
123
|
+
const valueStr = String(value).toUpperCase();
|
|
124
|
+
|
|
125
|
+
if (!valueStr || !allowedValues.includes(valueStr)) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
`Input must be one of the following: ${allowedValues.join(', ')}`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
209
130
|
|
|
131
|
+
return valueStr;
|
|
132
|
+
}
|
|
210
133
|
/**
|
|
211
134
|
* Check the given string or ICalOrganizer. Parses
|
|
212
135
|
* the string for name and email address if possible.
|
|
@@ -214,43 +137,47 @@ export function generateCustomAttributes (data: {x: [string, string][]}): string
|
|
|
214
137
|
* @param attribute Attribute name for error messages
|
|
215
138
|
* @param value Value to parse name/email from
|
|
216
139
|
*/
|
|
217
|
-
export function checkNameAndMail
|
|
140
|
+
export function checkNameAndMail(
|
|
141
|
+
attribute: string,
|
|
142
|
+
value: ICalOrganizer | string,
|
|
143
|
+
): ICalOrganizer {
|
|
218
144
|
let result: ICalOrganizer | null = null;
|
|
219
145
|
|
|
220
146
|
if (typeof value === 'string') {
|
|
221
147
|
const match = value.match(/^(.+) ?<([^>]+)>$/);
|
|
222
148
|
if (match) {
|
|
223
149
|
result = {
|
|
150
|
+
email: match[2].trim(),
|
|
224
151
|
name: match[1].trim(),
|
|
225
|
-
email: match[2].trim()
|
|
226
152
|
};
|
|
227
|
-
}
|
|
228
|
-
else if(value.includes('@')) {
|
|
153
|
+
} else if (value.includes('@')) {
|
|
229
154
|
result = {
|
|
155
|
+
email: value.trim(),
|
|
230
156
|
name: value.trim(),
|
|
231
|
-
email: value.trim()
|
|
232
157
|
};
|
|
233
158
|
}
|
|
234
|
-
}
|
|
235
|
-
else if (typeof value === 'object') {
|
|
159
|
+
} else if (typeof value === 'object') {
|
|
236
160
|
result = {
|
|
237
|
-
name: value.name,
|
|
238
161
|
email: value.email,
|
|
239
162
|
mailto: value.mailto,
|
|
240
|
-
|
|
163
|
+
name: value.name,
|
|
164
|
+
sentBy: value.sentBy,
|
|
241
165
|
};
|
|
242
166
|
}
|
|
243
167
|
|
|
244
168
|
if (!result && typeof value === 'string') {
|
|
245
169
|
throw new Error(
|
|
246
|
-
'`' +
|
|
247
|
-
|
|
170
|
+
'`' +
|
|
171
|
+
attribute +
|
|
172
|
+
"` isn't formated correctly. See https://sebbo2002.github.io/ical-generator/develop/" +
|
|
173
|
+
'reference/interfaces/ICalOrganizer.html',
|
|
248
174
|
);
|
|
249
|
-
}
|
|
250
|
-
else if (!result) {
|
|
175
|
+
} else if (!result) {
|
|
251
176
|
throw new Error(
|
|
252
|
-
'`' +
|
|
253
|
-
|
|
177
|
+
'`' +
|
|
178
|
+
attribute +
|
|
179
|
+
'` needs to be a valid formed string or an object. See https://sebbo2002.github.io/' +
|
|
180
|
+
'ical-generator/develop/reference/interfaces/ICalOrganizer.html',
|
|
254
181
|
);
|
|
255
182
|
}
|
|
256
183
|
|
|
@@ -260,107 +187,258 @@ export function checkNameAndMail (attribute: string, value: string | ICalOrganiz
|
|
|
260
187
|
|
|
261
188
|
return result;
|
|
262
189
|
}
|
|
263
|
-
|
|
264
190
|
/**
|
|
265
|
-
*
|
|
266
|
-
* valid one for the type `type`
|
|
191
|
+
* Escapes special characters in the given string
|
|
267
192
|
*/
|
|
268
|
-
export function
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return valueStr;
|
|
193
|
+
export function escape(str: string | unknown, inQuotes: boolean): string {
|
|
194
|
+
return String(str)
|
|
195
|
+
.replace(inQuotes ? /[\\"]/g : /[\\;,]/g, function (match) {
|
|
196
|
+
return '\\' + match;
|
|
197
|
+
})
|
|
198
|
+
.replace(/(?:\r\n|\r|\n)/g, '\\n');
|
|
277
199
|
}
|
|
278
200
|
|
|
279
201
|
/**
|
|
280
|
-
*
|
|
281
|
-
* returns the internal representation (= moment object)
|
|
202
|
+
* Trim line length of given string
|
|
282
203
|
*/
|
|
283
|
-
export function
|
|
204
|
+
export function foldLines(input: string): string {
|
|
205
|
+
return input
|
|
206
|
+
.split('\r\n')
|
|
207
|
+
.map(function (line) {
|
|
208
|
+
let result = '';
|
|
209
|
+
let c = 0;
|
|
210
|
+
for (let i = 0; i < line.length; i++) {
|
|
211
|
+
let ch = line.charAt(i);
|
|
212
|
+
|
|
213
|
+
// surrogate pair, see https://mathiasbynens.be/notes/javascript-encoding#surrogate-pairs
|
|
214
|
+
if (ch >= '\ud800' && ch <= '\udbff') {
|
|
215
|
+
ch += line.charAt(++i);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// TextEncoder is available in browsers and node.js >= 11.0.0
|
|
219
|
+
const charsize = new TextEncoder().encode(ch).length;
|
|
220
|
+
c += charsize;
|
|
221
|
+
if (c > 74) {
|
|
222
|
+
result += '\r\n ';
|
|
223
|
+
c = charsize;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
result += ch;
|
|
227
|
+
}
|
|
228
|
+
return result;
|
|
229
|
+
})
|
|
230
|
+
.join('\r\n');
|
|
231
|
+
}
|
|
284
232
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
233
|
+
/**
|
|
234
|
+
* Converts a valid date/time object supported by this library to a string.
|
|
235
|
+
*/
|
|
236
|
+
export function formatDate(
|
|
237
|
+
timezone: null | string,
|
|
238
|
+
d: ICalDateTimeValue,
|
|
239
|
+
dateonly?: boolean,
|
|
240
|
+
floating?: boolean,
|
|
241
|
+
): string {
|
|
242
|
+
if (timezone?.startsWith('/')) {
|
|
243
|
+
timezone = timezone.substr(1);
|
|
294
244
|
}
|
|
295
245
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return value;
|
|
299
|
-
}
|
|
246
|
+
if (typeof d === 'string' || d instanceof Date) {
|
|
247
|
+
const m = new Date(d);
|
|
300
248
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
249
|
+
// (!dateonly && !floating) || !timezone => utc
|
|
250
|
+
let s =
|
|
251
|
+
m.getUTCFullYear() +
|
|
252
|
+
String(m.getUTCMonth() + 1).padStart(2, '0') +
|
|
253
|
+
m.getUTCDate().toString().padStart(2, '0');
|
|
305
254
|
|
|
306
|
-
|
|
307
|
-
|
|
255
|
+
// (dateonly || floating) && timezone => tz
|
|
256
|
+
if (timezone) {
|
|
257
|
+
s =
|
|
258
|
+
m.getFullYear() +
|
|
259
|
+
String(m.getMonth() + 1).padStart(2, '0') +
|
|
260
|
+
m.getDate().toString().padStart(2, '0');
|
|
261
|
+
}
|
|
308
262
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
263
|
+
if (dateonly) {
|
|
264
|
+
return s;
|
|
265
|
+
}
|
|
313
266
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
267
|
+
if (timezone) {
|
|
268
|
+
s +=
|
|
269
|
+
'T' +
|
|
270
|
+
m.getHours().toString().padStart(2, '0') +
|
|
271
|
+
m.getMinutes().toString().padStart(2, '0') +
|
|
272
|
+
m.getSeconds().toString().padStart(2, '0');
|
|
317
273
|
|
|
318
|
-
|
|
274
|
+
return s;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
s +=
|
|
278
|
+
'T' +
|
|
279
|
+
m.getUTCHours().toString().padStart(2, '0') +
|
|
280
|
+
m.getUTCMinutes().toString().padStart(2, '0') +
|
|
281
|
+
m.getUTCSeconds().toString().padStart(2, '0') +
|
|
282
|
+
(floating ? '' : 'Z');
|
|
283
|
+
|
|
284
|
+
return s;
|
|
285
|
+
} else if (isMoment(d)) {
|
|
286
|
+
// @see https://momentjs.com/timezone/docs/#/using-timezones/parsing-in-zone/
|
|
287
|
+
const m = timezone
|
|
288
|
+
? isMomentTZ(d) && !d.tz()
|
|
289
|
+
? d.clone().tz(timezone)
|
|
290
|
+
: d
|
|
291
|
+
: floating || (dateonly && isMomentTZ(d) && d.tz())
|
|
292
|
+
? d
|
|
293
|
+
: d.utc();
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
m.format('YYYYMMDD') +
|
|
297
|
+
(!dateonly
|
|
298
|
+
? 'T' + m.format('HHmmss') + (floating || timezone ? '' : 'Z')
|
|
299
|
+
: '')
|
|
300
|
+
);
|
|
301
|
+
} else if (isLuxonDate(d)) {
|
|
302
|
+
const m = timezone
|
|
303
|
+
? d.setZone(timezone)
|
|
304
|
+
: floating || (dateonly && d.zone.type !== 'system')
|
|
305
|
+
? d
|
|
306
|
+
: d.setZone('utc');
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
m.toFormat('yyyyLLdd') +
|
|
310
|
+
(!dateonly
|
|
311
|
+
? 'T' + m.toFormat('HHmmss') + (floating || timezone ? '' : 'Z')
|
|
312
|
+
: '')
|
|
313
|
+
);
|
|
314
|
+
} else {
|
|
315
|
+
// @see https://day.js.org/docs/en/plugin/utc
|
|
316
|
+
|
|
317
|
+
let m = d;
|
|
318
|
+
if (timezone) {
|
|
319
|
+
m = typeof d.tz === 'function' ? d.tz(timezone) : d;
|
|
320
|
+
} else if (floating) {
|
|
321
|
+
// m = d;
|
|
322
|
+
} else if (typeof d.utc === 'function') {
|
|
323
|
+
m = d.utc();
|
|
324
|
+
} else {
|
|
325
|
+
throw new Error(
|
|
326
|
+
'Unable to convert dayjs object to UTC value: UTC plugin is not available!',
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return (
|
|
331
|
+
m.format('YYYYMMDD') +
|
|
332
|
+
(!dateonly
|
|
333
|
+
? 'T' + m.format('HHmmss') + (floating || timezone ? '' : 'Z')
|
|
334
|
+
: '')
|
|
335
|
+
);
|
|
336
|
+
}
|
|
319
337
|
}
|
|
320
338
|
|
|
321
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Converts a valid date/time object supported by this library to a string.
|
|
341
|
+
* For information about this format, see RFC 5545, section 3.3.5
|
|
342
|
+
* https://tools.ietf.org/html/rfc5545#section-3.3.5
|
|
343
|
+
*/
|
|
344
|
+
export function formatDateTZ(
|
|
345
|
+
timezone: null | string,
|
|
346
|
+
property: string,
|
|
347
|
+
date: Date | ICalDateTimeValue | string,
|
|
348
|
+
eventData?: { floating?: boolean | null; timezone?: null | string },
|
|
349
|
+
): string {
|
|
350
|
+
let tzParam = '';
|
|
351
|
+
let floating = eventData?.floating || false;
|
|
322
352
|
|
|
323
|
-
|
|
324
|
-
|
|
353
|
+
if (eventData?.timezone) {
|
|
354
|
+
tzParam = ';TZID=' + eventData.timezone;
|
|
355
|
+
|
|
356
|
+
// This isn't a 'floating' event because it has a timezone;
|
|
357
|
+
// but we use it to omit the 'Z' UTC specifier in formatDate()
|
|
358
|
+
floating = true;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return (
|
|
362
|
+
property + tzParam + ':' + formatDate(timezone, date, false, floating)
|
|
363
|
+
);
|
|
325
364
|
}
|
|
326
|
-
|
|
327
|
-
|
|
365
|
+
|
|
366
|
+
export function generateCustomAttributes(data: {
|
|
367
|
+
x: [string, string][];
|
|
368
|
+
}): string {
|
|
369
|
+
const str = data.x
|
|
370
|
+
.map(([key, value]) => key.toUpperCase() + ':' + escape(value, false))
|
|
371
|
+
.join('\r\n');
|
|
372
|
+
return str.length ? str + '\r\n' : '';
|
|
328
373
|
}
|
|
374
|
+
|
|
329
375
|
export function isDayjs(value: ICalDateTimeValue): value is ICalDayJsStub {
|
|
330
|
-
return
|
|
376
|
+
return (
|
|
377
|
+
typeof value === 'object' &&
|
|
331
378
|
value !== null &&
|
|
332
379
|
!(value instanceof Date) &&
|
|
333
380
|
!isMoment(value) &&
|
|
334
|
-
!isLuxonDate(value)
|
|
335
|
-
|
|
336
|
-
export function isLuxonDate(value: ICalDateTimeValue): value is ICalLuxonDateTimeStub {
|
|
337
|
-
return typeof value === 'object' && value !== null && 'toJSDate' in value && typeof value.toJSDate === 'function';
|
|
381
|
+
!isLuxonDate(value)
|
|
382
|
+
);
|
|
338
383
|
}
|
|
339
384
|
|
|
340
|
-
export function
|
|
341
|
-
|
|
385
|
+
export function isLuxonDate(
|
|
386
|
+
value: ICalDateTimeValue,
|
|
387
|
+
): value is ICalLuxonDateTimeStub {
|
|
388
|
+
return (
|
|
389
|
+
typeof value === 'object' &&
|
|
390
|
+
value !== null &&
|
|
391
|
+
'toJSDate' in value &&
|
|
392
|
+
typeof value.toJSDate === 'function'
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
export function isMoment(value: ICalDateTimeValue): value is ICalMomentStub {
|
|
396
|
+
// @ts-expect-error _isAMomentObject is a private property
|
|
397
|
+
return value != null && value._isAMomentObject != null;
|
|
398
|
+
}
|
|
399
|
+
export function isMomentDuration(
|
|
400
|
+
value: unknown,
|
|
401
|
+
): value is ICalMomentDurationStub {
|
|
402
|
+
return (
|
|
403
|
+
value !== null &&
|
|
404
|
+
typeof value === 'object' &&
|
|
405
|
+
'asSeconds' in value &&
|
|
406
|
+
typeof value.asSeconds === 'function'
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
export function isMomentTZ(
|
|
410
|
+
value: ICalDateTimeValue,
|
|
411
|
+
): value is ICalMomentTimezoneStub {
|
|
412
|
+
return isMoment(value) && 'tz' in value && typeof value.tz === 'function';
|
|
342
413
|
}
|
|
343
414
|
|
|
344
415
|
export function isRRule(value: unknown): value is ICalRRuleStub {
|
|
345
|
-
return
|
|
416
|
+
return (
|
|
417
|
+
value !== null &&
|
|
418
|
+
typeof value === 'object' &&
|
|
419
|
+
'between' in value &&
|
|
420
|
+
typeof value.between === 'function' &&
|
|
421
|
+
typeof value.toString === 'function'
|
|
422
|
+
);
|
|
346
423
|
}
|
|
347
424
|
|
|
348
|
-
export function
|
|
349
|
-
if(
|
|
350
|
-
return
|
|
425
|
+
export function toDate(value: ICalDateTimeValue): Date {
|
|
426
|
+
if (typeof value === 'string' || value instanceof Date) {
|
|
427
|
+
return new Date(value);
|
|
351
428
|
}
|
|
352
|
-
|
|
353
|
-
|
|
429
|
+
|
|
430
|
+
if (isLuxonDate(value)) {
|
|
431
|
+
return value.toJSDate();
|
|
354
432
|
}
|
|
355
433
|
|
|
356
|
-
return value.
|
|
434
|
+
return value.toDate();
|
|
357
435
|
}
|
|
358
436
|
|
|
359
437
|
export function toDurationString(seconds: number): string {
|
|
360
438
|
let string = '';
|
|
361
439
|
|
|
362
440
|
// < 0
|
|
363
|
-
if(seconds < 0) {
|
|
441
|
+
if (seconds < 0) {
|
|
364
442
|
string = '-';
|
|
365
443
|
seconds *= -1;
|
|
366
444
|
}
|
|
@@ -368,35 +446,47 @@ export function toDurationString(seconds: number): string {
|
|
|
368
446
|
string += 'P';
|
|
369
447
|
|
|
370
448
|
// DAYS
|
|
371
|
-
if(seconds >= 86400) {
|
|
449
|
+
if (seconds >= 86400) {
|
|
372
450
|
string += Math.floor(seconds / 86400) + 'D';
|
|
373
451
|
seconds %= 86400;
|
|
374
452
|
}
|
|
375
|
-
if(!seconds && string.length > 1) {
|
|
453
|
+
if (!seconds && string.length > 1) {
|
|
376
454
|
return string;
|
|
377
455
|
}
|
|
378
456
|
|
|
379
457
|
string += 'T';
|
|
380
458
|
|
|
381
459
|
// HOURS
|
|
382
|
-
if(seconds >= 3600) {
|
|
460
|
+
if (seconds >= 3600) {
|
|
383
461
|
string += Math.floor(seconds / 3600) + 'H';
|
|
384
462
|
seconds %= 3600;
|
|
385
463
|
}
|
|
386
464
|
|
|
387
465
|
// MINUTES
|
|
388
|
-
if(seconds >= 60) {
|
|
466
|
+
if (seconds >= 60) {
|
|
389
467
|
string += Math.floor(seconds / 60) + 'M';
|
|
390
468
|
seconds %= 60;
|
|
391
469
|
}
|
|
392
470
|
|
|
393
471
|
// SECONDS
|
|
394
|
-
if(seconds > 0) {
|
|
472
|
+
if (seconds > 0) {
|
|
395
473
|
string += seconds + 'S';
|
|
396
|
-
}
|
|
397
|
-
else if(string.length <= 2) {
|
|
474
|
+
} else if (string.length <= 2) {
|
|
398
475
|
string += '0S';
|
|
399
476
|
}
|
|
400
477
|
|
|
401
478
|
return string;
|
|
402
479
|
}
|
|
480
|
+
|
|
481
|
+
export function toJSON(
|
|
482
|
+
value: ICalDateTimeValue | null | undefined,
|
|
483
|
+
): null | string | undefined {
|
|
484
|
+
if (!value) {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
if (typeof value === 'string') {
|
|
488
|
+
return value;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return value.toJSON();
|
|
492
|
+
}
|