@knime/utils 1.12.1 → 2.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/CHANGELOG.md +17 -0
- package/README.md +0 -9
- package/dist/index.js +947 -745
- package/dist/index.js.map +1 -1
- package/dist/test-utils/index.js +41 -38
- package/dist/test-utils/index.js.map +1 -1
- package/package.json +8 -17
- package/audit/README.md +0 -118
- package/audit/bulkAudit.js +0 -671
- package/audit/cli.js +0 -117
package/dist/index.js
CHANGED
|
@@ -1,755 +1,957 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import prettyBytes from
|
|
3
|
-
import DomPurify from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
};
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
1
|
+
import { getDate, getMonth, getYear, isAfter, isBefore, isValid, set } from "date-fns";
|
|
2
|
+
import prettyBytes from "pretty-bytes";
|
|
3
|
+
import DomPurify from "dompurify";
|
|
4
|
+
//#region \0rolldown/runtime.js
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __exportAll = (all, no_symbols) => {
|
|
7
|
+
let target = {};
|
|
8
|
+
for (var name in all) __defProp(target, name, {
|
|
9
|
+
get: all[name],
|
|
10
|
+
enumerable: true
|
|
11
|
+
});
|
|
12
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
return target;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/capitalize.ts
|
|
17
|
+
/**
|
|
18
|
+
* Uppercases first letter of string
|
|
19
|
+
* @param string to be capitalized first string, e.g. "workflow"
|
|
20
|
+
* @return Capitalized String, e.g. "Workflow"
|
|
21
|
+
*/
|
|
22
|
+
var capitalize = (input) => input.charAt(0).toUpperCase() + input.substring(1);
|
|
23
|
+
var formats = {
|
|
24
|
+
customFormat: (input, delimiter) => capitalize(input.replace(delimiter, " ").toLowerCase()),
|
|
25
|
+
kebabFormat: (input) => formats.customFormat(input, "-"),
|
|
26
|
+
snakeFormat: (input) => formats.customFormat(input, "_"),
|
|
27
|
+
camelPascalCase: (input) => capitalize((input.match(/([A-Z]?[^A-Z]*)/g) ?? []).slice(0, -1).join(" ").toLowerCase())
|
|
28
|
+
};
|
|
29
|
+
var caseFormatter = ({ string, delimiter, format }) => {
|
|
30
|
+
if (delimiter) return formats.customFormat(string, delimiter);
|
|
31
|
+
if (format) return formats[format](string, delimiter ?? "");
|
|
32
|
+
return capitalize(string);
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/updateDate.ts
|
|
36
|
+
/**
|
|
37
|
+
* Updates the date part (year, day and month) of a date object (base)
|
|
38
|
+
* time, offset (timezone) and so on will be left untouched.
|
|
39
|
+
*
|
|
40
|
+
* @param base - Date which will be used (copied) to set day, month and year.
|
|
41
|
+
* @param date - Extract day, month and year from this date object.
|
|
42
|
+
* @returns Copy of base with day, month and year of date.
|
|
43
|
+
*/
|
|
44
|
+
var updateDate_default = (base, date) => {
|
|
45
|
+
if (date) {
|
|
46
|
+
base = isValid(base) ? base : new Date(Date.UTC(0, 0));
|
|
47
|
+
return set(base, {
|
|
48
|
+
year: getYear(date),
|
|
49
|
+
month: getMonth(date),
|
|
50
|
+
date: getDate(date)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return base;
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/updateTime.ts
|
|
57
|
+
/**
|
|
58
|
+
* Updates the time part (hour, minute, second and millisecond) of a date object (base)
|
|
59
|
+
* date, offset (timezone) and so on will be left untouched.
|
|
60
|
+
*
|
|
61
|
+
* @param base - Date which will be used (copied) to set day, month and year.
|
|
62
|
+
* @param date - Extract hour, minute, second and millisecond from this date object.
|
|
63
|
+
* @returns Copy of base with hour, minute, second and millisecond changed.
|
|
64
|
+
*/
|
|
65
|
+
var updateTime_default = (base, date) => {
|
|
66
|
+
const d = new Date(base);
|
|
67
|
+
if (date) {
|
|
68
|
+
d.setHours(date.getHours());
|
|
69
|
+
d.setMinutes(date.getMinutes());
|
|
70
|
+
d.setSeconds(date.getSeconds());
|
|
71
|
+
d.setMilliseconds(date.getMilliseconds());
|
|
72
|
+
}
|
|
73
|
+
return d;
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/dateMinMaxCheck.ts
|
|
77
|
+
/**
|
|
78
|
+
* Check if date is before min.
|
|
79
|
+
* @param date
|
|
80
|
+
* @param min
|
|
81
|
+
* @param checkDate - check date part (year, day, month).
|
|
82
|
+
* @param checkTime - check time part (hour, minutes etc.).
|
|
83
|
+
* @returns whether limit is kept or not.
|
|
84
|
+
*/
|
|
85
|
+
var isBeforeMinDate = (date, min, checkDate, checkTime) => {
|
|
86
|
+
if (min) {
|
|
87
|
+
if (checkTime && checkDate) return isBefore(date, min);
|
|
88
|
+
if (checkTime) {
|
|
89
|
+
const base = /* @__PURE__ */ new Date(0);
|
|
90
|
+
return isBefore(updateTime_default(base, date), updateTime_default(base, min));
|
|
91
|
+
}
|
|
92
|
+
if (checkDate) {
|
|
93
|
+
const base = /* @__PURE__ */ new Date(0);
|
|
94
|
+
return isBefore(updateDate_default(base, date), updateDate_default(base, min));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Check
|
|
101
|
+
* @param date - date to check.
|
|
102
|
+
* @param max - maximum date.
|
|
103
|
+
* @param checkDate - check date part (year, day, month).
|
|
104
|
+
* @param checkTime - check time part (hour, minutes etc.).
|
|
105
|
+
* @returns whether limit is kept or not.
|
|
106
|
+
*/
|
|
107
|
+
var isAfterMaxDate = (date, max, checkDate, checkTime) => {
|
|
108
|
+
if (max) {
|
|
109
|
+
if (checkTime && checkDate) return isAfter(date, max);
|
|
110
|
+
if (checkTime) {
|
|
111
|
+
const base = /* @__PURE__ */ new Date(0);
|
|
112
|
+
return isAfter(updateTime_default(base, date), updateTime_default(base, max));
|
|
113
|
+
}
|
|
114
|
+
if (checkDate) {
|
|
115
|
+
const base = /* @__PURE__ */ new Date(0);
|
|
116
|
+
return isAfter(updateDate_default(base, date), updateDate_default(base, max));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/debounce.ts
|
|
123
|
+
var debounce = (callback, wait) => {
|
|
124
|
+
let timer;
|
|
125
|
+
let lastCall = 0;
|
|
126
|
+
return (...args) => {
|
|
127
|
+
const [value, index] = args;
|
|
128
|
+
clearTimeout(timer);
|
|
129
|
+
const now = Date.now();
|
|
130
|
+
if (now - lastCall > wait) {
|
|
131
|
+
lastCall = now;
|
|
132
|
+
callback(value, index);
|
|
133
|
+
} else timer = setTimeout(() => {
|
|
134
|
+
lastCall = now;
|
|
135
|
+
callback(value, index);
|
|
136
|
+
}, wait);
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
var filters = Object.assign({}, ...[
|
|
140
|
+
{
|
|
141
|
+
id: "search",
|
|
142
|
+
normalize(searchTerm, caseSensitiveSearch) {
|
|
143
|
+
return caseSensitiveSearch ? searchTerm : searchTerm.toLowerCase();
|
|
144
|
+
},
|
|
145
|
+
test(text, normalizedSearchTerm, caseSensitiveSearch, inverseSearch) {
|
|
146
|
+
const matches = (caseSensitiveSearch ? text : text.toLowerCase()).includes(normalizedSearchTerm);
|
|
147
|
+
return inverseSearch ? !matches : matches;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: "wildcard",
|
|
152
|
+
normalize(searchTerm, caseSensitiveSearch) {
|
|
153
|
+
if (searchTerm.length > 0) searchTerm = `^${searchTerm.replace(/[-[\]{}()+.,\\^$|#\s]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".?")}$`;
|
|
154
|
+
else return { test: () => false };
|
|
155
|
+
try {
|
|
156
|
+
return new RegExp(searchTerm, caseSensitiveSearch ? "" : "i");
|
|
157
|
+
} catch (_error) {
|
|
158
|
+
return /$^/;
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
test(text, normalizedSearchTerm, caseSensitiveSearch, inverseSearch) {
|
|
162
|
+
const matches = normalizedSearchTerm.test(text);
|
|
163
|
+
return inverseSearch ? !matches : matches;
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: "regex",
|
|
168
|
+
normalize(searchTerm, caseSensitiveSearch) {
|
|
169
|
+
try {
|
|
170
|
+
const flags = caseSensitiveSearch ? "" : "i";
|
|
171
|
+
return new RegExp(`^(${searchTerm})$`, flags);
|
|
172
|
+
} catch (_error) {
|
|
173
|
+
return /$^/;
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
test(text, normalizedSearchTerm, caseSensitiveSearch, inverseSearch) {
|
|
177
|
+
const matches = normalizedSearchTerm.test(text);
|
|
178
|
+
return inverseSearch ? !matches : matches;
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: "type",
|
|
183
|
+
normalize(selectedTypes) {
|
|
184
|
+
return { test: (type) => selectedTypes.includes(type) };
|
|
185
|
+
},
|
|
186
|
+
test(type, normalizedSearchTerm) {
|
|
187
|
+
if (typeof type === "undefined") return false;
|
|
188
|
+
return normalizedSearchTerm.test(type);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
].map((obj) => ({ [obj.id]: obj })));
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/localTimezone.ts
|
|
194
|
+
/**
|
|
195
|
+
* Get the users local timezone.
|
|
196
|
+
*
|
|
197
|
+
* @returns current users timezone (browser based) tz db string (e. g. Europe/Berlin).
|
|
198
|
+
*/
|
|
199
|
+
var localTimezone_default = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/format.ts
|
|
202
|
+
/**
|
|
203
|
+
* Converts the specified date String to human readable text containing the day, month, and year.
|
|
204
|
+
* Example: '2018-07-31T09:44:31+00:00' => 'Jul 31, 2018'
|
|
205
|
+
*
|
|
206
|
+
* @param dateString String representation of the Date to format
|
|
207
|
+
* @param useTimeZone to set the timeZone where the user is located, and display local date and time
|
|
208
|
+
* @returns human readable date String
|
|
209
|
+
*/
|
|
210
|
+
var formatDateString = (dateString, useTimeZone = false) => {
|
|
211
|
+
const date = new Date(dateString);
|
|
212
|
+
if (isNaN(date)) throw Error("Invalid Date format");
|
|
213
|
+
const baseDateOptions = {
|
|
214
|
+
day: "numeric",
|
|
215
|
+
month: "short",
|
|
216
|
+
year: "numeric"
|
|
217
|
+
};
|
|
218
|
+
const dateOptions = useTimeZone ? {
|
|
219
|
+
...baseDateOptions,
|
|
220
|
+
timeZone: localTimezone_default()
|
|
221
|
+
} : baseDateOptions;
|
|
222
|
+
return date.toLocaleDateString("en-US", dateOptions);
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Converts the specified time String to human readable text containing the hour (12-hour) and minute.
|
|
226
|
+
* Example: '2018-07-31T09:44:31+00:00' => '9:44 AM'
|
|
227
|
+
*
|
|
228
|
+
* @param timeString String representation of the Date (including time) to format
|
|
229
|
+
* @param useTimeZone to set the timeZone where the user is located, and display local date and time
|
|
230
|
+
* @returns human readable time String
|
|
231
|
+
*/
|
|
232
|
+
var formatTimeString = (timeString, useTimeZone = false) => {
|
|
233
|
+
const time = new Date(timeString);
|
|
234
|
+
if (isNaN(time)) throw Error("Invalid Date format");
|
|
235
|
+
const baseTimeOptions = {
|
|
236
|
+
hour: "numeric",
|
|
237
|
+
minute: "2-digit"
|
|
238
|
+
};
|
|
239
|
+
const timeOptions = useTimeZone ? {
|
|
240
|
+
...baseTimeOptions,
|
|
241
|
+
timeZone: localTimezone_default()
|
|
242
|
+
} : baseTimeOptions;
|
|
243
|
+
return time.toLocaleTimeString("en-US", timeOptions);
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Converts the specified time String to human readable text containing the date (day, month, year) and time (hour,
|
|
247
|
+
* minute; 12-hour).
|
|
248
|
+
* Example: '2018-07-31T09:44:31+00:00' => 'Jul 31, 2018 9:44 AM'
|
|
249
|
+
*
|
|
250
|
+
* @param dateTimeString String representation of the Date (including time and date) to format
|
|
251
|
+
* @param useTimeZone to set the timeZone where the user is located, and display local date and time
|
|
252
|
+
* @returns human readable date/time String
|
|
253
|
+
*/
|
|
254
|
+
var formatDateTimeString = (dateTimeString, useTimeZone = false) => {
|
|
255
|
+
return `${formatDateString(dateTimeString, useTimeZone)} ${formatTimeString(dateTimeString, useTimeZone)}`;
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* Converts the specified date and time to the user time zone with option to display (day, month, year) only or with time (hour,
|
|
259
|
+
* minute; 12-hour).
|
|
260
|
+
*
|
|
261
|
+
* @param showTime String representation of the Date to convert and format
|
|
262
|
+
* @param String | number} date String representation of the Date to convert and format
|
|
263
|
+
* @returns human readable date/time String converted to user time zone
|
|
264
|
+
*/
|
|
265
|
+
var formatLocalDateTimeString = (date, showTime) => showTime ? formatDateTimeString(date, true) : formatDateString(date, true);
|
|
266
|
+
var formatFileSize = (bytes) => {
|
|
267
|
+
return prettyBytes(Number.isFinite(bytes) && bytes >= 0 ? bytes : 0);
|
|
268
|
+
};
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region src/getDeepActiveElement.ts
|
|
271
|
+
var getDeepActiveElement = () => {
|
|
272
|
+
let element = document?.activeElement;
|
|
273
|
+
while (element?.shadowRoot) element = element?.shadowRoot?.activeElement;
|
|
274
|
+
return element;
|
|
275
|
+
};
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region src/getWrappedAroundIndex.ts
|
|
278
|
+
/**
|
|
279
|
+
* Since (a % b) yields a negative outcome for negative a, we need this method in order
|
|
280
|
+
* to correctly compute wrapped around indices in lists
|
|
281
|
+
* @param {number} index an arbitrary integer
|
|
282
|
+
* @param {number} length a positive integer
|
|
283
|
+
* @returns {number} the non-negative modulo outcome
|
|
284
|
+
*/
|
|
285
|
+
var getWrappedAroundIndex_default = (index, length) => (index % length + length) % length;
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/intervalUtils.ts
|
|
288
|
+
var intervalUtils_exports = /* @__PURE__ */ __exportAll({
|
|
289
|
+
formatIntervalToHumanReadableIntervalString: () => formatIntervalToHumanReadableIntervalString,
|
|
290
|
+
formatIntervalToISOIntervalString: () => formatIntervalToISOIntervalString,
|
|
291
|
+
isValidHumanReadableIntervalString: () => isValidHumanReadableIntervalString,
|
|
292
|
+
isValidISOIntervalString: () => isValidISOIntervalString,
|
|
293
|
+
isValidIntervalString: () => isValidIntervalString,
|
|
294
|
+
isZero: () => isZero,
|
|
295
|
+
parseGenericIntervalString: () => parseGenericIntervalString,
|
|
296
|
+
parseHumanReadableIntervalString: () => parseHumanReadableIntervalString,
|
|
297
|
+
parseISOIntervalString: () => parseISOIntervalString
|
|
298
|
+
});
|
|
299
|
+
var extractPeriodFromRegexMatch = (negative, match) => {
|
|
300
|
+
return {
|
|
301
|
+
negative,
|
|
302
|
+
years: parseInt(match[1] ?? "0", 10),
|
|
303
|
+
months: parseInt(match[2] ?? "0", 10),
|
|
304
|
+
weeks: parseInt(match[3] ?? "0", 10),
|
|
305
|
+
days: parseInt(match[4] ?? "0", 10)
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
var extractDurationFromRegexMatch = (negative, match) => {
|
|
309
|
+
const milliseconds = parseInt(match[4]?.padEnd(3, "0") ?? "0", 10);
|
|
310
|
+
return {
|
|
311
|
+
negative,
|
|
312
|
+
hours: parseInt(match[1] ?? "0", 10),
|
|
313
|
+
minutes: parseInt(match[2] ?? "0", 10),
|
|
314
|
+
seconds: parseInt(match[3] ?? "0", 10),
|
|
315
|
+
milliseconds
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
var isZero = (interval) => {
|
|
319
|
+
if (interval.type === "DATE") return interval.interval.years === 0 && interval.interval.months === 0 && interval.interval.weeks === 0 && interval.interval.days === 0;
|
|
320
|
+
else return interval.interval.hours === 0 && interval.interval.minutes === 0 && interval.interval.seconds === 0 && interval.interval.milliseconds === 0;
|
|
321
|
+
};
|
|
322
|
+
/**
|
|
323
|
+
* Take an interval object and convert it to an ISO duration or period string. All parts of the
|
|
324
|
+
* relevant part of the Interval object are included in the output, even if they are zero.
|
|
325
|
+
*
|
|
326
|
+
* Technically the ISO standard allows to mix period and duration parts, but we don't support that
|
|
327
|
+
* here because it's incredibly hard to deal with all the edge cases. Maybe in a future ticket.
|
|
328
|
+
*
|
|
329
|
+
* The output here is allowed to be negative, in which case the minus sign is prepended to the
|
|
330
|
+
* output.
|
|
331
|
+
*
|
|
332
|
+
* @param toFormat The PeriodOrDuration object to format
|
|
333
|
+
*/
|
|
334
|
+
var formatIntervalToISOIntervalString = (toFormat) => {
|
|
335
|
+
let output = "P";
|
|
336
|
+
if (toFormat.type === "DATE") output += `${toFormat.interval.years}Y${toFormat.interval.months}M${toFormat.interval.weeks}W${toFormat.interval.days}D`;
|
|
337
|
+
else output += `T${toFormat.interval.hours}H${toFormat.interval.minutes}M${toFormat.interval.seconds}.${toFormat.interval.milliseconds.toString().padStart(3, "0")}S`;
|
|
338
|
+
if (toFormat.interval.negative) output = `-${output}`;
|
|
339
|
+
return output;
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* Take an interval object and convert it to a human readable string. Only non-zero parts are
|
|
343
|
+
* included in the output (unless all parts are 0).
|
|
344
|
+
*
|
|
345
|
+
* The output here is allowed to be negative, in which case the minus sign is prepended to the
|
|
346
|
+
* output and we wrap the whole thing in brackets e.g. -(1 year 2 days).
|
|
347
|
+
*
|
|
348
|
+
* @param toFormat The PeriodOrDuration object to format
|
|
349
|
+
*/
|
|
350
|
+
var formatIntervalToHumanReadableIntervalString = (toFormat) => {
|
|
351
|
+
const formatPart = (value, unit) => {
|
|
352
|
+
if (value === 0) return "";
|
|
353
|
+
else if (value === 1) return `${value} ${unit} `;
|
|
354
|
+
else return `${value} ${unit}s `;
|
|
355
|
+
};
|
|
356
|
+
let output = "";
|
|
357
|
+
if (toFormat.type === "DATE") {
|
|
358
|
+
if (isZero(toFormat)) return "0 days";
|
|
359
|
+
output += formatPart(toFormat.interval.years, "year");
|
|
360
|
+
output += formatPart(toFormat.interval.months, "month");
|
|
361
|
+
output += formatPart(toFormat.interval.weeks, "week");
|
|
362
|
+
output += formatPart(toFormat.interval.days, "day");
|
|
363
|
+
} else {
|
|
364
|
+
if (isZero(toFormat)) return "0 seconds";
|
|
365
|
+
output += formatPart(toFormat.interval.hours, "hour");
|
|
366
|
+
output += formatPart(toFormat.interval.minutes, "minute");
|
|
367
|
+
const milliSecondsZero = toFormat.interval.milliseconds === 0;
|
|
368
|
+
if (toFormat.interval.seconds !== 0 || !milliSecondsZero) if (milliSecondsZero) output += formatPart(toFormat.interval.seconds, "second");
|
|
369
|
+
else output += `${toFormat.interval.seconds}.${toFormat.interval.milliseconds.toString().padStart(3, "0")} seconds `;
|
|
370
|
+
}
|
|
371
|
+
if (toFormat.interval.negative) output = `-(${output.trim()})`;
|
|
372
|
+
return output.trim();
|
|
373
|
+
};
|
|
374
|
+
var yearsPart = "(\\d+)\\s*y(?:ears?)?";
|
|
375
|
+
var monthsPart = "(\\d+)\\s*m(?:o(?:nths?)?)?";
|
|
376
|
+
var weeksPart = "(\\d+)\\s*w(?:eeks?)?";
|
|
377
|
+
var daysPart = "(\\d+)\\s*d(?:ays?)?";
|
|
378
|
+
var hoursPart = "(\\d+)\\s*h(?:ours?)?";
|
|
379
|
+
var minutesPart = "(\\d+)\\s*m(?:in(?:s|utes?)?)?";
|
|
380
|
+
var secondsPart = "(\\d+)(?:[,.](\\d{1,3}))?\\s*s(?:ec(?:s|onds?)?)?";
|
|
381
|
+
/**
|
|
382
|
+
* Matches a human readable period string, e.g. "1y 2mo 3weeks 4day" (each part is optional)
|
|
383
|
+
*/
|
|
384
|
+
var humanReadablePeriodRegex = new RegExp(`^(?:${yearsPart})?\\s*(?:${monthsPart})?\\s*(?:${weeksPart})?\\s*(?:${daysPart})?\\s*$`, "i");
|
|
385
|
+
/**
|
|
386
|
+
* Matches a human readable duration string, e.g. "1h 2m 3.456s" (each part is optional)
|
|
387
|
+
*/
|
|
388
|
+
var humanReadableDurationRegex = new RegExp(`^(?:${hoursPart})?\\s*(?:${minutesPart})?\\s*(?:${secondsPart})?$`, "i");
|
|
389
|
+
/**
|
|
390
|
+
* Matches a negative human readable period string, e.g. "-(1y 2mo 3weeks 4day)" (each part is optional)
|
|
391
|
+
*/
|
|
392
|
+
var negativeHumanReadablePeriodRegex = new RegExp(`^\\s*-\\s*\\(\\s*${humanReadablePeriodRegex.source.replace(/[$^]/g, "")}\\s*\\)\\s*$`, "i");
|
|
393
|
+
/**
|
|
394
|
+
* Matches a negative human readable period string with one field like "-1y" or "-1w"
|
|
395
|
+
*/
|
|
396
|
+
var negativeHumanReadablePeriodRegexWithSingleField = new RegExp(`^\\s*-\\s*(?:\\s*${yearsPart}|${monthsPart}|${weeksPart}|${daysPart})\\s*$`, "i");
|
|
397
|
+
/**
|
|
398
|
+
* Matches a negative human readable duration string, e.g. "-(1h 2m 3.456s)" (each part is optional)
|
|
399
|
+
*/
|
|
400
|
+
var negativeHumanReadableDurationRegex = new RegExp(`^\\s*-\\s*\\(\\s*${humanReadableDurationRegex.source.replace(/[$^]/g, "")}\\s*\\)\\s*$`, "i");
|
|
401
|
+
/**
|
|
402
|
+
* Matches a negative human readable duration string with one field like "-1h" or "-1.5s"
|
|
403
|
+
*/
|
|
404
|
+
var negativeHumanReadableDurationRegexWithSingleField = new RegExp(`^\\s*-\\s*(?:\\s*${hoursPart}|${minutesPart}|${secondsPart})\\s*$`, "i");
|
|
405
|
+
/**
|
|
406
|
+
* Try to parse a human readable interval string into an Interval object. Any parts not specified
|
|
407
|
+
* are assumed to be zero. Note that the string must be either a period or a duration, not a mix of
|
|
408
|
+
* both. So for example, "1y 2mo 3weeks 4day" is fine, as is "1h 2m 3.456s". However, "1y 2mo 1sec"
|
|
409
|
+
* is not, since it's a mix of both.
|
|
410
|
+
*
|
|
411
|
+
* Negative intervals are allowed, although if multiple fields are provided the string must include
|
|
412
|
+
* brackets, so "-(1y 2mo)" is also valid, as is "-5 seconds".
|
|
413
|
+
*
|
|
414
|
+
* The string is required to have at least some content, any string that is blank will throw an error.
|
|
415
|
+
*
|
|
416
|
+
* @param intervalString The human readable time string
|
|
417
|
+
*/
|
|
418
|
+
var parseHumanReadableIntervalString = (intervalString) => {
|
|
419
|
+
intervalString = intervalString?.trim();
|
|
420
|
+
if (!intervalString) throw new Error("Empty interval string");
|
|
421
|
+
const matchPositivePeriod = humanReadablePeriodRegex.exec(intervalString);
|
|
422
|
+
const matchNegativePeriod = negativeHumanReadablePeriodRegex.exec(intervalString) ?? negativeHumanReadablePeriodRegexWithSingleField.exec(intervalString);
|
|
423
|
+
const matchPositiveDuration = humanReadableDurationRegex.exec(intervalString);
|
|
424
|
+
const matchNegativeDuration = negativeHumanReadableDurationRegex.exec(intervalString) ?? negativeHumanReadableDurationRegexWithSingleField.exec(intervalString);
|
|
425
|
+
const matchPeriod = matchPositivePeriod ?? matchNegativePeriod;
|
|
426
|
+
const matchDuration = matchPositiveDuration ?? matchNegativeDuration;
|
|
427
|
+
const negative = (matchNegativePeriod ?? matchNegativeDuration) !== null;
|
|
428
|
+
if (matchDuration && matchPeriod) throw new Error("Ambiguous time format");
|
|
429
|
+
if (matchPeriod) return {
|
|
430
|
+
type: "DATE",
|
|
431
|
+
interval: extractPeriodFromRegexMatch(negative, matchPeriod)
|
|
432
|
+
};
|
|
433
|
+
else if (matchDuration) return {
|
|
434
|
+
type: "TIME",
|
|
435
|
+
interval: extractDurationFromRegexMatch(negative, matchDuration)
|
|
436
|
+
};
|
|
437
|
+
else throw new Error(`Invalid human readable time: ${intervalString}`);
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Check if the given string can be understood as a human readable duration or period string. The
|
|
441
|
+
* type parameter specifies whether the string should be a date, time, or either.
|
|
442
|
+
*
|
|
443
|
+
* @param time the string to check
|
|
444
|
+
* @param expectedType the type of the string - either "DATE", "TIME", or "ANY"
|
|
445
|
+
*/
|
|
446
|
+
var isValidHumanReadableIntervalString = (time, expectedType) => {
|
|
447
|
+
try {
|
|
448
|
+
const validationResult = parseHumanReadableIntervalString(time);
|
|
449
|
+
const actualType = validationResult.type;
|
|
450
|
+
const negative = validationResult.interval.negative;
|
|
451
|
+
if (actualType === expectedType || expectedType === "DATE_OR_TIME") return {
|
|
452
|
+
valid: true,
|
|
453
|
+
type: actualType,
|
|
454
|
+
negative
|
|
455
|
+
};
|
|
456
|
+
else return { valid: false };
|
|
457
|
+
} catch (_e) {
|
|
458
|
+
return { valid: false };
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
/**
|
|
462
|
+
* Convert an ISO duration OR period string to an Interval object. So for example,
|
|
463
|
+
* "P1Y2M3W4D" is fine, as is "PT1H2M3.456S". However, "P1Y2M3W4D1H2M3.456S" is not, since
|
|
464
|
+
* it's a mix of both. We're more forgiving than the ISO standard, so we allow for missing parts.
|
|
465
|
+
* Also, the string is allowed to be negative, so "-P1Y2M3W4D" is also valid.
|
|
466
|
+
*
|
|
467
|
+
* The string is required to have at least some content, so the strings "", "P", and "PT" are
|
|
468
|
+
* considered invalid (also if they start with a -).
|
|
469
|
+
*
|
|
470
|
+
* @param isoString The ISO duration or period string.
|
|
471
|
+
*/
|
|
472
|
+
var parseISOIntervalString = (isoString) => {
|
|
473
|
+
isoString = isoString?.trim();
|
|
474
|
+
if ([
|
|
475
|
+
"",
|
|
476
|
+
"P",
|
|
477
|
+
"PT",
|
|
478
|
+
"-",
|
|
479
|
+
"-P",
|
|
480
|
+
"-PT"
|
|
481
|
+
].includes(isoString)) throw new Error("Empty ISO duration");
|
|
482
|
+
const periodRegex = /^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?$/;
|
|
483
|
+
const durationRegex = /^-?PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:[,.](\d{1,3}))?S)?$/;
|
|
484
|
+
const matchPeriod = periodRegex.exec(isoString);
|
|
485
|
+
const matchDuration = durationRegex.exec(isoString);
|
|
486
|
+
if (matchPeriod) return {
|
|
487
|
+
type: "DATE",
|
|
488
|
+
interval: extractPeriodFromRegexMatch(isoString.startsWith("-"), matchPeriod)
|
|
489
|
+
};
|
|
490
|
+
else if (matchDuration) return {
|
|
491
|
+
type: "TIME",
|
|
492
|
+
interval: extractDurationFromRegexMatch(isoString.startsWith("-"), matchDuration)
|
|
493
|
+
};
|
|
494
|
+
else throw new Error(`Invalid ISO duration: ${isoString}`);
|
|
495
|
+
};
|
|
496
|
+
/**
|
|
497
|
+
* Check if the given string is a valid duration or period ISO string. The type parameter
|
|
498
|
+
* specifies whether the string should be a date, time, or either.
|
|
499
|
+
*
|
|
500
|
+
* @param isoString the string to check
|
|
501
|
+
* @param type the type of the string - either "DATE", "TIME", or "ANY"
|
|
502
|
+
*/
|
|
503
|
+
var isValidISOIntervalString = (isoString, type) => {
|
|
504
|
+
try {
|
|
505
|
+
const validationResult = parseISOIntervalString(isoString);
|
|
506
|
+
const actualType = validationResult.type;
|
|
507
|
+
const negative = validationResult.interval.negative;
|
|
508
|
+
if (actualType === type || type === "DATE_OR_TIME") return {
|
|
509
|
+
valid: true,
|
|
510
|
+
type: actualType,
|
|
511
|
+
negative
|
|
512
|
+
};
|
|
513
|
+
else return { valid: false };
|
|
514
|
+
} catch (_e) {
|
|
515
|
+
return { valid: false };
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
/**
|
|
519
|
+
* Try to convert an interval string to an Interval object. The string can be either an ISO
|
|
520
|
+
* duration/period string or a human readable string. If the string is not valid, an error is
|
|
521
|
+
* thrown.
|
|
522
|
+
*
|
|
523
|
+
* @param time the time string, either ISO or human readable
|
|
524
|
+
*/
|
|
525
|
+
var parseGenericIntervalString = (time) => {
|
|
526
|
+
const validISO = isValidISOIntervalString(time, "DATE_OR_TIME");
|
|
527
|
+
const validHumanReadable = isValidHumanReadableIntervalString(time, "DATE_OR_TIME");
|
|
528
|
+
if (validISO.valid) return parseISOIntervalString(time);
|
|
529
|
+
else if (validHumanReadable.valid) return parseHumanReadableIntervalString(time);
|
|
530
|
+
else throw new Error(`Invalid interval string: ${time}`);
|
|
531
|
+
};
|
|
532
|
+
/**
|
|
533
|
+
* Check if the given string is a valid interval string, either human readable or ISO. The type parameter
|
|
534
|
+
* specifies whether the string should be a period, duration, or either.
|
|
535
|
+
*
|
|
536
|
+
* @param time the time string to check
|
|
537
|
+
* @param type the type of the string - either "DATE", "TIME", or "ANY"
|
|
538
|
+
*/
|
|
539
|
+
var isValidIntervalString = (time, type) => {
|
|
540
|
+
const validISO = isValidISOIntervalString(time, type);
|
|
541
|
+
const validHumanReadable = isValidHumanReadableIntervalString(time, type);
|
|
542
|
+
if (validISO.valid) return validISO;
|
|
543
|
+
else if (validHumanReadable.valid) return validHumanReadable;
|
|
544
|
+
else return { valid: false };
|
|
545
|
+
};
|
|
546
|
+
//#endregion
|
|
547
|
+
//#region src/numIntegerDigits.ts
|
|
548
|
+
/**
|
|
549
|
+
* Count the number of integer digits for a given number.
|
|
550
|
+
*
|
|
551
|
+
* @param input number.
|
|
552
|
+
* @returns number of integer digits x has. 1234 = 4 but 1234.44 is also 4.
|
|
553
|
+
*/
|
|
554
|
+
var numIntegerDigits_default = (input) => Math.max(Math.floor(Math.log10(Math.abs(input))), 0) + 1;
|
|
555
|
+
//#endregion
|
|
556
|
+
//#region src/promise/createAbortablePromise.ts
|
|
557
|
+
var AbortError = class extends Error {};
|
|
558
|
+
/**
|
|
559
|
+
* Helper to create an abortable promise. Returns an AbortController and a Function
|
|
560
|
+
* that you can pass your async handler to. Whenever the AbortController signal is
|
|
561
|
+
* aborted then the async handler's promise will reject with an AbortError
|
|
562
|
+
*
|
|
563
|
+
* Example:
|
|
564
|
+
* ```
|
|
565
|
+
* import { abortUtils } from "@knime/utils"
|
|
566
|
+
* const myFetchCall = async (params...) => {...};
|
|
567
|
+
*
|
|
568
|
+
* try {
|
|
569
|
+
* const { runAbortablePromise, abortController } = createAbortablePromise(() =>
|
|
570
|
+
* myFetchCall(params...),
|
|
571
|
+
* );
|
|
572
|
+
* } catch (e) {
|
|
573
|
+
* if (e instanceof abortUtils.AbortError) {
|
|
574
|
+
* console.info('ignore due to abort');
|
|
575
|
+
* return;
|
|
576
|
+
* }
|
|
577
|
+
* }
|
|
578
|
+
*
|
|
579
|
+
* // somewhere else (while request is in-flight)
|
|
580
|
+
* abortController.abort(new abortUtils.AbortError('reason here'))
|
|
581
|
+
* ```
|
|
582
|
+
*/
|
|
583
|
+
var createAbortablePromise = () => {
|
|
584
|
+
const abortController = new AbortController();
|
|
585
|
+
const runAbortablePromise = (request) => {
|
|
586
|
+
return new Promise((resolve, reject) => {
|
|
587
|
+
const abortListener = ({ target }) => {
|
|
588
|
+
abortController.signal.removeEventListener("abort", abortListener);
|
|
589
|
+
const reason = target.reason;
|
|
590
|
+
reject(reason instanceof AbortError ? reason : new AbortError(reason));
|
|
591
|
+
};
|
|
592
|
+
request().then(resolve).catch((error) => {
|
|
593
|
+
if (error instanceof AbortError) return;
|
|
594
|
+
reject(error);
|
|
595
|
+
});
|
|
596
|
+
abortController.signal.addEventListener("abort", abortListener);
|
|
597
|
+
});
|
|
598
|
+
};
|
|
599
|
+
return {
|
|
600
|
+
abortController,
|
|
601
|
+
runAbortablePromise
|
|
602
|
+
};
|
|
603
|
+
};
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/promise/createUnwrappedPromise.ts
|
|
606
|
+
var createUnwrappedPromise = () => {
|
|
607
|
+
let resolve = () => {};
|
|
608
|
+
let reject = () => {};
|
|
609
|
+
const promise = new Promise((res, rej) => {
|
|
610
|
+
resolve = res;
|
|
611
|
+
reject = rej;
|
|
612
|
+
});
|
|
613
|
+
return {
|
|
614
|
+
resolve,
|
|
615
|
+
reject,
|
|
616
|
+
promise
|
|
617
|
+
};
|
|
618
|
+
};
|
|
619
|
+
//#endregion
|
|
620
|
+
//#region src/sleep.ts
|
|
621
|
+
/**
|
|
622
|
+
* Returns promise that resolves after ms.
|
|
623
|
+
*/
|
|
498
624
|
function sleep(ms) {
|
|
499
|
-
|
|
625
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
500
626
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
}
|
|
525
|
-
throw error;
|
|
526
|
-
}
|
|
627
|
+
/**
|
|
628
|
+
* Helper to add retry capability to an async function
|
|
629
|
+
* @param fn async function
|
|
630
|
+
* @param retryCount max number of retries. defaults to 5
|
|
631
|
+
* @param retryDelayMS delay in-between retries in millisecs. defaults to 0
|
|
632
|
+
* @param excludeError predicate fn to exclude specific errors from causing a retry
|
|
633
|
+
*/
|
|
634
|
+
async function retryPromise({ fn, retryCount = 5, retryDelayMS = 0, excludeError }) {
|
|
635
|
+
try {
|
|
636
|
+
return await fn();
|
|
637
|
+
} catch (error) {
|
|
638
|
+
if (excludeError?.(error)) throw error;
|
|
639
|
+
if (retryCount > 0) {
|
|
640
|
+
await sleep(retryDelayMS);
|
|
641
|
+
return await retryPromise({
|
|
642
|
+
fn,
|
|
643
|
+
retryCount: retryCount - 1,
|
|
644
|
+
retryDelayMS,
|
|
645
|
+
excludeError
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
throw error;
|
|
649
|
+
}
|
|
527
650
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/promise/index.ts
|
|
653
|
+
var promise_exports = /* @__PURE__ */ __exportAll({
|
|
654
|
+
AbortError: () => AbortError,
|
|
655
|
+
DEFAULT_RETRY_COUNT: () => 5,
|
|
656
|
+
DEFAULT_RETRY_DELAY_MS: () => 0,
|
|
657
|
+
createAbortablePromise: () => createAbortablePromise,
|
|
658
|
+
createUnwrappedPromise: () => createUnwrappedPromise,
|
|
659
|
+
retryPromise: () => retryPromise
|
|
660
|
+
});
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/sanitization.ts
|
|
663
|
+
var ALLOWED_TAGS = [
|
|
664
|
+
"p",
|
|
665
|
+
"div",
|
|
666
|
+
"h1",
|
|
667
|
+
"h2",
|
|
668
|
+
"h3",
|
|
669
|
+
"h4",
|
|
670
|
+
"h5",
|
|
671
|
+
"h6",
|
|
672
|
+
"ul",
|
|
673
|
+
"ol",
|
|
674
|
+
"li",
|
|
675
|
+
"blockquote",
|
|
676
|
+
"b",
|
|
677
|
+
"i",
|
|
678
|
+
"s",
|
|
679
|
+
"u",
|
|
680
|
+
"sup",
|
|
681
|
+
"sub",
|
|
682
|
+
"ins",
|
|
683
|
+
"del",
|
|
684
|
+
"strong",
|
|
685
|
+
"strike",
|
|
686
|
+
"tt",
|
|
687
|
+
"code",
|
|
688
|
+
"big",
|
|
689
|
+
"small",
|
|
690
|
+
"br",
|
|
691
|
+
"span",
|
|
692
|
+
"em"
|
|
569
693
|
];
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
694
|
+
/**
|
|
695
|
+
* Sanitizes Raw HTML and only allow specific tags to be used, as per OWASP standards.
|
|
696
|
+
* @param rawHTML
|
|
697
|
+
* @param options.allowStyleAttribute - Allow the style attribute on elements
|
|
698
|
+
* @param options.allowHyperlinks - Allow anchor tags with href attribute
|
|
699
|
+
* @returns sanitized html
|
|
700
|
+
*/
|
|
701
|
+
var sanitizeHTML = (rawHTML, options = {
|
|
702
|
+
allowStyleAttribute: false,
|
|
703
|
+
allowHyperlinks: false
|
|
573
704
|
}) => {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
705
|
+
const { allowStyleAttribute, allowHyperlinks } = options;
|
|
706
|
+
const ALLOWED_ATTR = [...allowStyleAttribute ? ["style"] : [], ...allowHyperlinks ? ["href"] : []];
|
|
707
|
+
const allowedTags = allowHyperlinks ? [...ALLOWED_TAGS, "a"] : ALLOWED_TAGS;
|
|
708
|
+
return DomPurify.sanitize(rawHTML, {
|
|
709
|
+
ALLOWED_TAGS: allowedTags,
|
|
710
|
+
ALLOWED_ATTR
|
|
711
|
+
});
|
|
712
|
+
};
|
|
713
|
+
/**
|
|
714
|
+
* Removes any HTML tag from the input string. Keeps HTML entities
|
|
715
|
+
* (e.g because these can be considered plain text)
|
|
716
|
+
* @param rawHTML
|
|
717
|
+
* @returns plain text
|
|
718
|
+
*/
|
|
719
|
+
var stripHTML = (rawHTML) => {
|
|
720
|
+
return DomPurify.sanitize(rawHTML, {
|
|
721
|
+
ALLOWED_TAGS: [],
|
|
722
|
+
ALLOWED_ATTR: []
|
|
723
|
+
});
|
|
724
|
+
};
|
|
725
|
+
var sanitization = {
|
|
726
|
+
sanitizeHTML,
|
|
727
|
+
stripHTML
|
|
728
|
+
};
|
|
729
|
+
//#endregion
|
|
730
|
+
//#region src/truncateString.ts
|
|
731
|
+
var defaultMaxLength = 160;
|
|
732
|
+
var truncateString_default = (string = "", maxLength = defaultMaxLength) => {
|
|
733
|
+
const dots = string.length > maxLength ? "…" : "";
|
|
734
|
+
return `${string.substring(0, maxLength - 1)}${dots}`;
|
|
735
|
+
};
|
|
736
|
+
//#endregion
|
|
737
|
+
//#region src/fileExtensions.ts
|
|
738
|
+
/**
|
|
739
|
+
* Gets the file extension
|
|
740
|
+
* @param nameOrPath can take a full file name (e.g "file.txt") or a path to a file
|
|
741
|
+
* (e.g "file://path/to/file.txt" OR "/path/to/file.txt")
|
|
742
|
+
* @returns just the file extension (e.g "txt")
|
|
743
|
+
*/
|
|
744
|
+
var getFileExtension = (nameOrPath) => {
|
|
745
|
+
const basename = nameOrPath.split(/[\\/]/).pop() ?? "";
|
|
746
|
+
const parts = basename.split(".");
|
|
747
|
+
if (basename === "" || parts.length === 1) return "";
|
|
748
|
+
return parts.at(-1) ?? "";
|
|
749
|
+
};
|
|
750
|
+
/**
|
|
751
|
+
* Metadata for .knar files, which corresponds to exported KNIME Workflow Groups
|
|
752
|
+
* or Components
|
|
753
|
+
*/
|
|
754
|
+
var KNAR = Object.freeze({
|
|
755
|
+
extension: "knar",
|
|
756
|
+
mimeType: "application/vnd.knime.workflow-group+zip",
|
|
757
|
+
matches(file) {
|
|
758
|
+
return getFileExtension(file.name) === this.extension;
|
|
759
|
+
}
|
|
611
760
|
});
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
761
|
+
/**
|
|
762
|
+
* Metadata for .knwf files, which corresponds to exported KNIME Workflows
|
|
763
|
+
*/
|
|
764
|
+
var KNWF = Object.freeze({
|
|
765
|
+
extension: "knwf",
|
|
766
|
+
mimeType: "application/vnd.knime.workflow+zip",
|
|
767
|
+
matches(file) {
|
|
768
|
+
return getFileExtension(file.name) === this.extension;
|
|
769
|
+
},
|
|
770
|
+
/**
|
|
771
|
+
* Gets the name of a .knwf file without the extension. If the file is not
|
|
772
|
+
* matched as a .knwf file then this function will return the default value,
|
|
773
|
+
* which is empty string ("") if param is not provided
|
|
774
|
+
*/
|
|
775
|
+
getNameOrDefault(file, defaultValue = "") {
|
|
776
|
+
if (!this.matches(file)) return defaultValue;
|
|
777
|
+
return file.name.replace(`.${this.extension}`, "");
|
|
778
|
+
}
|
|
630
779
|
});
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
};
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
780
|
+
var knimeFileFormats = {
|
|
781
|
+
KNAR,
|
|
782
|
+
KNWF
|
|
783
|
+
};
|
|
784
|
+
/**
|
|
785
|
+
* Gets the mime type from a given file. Defaults to `application/octet-stream`
|
|
786
|
+
* if mimeType cannot be detected
|
|
787
|
+
* @param file File
|
|
788
|
+
* @returns mimeType
|
|
789
|
+
*/
|
|
790
|
+
var getFileMimeType = (file) => {
|
|
791
|
+
const DEFAULT_MIMETYPE = "application/octet-stream";
|
|
792
|
+
if (!getFileExtension(file.name)) return DEFAULT_MIMETYPE;
|
|
793
|
+
if (KNWF.matches(file)) return KNWF.mimeType;
|
|
794
|
+
if (KNAR.matches(file)) return KNAR.mimeType;
|
|
795
|
+
if (!file.type) return DEFAULT_MIMETYPE;
|
|
796
|
+
return file.type;
|
|
797
|
+
};
|
|
798
|
+
//#endregion
|
|
799
|
+
//#region src/hotkeys/enums.ts
|
|
800
|
+
/**
|
|
801
|
+
* Platforms that influence how modifier keys are rendered. macOS substitutes
|
|
802
|
+
* dedicated glyphs (`⌘`, `⌥`, `⇧`, …), every other platform uses the textual
|
|
803
|
+
* rendering (`Ctrl`, `Alt`, `Shift`, …).
|
|
804
|
+
*/
|
|
805
|
+
var hotkeyPlatform = {
|
|
806
|
+
MAC_OS: "macOS",
|
|
807
|
+
OTHER: "other"
|
|
653
808
|
};
|
|
654
809
|
Object.values(hotkeyPlatform);
|
|
810
|
+
//#endregion
|
|
811
|
+
//#region src/platform/navigator.ts
|
|
812
|
+
var navigator_exports = /* @__PURE__ */ __exportAll({
|
|
813
|
+
isMac: () => isMac,
|
|
814
|
+
isWindows: () => isWindows
|
|
815
|
+
});
|
|
816
|
+
/**
|
|
817
|
+
*
|
|
818
|
+
* @returns true if the platform of the user is Mac
|
|
819
|
+
*/
|
|
820
|
+
var isMac = () => navigator?.userAgent?.toLowerCase()?.includes("mac");
|
|
821
|
+
/**
|
|
822
|
+
*
|
|
823
|
+
* @returns true if the platform of the user is Windows
|
|
824
|
+
*/
|
|
825
|
+
var isWindows = () => navigator?.userAgent?.toLowerCase()?.includes("windows");
|
|
826
|
+
//#endregion
|
|
827
|
+
//#region src/hotkeys/format.ts
|
|
828
|
+
var globalKeyMap = {
|
|
829
|
+
ArrowUp: "↑",
|
|
830
|
+
ArrowDown: "↓",
|
|
831
|
+
ArrowLeft: "←",
|
|
832
|
+
ArrowRight: "→",
|
|
833
|
+
Enter: "↵",
|
|
834
|
+
" ": "Space",
|
|
835
|
+
CtrlOrCmd: "Ctrl"
|
|
836
|
+
};
|
|
837
|
+
var MacOSkeyMap = {
|
|
838
|
+
Shift: "⇧",
|
|
839
|
+
Delete: "⌫",
|
|
840
|
+
CtrlOrCmd: "⌘",
|
|
841
|
+
Ctrl: "⌃",
|
|
842
|
+
Alt: "⌥",
|
|
843
|
+
Enter: "↩"
|
|
844
|
+
};
|
|
845
|
+
/**
|
|
846
|
+
* Returns a string representation of a single hotkey. Replaces some special key names with symbols.
|
|
847
|
+
*
|
|
848
|
+
* By default the platform is auto-detected from the user agent via `isMac()`.
|
|
849
|
+
* Pass `platform` to force a specific platform's glyphs — useful for SSR,
|
|
850
|
+
* tests, or rendering multiple platforms on the same page.
|
|
851
|
+
*/
|
|
852
|
+
var formatHotkey = (hotkey, platform) => {
|
|
853
|
+
/**
|
|
854
|
+
* Returns the symbol corresponding to the `key` based on the given
|
|
855
|
+
* `formatMap`. Otherwise, if not found, returns the same `key` value given
|
|
856
|
+
*/
|
|
857
|
+
const mapSymbols = (formatMap) => (key) => formatMap[key] ?? key;
|
|
858
|
+
/**
|
|
859
|
+
* Pipe function implementation. Receives a list of functions to execute in order
|
|
860
|
+
* and will pipe the parameter passed at the end to each function returning the final output
|
|
861
|
+
*/
|
|
862
|
+
const pipe = (...fns) => fns.reduce((f, g) => (arg) => g(f(arg)), (arg) => arg);
|
|
863
|
+
const macKeyFormatter = pipe(mapSymbols(MacOSkeyMap), mapSymbols(globalKeyMap));
|
|
864
|
+
const generalKeyFormatter = mapSymbols(globalKeyMap);
|
|
865
|
+
return (platform === void 0 ? isMac() : platform === hotkeyPlatform.MAC_OS) ? macKeyFormatter(hotkey) : generalKeyFormatter(hotkey);
|
|
866
|
+
};
|
|
867
|
+
var getDefaultSeparator = () => isMac() ? " " : "+";
|
|
868
|
+
/**
|
|
869
|
+
* Returns a string representation of a list of hotkeys. Replaces some special key names with symbols
|
|
870
|
+
*/
|
|
871
|
+
var formatHotkeys = (hotkeys, getSeparator = getDefaultSeparator) => hotkeys.map((hotkey) => formatHotkey(hotkey)).join(getSeparator());
|
|
872
|
+
/**
|
|
873
|
+
* Appends a formatted hotkey shortcut to the given string. Useful for tooltips
|
|
874
|
+
*/
|
|
875
|
+
var textWithHotkeys = (text, hotkeys) => {
|
|
876
|
+
return `${text} – ${formatHotkeys(hotkeys)}`;
|
|
877
|
+
};
|
|
878
|
+
//#endregion
|
|
879
|
+
//#region src/hotkeys/match.ts
|
|
880
|
+
/**
|
|
881
|
+
* Checks whether a pressed `Digit` key falls within a numeric hotkey range such
|
|
882
|
+
* as `1-9`.
|
|
883
|
+
* @param keyCode - The `KeyboardEvent.code` to check (e.g. `Digit5`).
|
|
884
|
+
* @param hotkey - The hotkey token, expected to be a single-digit range like `1-9`.
|
|
885
|
+
* @returns True if the pressed digit lies within the inclusive range.
|
|
886
|
+
*/
|
|
887
|
+
var isDigitKeyInRange = (keyCode, hotkey) => {
|
|
888
|
+
if (hotkey.length !== 3 || !keyCode?.startsWith("Digit")) return false;
|
|
889
|
+
const keyNumber = Number(keyCode.slice(5));
|
|
890
|
+
const [lower, upper] = hotkey.split("-");
|
|
891
|
+
return Boolean(lower) && Boolean(upper) && Number.parseInt(lower, 10) <= keyNumber && keyNumber <= Number.parseInt(upper, 10);
|
|
892
|
+
};
|
|
893
|
+
/**
|
|
894
|
+
* Checks whether a keyboard event matches a hotkey definition. The last token is
|
|
895
|
+
* treated as the character; any preceding tokens are modifiers. The special
|
|
896
|
+
* `CtrlOrCmd` modifier resolves to the platform's primary modifier (Meta/`⌘` on
|
|
897
|
+
* macOS, Ctrl elsewhere).
|
|
898
|
+
* @param event - The keyboard event to check.
|
|
899
|
+
* @param hotkeys - The ordered hotkey tokens (modifiers followed by the character).
|
|
900
|
+
* @returns True if the event matches the given hotkey, otherwise false.
|
|
901
|
+
*/
|
|
902
|
+
var match = (event, hotkeys) => {
|
|
903
|
+
const { key, code, metaKey, ctrlKey, shiftKey, altKey } = event;
|
|
904
|
+
const modifiers = hotkeys.slice();
|
|
905
|
+
const character = modifiers.pop() ?? "";
|
|
906
|
+
const ctrlOrMeta = isMac() ? "Meta" : "Ctrl";
|
|
907
|
+
const platformModifiers = new Set(modifiers.map((modifier) => modifier === "CtrlOrCmd" ? ctrlOrMeta : modifier));
|
|
908
|
+
const metaMatches = Boolean(metaKey) === platformModifiers.has("Meta");
|
|
909
|
+
const ctrlMatches = Boolean(ctrlKey) === platformModifiers.has("Ctrl");
|
|
910
|
+
const shiftMatches = Boolean(shiftKey) === platformModifiers.has("Shift");
|
|
911
|
+
const altMatches = Boolean(altKey) === platformModifiers.has("Alt");
|
|
912
|
+
const keysMatch = key.toUpperCase() === character.toUpperCase() || character.includes("-") && isDigitKeyInRange(code, character) || isMac() && character === "Delete" && key === "Backspace";
|
|
913
|
+
return metaMatches && ctrlMatches && shiftMatches && altMatches && keysMatch;
|
|
914
|
+
};
|
|
915
|
+
//#endregion
|
|
916
|
+
//#region src/hotkeys/modifiers.ts
|
|
917
|
+
/**
|
|
918
|
+
* Checks if any modifier key (Ctrl, Meta, Alt, or Shift) is pressed.
|
|
919
|
+
* @param event - The keyboard event to check.
|
|
920
|
+
* @returns True if a modifier key is pressed, otherwise false.
|
|
921
|
+
*/
|
|
922
|
+
var isModifierKeyPressed = (event) => {
|
|
923
|
+
return event.ctrlKey || event.metaKey || event.altKey || event.shiftKey;
|
|
924
|
+
};
|
|
925
|
+
/**
|
|
926
|
+
* Checks if a specific key (or keys) were pressed without any modifier keys.
|
|
927
|
+
* @param event - The keyboard event to check.
|
|
928
|
+
* @param keys - The key or keys to check for.
|
|
929
|
+
* @returns True if the specified key(s) were pressed without modifiers, otherwise false.
|
|
930
|
+
*/
|
|
931
|
+
var isKeyWithoutModifiers = (event, keys) => {
|
|
932
|
+
return (Array.isArray(keys) ? keys : [keys]).includes(event.key) && !isModifierKeyPressed(event);
|
|
933
|
+
};
|
|
934
|
+
/**
|
|
935
|
+
* Returns the name of the primary modifier key for the current platform.
|
|
936
|
+
*/
|
|
937
|
+
var getMetaOrCtrlKey = () => {
|
|
938
|
+
return isMac() ? "metaKey" : "ctrlKey";
|
|
939
|
+
};
|
|
940
|
+
//#endregion
|
|
941
|
+
//#region src/hotkeys/index.ts
|
|
942
|
+
/**
|
|
943
|
+
* Grouped keyboard-shortcut helpers, exposed as a single namespace for
|
|
944
|
+
* ergonomic access (e.g. `hotkeys.formatHotkey`).
|
|
945
|
+
*/
|
|
946
|
+
var hotkeys = {
|
|
947
|
+
formatHotkeys,
|
|
948
|
+
formatHotkey,
|
|
949
|
+
getDefaultSeparator,
|
|
950
|
+
hotkeyPlatform,
|
|
951
|
+
textWithHotkeys,
|
|
952
|
+
match
|
|
953
|
+
};
|
|
954
|
+
//#endregion
|
|
955
|
+
export { capitalize, caseFormatter, debounce, filters, formatDateString, formatDateTimeString, formatFileSize, formatLocalDateTimeString, formatTimeString, getDeepActiveElement, getFileExtension, getFileMimeType, localTimezone_default as getLocalTimeZone, getMetaOrCtrlKey, getWrappedAroundIndex_default as getWrappedAroundIndex, hotkeys, intervalUtils_exports as intervalUtils, isAfterMaxDate, isBeforeMinDate, isKeyWithoutModifiers, isModifierKeyPressed, knimeFileFormats, match, navigator_exports as navigatorUtils, numIntegerDigits_default as numIntegerDigits, promise_exports as promise, sanitization, sleep, truncateString_default as truncateString, updateDate_default as updateDate, updateTime_default as updateTime };
|
|
655
956
|
|
|
656
|
-
|
|
657
|
-
const isWindows = () => navigator?.userAgent?.toLowerCase()?.includes("windows");
|
|
658
|
-
|
|
659
|
-
const navigator$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
660
|
-
__proto__: null,
|
|
661
|
-
isMac,
|
|
662
|
-
isWindows
|
|
663
|
-
}, Symbol.toStringTag, { value: 'Module' }));
|
|
664
|
-
|
|
665
|
-
const globalKeyMap = {
|
|
666
|
-
ArrowUp: "↑",
|
|
667
|
-
ArrowDown: "↓",
|
|
668
|
-
ArrowLeft: "←",
|
|
669
|
-
ArrowRight: "→",
|
|
670
|
-
Enter: "↵",
|
|
671
|
-
" ": "Space",
|
|
672
|
-
// we use event.key and there space is an actual space not the code "Space"
|
|
673
|
-
CtrlOrCmd: "Ctrl"
|
|
674
|
-
};
|
|
675
|
-
const MacOSkeyMap = {
|
|
676
|
-
Shift: "⇧",
|
|
677
|
-
Delete: "⌫",
|
|
678
|
-
CtrlOrCmd: "⌘",
|
|
679
|
-
Ctrl: "⌃",
|
|
680
|
-
Alt: "⌥",
|
|
681
|
-
Enter: "↩"
|
|
682
|
-
};
|
|
683
|
-
const formatHotkey = (hotkey, platform) => {
|
|
684
|
-
const mapSymbols = (formatMap) => (key) => formatMap[key] ?? key;
|
|
685
|
-
const pipe = (...fns) => fns.reduce(
|
|
686
|
-
(f, g) => (arg) => g(f(arg)),
|
|
687
|
-
(arg) => arg
|
|
688
|
-
);
|
|
689
|
-
const macKeyFormatter = pipe(
|
|
690
|
-
mapSymbols(MacOSkeyMap),
|
|
691
|
-
mapSymbols(globalKeyMap)
|
|
692
|
-
);
|
|
693
|
-
const generalKeyFormatter = mapSymbols(globalKeyMap);
|
|
694
|
-
const useMacFormatter = platform === void 0 ? isMac() : platform === hotkeyPlatform.MAC_OS;
|
|
695
|
-
return useMacFormatter ? macKeyFormatter(hotkey) : generalKeyFormatter(hotkey);
|
|
696
|
-
};
|
|
697
|
-
const getDefaultSeparator = () => isMac() ? " " : "+";
|
|
698
|
-
const formatHotkeys = (hotkeys, getSeparator = getDefaultSeparator) => hotkeys.map((hotkey) => formatHotkey(hotkey)).join(getSeparator());
|
|
699
|
-
const textWithHotkeys = (text, hotkeys) => {
|
|
700
|
-
return `${text} – ${formatHotkeys(hotkeys)}`;
|
|
701
|
-
};
|
|
702
|
-
|
|
703
|
-
const isDigitKeyInRange = (keyCode, hotkey) => {
|
|
704
|
-
const digitRangeLength = 3;
|
|
705
|
-
if (hotkey.length !== digitRangeLength || !keyCode?.startsWith("Digit")) {
|
|
706
|
-
return false;
|
|
707
|
-
}
|
|
708
|
-
const keyNumber = Number(keyCode.slice("Digit".length));
|
|
709
|
-
const [lower, upper] = hotkey.split("-");
|
|
710
|
-
return Boolean(lower) && Boolean(upper) && Number.parseInt(lower, 10) <= keyNumber && keyNumber <= Number.parseInt(upper, 10);
|
|
711
|
-
};
|
|
712
|
-
const match = (event, hotkeys) => {
|
|
713
|
-
const { key, code, metaKey, ctrlKey, shiftKey, altKey } = event;
|
|
714
|
-
const modifiers = hotkeys.slice();
|
|
715
|
-
const character = modifiers.pop() ?? "";
|
|
716
|
-
const ctrlOrMeta = isMac() ? "Meta" : "Ctrl";
|
|
717
|
-
const platformModifiers = new Set(
|
|
718
|
-
modifiers.map(
|
|
719
|
-
(modifier) => modifier === "CtrlOrCmd" ? ctrlOrMeta : modifier
|
|
720
|
-
)
|
|
721
|
-
);
|
|
722
|
-
const metaMatches = Boolean(metaKey) === platformModifiers.has("Meta");
|
|
723
|
-
const ctrlMatches = Boolean(ctrlKey) === platformModifiers.has("Ctrl");
|
|
724
|
-
const shiftMatches = Boolean(shiftKey) === platformModifiers.has("Shift");
|
|
725
|
-
const altMatches = Boolean(altKey) === platformModifiers.has("Alt");
|
|
726
|
-
const keysMatch = (
|
|
727
|
-
// keys are matched case insensitively
|
|
728
|
-
key.toUpperCase() === character.toUpperCase() || character.includes("-") && isDigitKeyInRange(code, character) || // on mac 'backspace' can be used instead of delete
|
|
729
|
-
isMac() && character === "Delete" && key === "Backspace"
|
|
730
|
-
);
|
|
731
|
-
return metaMatches && ctrlMatches && shiftMatches && altMatches && keysMatch;
|
|
732
|
-
};
|
|
733
|
-
|
|
734
|
-
const isModifierKeyPressed = (event) => {
|
|
735
|
-
return event.ctrlKey || event.metaKey || event.altKey || event.shiftKey;
|
|
736
|
-
};
|
|
737
|
-
const isKeyWithoutModifiers = (event, keys) => {
|
|
738
|
-
const keyList = Array.isArray(keys) ? keys : [keys];
|
|
739
|
-
return keyList.includes(event.key) && !isModifierKeyPressed(event);
|
|
740
|
-
};
|
|
741
|
-
const getMetaOrCtrlKey = () => {
|
|
742
|
-
return isMac() ? "metaKey" : "ctrlKey";
|
|
743
|
-
};
|
|
744
|
-
|
|
745
|
-
const hotkeys = {
|
|
746
|
-
formatHotkeys,
|
|
747
|
-
formatHotkey,
|
|
748
|
-
getDefaultSeparator,
|
|
749
|
-
hotkeyPlatform,
|
|
750
|
-
textWithHotkeys,
|
|
751
|
-
match
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
export { capitalize, caseFormatter, debounce, filters, formatDateString, formatDateTimeString, formatFileSize, formatLocalDateTimeString, formatTimeString, getDeepActiveElement, getFileExtension, getFileMimeType, getLocalTimeZone, getMetaOrCtrlKey, getWrappedAroundIndex, hotkeys, intervalUtils, isAfterMaxDate, isBeforeMinDate, isKeyWithoutModifiers, isModifierKeyPressed, knimeFileFormats, match, navigator$1 as navigatorUtils, numIntegerDigits, index as promise, sanitization, sleep, truncateString, updateDate, updateTime };
|
|
755
|
-
//# sourceMappingURL=index.js.map
|
|
957
|
+
//# sourceMappingURL=index.js.map
|