@knime/utils 1.11.1 → 1.12.0

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.
Files changed (97) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +67 -14
  3. package/dist/globals.d.ts +8 -0
  4. package/dist/index.js +751 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/src/capitalize.d.ts +20 -0
  7. package/dist/src/capitalize.d.ts.map +1 -0
  8. package/dist/src/dateMinMaxCheck.d.ts +19 -0
  9. package/dist/src/dateMinMaxCheck.d.ts.map +1 -0
  10. package/dist/src/debounce.d.ts +4 -0
  11. package/dist/src/debounce.d.ts.map +1 -0
  12. package/dist/src/fileExtensions.d.ts +33 -0
  13. package/dist/src/fileExtensions.d.ts.map +1 -0
  14. package/dist/src/filters.d.ts +13 -0
  15. package/dist/src/filters.d.ts.map +1 -0
  16. package/dist/src/format.d.ts +39 -0
  17. package/dist/src/format.d.ts.map +1 -0
  18. package/dist/src/getDeepActiveElement.d.ts +3 -0
  19. package/dist/src/getDeepActiveElement.d.ts.map +1 -0
  20. package/{src/getWrappedAroundIndex.ts → dist/src/getWrappedAroundIndex.d.ts} +3 -2
  21. package/dist/src/getWrappedAroundIndex.d.ts.map +1 -0
  22. package/dist/src/hotkeys/enums.d.ts +11 -0
  23. package/dist/src/hotkeys/enums.d.ts.map +1 -0
  24. package/dist/src/hotkeys/format.d.ts +15 -0
  25. package/dist/src/hotkeys/format.d.ts.map +1 -0
  26. package/dist/src/hotkeys/index.d.ts +19 -0
  27. package/dist/src/hotkeys/index.d.ts.map +1 -0
  28. package/dist/src/hotkeys/match.d.ts +12 -0
  29. package/dist/src/hotkeys/match.d.ts.map +1 -0
  30. package/dist/src/hotkeys/modifiers.d.ts +18 -0
  31. package/dist/src/hotkeys/modifiers.d.ts.map +1 -0
  32. package/dist/src/hotkeys/types.d.ts +10 -0
  33. package/dist/src/hotkeys/types.d.ts.map +1 -0
  34. package/dist/src/index.d.ts +21 -0
  35. package/dist/src/index.d.ts.map +1 -0
  36. package/dist/src/intervalUtils.d.ts +114 -0
  37. package/dist/src/intervalUtils.d.ts.map +1 -0
  38. package/{src/localTimezone.ts → dist/src/localTimezone.d.ts} +3 -2
  39. package/dist/src/localTimezone.d.ts.map +1 -0
  40. package/{src/numIntegerDigits.ts → dist/src/numIntegerDigits.d.ts} +3 -2
  41. package/dist/src/numIntegerDigits.d.ts.map +1 -0
  42. package/dist/src/platform/index.d.ts +2 -0
  43. package/dist/src/platform/index.d.ts.map +1 -0
  44. package/dist/src/platform/navigator.d.ts +11 -0
  45. package/dist/src/platform/navigator.d.ts.map +1 -0
  46. package/dist/src/promise/createAbortablePromise.d.ts +32 -0
  47. package/dist/src/promise/createAbortablePromise.d.ts.map +1 -0
  48. package/dist/src/promise/createUnwrappedPromise.d.ts +7 -0
  49. package/dist/src/promise/createUnwrappedPromise.d.ts.map +1 -0
  50. package/dist/src/promise/index.d.ts +4 -0
  51. package/dist/src/promise/index.d.ts.map +1 -0
  52. package/dist/src/promise/retryPromise.d.ts +16 -0
  53. package/dist/src/promise/retryPromise.d.ts.map +1 -0
  54. package/dist/src/sanitization.d.ts +8 -0
  55. package/dist/src/sanitization.d.ts.map +1 -0
  56. package/dist/src/sleep.d.ts +5 -0
  57. package/dist/src/sleep.d.ts.map +1 -0
  58. package/dist/src/truncateString.d.ts +3 -0
  59. package/dist/src/truncateString.d.ts.map +1 -0
  60. package/dist/src/updateDate.d.ts +11 -0
  61. package/dist/src/updateDate.d.ts.map +1 -0
  62. package/{src/updateTime.ts → dist/src/updateTime.d.ts} +3 -11
  63. package/dist/src/updateTime.d.ts.map +1 -0
  64. package/dist/test-utils/index.d.ts +3 -0
  65. package/dist/test-utils/index.d.ts.map +1 -0
  66. package/dist/test-utils/index.js +40 -0
  67. package/dist/test-utils/index.js.map +1 -0
  68. package/dist/test-utils/muteConsole.d.ts +8 -0
  69. package/dist/test-utils/muteConsole.d.ts.map +1 -0
  70. package/package.json +51 -33
  71. package/src/capitalize.ts +0 -45
  72. package/src/dateMinMaxCheck.ts +0 -68
  73. package/src/debounce.ts +0 -28
  74. package/src/fileExtensions.ts +0 -87
  75. package/src/filters.ts +0 -114
  76. package/src/format.ts +0 -113
  77. package/src/formatHotkeys.ts +0 -98
  78. package/src/getDeepActiveElement.ts +0 -9
  79. package/src/hotkeys.ts +0 -32
  80. package/src/index.ts +0 -76
  81. package/src/intervalUtils.ts +0 -434
  82. package/src/navigator.ts +0 -13
  83. package/src/promise/createAbortablePromise.ts +0 -56
  84. package/src/promise/createUnwrappedPromise.ts +0 -17
  85. package/src/promise/index.ts +0 -3
  86. package/src/promise/retryPromise.ts +0 -45
  87. package/src/sanitization.ts +0 -72
  88. package/src/sleep.ts +0 -6
  89. package/src/truncateString.ts +0 -7
  90. package/src/updateDate.ts +0 -23
  91. package/src/uploadManager/index.ts +0 -370
  92. package/test-utils/index.ts +0 -3
  93. package/test-utils/muteConsole.ts +0 -54
  94. /package/{src/audit → audit}/README.md +0 -0
  95. /package/{src/audit → audit}/bulkAudit.js +0 -0
  96. /package/{src/audit → audit}/cli.js +0 -0
  97. /package/{src/config/globals.d.ts → globals.d.ts} +0 -0
package/dist/index.js ADDED
@@ -0,0 +1,751 @@
1
+ import { isValid, set, getDate, getMonth, getYear, isAfter, isBefore } from 'date-fns';
2
+ import prettyBytes from 'pretty-bytes';
3
+ import DomPurify from 'dompurify';
4
+
5
+ const capitalize = (input) => input.charAt(0).toUpperCase() + input.substring(1);
6
+ const formats = {
7
+ customFormat: (input, delimiter) => capitalize(input.replace(delimiter, " ").toLowerCase()),
8
+ kebabFormat: (input) => formats.customFormat(input, "-"),
9
+ snakeFormat: (input) => formats.customFormat(input, "_"),
10
+ camelPascalCase: (input) => capitalize(
11
+ (input.match(/([A-Z]?[^A-Z]*)/g) ?? []).slice(0, -1).join(" ").toLowerCase()
12
+ )
13
+ };
14
+ const caseFormatter = ({
15
+ string,
16
+ delimiter,
17
+ format
18
+ }) => {
19
+ if (delimiter) {
20
+ return formats.customFormat(string, delimiter);
21
+ }
22
+ if (format) {
23
+ return formats[format](string, delimiter ?? "");
24
+ }
25
+ return capitalize(string);
26
+ };
27
+
28
+ const updateDate = (base, date) => {
29
+ if (date) {
30
+ base = isValid(base) ? base : new Date(Date.UTC(0, 0));
31
+ return set(base, {
32
+ year: getYear(date),
33
+ month: getMonth(date),
34
+ date: getDate(date)
35
+ });
36
+ }
37
+ return base;
38
+ };
39
+
40
+ const updateTime = (base, date) => {
41
+ const d = new Date(base);
42
+ if (date) {
43
+ d.setHours(date.getHours());
44
+ d.setMinutes(date.getMinutes());
45
+ d.setSeconds(date.getSeconds());
46
+ d.setMilliseconds(date.getMilliseconds());
47
+ }
48
+ return d;
49
+ };
50
+
51
+ const isBeforeMinDate = (date, min, checkDate, checkTime) => {
52
+ if (min) {
53
+ if (checkTime && checkDate) {
54
+ return isBefore(date, min);
55
+ }
56
+ if (checkTime) {
57
+ const base = /* @__PURE__ */ new Date(0);
58
+ return isBefore(updateTime(base, date), updateTime(base, min));
59
+ }
60
+ if (checkDate) {
61
+ const base = /* @__PURE__ */ new Date(0);
62
+ return isBefore(updateDate(base, date), updateDate(base, min));
63
+ }
64
+ }
65
+ return false;
66
+ };
67
+ const isAfterMaxDate = (date, max, checkDate, checkTime) => {
68
+ if (max) {
69
+ if (checkTime && checkDate) {
70
+ return isAfter(date, max);
71
+ }
72
+ if (checkTime) {
73
+ const base = /* @__PURE__ */ new Date(0);
74
+ return isAfter(updateTime(base, date), updateTime(base, max));
75
+ }
76
+ if (checkDate) {
77
+ const base = /* @__PURE__ */ new Date(0);
78
+ return isAfter(updateDate(base, date), updateDate(base, max));
79
+ }
80
+ }
81
+ return false;
82
+ };
83
+
84
+ const debounce = (callback, wait) => {
85
+ let timer;
86
+ let lastCall = 0;
87
+ return (...args) => {
88
+ const [value, index] = args;
89
+ clearTimeout(timer);
90
+ const now = Date.now();
91
+ const timeFromLastCall = now - lastCall;
92
+ if (timeFromLastCall > wait) {
93
+ lastCall = now;
94
+ callback(value, index);
95
+ } else {
96
+ timer = setTimeout(() => {
97
+ lastCall = now;
98
+ callback(value, index);
99
+ }, wait);
100
+ }
101
+ };
102
+ };
103
+
104
+ const modeDefinitions = [
105
+ {
106
+ id: "search",
107
+ normalize(searchTerm, caseSensitiveSearch) {
108
+ return caseSensitiveSearch ? searchTerm : searchTerm.toLowerCase();
109
+ },
110
+ test(text, normalizedSearchTerm, caseSensitiveSearch, inverseSearch) {
111
+ const testText = caseSensitiveSearch ? text : text.toLowerCase();
112
+ const matches = testText.includes(normalizedSearchTerm);
113
+ return inverseSearch ? !matches : matches;
114
+ }
115
+ },
116
+ {
117
+ id: "wildcard",
118
+ normalize(searchTerm, caseSensitiveSearch) {
119
+ if (searchTerm.length > 0) {
120
+ const escapedSearchTerm = searchTerm.replace(
121
+ /[-[\]{}()+.,\\^$|#\s]/g,
122
+ "\\$&"
123
+ );
124
+ const wildcardSearchTerm = escapedSearchTerm.replace(/\*/g, ".*").replace(/\?/g, ".?");
125
+ searchTerm = `^${wildcardSearchTerm}$`;
126
+ } else {
127
+ return { test: () => false };
128
+ }
129
+ try {
130
+ const flags = caseSensitiveSearch ? "" : "i";
131
+ return new RegExp(searchTerm, flags);
132
+ } catch (_error) {
133
+ return /$^/;
134
+ }
135
+ },
136
+ test(text, normalizedSearchTerm, caseSensitiveSearch, inverseSearch) {
137
+ const matches = normalizedSearchTerm.test(text);
138
+ return inverseSearch ? !matches : matches;
139
+ }
140
+ },
141
+ {
142
+ id: "regex",
143
+ normalize(searchTerm, caseSensitiveSearch) {
144
+ try {
145
+ const flags = caseSensitiveSearch ? "" : "i";
146
+ return new RegExp(`^(${searchTerm})$`, flags);
147
+ } catch (_error) {
148
+ return /$^/;
149
+ }
150
+ },
151
+ test(text, normalizedSearchTerm, caseSensitiveSearch, inverseSearch) {
152
+ const matches = normalizedSearchTerm.test(text);
153
+ return inverseSearch ? !matches : matches;
154
+ }
155
+ },
156
+ {
157
+ id: "type",
158
+ normalize(selectedTypes) {
159
+ return { test: (type) => selectedTypes.includes(type) };
160
+ },
161
+ test(type, normalizedSearchTerm) {
162
+ if (typeof type === "undefined") {
163
+ return false;
164
+ }
165
+ return normalizedSearchTerm.test(type);
166
+ }
167
+ }
168
+ ];
169
+ const filters = Object.assign({}, ...modeDefinitions.map((obj) => ({ [obj.id]: obj })));
170
+
171
+ const getLocalTimeZone = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
172
+
173
+ const formatDateString = (dateString, useTimeZone = false) => {
174
+ const date = new Date(dateString);
175
+ if (isNaN(date)) {
176
+ throw Error("Invalid Date format");
177
+ }
178
+ const baseDateOptions = {
179
+ day: "numeric",
180
+ month: "short",
181
+ year: "numeric"
182
+ };
183
+ const dateOptions = useTimeZone ? { ...baseDateOptions, timeZone: getLocalTimeZone() } : baseDateOptions;
184
+ return date.toLocaleDateString("en-US", dateOptions);
185
+ };
186
+ const formatTimeString = (timeString, useTimeZone = false) => {
187
+ const time = new Date(timeString);
188
+ if (isNaN(time)) {
189
+ throw Error("Invalid Date format");
190
+ }
191
+ const baseTimeOptions = {
192
+ hour: "numeric",
193
+ minute: "2-digit"
194
+ };
195
+ const timeOptions = useTimeZone ? { ...baseTimeOptions, timeZone: getLocalTimeZone() } : baseTimeOptions;
196
+ return time.toLocaleTimeString("en-US", timeOptions);
197
+ };
198
+ const formatDateTimeString = (dateTimeString, useTimeZone = false) => {
199
+ return `${formatDateString(dateTimeString, useTimeZone)} ${formatTimeString(
200
+ dateTimeString,
201
+ useTimeZone
202
+ )}`;
203
+ };
204
+ const formatLocalDateTimeString = (date, showTime) => showTime ? formatDateTimeString(date, true) : formatDateString(date, true);
205
+ const formatFileSize = (bytes) => {
206
+ const safeBytes = Number.isFinite(bytes) && bytes >= 0 ? bytes : 0;
207
+ return prettyBytes(safeBytes);
208
+ };
209
+
210
+ const getDeepActiveElement = () => {
211
+ let element = document?.activeElement;
212
+ while (element?.shadowRoot) {
213
+ element = element?.shadowRoot?.activeElement;
214
+ }
215
+ return element;
216
+ };
217
+
218
+ const getWrappedAroundIndex = (index, length) => (index % length + length) % length;
219
+
220
+ const extractPeriodFromRegexMatch = (negative, match) => {
221
+ return {
222
+ negative,
223
+ years: parseInt(match[1] ?? "0", 10),
224
+ months: parseInt(match[2] ?? "0", 10),
225
+ weeks: parseInt(match[3] ?? "0", 10),
226
+ days: parseInt(match[4] ?? "0", 10)
227
+ };
228
+ };
229
+ const extractDurationFromRegexMatch = (negative, match) => {
230
+ const milliseconds = parseInt(match[4]?.padEnd(3, "0") ?? "0", 10);
231
+ return {
232
+ negative,
233
+ hours: parseInt(match[1] ?? "0", 10),
234
+ minutes: parseInt(match[2] ?? "0", 10),
235
+ seconds: parseInt(match[3] ?? "0", 10),
236
+ milliseconds
237
+ };
238
+ };
239
+ const isZero = (interval) => {
240
+ if (interval.type === "DATE") {
241
+ return interval.interval.years === 0 && interval.interval.months === 0 && interval.interval.weeks === 0 && interval.interval.days === 0;
242
+ } else {
243
+ return interval.interval.hours === 0 && interval.interval.minutes === 0 && interval.interval.seconds === 0 && interval.interval.milliseconds === 0;
244
+ }
245
+ };
246
+ const formatIntervalToISOIntervalString = (toFormat) => {
247
+ let output = "P";
248
+ if (toFormat.type === "DATE") {
249
+ output += `${toFormat.interval.years}Y${toFormat.interval.months}M${toFormat.interval.weeks}W${toFormat.interval.days}D`;
250
+ } else {
251
+ output += `T${toFormat.interval.hours}H${toFormat.interval.minutes}M${toFormat.interval.seconds}.${toFormat.interval.milliseconds.toString().padStart(3, "0")}S`;
252
+ }
253
+ if (toFormat.interval.negative) {
254
+ output = `-${output}`;
255
+ }
256
+ return output;
257
+ };
258
+ const formatIntervalToHumanReadableIntervalString = (toFormat) => {
259
+ const formatPart = (value, unit) => {
260
+ if (value === 0) {
261
+ return "";
262
+ } else if (value === 1) {
263
+ return `${value} ${unit} `;
264
+ } else {
265
+ return `${value} ${unit}s `;
266
+ }
267
+ };
268
+ let output = "";
269
+ if (toFormat.type === "DATE") {
270
+ if (isZero(toFormat)) {
271
+ return "0 days";
272
+ }
273
+ output += formatPart(toFormat.interval.years, "year");
274
+ output += formatPart(toFormat.interval.months, "month");
275
+ output += formatPart(toFormat.interval.weeks, "week");
276
+ output += formatPart(toFormat.interval.days, "day");
277
+ } else {
278
+ if (isZero(toFormat)) {
279
+ return "0 seconds";
280
+ }
281
+ output += formatPart(toFormat.interval.hours, "hour");
282
+ output += formatPart(toFormat.interval.minutes, "minute");
283
+ const milliSecondsZero = toFormat.interval.milliseconds === 0;
284
+ if (toFormat.interval.seconds !== 0 || !milliSecondsZero) {
285
+ if (milliSecondsZero) {
286
+ output += formatPart(toFormat.interval.seconds, "second");
287
+ } else {
288
+ output += `${toFormat.interval.seconds}.${toFormat.interval.milliseconds.toString().padStart(3, "0")} seconds `;
289
+ }
290
+ }
291
+ }
292
+ if (toFormat.interval.negative) {
293
+ output = `-(${output.trim()})`;
294
+ }
295
+ return output.trim();
296
+ };
297
+ const yearsPart = "(\\d+)\\s*y(?:ears?)?";
298
+ const monthsPart = "(\\d+)\\s*m(?:o(?:nths?)?)?";
299
+ const weeksPart = "(\\d+)\\s*w(?:eeks?)?";
300
+ const daysPart = "(\\d+)\\s*d(?:ays?)?";
301
+ const hoursPart = "(\\d+)\\s*h(?:ours?)?";
302
+ const minutesPart = "(\\d+)\\s*m(?:in(?:s|utes?)?)?";
303
+ const secondsPart = "(\\d+)(?:[,.](\\d{1,3}))?\\s*s(?:ec(?:s|onds?)?)?";
304
+ const humanReadablePeriodRegex = new RegExp(
305
+ `^(?:${yearsPart})?\\s*(?:${monthsPart})?\\s*(?:${weeksPart})?\\s*(?:${daysPart})?\\s*$`,
306
+ "i"
307
+ );
308
+ const humanReadableDurationRegex = new RegExp(
309
+ `^(?:${hoursPart})?\\s*(?:${minutesPart})?\\s*(?:${secondsPart})?$`,
310
+ "i"
311
+ );
312
+ const negativeHumanReadablePeriodRegex = new RegExp(
313
+ `^\\s*-\\s*\\(\\s*${humanReadablePeriodRegex.source.replace(/[$^]/g, "")}\\s*\\)\\s*$`,
314
+ "i"
315
+ );
316
+ const negativeHumanReadablePeriodRegexWithSingleField = new RegExp(
317
+ `^\\s*-\\s*(?:\\s*${yearsPart}|${monthsPart}|${weeksPart}|${daysPart})\\s*$`,
318
+ "i"
319
+ );
320
+ const negativeHumanReadableDurationRegex = new RegExp(
321
+ `^\\s*-\\s*\\(\\s*${humanReadableDurationRegex.source.replace(/[$^]/g, "")}\\s*\\)\\s*$`,
322
+ "i"
323
+ );
324
+ const negativeHumanReadableDurationRegexWithSingleField = new RegExp(
325
+ `^\\s*-\\s*(?:\\s*${hoursPart}|${minutesPart}|${secondsPart})\\s*$`,
326
+ "i"
327
+ );
328
+ const parseHumanReadableIntervalString = (intervalString) => {
329
+ intervalString = intervalString?.trim();
330
+ if (!intervalString) {
331
+ throw new Error("Empty interval string");
332
+ }
333
+ const matchPositivePeriod = humanReadablePeriodRegex.exec(intervalString);
334
+ const matchNegativePeriod = negativeHumanReadablePeriodRegex.exec(intervalString) ?? negativeHumanReadablePeriodRegexWithSingleField.exec(intervalString);
335
+ const matchPositiveDuration = humanReadableDurationRegex.exec(intervalString);
336
+ const matchNegativeDuration = negativeHumanReadableDurationRegex.exec(intervalString) ?? negativeHumanReadableDurationRegexWithSingleField.exec(intervalString);
337
+ const matchPeriod = matchPositivePeriod ?? matchNegativePeriod;
338
+ const matchDuration = matchPositiveDuration ?? matchNegativeDuration;
339
+ const negative = (matchNegativePeriod ?? matchNegativeDuration) !== null;
340
+ if (matchDuration && matchPeriod) {
341
+ throw new Error("Ambiguous time format");
342
+ }
343
+ if (matchPeriod) {
344
+ return {
345
+ type: "DATE",
346
+ interval: extractPeriodFromRegexMatch(negative, matchPeriod)
347
+ };
348
+ } else if (matchDuration) {
349
+ return {
350
+ type: "TIME",
351
+ interval: extractDurationFromRegexMatch(negative, matchDuration)
352
+ };
353
+ } else {
354
+ throw new Error(`Invalid human readable time: ${intervalString}`);
355
+ }
356
+ };
357
+ const isValidHumanReadableIntervalString = (time, expectedType) => {
358
+ try {
359
+ const validationResult = parseHumanReadableIntervalString(time);
360
+ const actualType = validationResult.type;
361
+ const negative = validationResult.interval.negative;
362
+ if (actualType === expectedType || expectedType === "DATE_OR_TIME") {
363
+ return {
364
+ valid: true,
365
+ type: actualType,
366
+ negative
367
+ };
368
+ } else {
369
+ return { valid: false };
370
+ }
371
+ } catch (_e) {
372
+ return { valid: false };
373
+ }
374
+ };
375
+ const parseISOIntervalString = (isoString) => {
376
+ isoString = isoString?.trim();
377
+ if (["", "P", "PT", "-", "-P", "-PT"].includes(isoString)) {
378
+ throw new Error("Empty ISO duration");
379
+ }
380
+ const periodRegex = /^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?$/;
381
+ const durationRegex = /^-?PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:[,.](\d{1,3}))?S)?$/;
382
+ const matchPeriod = periodRegex.exec(isoString);
383
+ const matchDuration = durationRegex.exec(isoString);
384
+ if (matchPeriod) {
385
+ return {
386
+ type: "DATE",
387
+ interval: extractPeriodFromRegexMatch(
388
+ isoString.startsWith("-"),
389
+ matchPeriod
390
+ )
391
+ };
392
+ } else if (matchDuration) {
393
+ return {
394
+ type: "TIME",
395
+ interval: extractDurationFromRegexMatch(
396
+ isoString.startsWith("-"),
397
+ matchDuration
398
+ )
399
+ };
400
+ } else {
401
+ throw new Error(`Invalid ISO duration: ${isoString}`);
402
+ }
403
+ };
404
+ const isValidISOIntervalString = (isoString, type) => {
405
+ try {
406
+ const validationResult = parseISOIntervalString(isoString);
407
+ const actualType = validationResult.type;
408
+ const negative = validationResult.interval.negative;
409
+ if (actualType === type || type === "DATE_OR_TIME") {
410
+ return {
411
+ valid: true,
412
+ type: actualType,
413
+ negative
414
+ };
415
+ } else {
416
+ return { valid: false };
417
+ }
418
+ } catch (_e) {
419
+ return { valid: false };
420
+ }
421
+ };
422
+ const parseGenericIntervalString = (time) => {
423
+ const validISO = isValidISOIntervalString(time, "DATE_OR_TIME");
424
+ const validHumanReadable = isValidHumanReadableIntervalString(
425
+ time,
426
+ "DATE_OR_TIME"
427
+ );
428
+ if (validISO.valid) {
429
+ return parseISOIntervalString(time);
430
+ } else if (validHumanReadable.valid) {
431
+ return parseHumanReadableIntervalString(time);
432
+ } else {
433
+ throw new Error(`Invalid interval string: ${time}`);
434
+ }
435
+ };
436
+ const isValidIntervalString = (time, type) => {
437
+ const validISO = isValidISOIntervalString(time, type);
438
+ const validHumanReadable = isValidHumanReadableIntervalString(time, type);
439
+ if (validISO.valid) {
440
+ return validISO;
441
+ } else if (validHumanReadable.valid) {
442
+ return validHumanReadable;
443
+ } else {
444
+ return { valid: false };
445
+ }
446
+ };
447
+
448
+ const intervalUtils = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
449
+ __proto__: null,
450
+ formatIntervalToHumanReadableIntervalString,
451
+ formatIntervalToISOIntervalString,
452
+ isValidHumanReadableIntervalString,
453
+ isValidISOIntervalString,
454
+ isValidIntervalString,
455
+ isZero,
456
+ parseGenericIntervalString,
457
+ parseHumanReadableIntervalString,
458
+ parseISOIntervalString
459
+ }, Symbol.toStringTag, { value: 'Module' }));
460
+
461
+ const numIntegerDigits = (input) => Math.max(Math.floor(Math.log10(Math.abs(input))), 0) + 1;
462
+
463
+ class AbortError extends Error {
464
+ }
465
+ const createAbortablePromise = () => {
466
+ const abortController = new AbortController();
467
+ const runAbortablePromise = (request) => {
468
+ return new Promise((resolve, reject) => {
469
+ const abortListener = ({ target }) => {
470
+ abortController.signal.removeEventListener("abort", abortListener);
471
+ const reason = target.reason;
472
+ reject(reason instanceof AbortError ? reason : new AbortError(reason));
473
+ };
474
+ request().then(resolve).catch((error) => {
475
+ if (error instanceof AbortError) {
476
+ return;
477
+ }
478
+ reject(error);
479
+ });
480
+ abortController.signal.addEventListener("abort", abortListener);
481
+ });
482
+ };
483
+ return { abortController, runAbortablePromise };
484
+ };
485
+
486
+ const createUnwrappedPromise = () => {
487
+ let resolve = () => {
488
+ };
489
+ let reject = () => {
490
+ };
491
+ const promise = new Promise((res, rej) => {
492
+ resolve = res;
493
+ reject = rej;
494
+ });
495
+ return { resolve, reject, promise };
496
+ };
497
+
498
+ function sleep(ms) {
499
+ return new Promise((resolve) => setTimeout(resolve, ms));
500
+ }
501
+
502
+ const DEFAULT_RETRY_DELAY_MS = 0;
503
+ const DEFAULT_RETRY_COUNT = 5;
504
+ async function retryPromise({
505
+ fn,
506
+ retryCount = DEFAULT_RETRY_COUNT,
507
+ retryDelayMS = DEFAULT_RETRY_DELAY_MS,
508
+ excludeError
509
+ }) {
510
+ try {
511
+ return await fn();
512
+ } catch (error) {
513
+ if (excludeError?.(error)) {
514
+ throw error;
515
+ }
516
+ if (retryCount > 0) {
517
+ await sleep(retryDelayMS);
518
+ return await retryPromise({
519
+ fn,
520
+ retryCount: retryCount - 1,
521
+ retryDelayMS,
522
+ excludeError
523
+ });
524
+ }
525
+ throw error;
526
+ }
527
+ }
528
+
529
+ const index = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
530
+ __proto__: null,
531
+ AbortError,
532
+ DEFAULT_RETRY_COUNT,
533
+ DEFAULT_RETRY_DELAY_MS,
534
+ createAbortablePromise,
535
+ createUnwrappedPromise,
536
+ retryPromise
537
+ }, Symbol.toStringTag, { value: 'Module' }));
538
+
539
+ const ALLOWED_TAGS = [
540
+ "p",
541
+ "div",
542
+ "h1",
543
+ "h2",
544
+ "h3",
545
+ "h4",
546
+ "h5",
547
+ "h6",
548
+ "ul",
549
+ "ol",
550
+ "li",
551
+ "blockquote",
552
+ "b",
553
+ "i",
554
+ "s",
555
+ "u",
556
+ "sup",
557
+ "sub",
558
+ "ins",
559
+ "del",
560
+ "strong",
561
+ "strike",
562
+ "tt",
563
+ "code",
564
+ "big",
565
+ "small",
566
+ "br",
567
+ "span",
568
+ "em"
569
+ ];
570
+ const sanitizeHTML = (rawHTML, options = {
571
+ allowStyleAttribute: false,
572
+ allowHyperlinks: false
573
+ }) => {
574
+ const { allowStyleAttribute, allowHyperlinks } = options;
575
+ const ALLOWED_ATTR = [
576
+ ...allowStyleAttribute ? ["style"] : [],
577
+ ...allowHyperlinks ? ["href"] : []
578
+ ];
579
+ const allowedTags = allowHyperlinks ? [...ALLOWED_TAGS, "a"] : ALLOWED_TAGS;
580
+ return DomPurify.sanitize(rawHTML, {
581
+ ALLOWED_TAGS: allowedTags,
582
+ ALLOWED_ATTR
583
+ });
584
+ };
585
+ const stripHTML = (rawHTML) => {
586
+ return DomPurify.sanitize(rawHTML, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
587
+ };
588
+ const sanitization = { sanitizeHTML, stripHTML };
589
+
590
+ const defaultMaxLength = 160;
591
+ const truncateString = (string = "", maxLength = defaultMaxLength) => {
592
+ const dots = string.length > maxLength ? "…" : "";
593
+ return `${string.substring(0, maxLength - 1)}${dots}`;
594
+ };
595
+
596
+ const getFileExtension = (nameOrPath) => {
597
+ const basename = nameOrPath.split(/[\\/]/).pop() ?? "";
598
+ const parts = basename.split(".");
599
+ if (basename === "" || parts.length === 1) {
600
+ return "";
601
+ }
602
+ return parts.at(-1) ?? "";
603
+ };
604
+ const KNAR = Object.freeze({
605
+ extension: "knar",
606
+ mimeType: "application/vnd.knime.workflow-group+zip",
607
+ matches(file) {
608
+ const extension = getFileExtension(file.name);
609
+ return extension === this.extension;
610
+ }
611
+ });
612
+ const KNWF = Object.freeze({
613
+ extension: "knwf",
614
+ mimeType: "application/vnd.knime.workflow+zip",
615
+ matches(file) {
616
+ const extension = getFileExtension(file.name);
617
+ return extension === this.extension;
618
+ },
619
+ /**
620
+ * Gets the name of a .knwf file without the extension. If the file is not
621
+ * matched as a .knwf file then this function will return the default value,
622
+ * which is empty string ("") if param is not provided
623
+ */
624
+ getNameOrDefault(file, defaultValue = "") {
625
+ if (!this.matches(file)) {
626
+ return defaultValue;
627
+ }
628
+ return file.name.replace(`.${this.extension}`, "");
629
+ }
630
+ });
631
+ const knimeFileFormats = { KNAR, KNWF };
632
+ const getFileMimeType = (file) => {
633
+ const DEFAULT_MIMETYPE = "application/octet-stream";
634
+ const extension = getFileExtension(file.name);
635
+ if (!extension) {
636
+ return DEFAULT_MIMETYPE;
637
+ }
638
+ if (KNWF.matches(file)) {
639
+ return KNWF.mimeType;
640
+ }
641
+ if (KNAR.matches(file)) {
642
+ return KNAR.mimeType;
643
+ }
644
+ if (!file.type) {
645
+ return DEFAULT_MIMETYPE;
646
+ }
647
+ return file.type;
648
+ };
649
+
650
+ const hotkeyPlatform = {
651
+ MAC_OS: "macOS",
652
+ OTHER: "other"
653
+ };
654
+ Object.values(hotkeyPlatform);
655
+
656
+ const isMac = () => navigator?.userAgent?.toLowerCase()?.includes("mac");
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
+
700
+ const isDigitKeyInRange = (keyCode, hotkey) => {
701
+ const digitRangeLength = 3;
702
+ if (hotkey.length !== digitRangeLength || !keyCode?.startsWith("Digit")) {
703
+ return false;
704
+ }
705
+ const keyNumber = Number(keyCode.slice("Digit".length));
706
+ const [lower, upper] = hotkey.split("-");
707
+ return Boolean(lower) && Boolean(upper) && Number.parseInt(lower, 10) <= keyNumber && keyNumber <= Number.parseInt(upper, 10);
708
+ };
709
+ const match = (event, hotkeys) => {
710
+ const { key, code, metaKey, ctrlKey, shiftKey, altKey } = event;
711
+ const modifiers = hotkeys.slice();
712
+ const character = modifiers.pop() ?? "";
713
+ const ctrlOrMeta = isMac() ? "Meta" : "Ctrl";
714
+ const platformModifiers = new Set(
715
+ modifiers.map(
716
+ (modifier) => modifier === "CtrlOrCmd" ? ctrlOrMeta : modifier
717
+ )
718
+ );
719
+ const metaMatches = Boolean(metaKey) === platformModifiers.has("Meta");
720
+ const ctrlMatches = Boolean(ctrlKey) === platformModifiers.has("Ctrl");
721
+ const shiftMatches = Boolean(shiftKey) === platformModifiers.has("Shift");
722
+ const altMatches = Boolean(altKey) === platformModifiers.has("Alt");
723
+ const keysMatch = (
724
+ // keys are matched case insensitively
725
+ key.toUpperCase() === character.toUpperCase() || character.includes("-") && isDigitKeyInRange(code, character) || // on mac 'backspace' can be used instead of delete
726
+ isMac() && character === "Delete" && key === "Backspace"
727
+ );
728
+ return metaMatches && ctrlMatches && shiftMatches && altMatches && keysMatch;
729
+ };
730
+
731
+ const isModifierKeyPressed = (event) => {
732
+ return event.ctrlKey || event.metaKey || event.altKey || event.shiftKey;
733
+ };
734
+ const isKeyWithoutModifiers = (event, keys) => {
735
+ const keyList = Array.isArray(keys) ? keys : [keys];
736
+ return keyList.includes(event.key) && !isModifierKeyPressed(event);
737
+ };
738
+ const getMetaOrCtrlKey = () => {
739
+ return isMac() ? "metaKey" : "ctrlKey";
740
+ };
741
+
742
+ const hotkeys = {
743
+ formatHotkeys,
744
+ formatHotkey,
745
+ getDefaultSeparator,
746
+ hotkeyPlatform,
747
+ match
748
+ };
749
+
750
+ 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 };
751
+ //# sourceMappingURL=index.js.map