@trackunit/shared-utils 1.8.50 → 1.8.54

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/index.cjs.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var zod = require('zod');
3
4
  var uuid = require('uuid');
4
5
 
5
6
  /**
@@ -19,7 +20,7 @@ const formatAddress = (address) => {
19
20
  * @example formatCoordinates({ latitude: 1.234567, longitude: 2.345678 }) // "1.234567, 2.345678"
20
21
  */
21
22
  const formatCoordinates = (coordinates, toFixed) => {
22
- return toFixed
23
+ return toFixed !== undefined
23
24
  ? `${Number(coordinates.latitude.toFixed(toFixed))}, ${Number(coordinates.longitude.toFixed(toFixed))}`
24
25
  : `${coordinates.latitude}, ${coordinates.longitude}`;
25
26
  };
@@ -45,7 +46,7 @@ const nonNullable = (value) => {
45
46
  *
46
47
  */
47
48
  const truthy = (value) => {
48
- return !!value;
49
+ return Boolean(value);
49
50
  };
50
51
  /**
51
52
  * Converts an object into an array of properly typed key-value pairs.
@@ -59,7 +60,9 @@ const truthy = (value) => {
59
60
  * @param {TObject} object - The object to convert.
60
61
  * @template TObject - The type of the object.
61
62
  */
62
- const objectEntries = (object) => Object.entries(object);
63
+ const objectEntries = (object) =>
64
+ // eslint-disable-next-line local-rules/no-typescript-assertion
65
+ Object.entries(object);
63
66
  /**
64
67
  * Converts an array of key-value pairs into an object.
65
68
  * This is a type-faithful alternative to Object.fromEntries().
@@ -68,6 +71,7 @@ const objectEntries = (object) => Object.entries(object);
68
71
  * @template TEntries - The type of the entries array.
69
72
  */
70
73
  const objectFromEntries = (entries) => {
74
+ // eslint-disable-next-line local-rules/no-typescript-assertion
71
75
  return Object.fromEntries(entries);
72
76
  };
73
77
  /**
@@ -84,6 +88,7 @@ const objectFromEntries = (entries) => {
84
88
  * @returns {(keyof TObject)[]} An array of the keys of the object.
85
89
  */
86
90
  const objectKeys = (object) => {
91
+ // eslint-disable-next-line local-rules/no-typescript-assertion
87
92
  return Object.keys(object).map(key => key);
88
93
  };
89
94
  /**
@@ -95,17 +100,20 @@ const objectKeys = (object) => {
95
100
  *
96
101
  * @template TObject - The type of the object.
97
102
  * @param {TObject} object - The object to get the values from.
98
- * @returns {TObject[keyof TObject][]} An array of the values of the object.
103
+ * @returns {Array} An array of the values of the object.
99
104
  */
100
- const objectValues = (object) => Object.values(object);
105
+ const objectValues = (object) =>
106
+ // eslint-disable-next-line local-rules/no-typescript-assertion
107
+ Object.values(object);
101
108
 
102
109
  /**
103
110
  * Returns a new array with the items from the previous array and the new array, but only if the item's key is unique.
104
111
  *
112
+ * @template TObject - the type of the items in the array
105
113
  * @param key The key to use to determine uniqueness
106
114
  * @param previous The previous array of items to merge with the new array
107
115
  * @param newArray The new array of items to merge with the previous array
108
- * @returns A new array with the items from the previous array and the new array, but only if the item's key is unique.
116
+ * @returns {Array<TObject>} A new array with the items from the previous array and the new array, but only if the item's key is unique.
109
117
  */
110
118
  const unionArraysByKey = (key, previous, newArray) => {
111
119
  const previousIds = previous?.map(edge => edge[key]) || [];
@@ -127,8 +135,9 @@ const isArrayEqual = (a, b) => a.length === b.length && a.every((v, i) => v ===
127
135
  /**
128
136
  * Checks if an array is not empty.
129
137
  *
138
+ * @template TItem
130
139
  * @param array - The array to check.
131
- * @returns The array if not empty, otherwise undefined.
140
+ * @returns {Array<TItem> | undefined} The array if not empty, otherwise undefined.
132
141
  */
133
142
  const arrayNotEmpty = (array) => array && array.length > 0 ? array : undefined;
134
143
 
@@ -160,14 +169,13 @@ const size = {
160
169
  LARGE: "large",
161
170
  };
162
171
 
163
- exports.HoursAndMinutesFormat = void 0;
164
- (function (HoursAndMinutesFormat) {
165
- HoursAndMinutesFormat["HOURS_MIN_SEC_LONG"] = "HOURS_MIN_SEC_LONG";
166
- HoursAndMinutesFormat["HOURS_MIN_SEC"] = "HOURS_MIN_SEC";
167
- HoursAndMinutesFormat["HOURS_MIN_LONG"] = "HOURS_MIN_LONG";
168
- HoursAndMinutesFormat["HOURS_MIN"] = "HOURS_MIN";
169
- HoursAndMinutesFormat["HOURS_LONG"] = "HOURS_LONG";
170
- })(exports.HoursAndMinutesFormat || (exports.HoursAndMinutesFormat = {}));
172
+ const HoursAndMinutesFormat = {
173
+ HOURS_MIN_SEC_LONG: "HOURS_MIN_SEC_LONG", // h [h] mm [min] ss [sec]
174
+ HOURS_MIN_SEC: "HOURS_MIN_SEC", // h[h] m[m] s[s]
175
+ HOURS_MIN_LONG: "HOURS_MIN_LONG", // h [hrs] mm [min]
176
+ HOURS_MIN: "HOURS_MIN", // h[h] m[m]
177
+ HOURS_LONG: "HOURS_LONG", // h [hrs]
178
+ };
171
179
  const DateTimeFormat = {
172
180
  DATE: {
173
181
  selectFormat: "dateOnly",
@@ -207,7 +215,7 @@ const DateTimeFormat = {
207
215
  */
208
216
  const getISOStringFromDate = (date) => {
209
217
  try {
210
- if (!date) {
218
+ if (date === null || date === undefined) {
211
219
  return null;
212
220
  }
213
221
  return new Date(date).toISOString();
@@ -278,7 +286,7 @@ function doNothing() {
278
286
  */
279
287
  const enumFromValue = (val, _enum) => {
280
288
  const enumName = objectKeys(_enum).find(k => _enum[k] === val);
281
- if (!enumName) {
289
+ if (enumName === undefined) {
282
290
  throw Error(`Unknown enum value: ${val} expect one of: ${JSON.stringify(objectValues(_enum))}`);
283
291
  }
284
292
  return _enum[enumName];
@@ -308,7 +316,7 @@ const enumOrUndefinedFromValue = (_enum, val) => {
308
316
  */
309
317
  const enumFromValueTypesafe = (val, _enum) => {
310
318
  const enumName = objectKeys(_enum).find(k => _enum[k] === val);
311
- if (!enumName) {
319
+ if (enumName === undefined) {
312
320
  throw Error(`Unknown enum value: ${String(val)} expect one of: ${JSON.stringify(objectValues(_enum))}`);
313
321
  }
314
322
  return _enum[enumName];
@@ -333,9 +341,10 @@ const exhaustiveCheck = (value) => {
333
341
 
334
342
  /**
335
343
  *
344
+ * @template TItem
336
345
  * @param arr1 An array of string or numbers
337
346
  * @param arr2 An array of string or numbers
338
- * @returns The elements shared between arr1 and arr2.
347
+ * @returns {Array<TItem>} The elements shared between arr1 and arr2.
339
348
  */
340
349
  function intersection(arr1, arr2) {
341
350
  const a = new Set(arr1);
@@ -345,9 +354,10 @@ function intersection(arr1, arr2) {
345
354
  }
346
355
  /**
347
356
  *
357
+ * @template TItem
348
358
  * @param arr1 An array of string or numbers
349
359
  * @param arr2 An array of string or numbers
350
- * @returns The elements present in arr1 but not arr2.
360
+ * @returns {Array<TItem>} The elements present in arr1 but not arr2.
351
361
  */
352
362
  function difference(arr1, arr2) {
353
363
  const a = new Set(arr1);
@@ -410,11 +420,11 @@ searchTerm) => {
410
420
  /**
411
421
  * Group an array of items by a key.
412
422
  *
413
- * @template T The type of items in the list.
414
- * @template K The type of the key.
415
- * @param {T[]} list The array of items to group.
416
- * @param {(item: T) => K} getKey A function to get the key to group by.
417
- * @returns {Map<K, T[]>} A map of the items grouped by the key.
423
+ * @template TItem The type of items in the list.
424
+ * @template KeyGroup The type of the key.
425
+ * @param {TItem[]} list The array of items to group.
426
+ * @param {(item: TItem) => KeyGroup} getKey A function to get the key to group by.
427
+ * @returns {Map<KeyGroup, TItem[]>} A map of the items grouped by the key.
418
428
  * @example
419
429
  * groupBy([{ name: "John", surname: "Doe" }, { name: "Jane", surname: "Doe" }], p => p.surname)
420
430
  * Returns: Map { "Doe" => [{ name: "John", surname: "Doe" }, { name: "Jane", surname: "Doe" }] }
@@ -496,7 +506,7 @@ const zeroPadToUUIDLength = (input, maxLength) => input.length < maxLength ? zer
496
506
  */
497
507
  const toUUID = (value) => {
498
508
  if (isUUID(value.toString())) {
499
- return value;
509
+ return value.toString();
500
510
  }
501
511
  // A valid UUID length is 36 but we subtract 4 because we insert 4 hyphens.
502
512
  const id = zeroPadToUUIDLength(value.toString(), 32);
@@ -519,7 +529,7 @@ const toID = (uuid) => Number(uuid.replace(/-/g, "").replace(/^0+/, ""));
519
529
  * A helper function that converts a list of UUID to a list of valid machine IDs.
520
530
  * NOTE that NaN will be removed so list cannot be expected to be of same size.
521
531
  *
522
- * @param uuid The list of UUIDs that should be converted to a list of valid machine IDs
532
+ * @param ids The list of UUIDs that should be converted to a list of valid machine IDs
523
533
  */
524
534
  const toIDs = (ids) => ids?.filter(id => !isNaN(toID(id))).map(id => toID(id)) ?? [];
525
535
 
@@ -532,7 +542,7 @@ const toIDs = (ids) => ids?.filter(id => !isNaN(toID(id))).map(id => toID(id)) ?
532
542
  * @param {number} options.maxHeight - The maximum height of the converted PNG image.
533
543
  * @param {number} options.maxWidth - The maximum width of the converted PNG image.
534
544
  * @param {number} options.idealArea - The ideal area of the converted PNG image.
535
- * @returns The converted PNG image as a data URL.
545
+ * @returns {string} The converted PNG image as a data URL.
536
546
  * @throws Error if unable to get the canvas context.
537
547
  */
538
548
  const toPNG = ({ image, dimensions, maxHeight, maxWidth, idealArea, }) => {
@@ -647,13 +657,15 @@ const fetchImageAsBase64 = async (url) => {
647
657
  /**
648
658
  * Deletes all undefined keys from an object.
649
659
  *
650
- * @param obj The object to delete undefined keys from.
651
- * @returns The object without undefined keys.
660
+ * @template TObject
661
+ * @param {TObject} obj The object to delete undefined keys from.
652
662
  * @example deleteUndefinedKeys({ a: 1, b: undefined }) // { a: 1 }
663
+ * @returns {TObject} The object without undefined keys.
653
664
  */
654
665
  const deleteUndefinedKeys = (obj) => {
655
666
  Object.keys(obj).forEach(key => {
656
667
  if (typeof obj[key] === "object" && obj[key] !== null) {
668
+ // eslint-disable-next-line local-rules/no-typescript-assertion
657
669
  deleteUndefinedKeys(obj[key]);
658
670
  }
659
671
  else if (obj[key] === undefined) {
@@ -665,8 +677,8 @@ const deleteUndefinedKeys = (obj) => {
665
677
  /**
666
678
  * Checks if an object is not empty.
667
679
  *
668
- * @param obj - The object to check.
669
- * @returns The object if not empty, otherwise undefined.
680
+ * @template TObject * @param obj - The object to check.
681
+ * @returns {TObject | undefined} The object if not empty, otherwise undefined.
670
682
  */
671
683
  const objNotEmpty = (obj) => obj && Object.keys(obj).length > 0 ? obj : undefined;
672
684
  /**
@@ -676,14 +688,16 @@ const pick = (obj, ...keys) => {
676
688
  return keys.reduce((acc, key) => {
677
689
  acc[key] = obj[key];
678
690
  return acc;
679
- }, {});
691
+ },
692
+ // eslint-disable-next-line local-rules/no-typescript-assertion
693
+ {});
680
694
  };
681
695
  /**
682
696
  * Returns an object with only the differences between two input objects.
683
697
  * Not recursive, only compares first level properties.
684
698
  */
685
699
  const getFirstLevelObjectPropertyDifferences = (obj1, obj2) => {
686
- return objectEntries(obj1).reduce((diff, [key, value]) => {
700
+ return Object.entries(obj1).reduce((diff, [key, value]) => {
687
701
  // Check if the property exists in obj2.
688
702
  if (key in obj2) {
689
703
  const val = obj2[key];
@@ -707,7 +721,8 @@ const getFirstLevelObjectPropertyDifferences = (obj1, obj2) => {
707
721
  * @example replaceNullableNumbersWithZero({ a: 1, b: null, c: undefined }) // { a: 1, b: 0, c: 0 }
708
722
  */
709
723
  const replaceNullableNumbersWithZero = (record) => {
710
- return Object.fromEntries(objectEntries(record).map(([key, value]) => [key, value ?? 0]));
724
+ // eslint-disable-next-line local-rules/no-typescript-assertion
725
+ return Object.fromEntries(Object.entries(record).map(([key, value]) => [key, value ?? 0]));
711
726
  };
712
727
  /**
713
728
  * Removes a property from an object in a type-safe way.
@@ -720,6 +735,7 @@ const replaceNullableNumbersWithZero = (record) => {
720
735
  const removeProperty = (obj, key) => {
721
736
  const { [key]: _, ...rest } = obj;
722
737
  // should be safe because we remove the key from the object, just no way to type it properly
738
+ // eslint-disable-next-line local-rules/no-typescript-assertion
723
739
  return rest;
724
740
  };
725
741
  /**
@@ -735,7 +751,6 @@ const removeProperties = (obj, keys) => {
735
751
  for (const key of keys) {
736
752
  delete result[key];
737
753
  }
738
- // should be safe because we remove the keys from the object, just no way to type it properly
739
754
  return result;
740
755
  };
741
756
 
@@ -891,7 +906,7 @@ const convertBlobToBase64 = (blob) => {
891
906
  const reader = new FileReader();
892
907
  reader.readAsDataURL(blob);
893
908
  reader.onload = () => {
894
- if (!reader.result) {
909
+ if (reader.result === null) {
895
910
  no(new Error("Failed to read blob data"));
896
911
  return;
897
912
  }
@@ -982,7 +997,7 @@ const stringCompareFromKey = (key) => (a, b) => {
982
997
  return collator.compare(aVal, bVal);
983
998
  }
984
999
  else {
985
- throw new Error(`Cannot compare property '${key}': values are not strings`);
1000
+ throw new Error(`Cannot compare property '${String(key)}': values are not strings`);
986
1001
  }
987
1002
  };
988
1003
  /**
@@ -1038,10 +1053,10 @@ const doNumberCompare = (a, b, options) => {
1038
1053
  return 0;
1039
1054
  }
1040
1055
  if (!isDefined(a)) {
1041
- return options && options.unknownAfterHighest ? 1 : -1;
1056
+ return (options?.unknownAfterHighest === true) ? 1 : -1;
1042
1057
  }
1043
1058
  if (!isDefined(b)) {
1044
- return options && options.unknownAfterHighest ? -1 : 1;
1059
+ return (options?.unknownAfterHighest === true) ? -1 : 1;
1045
1060
  }
1046
1061
  return a - b;
1047
1062
  };
@@ -1072,13 +1087,13 @@ function isDefined(value) {
1072
1087
  * @example booleanCompare(false, true) // 1
1073
1088
  */
1074
1089
  const booleanCompare = (a, b) => {
1075
- if (!a && !b) {
1090
+ if (a !== true && b !== true) {
1076
1091
  return 0;
1077
1092
  }
1078
- if (!a) {
1093
+ if (a !== true) {
1079
1094
  return 1;
1080
1095
  }
1081
- if (!b) {
1096
+ if (b !== true) {
1082
1097
  return -1;
1083
1098
  }
1084
1099
  return 0;
@@ -1136,6 +1151,25 @@ const stripHiddenCharacters = (input) => {
1136
1151
  return input.replace(hiddenRegex, "");
1137
1152
  };
1138
1153
 
1154
+ const svgElementSchema = zod.z.object({
1155
+ nodeName: zod.z.string(),
1156
+ width: zod.z.object({
1157
+ baseVal: zod.z.object({
1158
+ value: zod.z.number(),
1159
+ }),
1160
+ }),
1161
+ height: zod.z.object({
1162
+ baseVal: zod.z.object({
1163
+ value: zod.z.number(),
1164
+ }),
1165
+ }),
1166
+ viewBox: zod.z.object({
1167
+ baseVal: zod.z.object({
1168
+ width: zod.z.number(),
1169
+ height: zod.z.number(),
1170
+ }),
1171
+ }),
1172
+ });
1139
1173
  /**
1140
1174
  * Convert the given value to HEX
1141
1175
  * If the value is not rgb, returns back the same value
@@ -1158,7 +1192,7 @@ const colorsFromStyleDeclaration = (styles) => {
1158
1192
  * Loads the dimensions of an SVG string.
1159
1193
  *
1160
1194
  * @param base64EncodedSVG The SVG string to load dimensions from.
1161
- * @returns A promise that resolves to an object containing the width and height of the SVG.
1195
+ * @returns {Promise<ImageDimensions>} A promise that resolves to an object containing the width and height of the SVG.
1162
1196
  * @throws {Error} If the SVG string is invalid or the dimensions cannot be determined.
1163
1197
  */
1164
1198
  const loadSVGDimensions = (base64EncodedSVG) => {
@@ -1167,12 +1201,17 @@ const loadSVGDimensions = (base64EncodedSVG) => {
1167
1201
  const svgAsString = atob(base64EncodedSVG.replace("data:image/svg+xml;base64,", ""));
1168
1202
  const parser = new DOMParser();
1169
1203
  const svgDoc = parser.parseFromString(svgAsString, "image/svg+xml");
1170
- const svgElement = svgDoc.documentElement;
1171
- // Check if parsing was successful
1172
- if (svgElement.nodeName === "parsererror") {
1204
+ // Check if parsing was successful first
1205
+ if (svgDoc.documentElement.nodeName === "parsererror") {
1173
1206
  reject(new Error("Invalid SVG string"));
1174
1207
  return;
1175
1208
  }
1209
+ const svgElementValidation = svgElementSchema.safeParse(svgDoc.documentElement);
1210
+ if (!svgElementValidation.success) {
1211
+ reject(new Error("Invalid SVG element structure"));
1212
+ return;
1213
+ }
1214
+ const svgElement = svgElementValidation.data;
1176
1215
  // Get dimensions
1177
1216
  const width = svgElement.width.baseVal.value;
1178
1217
  const height = svgElement.height.baseVal.value;
@@ -1214,14 +1253,16 @@ const getAllColors = (base64EncodedSVG) => {
1214
1253
  });
1215
1254
  svgImage.querySelectorAll("style").forEach(element => {
1216
1255
  const cssRules = element.sheet?.cssRules;
1217
- if (cssRules?.length) {
1256
+ if (cssRules && cssRules.length > 0) {
1218
1257
  for (let i = 0; i < cssRules.length; i++) {
1219
1258
  // Checking if the style attribute exists
1220
- const cssRule = cssRules[i]; // Replace type casting with type assertion
1221
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1222
- if (cssRule.style) {
1223
- const cssRuleStyles = cssRule.style;
1224
- colors.push(...colorsFromStyleDeclaration(cssRuleStyles));
1259
+ const cssRuleSchema = zod.z.object({
1260
+ style: zod.z.instanceof(CSSStyleDeclaration).optional(),
1261
+ });
1262
+ const cssRuleValidation = cssRuleSchema.safeParse(cssRules[i]);
1263
+ if (cssRuleValidation.success && cssRuleValidation.data.style) {
1264
+ const style = cssRuleValidation.data.style;
1265
+ colors.push(...colorsFromStyleDeclaration(style));
1225
1266
  }
1226
1267
  }
1227
1268
  }
@@ -1252,10 +1293,12 @@ const getAllColors = (base64EncodedSVG) => {
1252
1293
  /**
1253
1294
  * Converts a Base64 encoded SVG to a Scaled Base64 PNG.
1254
1295
  *
1255
- * @param {string} base64EncodedSVG The Base64 encoded svg string to convert
1256
- * @param {number} maxWidth The max width(px) of the output PNG
1257
- * @param {number} maxHeight The max height(px) of the output PNG
1258
- * @returns {Promise<string>} A Base64 encoded PNG, scaled to the given parameters
1296
+ * @param params The parameters object
1297
+ * @param params.base64EncodedSVG The Base64 encoded svg string to convert
1298
+ * @param params.maxWidth The max width(px) of the output PNG
1299
+ * @param params.maxHeight The max height(px) of the output PNG
1300
+ * @param params.idealArea The ideal area for the image
1301
+ * @returns {Promise<string>} A Base64 encoded PNG, scaled to the given parameters
1259
1302
  */
1260
1303
  const svgToPNG = async ({ base64EncodedSVG, maxWidth, maxHeight, idealArea, }) => {
1261
1304
  const [image, dimensions] = await Promise.all([
@@ -1340,6 +1383,7 @@ const convertYardsToMeters = (value) => {
1340
1383
  };
1341
1384
 
1342
1385
  exports.DateTimeFormat = DateTimeFormat;
1386
+ exports.HoursAndMinutesFormat = HoursAndMinutesFormat;
1343
1387
  exports.align = align;
1344
1388
  exports.alphabeticallySort = alphabeticallySort;
1345
1389
  exports.arrayLengthCompare = arrayLengthCompare;
package/index.esm.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { z } from 'zod';
1
2
  import { v3, v4, v5 } from 'uuid';
2
3
 
3
4
  /**
@@ -17,7 +18,7 @@ const formatAddress = (address) => {
17
18
  * @example formatCoordinates({ latitude: 1.234567, longitude: 2.345678 }) // "1.234567, 2.345678"
18
19
  */
19
20
  const formatCoordinates = (coordinates, toFixed) => {
20
- return toFixed
21
+ return toFixed !== undefined
21
22
  ? `${Number(coordinates.latitude.toFixed(toFixed))}, ${Number(coordinates.longitude.toFixed(toFixed))}`
22
23
  : `${coordinates.latitude}, ${coordinates.longitude}`;
23
24
  };
@@ -43,7 +44,7 @@ const nonNullable = (value) => {
43
44
  *
44
45
  */
45
46
  const truthy = (value) => {
46
- return !!value;
47
+ return Boolean(value);
47
48
  };
48
49
  /**
49
50
  * Converts an object into an array of properly typed key-value pairs.
@@ -57,7 +58,9 @@ const truthy = (value) => {
57
58
  * @param {TObject} object - The object to convert.
58
59
  * @template TObject - The type of the object.
59
60
  */
60
- const objectEntries = (object) => Object.entries(object);
61
+ const objectEntries = (object) =>
62
+ // eslint-disable-next-line local-rules/no-typescript-assertion
63
+ Object.entries(object);
61
64
  /**
62
65
  * Converts an array of key-value pairs into an object.
63
66
  * This is a type-faithful alternative to Object.fromEntries().
@@ -66,6 +69,7 @@ const objectEntries = (object) => Object.entries(object);
66
69
  * @template TEntries - The type of the entries array.
67
70
  */
68
71
  const objectFromEntries = (entries) => {
72
+ // eslint-disable-next-line local-rules/no-typescript-assertion
69
73
  return Object.fromEntries(entries);
70
74
  };
71
75
  /**
@@ -82,6 +86,7 @@ const objectFromEntries = (entries) => {
82
86
  * @returns {(keyof TObject)[]} An array of the keys of the object.
83
87
  */
84
88
  const objectKeys = (object) => {
89
+ // eslint-disable-next-line local-rules/no-typescript-assertion
85
90
  return Object.keys(object).map(key => key);
86
91
  };
87
92
  /**
@@ -93,17 +98,20 @@ const objectKeys = (object) => {
93
98
  *
94
99
  * @template TObject - The type of the object.
95
100
  * @param {TObject} object - The object to get the values from.
96
- * @returns {TObject[keyof TObject][]} An array of the values of the object.
101
+ * @returns {Array} An array of the values of the object.
97
102
  */
98
- const objectValues = (object) => Object.values(object);
103
+ const objectValues = (object) =>
104
+ // eslint-disable-next-line local-rules/no-typescript-assertion
105
+ Object.values(object);
99
106
 
100
107
  /**
101
108
  * Returns a new array with the items from the previous array and the new array, but only if the item's key is unique.
102
109
  *
110
+ * @template TObject - the type of the items in the array
103
111
  * @param key The key to use to determine uniqueness
104
112
  * @param previous The previous array of items to merge with the new array
105
113
  * @param newArray The new array of items to merge with the previous array
106
- * @returns A new array with the items from the previous array and the new array, but only if the item's key is unique.
114
+ * @returns {Array<TObject>} A new array with the items from the previous array and the new array, but only if the item's key is unique.
107
115
  */
108
116
  const unionArraysByKey = (key, previous, newArray) => {
109
117
  const previousIds = previous?.map(edge => edge[key]) || [];
@@ -125,8 +133,9 @@ const isArrayEqual = (a, b) => a.length === b.length && a.every((v, i) => v ===
125
133
  /**
126
134
  * Checks if an array is not empty.
127
135
  *
136
+ * @template TItem
128
137
  * @param array - The array to check.
129
- * @returns The array if not empty, otherwise undefined.
138
+ * @returns {Array<TItem> | undefined} The array if not empty, otherwise undefined.
130
139
  */
131
140
  const arrayNotEmpty = (array) => array && array.length > 0 ? array : undefined;
132
141
 
@@ -158,14 +167,13 @@ const size = {
158
167
  LARGE: "large",
159
168
  };
160
169
 
161
- var HoursAndMinutesFormat;
162
- (function (HoursAndMinutesFormat) {
163
- HoursAndMinutesFormat["HOURS_MIN_SEC_LONG"] = "HOURS_MIN_SEC_LONG";
164
- HoursAndMinutesFormat["HOURS_MIN_SEC"] = "HOURS_MIN_SEC";
165
- HoursAndMinutesFormat["HOURS_MIN_LONG"] = "HOURS_MIN_LONG";
166
- HoursAndMinutesFormat["HOURS_MIN"] = "HOURS_MIN";
167
- HoursAndMinutesFormat["HOURS_LONG"] = "HOURS_LONG";
168
- })(HoursAndMinutesFormat || (HoursAndMinutesFormat = {}));
170
+ const HoursAndMinutesFormat = {
171
+ HOURS_MIN_SEC_LONG: "HOURS_MIN_SEC_LONG", // h [h] mm [min] ss [sec]
172
+ HOURS_MIN_SEC: "HOURS_MIN_SEC", // h[h] m[m] s[s]
173
+ HOURS_MIN_LONG: "HOURS_MIN_LONG", // h [hrs] mm [min]
174
+ HOURS_MIN: "HOURS_MIN", // h[h] m[m]
175
+ HOURS_LONG: "HOURS_LONG", // h [hrs]
176
+ };
169
177
  const DateTimeFormat = {
170
178
  DATE: {
171
179
  selectFormat: "dateOnly",
@@ -205,7 +213,7 @@ const DateTimeFormat = {
205
213
  */
206
214
  const getISOStringFromDate = (date) => {
207
215
  try {
208
- if (!date) {
216
+ if (date === null || date === undefined) {
209
217
  return null;
210
218
  }
211
219
  return new Date(date).toISOString();
@@ -276,7 +284,7 @@ function doNothing() {
276
284
  */
277
285
  const enumFromValue = (val, _enum) => {
278
286
  const enumName = objectKeys(_enum).find(k => _enum[k] === val);
279
- if (!enumName) {
287
+ if (enumName === undefined) {
280
288
  throw Error(`Unknown enum value: ${val} expect one of: ${JSON.stringify(objectValues(_enum))}`);
281
289
  }
282
290
  return _enum[enumName];
@@ -306,7 +314,7 @@ const enumOrUndefinedFromValue = (_enum, val) => {
306
314
  */
307
315
  const enumFromValueTypesafe = (val, _enum) => {
308
316
  const enumName = objectKeys(_enum).find(k => _enum[k] === val);
309
- if (!enumName) {
317
+ if (enumName === undefined) {
310
318
  throw Error(`Unknown enum value: ${String(val)} expect one of: ${JSON.stringify(objectValues(_enum))}`);
311
319
  }
312
320
  return _enum[enumName];
@@ -331,9 +339,10 @@ const exhaustiveCheck = (value) => {
331
339
 
332
340
  /**
333
341
  *
342
+ * @template TItem
334
343
  * @param arr1 An array of string or numbers
335
344
  * @param arr2 An array of string or numbers
336
- * @returns The elements shared between arr1 and arr2.
345
+ * @returns {Array<TItem>} The elements shared between arr1 and arr2.
337
346
  */
338
347
  function intersection(arr1, arr2) {
339
348
  const a = new Set(arr1);
@@ -343,9 +352,10 @@ function intersection(arr1, arr2) {
343
352
  }
344
353
  /**
345
354
  *
355
+ * @template TItem
346
356
  * @param arr1 An array of string or numbers
347
357
  * @param arr2 An array of string or numbers
348
- * @returns The elements present in arr1 but not arr2.
358
+ * @returns {Array<TItem>} The elements present in arr1 but not arr2.
349
359
  */
350
360
  function difference(arr1, arr2) {
351
361
  const a = new Set(arr1);
@@ -408,11 +418,11 @@ searchTerm) => {
408
418
  /**
409
419
  * Group an array of items by a key.
410
420
  *
411
- * @template T The type of items in the list.
412
- * @template K The type of the key.
413
- * @param {T[]} list The array of items to group.
414
- * @param {(item: T) => K} getKey A function to get the key to group by.
415
- * @returns {Map<K, T[]>} A map of the items grouped by the key.
421
+ * @template TItem The type of items in the list.
422
+ * @template KeyGroup The type of the key.
423
+ * @param {TItem[]} list The array of items to group.
424
+ * @param {(item: TItem) => KeyGroup} getKey A function to get the key to group by.
425
+ * @returns {Map<KeyGroup, TItem[]>} A map of the items grouped by the key.
416
426
  * @example
417
427
  * groupBy([{ name: "John", surname: "Doe" }, { name: "Jane", surname: "Doe" }], p => p.surname)
418
428
  * Returns: Map { "Doe" => [{ name: "John", surname: "Doe" }, { name: "Jane", surname: "Doe" }] }
@@ -494,7 +504,7 @@ const zeroPadToUUIDLength = (input, maxLength) => input.length < maxLength ? zer
494
504
  */
495
505
  const toUUID = (value) => {
496
506
  if (isUUID(value.toString())) {
497
- return value;
507
+ return value.toString();
498
508
  }
499
509
  // A valid UUID length is 36 but we subtract 4 because we insert 4 hyphens.
500
510
  const id = zeroPadToUUIDLength(value.toString(), 32);
@@ -517,7 +527,7 @@ const toID = (uuid) => Number(uuid.replace(/-/g, "").replace(/^0+/, ""));
517
527
  * A helper function that converts a list of UUID to a list of valid machine IDs.
518
528
  * NOTE that NaN will be removed so list cannot be expected to be of same size.
519
529
  *
520
- * @param uuid The list of UUIDs that should be converted to a list of valid machine IDs
530
+ * @param ids The list of UUIDs that should be converted to a list of valid machine IDs
521
531
  */
522
532
  const toIDs = (ids) => ids?.filter(id => !isNaN(toID(id))).map(id => toID(id)) ?? [];
523
533
 
@@ -530,7 +540,7 @@ const toIDs = (ids) => ids?.filter(id => !isNaN(toID(id))).map(id => toID(id)) ?
530
540
  * @param {number} options.maxHeight - The maximum height of the converted PNG image.
531
541
  * @param {number} options.maxWidth - The maximum width of the converted PNG image.
532
542
  * @param {number} options.idealArea - The ideal area of the converted PNG image.
533
- * @returns The converted PNG image as a data URL.
543
+ * @returns {string} The converted PNG image as a data URL.
534
544
  * @throws Error if unable to get the canvas context.
535
545
  */
536
546
  const toPNG = ({ image, dimensions, maxHeight, maxWidth, idealArea, }) => {
@@ -645,13 +655,15 @@ const fetchImageAsBase64 = async (url) => {
645
655
  /**
646
656
  * Deletes all undefined keys from an object.
647
657
  *
648
- * @param obj The object to delete undefined keys from.
649
- * @returns The object without undefined keys.
658
+ * @template TObject
659
+ * @param {TObject} obj The object to delete undefined keys from.
650
660
  * @example deleteUndefinedKeys({ a: 1, b: undefined }) // { a: 1 }
661
+ * @returns {TObject} The object without undefined keys.
651
662
  */
652
663
  const deleteUndefinedKeys = (obj) => {
653
664
  Object.keys(obj).forEach(key => {
654
665
  if (typeof obj[key] === "object" && obj[key] !== null) {
666
+ // eslint-disable-next-line local-rules/no-typescript-assertion
655
667
  deleteUndefinedKeys(obj[key]);
656
668
  }
657
669
  else if (obj[key] === undefined) {
@@ -663,8 +675,8 @@ const deleteUndefinedKeys = (obj) => {
663
675
  /**
664
676
  * Checks if an object is not empty.
665
677
  *
666
- * @param obj - The object to check.
667
- * @returns The object if not empty, otherwise undefined.
678
+ * @template TObject * @param obj - The object to check.
679
+ * @returns {TObject | undefined} The object if not empty, otherwise undefined.
668
680
  */
669
681
  const objNotEmpty = (obj) => obj && Object.keys(obj).length > 0 ? obj : undefined;
670
682
  /**
@@ -674,14 +686,16 @@ const pick = (obj, ...keys) => {
674
686
  return keys.reduce((acc, key) => {
675
687
  acc[key] = obj[key];
676
688
  return acc;
677
- }, {});
689
+ },
690
+ // eslint-disable-next-line local-rules/no-typescript-assertion
691
+ {});
678
692
  };
679
693
  /**
680
694
  * Returns an object with only the differences between two input objects.
681
695
  * Not recursive, only compares first level properties.
682
696
  */
683
697
  const getFirstLevelObjectPropertyDifferences = (obj1, obj2) => {
684
- return objectEntries(obj1).reduce((diff, [key, value]) => {
698
+ return Object.entries(obj1).reduce((diff, [key, value]) => {
685
699
  // Check if the property exists in obj2.
686
700
  if (key in obj2) {
687
701
  const val = obj2[key];
@@ -705,7 +719,8 @@ const getFirstLevelObjectPropertyDifferences = (obj1, obj2) => {
705
719
  * @example replaceNullableNumbersWithZero({ a: 1, b: null, c: undefined }) // { a: 1, b: 0, c: 0 }
706
720
  */
707
721
  const replaceNullableNumbersWithZero = (record) => {
708
- return Object.fromEntries(objectEntries(record).map(([key, value]) => [key, value ?? 0]));
722
+ // eslint-disable-next-line local-rules/no-typescript-assertion
723
+ return Object.fromEntries(Object.entries(record).map(([key, value]) => [key, value ?? 0]));
709
724
  };
710
725
  /**
711
726
  * Removes a property from an object in a type-safe way.
@@ -718,6 +733,7 @@ const replaceNullableNumbersWithZero = (record) => {
718
733
  const removeProperty = (obj, key) => {
719
734
  const { [key]: _, ...rest } = obj;
720
735
  // should be safe because we remove the key from the object, just no way to type it properly
736
+ // eslint-disable-next-line local-rules/no-typescript-assertion
721
737
  return rest;
722
738
  };
723
739
  /**
@@ -733,7 +749,6 @@ const removeProperties = (obj, keys) => {
733
749
  for (const key of keys) {
734
750
  delete result[key];
735
751
  }
736
- // should be safe because we remove the keys from the object, just no way to type it properly
737
752
  return result;
738
753
  };
739
754
 
@@ -889,7 +904,7 @@ const convertBlobToBase64 = (blob) => {
889
904
  const reader = new FileReader();
890
905
  reader.readAsDataURL(blob);
891
906
  reader.onload = () => {
892
- if (!reader.result) {
907
+ if (reader.result === null) {
893
908
  no(new Error("Failed to read blob data"));
894
909
  return;
895
910
  }
@@ -980,7 +995,7 @@ const stringCompareFromKey = (key) => (a, b) => {
980
995
  return collator.compare(aVal, bVal);
981
996
  }
982
997
  else {
983
- throw new Error(`Cannot compare property '${key}': values are not strings`);
998
+ throw new Error(`Cannot compare property '${String(key)}': values are not strings`);
984
999
  }
985
1000
  };
986
1001
  /**
@@ -1036,10 +1051,10 @@ const doNumberCompare = (a, b, options) => {
1036
1051
  return 0;
1037
1052
  }
1038
1053
  if (!isDefined(a)) {
1039
- return options && options.unknownAfterHighest ? 1 : -1;
1054
+ return (options?.unknownAfterHighest === true) ? 1 : -1;
1040
1055
  }
1041
1056
  if (!isDefined(b)) {
1042
- return options && options.unknownAfterHighest ? -1 : 1;
1057
+ return (options?.unknownAfterHighest === true) ? -1 : 1;
1043
1058
  }
1044
1059
  return a - b;
1045
1060
  };
@@ -1070,13 +1085,13 @@ function isDefined(value) {
1070
1085
  * @example booleanCompare(false, true) // 1
1071
1086
  */
1072
1087
  const booleanCompare = (a, b) => {
1073
- if (!a && !b) {
1088
+ if (a !== true && b !== true) {
1074
1089
  return 0;
1075
1090
  }
1076
- if (!a) {
1091
+ if (a !== true) {
1077
1092
  return 1;
1078
1093
  }
1079
- if (!b) {
1094
+ if (b !== true) {
1080
1095
  return -1;
1081
1096
  }
1082
1097
  return 0;
@@ -1134,6 +1149,25 @@ const stripHiddenCharacters = (input) => {
1134
1149
  return input.replace(hiddenRegex, "");
1135
1150
  };
1136
1151
 
1152
+ const svgElementSchema = z.object({
1153
+ nodeName: z.string(),
1154
+ width: z.object({
1155
+ baseVal: z.object({
1156
+ value: z.number(),
1157
+ }),
1158
+ }),
1159
+ height: z.object({
1160
+ baseVal: z.object({
1161
+ value: z.number(),
1162
+ }),
1163
+ }),
1164
+ viewBox: z.object({
1165
+ baseVal: z.object({
1166
+ width: z.number(),
1167
+ height: z.number(),
1168
+ }),
1169
+ }),
1170
+ });
1137
1171
  /**
1138
1172
  * Convert the given value to HEX
1139
1173
  * If the value is not rgb, returns back the same value
@@ -1156,7 +1190,7 @@ const colorsFromStyleDeclaration = (styles) => {
1156
1190
  * Loads the dimensions of an SVG string.
1157
1191
  *
1158
1192
  * @param base64EncodedSVG The SVG string to load dimensions from.
1159
- * @returns A promise that resolves to an object containing the width and height of the SVG.
1193
+ * @returns {Promise<ImageDimensions>} A promise that resolves to an object containing the width and height of the SVG.
1160
1194
  * @throws {Error} If the SVG string is invalid or the dimensions cannot be determined.
1161
1195
  */
1162
1196
  const loadSVGDimensions = (base64EncodedSVG) => {
@@ -1165,12 +1199,17 @@ const loadSVGDimensions = (base64EncodedSVG) => {
1165
1199
  const svgAsString = atob(base64EncodedSVG.replace("data:image/svg+xml;base64,", ""));
1166
1200
  const parser = new DOMParser();
1167
1201
  const svgDoc = parser.parseFromString(svgAsString, "image/svg+xml");
1168
- const svgElement = svgDoc.documentElement;
1169
- // Check if parsing was successful
1170
- if (svgElement.nodeName === "parsererror") {
1202
+ // Check if parsing was successful first
1203
+ if (svgDoc.documentElement.nodeName === "parsererror") {
1171
1204
  reject(new Error("Invalid SVG string"));
1172
1205
  return;
1173
1206
  }
1207
+ const svgElementValidation = svgElementSchema.safeParse(svgDoc.documentElement);
1208
+ if (!svgElementValidation.success) {
1209
+ reject(new Error("Invalid SVG element structure"));
1210
+ return;
1211
+ }
1212
+ const svgElement = svgElementValidation.data;
1174
1213
  // Get dimensions
1175
1214
  const width = svgElement.width.baseVal.value;
1176
1215
  const height = svgElement.height.baseVal.value;
@@ -1212,14 +1251,16 @@ const getAllColors = (base64EncodedSVG) => {
1212
1251
  });
1213
1252
  svgImage.querySelectorAll("style").forEach(element => {
1214
1253
  const cssRules = element.sheet?.cssRules;
1215
- if (cssRules?.length) {
1254
+ if (cssRules && cssRules.length > 0) {
1216
1255
  for (let i = 0; i < cssRules.length; i++) {
1217
1256
  // Checking if the style attribute exists
1218
- const cssRule = cssRules[i]; // Replace type casting with type assertion
1219
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1220
- if (cssRule.style) {
1221
- const cssRuleStyles = cssRule.style;
1222
- colors.push(...colorsFromStyleDeclaration(cssRuleStyles));
1257
+ const cssRuleSchema = z.object({
1258
+ style: z.instanceof(CSSStyleDeclaration).optional(),
1259
+ });
1260
+ const cssRuleValidation = cssRuleSchema.safeParse(cssRules[i]);
1261
+ if (cssRuleValidation.success && cssRuleValidation.data.style) {
1262
+ const style = cssRuleValidation.data.style;
1263
+ colors.push(...colorsFromStyleDeclaration(style));
1223
1264
  }
1224
1265
  }
1225
1266
  }
@@ -1250,10 +1291,12 @@ const getAllColors = (base64EncodedSVG) => {
1250
1291
  /**
1251
1292
  * Converts a Base64 encoded SVG to a Scaled Base64 PNG.
1252
1293
  *
1253
- * @param {string} base64EncodedSVG The Base64 encoded svg string to convert
1254
- * @param {number} maxWidth The max width(px) of the output PNG
1255
- * @param {number} maxHeight The max height(px) of the output PNG
1256
- * @returns {Promise<string>} A Base64 encoded PNG, scaled to the given parameters
1294
+ * @param params The parameters object
1295
+ * @param params.base64EncodedSVG The Base64 encoded svg string to convert
1296
+ * @param params.maxWidth The max width(px) of the output PNG
1297
+ * @param params.maxHeight The max height(px) of the output PNG
1298
+ * @param params.idealArea The ideal area for the image
1299
+ * @returns {Promise<string>} A Base64 encoded PNG, scaled to the given parameters
1257
1300
  */
1258
1301
  const svgToPNG = async ({ base64EncodedSVG, maxWidth, maxHeight, idealArea, }) => {
1259
1302
  const [image, dimensions] = await Promise.all([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/shared-utils",
3
- "version": "1.8.50",
3
+ "version": "1.8.54",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "engines": {
6
6
  "node": ">=22.x"
@@ -8,7 +8,8 @@
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "dependencies": {
10
10
  "uuid": "^11.1.0",
11
- "@trackunit/react-test-setup": "1.3.50"
11
+ "@trackunit/react-test-setup": "1.3.53",
12
+ "zod": "^3.23.8"
12
13
  },
13
14
  "module": "./index.esm.js",
14
15
  "main": "./index.cjs.js",
@@ -1,10 +1,11 @@
1
- export declare enum HoursAndMinutesFormat {
2
- HOURS_MIN_SEC_LONG = "HOURS_MIN_SEC_LONG",// h [h] mm [min] ss [sec]
3
- HOURS_MIN_SEC = "HOURS_MIN_SEC",// h[h] m[m] s[s]
4
- HOURS_MIN_LONG = "HOURS_MIN_LONG",// h [hrs] mm [min]
5
- HOURS_MIN = "HOURS_MIN",// h[h] m[m]
6
- HOURS_LONG = "HOURS_LONG"
7
- }
1
+ export declare const HoursAndMinutesFormat: {
2
+ readonly HOURS_MIN_SEC_LONG: "HOURS_MIN_SEC_LONG";
3
+ readonly HOURS_MIN_SEC: "HOURS_MIN_SEC";
4
+ readonly HOURS_MIN_LONG: "HOURS_MIN_LONG";
5
+ readonly HOURS_MIN: "HOURS_MIN";
6
+ readonly HOURS_LONG: "HOURS_LONG";
7
+ };
8
+ export type HoursAndMinutesFormatType = (typeof HoursAndMinutesFormat)[keyof typeof HoursAndMinutesFormat];
8
9
  export declare const DateTimeFormat: {
9
10
  readonly DATE: {
10
11
  readonly selectFormat: "dateOnly";
@@ -19,11 +19,11 @@ export declare const getDifferenceBetweenDates: (date1: Date, date2: Date, unit:
19
19
  * @returns {Date} The start of the day for the given date.
20
20
  * @example getStartOfDay(new Date("2021-05-19T12:34:56")) // "2021-05-19T00:00:00"
21
21
  */
22
- export declare const getStartOfDay: <T extends string | number | Date>(date: T) => Date;
22
+ export declare const getStartOfDay: <TDate extends string | number | Date>(date: TDate) => Date;
23
23
  /**
24
24
  * @description Returns the end of the day for a given date.
25
25
  * @param date A date object or a date string.
26
26
  * @returns {Date} The end of the day for the given date.
27
27
  * @example getEndOfDay(new Date("2021-05-19T12:34:56")) // "2021-05-19T23:59:59"
28
28
  */
29
- export declare const getEndOfDay: <T extends string | number | Date>(date: T) => Date;
29
+ export declare const getEndOfDay: <TDate extends string | number | Date>(date: TDate) => Date;
package/src/Maybe.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * Maybe type
3
3
  */
4
- export type Maybe<T> = T | null;
4
+ export type Maybe<TValue> = TValue | null;
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Returns a new array with the items from the previous array and the new array, but only if the item's key is unique.
3
3
  *
4
+ * @template TObject - the type of the items in the array
4
5
  * @param key The key to use to determine uniqueness
5
6
  * @param previous The previous array of items to merge with the new array
6
7
  * @param newArray The new array of items to merge with the previous array
7
- * @returns A new array with the items from the previous array and the new array, but only if the item's key is unique.
8
+ * @returns {Array<TObject>} A new array with the items from the previous array and the new array, but only if the item's key is unique.
8
9
  */
9
10
  export declare const unionArraysByKey: <TObject extends object>(key: keyof TObject, previous: Array<TObject> | undefined | null, newArray: Array<TObject> | undefined | null) => Array<TObject>;
10
11
  /**
@@ -14,7 +15,8 @@ export declare const isArrayEqual: <TItem extends string | number>(a: Array<TIte
14
15
  /**
15
16
  * Checks if an array is not empty.
16
17
  *
18
+ * @template TItem
17
19
  * @param array - The array to check.
18
- * @returns The array if not empty, otherwise undefined.
20
+ * @returns {Array<TItem> | undefined} The array if not empty, otherwise undefined.
19
21
  */
20
22
  export declare const arrayNotEmpty: <TItem>(array?: Array<TItem>) => Array<TItem> | undefined;
@@ -1,4 +1,4 @@
1
- export type DeepPartialNullable<T> = T extends Array<any> ? DeepPartialNullableArray<T[number]> : T extends object ? {
2
- [P in keyof T]?: DeepPartialNullable<T[P]> | null;
3
- } : T | null;
4
- export type DeepPartialNullableArray<T> = Array<DeepPartialNullable<T>>;
1
+ export type DeepPartialNullable<TObject> = TObject extends Array<unknown> ? DeepPartialNullableArray<TObject[number]> : TObject extends object ? {
2
+ [P in keyof TObject]?: DeepPartialNullable<TObject[P]> | null;
3
+ } : TObject | null;
4
+ export type DeepPartialNullableArray<TItem> = Array<DeepPartialNullable<TItem>>;
@@ -6,7 +6,7 @@
6
6
  * @returns {Record<string, string>} The enum value.
7
7
  * @example enumFromValue("MACHINE", AssetType) // AssetType.MACHINE
8
8
  */
9
- export declare const enumFromValue: <T extends Record<string, string | number>>(val: string | number, _enum: T) => T[keyof T];
9
+ export declare const enumFromValue: <TEnum extends Record<string, string | number>>(val: string | number, _enum: TEnum) => TEnum[keyof TEnum];
10
10
  /**
11
11
  * Returns the enum value from a string value or undefined if the string value is undefined or null.
12
12
  *
@@ -15,7 +15,7 @@ export declare const enumFromValue: <T extends Record<string, string | number>>(
15
15
  * @returns {Record<string, string> | undefined} The enum value or undefined.
16
16
  * @example enumFromValue("MACHINE", AssetType) // AssetType.MACHINE
17
17
  */
18
- export declare const enumOrUndefinedFromValue: <T extends Record<string, string>>(_enum: T, val?: string | null) => T[keyof T] | undefined;
18
+ export declare const enumOrUndefinedFromValue: <TEnum extends Record<string, string>>(_enum: TEnum, val?: string | null) => TEnum[keyof TEnum] | undefined;
19
19
  /**
20
20
  * Returns the enum value from a string value or undefined if the string value is undefined or null.
21
21
  * This is a typesafe version of enumOrUndefinedFromValue.
@@ -25,4 +25,4 @@ export declare const enumOrUndefinedFromValue: <T extends Record<string, string>
25
25
  * @returns {Record<string, string> | undefined} The enum value or undefined.
26
26
  * @example enumFromValue("MACHINE", AssetType) // AssetType.MACHINE
27
27
  */
28
- export declare const enumFromValueTypesafe: <T extends Record<string, string>>(val: keyof T, _enum: T) => T[keyof T];
28
+ export declare const enumFromValueTypesafe: <TEnum extends Record<string, string>>(val: keyof TEnum, _enum: TEnum) => TEnum[keyof TEnum];
@@ -1,14 +1,16 @@
1
1
  /**
2
2
  *
3
+ * @template TItem
3
4
  * @param arr1 An array of string or numbers
4
5
  * @param arr2 An array of string or numbers
5
- * @returns The elements shared between arr1 and arr2.
6
+ * @returns {Array<TItem>} The elements shared between arr1 and arr2.
6
7
  */
7
- export declare function intersection<T>(arr1: Array<T>, arr2: Array<T>): Array<T>;
8
+ export declare function intersection<TItem>(arr1: Array<TItem>, arr2: Array<TItem>): Array<TItem>;
8
9
  /**
9
10
  *
11
+ * @template TItem
10
12
  * @param arr1 An array of string or numbers
11
13
  * @param arr2 An array of string or numbers
12
- * @returns The elements present in arr1 but not arr2.
14
+ * @returns {Array<TItem>} The elements present in arr1 but not arr2.
13
15
  */
14
- export declare function difference<T>(arr1: Array<T>, arr2: Array<T>): Array<T>;
16
+ export declare function difference<TItem>(arr1: Array<TItem>, arr2: Array<TItem>): Array<TItem>;
package/src/filter.d.ts CHANGED
@@ -11,20 +11,20 @@ import { Maybe } from "./Maybe";
11
11
  * @returns {[]} The filtered array
12
12
  * @example filterByMultiple([{ name: "John", surname: "Doe" }, { name: "Jane", surname: "Doe" }], [p => p.name, p => p.surname], "John") // [{ name: "John", surname: "Doe" }]
13
13
  */
14
- export declare function filterByMultiple<T>(array: Array<T> | null | undefined, props: (p: T) => Array<Maybe<string> | undefined> | null | undefined, match: string): Array<T>;
14
+ export declare function filterByMultiple<TItem>(array: Array<TItem> | null | undefined, props: (p: TItem) => Array<Maybe<string> | undefined> | null | undefined, match: string): Array<TItem>;
15
15
  /**
16
16
  * Filter an array of items based on a list of properties and a search term.
17
17
  * The provided properties will be matched based on the term split on space.
18
18
  * All terms must have at least one match
19
19
  * The terms can match the same property multiple times
20
20
  */
21
- export declare const fuzzySearch: <T>(
21
+ export declare const fuzzySearch: <TItem>(
22
22
  /** The elements that should be filtered */
23
- elementsToFilter: Array<T>,
23
+ elementsToFilter: Array<TItem>,
24
24
  /**
25
25
  * A function to run on each element
26
26
  * to get an array of strings which should be matched
27
27
  */
28
- filterableProps: (element: T) => Array<string>,
28
+ filterableProps: (element: TItem) => Array<string>,
29
29
  /** A string of the search to match against the element props*/
30
- searchTerm: string) => Array<T>;
30
+ searchTerm: string) => Array<TItem>;
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Group an array of items by a key.
3
3
  *
4
- * @template T The type of items in the list.
5
- * @template K The type of the key.
6
- * @param {T[]} list The array of items to group.
7
- * @param {(item: T) => K} getKey A function to get the key to group by.
8
- * @returns {Map<K, T[]>} A map of the items grouped by the key.
4
+ * @template TItem The type of items in the list.
5
+ * @template KeyGroup The type of the key.
6
+ * @param {TItem[]} list The array of items to group.
7
+ * @param {(item: TItem) => KeyGroup} getKey A function to get the key to group by.
8
+ * @returns {Map<KeyGroup, TItem[]>} A map of the items grouped by the key.
9
9
  * @example
10
10
  * groupBy([{ name: "John", surname: "Doe" }, { name: "Jane", surname: "Doe" }], p => p.surname)
11
11
  * Returns: Map { "Doe" => [{ name: "John", surname: "Doe" }, { name: "Jane", surname: "Doe" }] }
12
12
  */
13
- export declare function groupBy<T, K>(list: Array<T>, getKey: (item: T) => K): Map<K, Array<T>>;
13
+ export declare function groupBy<TItem, KeyGroup>(list: Array<TItem>, getKey: (item: TItem) => KeyGroup): Map<KeyGroup, Array<TItem>>;
package/src/idUtils.d.ts CHANGED
@@ -21,6 +21,6 @@ export declare const toID: (uuid: string) => number;
21
21
  * A helper function that converts a list of UUID to a list of valid machine IDs.
22
22
  * NOTE that NaN will be removed so list cannot be expected to be of same size.
23
23
  *
24
- * @param uuid The list of UUIDs that should be converted to a list of valid machine IDs
24
+ * @param ids The list of UUIDs that should be converted to a list of valid machine IDs
25
25
  */
26
- export declare const toIDs: (ids: Array<string> | null | undefined) => number[];
26
+ export declare const toIDs: (ids: Array<string> | null | undefined) => Array<number>;
@@ -11,7 +11,7 @@ export interface ImageDimensions {
11
11
  * @param {number} options.maxHeight - The maximum height of the converted PNG image.
12
12
  * @param {number} options.maxWidth - The maximum width of the converted PNG image.
13
13
  * @param {number} options.idealArea - The ideal area of the converted PNG image.
14
- * @returns The converted PNG image as a data URL.
14
+ * @returns {string} The converted PNG image as a data URL.
15
15
  * @throws Error if unable to get the canvas context.
16
16
  */
17
17
  export declare const toPNG: ({ image, dimensions, maxHeight, maxWidth, idealArea, }: {
@@ -2,22 +2,23 @@ import { MappedOmit } from "./typeUtils";
2
2
  /**
3
3
  * Deletes all undefined keys from an object.
4
4
  *
5
- * @param obj The object to delete undefined keys from.
6
- * @returns The object without undefined keys.
5
+ * @template TObject
6
+ * @param {TObject} obj The object to delete undefined keys from.
7
7
  * @example deleteUndefinedKeys({ a: 1, b: undefined }) // { a: 1 }
8
+ * @returns {TObject} The object without undefined keys.
8
9
  */
9
- export declare const deleteUndefinedKeys: <T extends Record<string, unknown>>(obj: T) => T;
10
+ export declare const deleteUndefinedKeys: <TObject extends Record<string, unknown>>(obj: TObject) => TObject;
10
11
  /**
11
12
  * Checks if an object is not empty.
12
13
  *
13
- * @param obj - The object to check.
14
- * @returns The object if not empty, otherwise undefined.
14
+ * @template TObject * @param obj - The object to check.
15
+ * @returns {TObject | undefined} The object if not empty, otherwise undefined.
15
16
  */
16
- export declare const objNotEmpty: <T extends object>(obj?: T) => T | undefined;
17
+ export declare const objNotEmpty: <TObject extends object>(obj?: TObject) => TObject | undefined;
17
18
  /**
18
19
  * Picks the given keys from an object, typesafe.
19
20
  */
20
- export declare const pick: <T, K extends keyof T>(obj: T, ...keys: Array<K>) => Pick<T, K>;
21
+ export declare const pick: <TObject, KeyObject extends keyof TObject>(obj: TObject, ...keys: Array<KeyObject>) => Pick<TObject, KeyObject>;
21
22
  /**
22
23
  * Returns an object with only the differences between two input objects.
23
24
  * Not recursive, only compares first level properties.
@@ -1,4 +1,4 @@
1
- interface IResizeImageOptions {
1
+ interface ResizeImageOptions {
2
2
  maxSize: number;
3
3
  file: File;
4
4
  }
@@ -22,7 +22,7 @@ export declare const getResizedDimensions: (width: number, height: number, maxWi
22
22
  /**
23
23
  * Resize an image to be no larger than the maxSize on each dimension
24
24
  */
25
- export declare const resizeImage: (settings: IResizeImageOptions) => Promise<Blob>;
25
+ export declare const resizeImage: (settings: ResizeImageOptions) => Promise<Blob>;
26
26
  /**
27
27
  * Convert a blob to a base64 string
28
28
  *
@@ -26,7 +26,7 @@ export declare const stringNaturalCompare: (a?: Maybe<string>, b?: Maybe<string>
26
26
  * @example stringCompare("a", "b") // -1
27
27
  * @example stringCompareFromKey("a", "b") // -1
28
28
  */
29
- export declare const stringCompareFromKey: <T>(key: keyof T) => (a: T, b: T) => number;
29
+ export declare const stringCompareFromKey: <TObject>(key: keyof TObject) => (a: TObject, b: TObject) => number;
30
30
  /**
31
31
  * Compare two dates
32
32
  *
@@ -70,7 +70,7 @@ export declare const numberCompareUnknownAfterHighest: (a?: Maybe<number>, b?: M
70
70
  * @example arrayCompare([1, 2], [1, 2], numberCompare) // 0
71
71
  * @example arrayCompare([1, 3], [1, 2], numberCompare) // 1
72
72
  */
73
- export declare const arrayLengthCompare: <T>(a?: Maybe<Array<T>>, b?: Maybe<Array<T>>) => number;
73
+ export declare const arrayLengthCompare: <TItem>(a?: Maybe<Array<TItem>>, b?: Maybe<Array<TItem>>) => number;
74
74
  /**
75
75
  * Compare two booleans
76
76
  *
package/src/svgTools.d.ts CHANGED
@@ -12,7 +12,7 @@ export declare const colorsFromStyleDeclaration: (styles: CSSStyleDeclaration) =
12
12
  * Loads the dimensions of an SVG string.
13
13
  *
14
14
  * @param base64EncodedSVG The SVG string to load dimensions from.
15
- * @returns A promise that resolves to an object containing the width and height of the SVG.
15
+ * @returns {Promise<ImageDimensions>} A promise that resolves to an object containing the width and height of the SVG.
16
16
  * @throws {Error} If the SVG string is invalid or the dimensions cannot be determined.
17
17
  */
18
18
  export declare const loadSVGDimensions: (base64EncodedSVG: string) => Promise<ImageDimensions>;
@@ -23,10 +23,12 @@ export declare const getAllColors: (base64EncodedSVG: string) => Array<string>;
23
23
  /**
24
24
  * Converts a Base64 encoded SVG to a Scaled Base64 PNG.
25
25
  *
26
- * @param {string} base64EncodedSVG The Base64 encoded svg string to convert
27
- * @param {number} maxWidth The max width(px) of the output PNG
28
- * @param {number} maxHeight The max height(px) of the output PNG
29
- * @returns {Promise<string>} A Base64 encoded PNG, scaled to the given parameters
26
+ * @param params The parameters object
27
+ * @param params.base64EncodedSVG The Base64 encoded svg string to convert
28
+ * @param params.maxWidth The max width(px) of the output PNG
29
+ * @param params.maxHeight The max height(px) of the output PNG
30
+ * @param params.idealArea The ideal area for the image
31
+ * @returns {Promise<string>} A Base64 encoded PNG, scaled to the given parameters
30
32
  */
31
33
  export declare const svgToPNG: ({ base64EncodedSVG, maxWidth, maxHeight, idealArea, }: {
32
34
  base64EncodedSVG: string;
@@ -114,7 +114,7 @@ export declare const objectKeys: <TObject extends Record<PropertyKey, unknown>>(
114
114
  *
115
115
  * @template TObject - The type of the object.
116
116
  * @param {TObject} object - The object to get the values from.
117
- * @returns {TObject[keyof TObject][]} An array of the values of the object.
117
+ * @returns {Array} An array of the values of the object.
118
118
  */
119
119
  export declare const objectValues: <TObject extends Record<PropertyKey, unknown>>(object: TObject) => Array<TObject[keyof TObject]>;
120
120
  export {};