@alextheman/utility 3.6.0 → 3.8.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.
package/dist/index.cjs CHANGED
@@ -25,24 +25,19 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
  }) : target, mod));
26
26
 
27
27
  //#endregion
28
- let path = require("path");
29
- path = __toESM(path);
30
28
  let zod = require("zod");
31
29
  zod = __toESM(zod);
30
+ let path = require("path");
31
+ path = __toESM(path);
32
32
 
33
33
  //#region src/constants/NAMESPACE_EXPORT_REGEX.ts
34
34
  const NAMESPACE_EXPORT_REGEX = "export\\s+\\*\\s+from";
35
35
  var NAMESPACE_EXPORT_REGEX_default = NAMESPACE_EXPORT_REGEX;
36
36
 
37
37
  //#endregion
38
- //#region src/functions/appendSemicolon.ts
39
- function appendSemicolon(stringToAppendTo) {
40
- if (stringToAppendTo.includes("\n")) throw new Error("MULTIPLE_LINE_ERROR");
41
- const stringWithNoTrailingWhitespace = stringToAppendTo.trimEnd();
42
- if (stringWithNoTrailingWhitespace === "") return "";
43
- return stringWithNoTrailingWhitespace[stringWithNoTrailingWhitespace.length - 1] === ";" ? stringWithNoTrailingWhitespace : `${stringWithNoTrailingWhitespace};`;
44
- }
45
- var appendSemicolon_default = appendSemicolon;
38
+ //#region src/constants/VERSION_NUMBER_REGEX.ts
39
+ const VERSION_NUMBER_REGEX = "^(?:v)?(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$";
40
+ var VERSION_NUMBER_REGEX_default = VERSION_NUMBER_REGEX;
46
41
 
47
42
  //#endregion
48
43
  //#region src/functions/arrayHelpers/fillArray.ts
@@ -96,7 +91,17 @@ var paralleliseArrays_default = paralleliseArrays;
96
91
  //#endregion
97
92
  //#region src/functions/parsers/parseIntStrict.ts
98
93
  const IntegerParsingError = /* @__PURE__ */ new TypeError("INTEGER_PARSING_ERROR");
99
- function parseIntStrict(...[string, radix]) {
94
+ /**
95
+ * Converts a string to an integer and throws an error if it cannot be converted.
96
+ *
97
+ * @param string — A string to convert into a number.
98
+ * @param radix - A value between 2 and 36 that specifies the base of the number in string. If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal. All other strings are considered decimal.
99
+ *
100
+ * @throws {TypeError} If the provided string cannot safely be converted to an integer.
101
+ *
102
+ * @returns The integer parsed from the input string.
103
+ */
104
+ function parseIntStrict(string, radix) {
100
105
  const trimmedString = string.trim();
101
106
  if (!(radix && radix > 10 && radix <= 36 ? new RegExp(`^[+-]?[0-9a-${String.fromCharCode(87 + radix - 1)}]+$`, "i") : /^[+-]?\d+$/).test(trimmedString)) throw IntegerParsingError;
102
107
  if (radix && radix < 10 && [...trimmedString].some((character) => {
@@ -109,7 +114,15 @@ function parseIntStrict(...[string, radix]) {
109
114
  var parseIntStrict_default = parseIntStrict;
110
115
 
111
116
  //#endregion
112
- //#region src/functions/getRandomNumber.ts
117
+ //#region src/functions/miscellaneous/getRandomNumber.ts
118
+ /**
119
+ * Gets a random number between the given bounds.
120
+ *
121
+ * @param lowerBound - The lowest number that can be chosen.
122
+ * @param upperBound - The highest number that can be chosen.
123
+ *
124
+ * @returns A random number between the provided lower bound and upper bound.
125
+ */
113
126
  function getRandomNumber(lowerBound, upperBound) {
114
127
  const parsedLowerBound = parseIntStrict_default(`${lowerBound}`);
115
128
  const parsedUpperBound = parseIntStrict_default(`${upperBound}`);
@@ -144,8 +157,8 @@ var randomiseArray_default = randomiseArray;
144
157
  /**
145
158
  * Creates an array of numbers within a given range.
146
159
  *
147
- * The range is inclusive of `start` and exclusive of `stop`.
148
- * The sign of `step` must match the direction of the range.
160
+ * - The range is inclusive of `start` and exclusive of `stop`.
161
+ * - The sign of `step` must match the direction of the range.
149
162
  *
150
163
  * @param start - The number to start at (inclusive).
151
164
  * @param stop - The number to stop at (exclusive).
@@ -171,96 +184,22 @@ function range(start, stop, step = 1) {
171
184
  var range_default = range;
172
185
 
173
186
  //#endregion
174
- //#region src/functions/camelToKebab.ts
175
- function camelToKebab(string) {
176
- return string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").toLowerCase();
177
- }
178
- var camelToKebab_default = camelToKebab;
179
-
180
- //#endregion
181
- //#region src/functions/convertFileToBase64.ts
182
- function convertFileToBase64(file) {
183
- return new Promise((resolve, reject) => {
184
- const reader = new FileReader();
185
- reader.readAsDataURL(file);
186
- reader.onload = () => {
187
- if (reader.result === null) {
188
- reject(/* @__PURE__ */ new Error("FILE_CONVERSION_ERROR"));
189
- return;
190
- }
191
- resolve(reader.result);
192
- };
193
- reader.onerror = () => {
194
- reject(/* @__PURE__ */ new Error("FILE_READER_ERROR"));
195
- };
196
- });
197
- }
198
- var convertFileToBase64_default = convertFileToBase64;
199
-
200
- //#endregion
201
- //#region src/functions/createFormData.ts
202
- function getNullableResolutionStrategy(key, strategy) {
203
- return (typeof strategy === "object" ? strategy[key] : strategy) ?? "empty";
204
- }
205
- function createFormData(data, options = {
206
- arrayResolution: "stringify",
207
- nullableResolution: "empty"
208
- }) {
209
- const formData = new FormData();
210
- function resolveNullablesByStrategy(key, value, resolutionStrategy) {
211
- switch (resolutionStrategy) {
212
- case "empty":
213
- formData.append(String(key), "");
214
- break;
215
- case "stringify":
216
- formData.append(String(key), JSON.stringify(value));
217
- break;
218
- case "omit": break;
219
- default: throw new TypeError("SLOPPY_PURE_JAVASCRIPT_USER_ERROR");
220
- }
221
- }
222
- function resolveNullables(key, value, options$1) {
223
- if (options$1.nullableResolution) {
224
- resolveNullablesByStrategy(key, value, getNullableResolutionStrategy(key, options$1.nullableResolution));
225
- return;
226
- }
227
- if (options$1.undefinedResolution || options$1.nullResolution) {
228
- if (data[key] === void 0 && options$1.undefinedResolution) {
229
- resolveNullablesByStrategy(key, value, getNullableResolutionStrategy(key, options$1.undefinedResolution));
230
- return;
231
- }
232
- if (data[key] === null && options$1.nullResolution) resolveNullablesByStrategy(key, value, getNullableResolutionStrategy(key, options$1.nullResolution));
233
- }
234
- }
235
- const entries = Object.entries(data);
236
- for (const [key, value] of entries) if (value instanceof Blob) formData.append(String(key), value);
237
- else if (value === void 0 || value === null) resolveNullables(key, value, options);
238
- else if (typeof value === "object") {
239
- if (Array.isArray(value)) {
240
- if (value.some((item) => {
241
- return item instanceof Blob;
242
- }) && (options.arrayResolution === "stringify" || typeof options.arrayResolution === "object" && options.arrayResolution[key] === "stringify")) throw new TypeError("CANNOT_STRINGIFY_BLOB");
243
- if (options.arrayResolution === "multiple" || typeof options.arrayResolution === "object" && options.arrayResolution[key] === "multiple") {
244
- for (const item of value) {
245
- if ((typeof item === "object" || !item) && !(item instanceof Blob)) throw new TypeError("NON_PRIMITIVE_ARRAY_ITEMS_FOUND");
246
- if (item instanceof Blob) formData.append(String(key), item);
247
- else formData.append(String(key), String(item));
248
- }
249
- continue;
250
- }
251
- }
252
- formData.append(String(key), JSON.stringify(value));
253
- } else formData.append(String(key), String(value));
254
- return formData;
255
- }
256
- var createFormData_default = createFormData;
257
-
258
- //#endregion
259
- //#region src/functions/createTemplateStringsArray.ts
260
- function createTemplateStringsArray(strings) {
261
- return Object.assign([...strings], { raw: [...strings] });
187
+ //#region src/functions/arrayHelpers/removeDuplicates.ts
188
+ /**
189
+ * Removes duplicate values from an array.
190
+ *
191
+ * @template ItemType - The type of the array items.
192
+ *
193
+ * @param array - The array to remove duplicates from.
194
+ *
195
+ * @returns A new array with a different reference in memory, with the duplicates removed.
196
+ */
197
+ function removeDuplicates(array) {
198
+ const outputArray = [];
199
+ for (const item of array) if (!outputArray.includes(item)) outputArray.push(item);
200
+ return outputArray;
262
201
  }
263
- var createTemplateStringsArray_default = createTemplateStringsArray;
202
+ var removeDuplicates_default = removeDuplicates;
264
203
 
265
204
  //#endregion
266
205
  //#region src/functions/date/addDaysToDate.ts
@@ -403,43 +342,111 @@ function isMonthlyMultiple(firstDate, secondDate) {
403
342
  var isMonthlyMultiple_default = isMonthlyMultiple;
404
343
 
405
344
  //#endregion
406
- //#region src/functions/deepCopy.ts
407
- function callDeepCopy(input) {
408
- return typeof input === "object" && input !== null ? deepCopy(input) : input;
409
- }
410
- function deepCopy(object) {
411
- if (Array.isArray(object)) return object.map((item) => {
412
- return callDeepCopy(item);
345
+ //#region src/functions/miscellaneous/convertFileToBase64.ts
346
+ /**
347
+ * Asynchronously converts a file to a base 64 string
348
+ *
349
+ * @param file - The file to convert.
350
+ *
351
+ * @throws {Error} If the file reader gives an error.
352
+ *
353
+ * @returns A promise that resolves to the encoded base 64 string.
354
+ */
355
+ function convertFileToBase64(file) {
356
+ return new Promise((resolve, reject) => {
357
+ const reader = new FileReader();
358
+ reader.readAsDataURL(file);
359
+ reader.onload = () => {
360
+ if (reader.result === null) {
361
+ reject(/* @__PURE__ */ new Error("FILE_CONVERSION_ERROR"));
362
+ return;
363
+ }
364
+ resolve(reader.result);
365
+ };
366
+ reader.onerror = () => {
367
+ reject(/* @__PURE__ */ new Error("FILE_READER_ERROR"));
368
+ };
413
369
  });
414
- const clonedObject = { ...object };
415
- for (const key in clonedObject) {
416
- const value = clonedObject[key];
417
- clonedObject[key] = callDeepCopy(value);
418
- }
419
- return clonedObject;
420
370
  }
421
- var deepCopy_default = deepCopy;
371
+ var convertFileToBase64_default = convertFileToBase64;
422
372
 
423
373
  //#endregion
424
- //#region src/functions/deepFreeze.ts
425
- function deepFreeze(object) {
426
- for (const value of Object.values(object)) {
427
- if (typeof value === "function") continue;
428
- if (value && typeof value === "object") deepFreeze(value);
429
- }
430
- return Object.freeze(object);
374
+ //#region src/functions/miscellaneous/createFormData.ts
375
+ function getNullableResolutionStrategy(key, strategy) {
376
+ return (typeof strategy === "object" ? strategy[key] : strategy) ?? "empty";
431
377
  }
432
- var deepFreeze_default = deepFreeze;
433
-
434
- //#endregion
435
- //#region src/functions/getRecordKeys.ts
436
- function getRecordKeys(record) {
437
- return Object.keys(record);
378
+ /**
379
+ * Creates FormData from a given object, resolving non-string types as appropriate.
380
+ *
381
+ * @template DataType - The type of the given data.
382
+ *
383
+ * @param data - The data to create FormData from.
384
+ * @param options - Options to apply to the conversion.
385
+ *
386
+ * @returns A FormData object with the data applied.
387
+ */
388
+ function createFormData(data, options = {
389
+ arrayResolution: "stringify",
390
+ nullableResolution: "empty"
391
+ }) {
392
+ const formData = new FormData();
393
+ function resolveNullablesByStrategy(key, value, resolutionStrategy) {
394
+ switch (resolutionStrategy) {
395
+ case "empty":
396
+ formData.append(String(key), "");
397
+ break;
398
+ case "stringify":
399
+ formData.append(String(key), JSON.stringify(value));
400
+ break;
401
+ case "omit": break;
402
+ default: throw new TypeError("SLOPPY_PURE_JAVASCRIPT_USER_ERROR");
403
+ }
404
+ }
405
+ function resolveNullables(key, value, options$1) {
406
+ if (options$1.nullableResolution) {
407
+ resolveNullablesByStrategy(key, value, getNullableResolutionStrategy(key, options$1.nullableResolution));
408
+ return;
409
+ }
410
+ if (options$1.undefinedResolution || options$1.nullResolution) {
411
+ if (data[key] === void 0 && options$1.undefinedResolution) {
412
+ resolveNullablesByStrategy(key, value, getNullableResolutionStrategy(key, options$1.undefinedResolution));
413
+ return;
414
+ }
415
+ if (data[key] === null && options$1.nullResolution) resolveNullablesByStrategy(key, value, getNullableResolutionStrategy(key, options$1.nullResolution));
416
+ }
417
+ }
418
+ const entries = Object.entries(data);
419
+ for (const [key, value] of entries) if (value instanceof Blob) formData.append(String(key), value);
420
+ else if (value === void 0 || value === null) resolveNullables(key, value, options);
421
+ else if (typeof value === "object") {
422
+ if (Array.isArray(value)) {
423
+ if (value.some((item) => {
424
+ return item instanceof Blob;
425
+ }) && (options.arrayResolution === "stringify" || typeof options.arrayResolution === "object" && options.arrayResolution[key] === "stringify")) throw new TypeError("CANNOT_STRINGIFY_BLOB");
426
+ if (options.arrayResolution === "multiple" || typeof options.arrayResolution === "object" && options.arrayResolution[key] === "multiple") {
427
+ for (const item of value) {
428
+ if ((typeof item === "object" || !item) && !(item instanceof Blob)) throw new TypeError("NON_PRIMITIVE_ARRAY_ITEMS_FOUND");
429
+ if (item instanceof Blob) formData.append(String(key), item);
430
+ else formData.append(String(key), String(item));
431
+ }
432
+ continue;
433
+ }
434
+ }
435
+ formData.append(String(key), JSON.stringify(value));
436
+ } else formData.append(String(key), String(value));
437
+ return formData;
438
438
  }
439
- var getRecordKeys_default = getRecordKeys;
439
+ var createFormData_default = createFormData;
440
440
 
441
441
  //#endregion
442
- //#region src/functions/isOrdered.ts
442
+ //#region src/functions/miscellaneous/isOrdered.ts
443
+ /**
444
+ * Checks to see if the given array is sorted in ascending order.
445
+ *
446
+ * @param array - The array to check.
447
+ *
448
+ * @returns `true` if the array is sorted in ascending order, and `false` otherwise.
449
+ */
443
450
  function isOrdered(array) {
444
451
  const newArray = [...array];
445
452
  newArray.sort();
@@ -449,47 +456,73 @@ function isOrdered(array) {
449
456
  var isOrdered_default = isOrdered;
450
457
 
451
458
  //#endregion
452
- //#region src/functions/kebabToCamel.ts
453
- function kebabToCamel(string, options) {
454
- if (string !== string.toLowerCase()) throw new Error("INVALID_KEBAB_CASE_INPUT");
455
- if (string.startsWith("-") || string.endsWith("-") || string.includes("--")) throw new Error("INVALID_KEBAB_CASE_INPUT");
456
- let outputString = "";
457
- let skip = false;
458
- for (const stringIndex in [...string]) {
459
- if (skip) {
460
- skip = false;
461
- continue;
462
- }
463
- const index = parseIntStrict_default(stringIndex);
464
- if (index === 0 && options?.startWithUpper) {
465
- outputString += string[index].toUpperCase();
466
- continue;
467
- }
468
- if (index === string.length - 1) {
469
- outputString += string[index];
470
- break;
471
- }
472
- if (string[index] === "-" && /^[a-zA-Z]+$/.test(string[index + 1])) {
473
- outputString += string[index + 1].toUpperCase();
474
- skip = true;
475
- } else outputString += string[index];
476
- }
477
- return outputString;
478
- }
479
- var kebabToCamel_default = kebabToCamel;
480
-
481
- //#endregion
482
- //#region src/functions/normalizeImportPath.ts
483
- function normalizeImportPath(importPath) {
484
- const normalizedPath = path.default.posix.normalize(importPath);
485
- if (importPath.startsWith("./") && !normalizedPath.startsWith("./")) return `./${normalizedPath}`;
486
- return normalizedPath;
487
- }
488
- const normaliseImportPath = normalizeImportPath;
489
- var normalizeImportPath_default = normalizeImportPath;
459
+ //#region src/functions/miscellaneous/stringListToArray.ts
460
+ /**
461
+ * Converts a stringly-typed list to a proper array.
462
+ *
463
+ * @param stringList - The stringly-typed list to convert.
464
+ * @param options - The options to apply to the conversion.
465
+ * @param options.separator - What each item in the list is separated by.
466
+ * @param options.trimWhitespace - An option to trim any extra whitespace.
467
+ *
468
+ * @returns A new array with each item being an item from the given list.
469
+ */
470
+ function stringListToArray(stringList, { separator = ",", trimWhitespace = true } = {}) {
471
+ if (trimWhitespace && stringList.trim() === "") return [];
472
+ const arrayList = stringList.split(separator ?? "");
473
+ return trimWhitespace ? arrayList.map((item) => {
474
+ return item.trim();
475
+ }) : arrayList;
476
+ }
477
+ var stringListToArray_default = stringListToArray;
478
+
479
+ //#endregion
480
+ //#region src/functions/miscellaneous/wait.ts
481
+ /**
482
+ * Waits for the given number of seconds
483
+ *
484
+ * @param seconds - The number of seconds to wait.
485
+ *
486
+ * @returns A Promise that resolves after the given number of seconds.
487
+ */
488
+ function wait(seconds) {
489
+ return new Promise((resolve, _) => {
490
+ setTimeout(() => {
491
+ resolve();
492
+ }, seconds * 1e3);
493
+ });
494
+ }
495
+ var wait_default = wait;
496
+
497
+ //#endregion
498
+ //#region src/functions/objectHelpers/getRecordKeys.ts
499
+ /**
500
+ * Gets the keys from a given record object, properly typed to be an array of the key of the input object's type.
501
+ *
502
+ * @template InputRecordType - The type of the input object.
503
+ *
504
+ * @param record - The record to get the keys from.
505
+ *
506
+ * @returns An array with all the keys of the input object in string form, but properly typed as `keyof InputRecordType`.
507
+ */
508
+ function getRecordKeys(record) {
509
+ return Object.keys(record);
510
+ }
511
+ var getRecordKeys_default = getRecordKeys;
490
512
 
491
513
  //#endregion
492
- //#region src/functions/omitProperties.ts
514
+ //#region src/functions/objectHelpers/omitProperties.ts
515
+ /**
516
+ * Omits properties from a given object.
517
+ *
518
+ * @template ObjectType - The type of the input object.
519
+ * @template KeysToOmit - A type representing the keys to omit from the object.
520
+ *
521
+ * @param object - The object to omit properties from.
522
+ * @param keysToOmit - The keys to omit from the object. Can either be a single string to omit one, or an array to omit multiple.
523
+ *
524
+ * @returns An object with a new reference in memory, with the properties omitted.
525
+ */
493
526
  function omitProperties(object, keysToOmit) {
494
527
  const outputObject = { ...object };
495
528
  (Array.isArray(keysToOmit) ? keysToOmit : [keysToOmit]).forEach((key) => {
@@ -501,6 +534,15 @@ var omitProperties_default = omitProperties;
501
534
 
502
535
  //#endregion
503
536
  //#region src/functions/parsers/parseBoolean.ts
537
+ /**
538
+ * Takes a stringly-typed boolean and converts it to an actual boolean type.
539
+ *
540
+ * @param inputString - The string to parse.
541
+ *
542
+ * @throws {TypeError} If the string is not either `true` or `false` (case insensitive).
543
+ *
544
+ * @returns The string parsed as an actual boolean.
545
+ */
504
546
  function parseBoolean(inputString) {
505
547
  const normalisedString = inputString.toLowerCase();
506
548
  if (!["true", "false"].includes(normalisedString)) throw new TypeError("INVALID_BOOLEAN_STRING");
@@ -517,6 +559,15 @@ const envSchema = zod.z.enum([
517
559
  "development",
518
560
  "production"
519
561
  ]);
562
+ /**
563
+ * Parses the input and verifies it matches one of the environments allowed by the Env types ("test" | "development" | "production").
564
+ *
565
+ * @param data - The data to parse.
566
+ *
567
+ * @throws {ZodError} If the data does not match one of the environments allowed by the Env types ("test" | "development" | "production").
568
+ *
569
+ * @returns The specified environment if allowed.
570
+ */
520
571
  function parseEnv(data) {
521
572
  return envSchema.parse(data);
522
573
  }
@@ -524,6 +575,16 @@ var parseEnv_default = parseEnv;
524
575
 
525
576
  //#endregion
526
577
  //#region src/functions/parsers/parseFormData.ts
578
+ /**
579
+ * Returns an object given FormData and an optional data parser function to call on the resulting object.
580
+ *
581
+ * @template DataType - The type of the resulting object when called from the dataParser.
582
+ *
583
+ * @param formData - The FormData to parse.
584
+ * @param dataParser - An optional parser to call on the object before it gets returned.
585
+ *
586
+ * @returns A parsed object based on the contents of the input formData and the result of parsing with the data parser if provided.
587
+ */
527
588
  function parseFormData(formData, dataParser) {
528
589
  const object = {};
529
590
  formData.forEach((value, key) => {
@@ -544,8 +605,14 @@ const httpErrorCodeLookup = {
544
605
  418: "I_AM_A_TEAPOT",
545
606
  500: "INTERNAL_SERVER_ERROR"
546
607
  };
608
+ /** Represents common errors you may get from a HTTP API request. */
547
609
  var APIError = class extends Error {
548
610
  status;
611
+ /**
612
+ * @param status - A HTTP status code. Can be any number, but numbers between 400 and 600 are encouraged to fit with HTTP status code conventions.
613
+ * @param message - An error message to display alongside the status code.
614
+ * @param options - Extra options to be passed to super Error constructor.
615
+ */
549
616
  constructor(status = 500, message, options) {
550
617
  super(message, options);
551
618
  this.status = status;
@@ -554,6 +621,13 @@ var APIError = class extends Error {
554
621
  Object.defineProperty(this, "message", { enumerable: true });
555
622
  Object.setPrototypeOf(this, new.target.prototype);
556
623
  }
624
+ /**
625
+ * Checks whether the given input may have been caused by an APIError.
626
+ *
627
+ * @param input - The input to check.
628
+ *
629
+ * @returns `true` if the input is an APIError, and `false` otherwise. The type of the input will also be narrowed down to APIError if `true`.
630
+ */
557
631
  static check(input) {
558
632
  const data = input;
559
633
  return typeof data === "object" && data !== null && typeof data?.status === "number" && typeof data?.message === "string";
@@ -563,6 +637,7 @@ var APIError_default = APIError;
563
637
 
564
638
  //#endregion
565
639
  //#region src/types/DataError.ts
640
+ /** Represents errors you may get that may've been caused by a specific piece of data. */
566
641
  var DataError = class extends Error {
567
642
  data;
568
643
  code;
@@ -581,6 +656,13 @@ var DataError = class extends Error {
581
656
  Object.defineProperty(this, "message", { enumerable: true });
582
657
  Object.setPrototypeOf(this, new.target.prototype);
583
658
  }
659
+ /**
660
+ * Checks whether the given input may have been caused by a DataError.
661
+ *
662
+ * @param input - The input to check.
663
+ *
664
+ * @returns `true` if the input is a DataError, and `false` otherwise. The type of the input will also be narrowed down to DataError if `true`.
665
+ */
584
666
  static check(input) {
585
667
  const data = input;
586
668
  return typeof data === "object" && data !== null && typeof data.message === "string" && typeof data.code === "string" && "data" in data;
@@ -608,6 +690,20 @@ var UUID_default = parseUUID;
608
690
 
609
691
  //#endregion
610
692
  //#region src/functions/parsers/parseZodSchema.ts
693
+ /**
694
+ * An alternative function to zodSchema.parse() that can be used to strictly parse Zod schemas.
695
+ *
696
+ * @template Output - The Zod output type.
697
+ * @template Input - The Zod input type.
698
+ * @template Internals - The Zod internal types based on the output and input types.
699
+ *
700
+ * @param schema - The Zod schema to use in parsing.
701
+ * @param data - The data to parse.
702
+ *
703
+ * @throws {DataError} If the given data cannot be parsed according to the schema.
704
+ *
705
+ * @returns The parsed data from the Zod schema.
706
+ */
611
707
  function parseZodSchema(schema, data) {
612
708
  const parsedResult = schema.safeParse(data);
613
709
  if (!parsedResult.success) throw new DataError_default(data);
@@ -616,27 +712,207 @@ function parseZodSchema(schema, data) {
616
712
  var parseZodSchema_default = parseZodSchema;
617
713
 
618
714
  //#endregion
619
- //#region src/functions/removeDuplicates.ts
620
- function removeDuplicates(array) {
621
- const outputArray = [];
622
- for (const item of array) if (!outputArray.includes(item)) outputArray.push(item);
623
- return outputArray;
715
+ //#region src/functions/recursive/deepCopy.ts
716
+ function callDeepCopy(input) {
717
+ return typeof input === "object" && input !== null ? deepCopy(input) : input;
624
718
  }
625
- var removeDuplicates_default = removeDuplicates;
719
+ /**
720
+ * Deeply copies an object or array such that all child objects/arrays are also copied.
721
+ *
722
+ * @template ObjectType - The type of the input object.
723
+ *
724
+ * @param object - The object to copy. May also be an array.
725
+ *
726
+ * @returns An identical object with a new reference in memory.
727
+ */
728
+ function deepCopy(object) {
729
+ if (Array.isArray(object)) return object.map((item) => {
730
+ return callDeepCopy(item);
731
+ });
732
+ const clonedObject = { ...object };
733
+ for (const key in clonedObject) {
734
+ const value = clonedObject[key];
735
+ clonedObject[key] = callDeepCopy(value);
736
+ }
737
+ return clonedObject;
738
+ }
739
+ var deepCopy_default = deepCopy;
626
740
 
627
741
  //#endregion
628
- //#region src/functions/stringListToArray.ts
629
- function stringListToArray(stringList, { separator = ",", trimWhitespace = true } = {}) {
630
- if (trimWhitespace && stringList.trim() === "") return [];
631
- const arrayList = stringList.split(separator ?? "");
632
- return trimWhitespace ? arrayList.map((item) => {
633
- return item.trim();
634
- }) : arrayList;
742
+ //#region src/functions/recursive/deepFreeze.ts
743
+ /**
744
+ * Deeply freezes an object or array such that all child objects/arrays are also frozen.
745
+ *
746
+ * Note that this will also freeze the input itself as well.
747
+ * If the intent is to create a newly frozen object with a different reference in memory, pass your object through deepCopy first before passing to deepFreeze.
748
+ *
749
+ * @template ObjectType - The type of the input object.
750
+ *
751
+ * @param object - The object to freeze. May also be an array.
752
+ *
753
+ * @returns The input object completely frozen.
754
+ */
755
+ function deepFreeze(object) {
756
+ for (const value of Object.values(object)) {
757
+ if (typeof value === "function") continue;
758
+ if (value && typeof value === "object") deepFreeze(value);
759
+ }
760
+ return Object.freeze(object);
635
761
  }
636
- var stringListToArray_default = stringListToArray;
762
+ var deepFreeze_default = deepFreeze;
763
+
764
+ //#endregion
765
+ //#region src/functions/stringHelpers/appendSemicolon.ts
766
+ /**
767
+ * Appends a semicolon to the end of a string, trimming where necessary first.
768
+ *
769
+ * @param stringToAppendTo - The string to append a semicolon to.
770
+ *
771
+ * @throws {Error} If the string contains multiple lines.
772
+ *
773
+ * @returns A string with the semicolon appended.
774
+ */
775
+ function appendSemicolon(stringToAppendTo) {
776
+ if (stringToAppendTo.includes("\n")) throw new Error("MULTIPLE_LINE_ERROR");
777
+ const stringWithNoTrailingWhitespace = stringToAppendTo.trimEnd();
778
+ if (stringWithNoTrailingWhitespace === "") return "";
779
+ return stringWithNoTrailingWhitespace[stringWithNoTrailingWhitespace.length - 1] === ";" ? stringWithNoTrailingWhitespace : `${stringWithNoTrailingWhitespace};`;
780
+ }
781
+ var appendSemicolon_default = appendSemicolon;
782
+
783
+ //#endregion
784
+ //#region src/functions/stringHelpers/camelToKebab.ts
785
+ /**
786
+ * Converts a string from camelCase to kebab-case
787
+ *
788
+ * @param string - The string to convert.
789
+ *
790
+ * @returns The string converted to kebab-case.
791
+ */
792
+ function camelToKebab(string) {
793
+ return string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").toLowerCase();
794
+ }
795
+ var camelToKebab_default = camelToKebab;
796
+
797
+ //#endregion
798
+ //#region src/functions/stringHelpers/kebabToCamel.ts
799
+ /**
800
+ * Converts a string from kebab-case to camelCase
801
+ *
802
+ * @param string - The string to convert.
803
+ * @param options - Options to apply to the conversion.
804
+ *
805
+ * @returns The string converted to camelCase.
806
+ */
807
+ function kebabToCamel(string, options) {
808
+ if (string !== string.toLowerCase()) throw new Error("INVALID_KEBAB_CASE_INPUT");
809
+ if (string.startsWith("-") || string.endsWith("-") || string.includes("--")) throw new Error("INVALID_KEBAB_CASE_INPUT");
810
+ let outputString = "";
811
+ let skip = false;
812
+ for (const stringIndex in [...string]) {
813
+ if (skip) {
814
+ skip = false;
815
+ continue;
816
+ }
817
+ const index = parseIntStrict_default(stringIndex);
818
+ if (index === 0 && options?.startWithUpper) {
819
+ outputString += string[index].toUpperCase();
820
+ continue;
821
+ }
822
+ if (index === string.length - 1) {
823
+ outputString += string[index];
824
+ break;
825
+ }
826
+ if (string[index] === "-" && /^[a-zA-Z]+$/.test(string[index + 1])) {
827
+ outputString += string[index + 1].toUpperCase();
828
+ skip = true;
829
+ } else outputString += string[index];
830
+ }
831
+ return outputString;
832
+ }
833
+ var kebabToCamel_default = kebabToCamel;
834
+
835
+ //#endregion
836
+ //#region src/functions/stringHelpers/normalizeImportPath.ts
837
+ /**
838
+ * Normalizes an import path meant for use in an import statement in JavaScript.
839
+ *
840
+ * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. If the path is a zero-length string, '.' is returned, representing the current working directory.
841
+ *
842
+ * If the path starts with ./, it is preserved (unlike what would happen with path.posix.normalize() normally).
843
+ *
844
+ * Helpful for custom linter rules that need to check (or fix) import paths.
845
+ *
846
+ * @param importPath - The import path to normalize.
847
+ *
848
+ * @returns The import path normalized.
849
+ */
850
+ function normalizeImportPath(importPath) {
851
+ const normalizedPath = path.default.posix.normalize(importPath);
852
+ if (importPath.startsWith("./") && !normalizedPath.startsWith("./")) return `./${normalizedPath}`;
853
+ return normalizedPath;
854
+ }
855
+ /**
856
+ * Normalises an import path meant for use in an import statement in JavaScript.
857
+ *
858
+ * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. If the path is a zero-length string, '.' is returned, representing the current working directory.
859
+ *
860
+ * If the path starts with ./, it is preserved (unlike what would happen with path.posix.normalize() normally).
861
+ *
862
+ * Helpful for custom linter rules that need to check (or fix) import paths.
863
+ *
864
+ * @param importPath - The import path to normalise.
865
+ *
866
+ * @returns The import path normalised.
867
+ */
868
+ const normaliseImportPath = normalizeImportPath;
869
+ var normalizeImportPath_default = normalizeImportPath;
870
+
871
+ //#endregion
872
+ //#region src/functions/stringHelpers/truncate.ts
873
+ /**
874
+ * Truncates a string and appends `...` to the end of it
875
+ *
876
+ * @param stringToTruncate - The string to truncate.
877
+ * @param maxLength - The length at which to start truncating. Note that this does not include the `...` part that would be appended.
878
+ *
879
+ * @returns A new string that has been truncated based on the length provided.
880
+ */
881
+ function truncate(stringToTruncate, maxLength = 5) {
882
+ return stringToTruncate.length > maxLength ? `${stringToTruncate.slice(0, maxLength)}...` : stringToTruncate;
883
+ }
884
+ var truncate_default = truncate;
885
+
886
+ //#endregion
887
+ //#region src/functions/taggedTemplate/createTemplateStringsArray.ts
888
+ /**
889
+ * Creates a template strings array given a regular array of strings
890
+ *
891
+ * @param strings - The array of strings.
892
+ *
893
+ * @returns A template strings array that can be passed as the first argument of any tagged template function.
894
+ */
895
+ function createTemplateStringsArray(strings) {
896
+ return deepFreeze_default(Object.assign([...strings], { raw: [...strings] }));
897
+ }
898
+ var createTemplateStringsArray_default = createTemplateStringsArray;
637
899
 
638
900
  //#endregion
639
901
  //#region src/functions/taggedTemplate/interpolate.ts
902
+ /**
903
+ * Returns the result of interpolating a template string when given the strings and interpolations separately.
904
+ *
905
+ * You can pass a template string directly by doing:
906
+ *
907
+ * interpolate`Template string here`.
908
+ *
909
+ * In this case, it will be functionally the same as if you just wrote the template string by itself.
910
+ *
911
+ * @param strings - The strings from the template to process.
912
+ * @param interpolations - An array of all interpolations from the template.
913
+ *
914
+ * @returns A new string with the strings and interpolations from the template applied.
915
+ */
640
916
  function interpolate(strings, ...interpolations) {
641
917
  let result = "";
642
918
  for (const [string, interpolation = ""] of paralleliseArrays_default(strings, interpolations)) result += string + interpolation;
@@ -646,11 +922,23 @@ var interpolate_default = interpolate;
646
922
 
647
923
  //#endregion
648
924
  //#region src/functions/taggedTemplate/interpolateObjects.ts
649
- function interpolateObjects(strings, ...values) {
925
+ /**
926
+ * Returns the result of interpolating a template string, also stringifying objects.
927
+ *
928
+ * You can pass a template string directly by doing:
929
+ *
930
+ * interpolateObjects`Template string here ${{ my: "object" }}`.
931
+ *
932
+ * @param strings - The strings from the template to process.
933
+ * @param interpolations - An array of all interpolations from the template.
934
+ *
935
+ * @returns A new string with the strings and interpolations from the template applied, with objects stringified.
936
+ */
937
+ function interpolateObjects(strings, ...interpolations) {
650
938
  let result = "";
651
939
  for (let i = 0; i < strings.length; i++) {
652
940
  result += strings[i];
653
- if (i !== strings.length - 1) result += values[i] && typeof values[i] === "object" ? JSON.stringify(values[i]) : values[i];
941
+ if (i !== strings.length - 1) result += interpolations[i] && typeof interpolations[i] === "object" ? JSON.stringify(interpolations[i]) : interpolations[i];
654
942
  }
655
943
  return result;
656
944
  }
@@ -682,6 +970,26 @@ function reduceLines$1(lines, { preserveTabs = true }) {
682
970
  }, tabSize).join("") : "") + line.trimStart();
683
971
  }).join("\n");
684
972
  }
973
+ /**
974
+ * Applies any options if provided, then removes any extraneous indents from a multi-line template string.
975
+ *
976
+ * You can pass a template string directly by doing:
977
+ *
978
+ * normaliseIndents`Template string here
979
+ * with a new line
980
+ * and another new line`.
981
+ *
982
+ * You may also pass the options first, then invoke the resulting function with a template string:
983
+ *
984
+ * normaliseIndents({ preserveTabs: false })`Template string here
985
+ * with a new line
986
+ * and another new line`.
987
+ *
988
+ * @param first - The strings from the template to process, or the options to apply.
989
+ * @param args - An array of all interpolations from the template.
990
+ *
991
+ * @returns An additional function to invoke, or a new string with the strings and interpolations from the template applied, and extraneous indents removed.
992
+ */
685
993
  function normaliseIndents(first, ...args) {
686
994
  if (typeof first === "object" && first !== null && !Array.isArray(first)) {
687
995
  const options$1 = first;
@@ -693,6 +1001,26 @@ function normaliseIndents(first, ...args) {
693
1001
  const options = typeof args[args.length - 1] === "object" && !Array.isArray(args[args.length - 1]) ? args.pop() : {};
694
1002
  return reduceLines$1(interpolate_default(strings, ...[...args]).split("\n"), options);
695
1003
  }
1004
+ /**
1005
+ * Applies any options if provided, then removes any extraneous indents from a multi-line template string.
1006
+ *
1007
+ * You can pass a template string directly by doing:
1008
+ *
1009
+ * normalizeIndents`Template string here
1010
+ * with a new line
1011
+ * and another new line`.
1012
+ *
1013
+ * You may also pass the options first, then invoke the resulting function with a template string:
1014
+ *
1015
+ * normalizeIndents({ preserveTabs: false })`Template string here
1016
+ * with a new line
1017
+ * and another new line`.
1018
+ *
1019
+ * @param first - The strings from the template to process, or the options to apply.
1020
+ * @param args - An array of all interpolations from the template.
1021
+ *
1022
+ * @returns An additional function to invoke, or a new string with the strings and interpolations from the template applied, and extraneous indents removed.
1023
+ */
696
1024
  const normalizeIndents = normaliseIndents;
697
1025
  var normaliseIndents_default = normaliseIndents;
698
1026
 
@@ -736,27 +1064,64 @@ function removeIndents(first, ...args) {
736
1064
  var removeIndents_default = removeIndents;
737
1065
 
738
1066
  //#endregion
739
- //#region src/functions/truncate.ts
740
- function truncate(stringToTruncate, maxLength = 5) {
741
- return stringToTruncate.length > maxLength ? `${stringToTruncate.slice(0, maxLength)}...` : stringToTruncate;
1067
+ //#region src/functions/versioning/parseVersion.ts
1068
+ /**
1069
+ * Parses a string and verifies it is a valid package version number.
1070
+ *
1071
+ * Valid formats: `X.Y.Z` or `vX.Y.Z`, where X, Y, and Z are non-negative integers.
1072
+ *
1073
+ * @param input - The version string to parse.
1074
+ * @param options - Extra options to apply.
1075
+ *
1076
+ * @throws {DataError} If the input is not a valid version number.
1077
+ *
1078
+ * @returns The validated version number, prefixed with `v` if it was not already.
1079
+ */
1080
+ function parseVersion(input, options) {
1081
+ if (!RegExp(VERSION_NUMBER_REGEX_default).test(input)) throw new DataError_default(input, `"${input}" is not a valid version number. Version numbers must be of the format "X.Y.Z" or "vX.Y.Z", where X, Y, and Z are non-negative integers.`, "INVALID_VERSION");
1082
+ if (options?.omitPrefix) return input.startsWith("v") ? input.slice(1) : input;
1083
+ return input.startsWith("v") ? input : `v${input}`;
742
1084
  }
743
- var truncate_default = truncate;
1085
+ var parseVersion_default = parseVersion;
744
1086
 
745
1087
  //#endregion
746
- //#region src/functions/wait.ts
747
- function wait(seconds) {
748
- return new Promise((resolve, _) => {
749
- setTimeout(() => {
750
- resolve();
751
- }, seconds * 1e3);
1088
+ //#region src/functions/versioning/getIndividualVersionNumbers.ts
1089
+ /**
1090
+ * Gets the individual version numbers from a given version number as a tuple of numbers.
1091
+ *
1092
+ * @param version - The version number.
1093
+ *
1094
+ * @returns A tuple of three numbers indicating `[major, minor, patch]`.
1095
+ */
1096
+ function getIndividualVersionNumbers(version) {
1097
+ return parseVersion_default(version, { omitPrefix: true }).split(".").map((versionNumber) => {
1098
+ return parseIntStrict_default(versionNumber);
752
1099
  });
753
1100
  }
754
- var wait_default = wait;
1101
+ var getIndividualVersionNumbers_default = getIndividualVersionNumbers;
1102
+
1103
+ //#endregion
1104
+ //#region src/functions/versioning/determineVersionType.ts
1105
+ /**
1106
+ * Determines whether the given version is a major, minor, or patch version.
1107
+ *
1108
+ * @param version - The version number.
1109
+ *
1110
+ * @returns Either `"major"`, `"minor"`, or `"patch"`, depending on the version type.
1111
+ */
1112
+ function determineVersionType(version) {
1113
+ const [_major, minor, patch] = getIndividualVersionNumbers_default(version);
1114
+ if (minor === 0 && patch === 0) return "major";
1115
+ if (patch === 0) return "minor";
1116
+ return "patch";
1117
+ }
1118
+ var determineVersionType_default = determineVersionType;
755
1119
 
756
1120
  //#endregion
757
1121
  exports.APIError = APIError_default;
758
1122
  exports.DataError = DataError_default;
759
1123
  exports.NAMESPACE_EXPORT_REGEX = NAMESPACE_EXPORT_REGEX_default;
1124
+ exports.VERSION_NUMBER_REGEX = VERSION_NUMBER_REGEX_default;
760
1125
  exports.addDaysToDate = addDaysToDate_default;
761
1126
  exports.appendSemicolon = appendSemicolon_default;
762
1127
  exports.camelToKebab = camelToKebab_default;
@@ -765,8 +1130,10 @@ exports.createFormData = createFormData_default;
765
1130
  exports.createTemplateStringsArray = createTemplateStringsArray_default;
766
1131
  exports.deepCopy = deepCopy_default;
767
1132
  exports.deepFreeze = deepFreeze_default;
1133
+ exports.determineVersionType = determineVersionType_default;
768
1134
  exports.fillArray = fillArray_default;
769
1135
  exports.formatDateAndTime = formatDateAndTime_default;
1136
+ exports.getIndividualVersionNumbers = getIndividualVersionNumbers_default;
770
1137
  exports.getRandomNumber = getRandomNumber_default;
771
1138
  exports.getRecordKeys = getRecordKeys_default;
772
1139
  exports.httpErrorCodeLookup = httpErrorCodeLookup;
@@ -790,6 +1157,7 @@ exports.parseEnv = parseEnv_default;
790
1157
  exports.parseFormData = parseFormData_default;
791
1158
  exports.parseIntStrict = parseIntStrict_default;
792
1159
  exports.parseUUID = UUID_default;
1160
+ exports.parseVersion = parseVersion_default;
793
1161
  exports.parseZodSchema = parseZodSchema_default;
794
1162
  exports.randomiseArray = randomiseArray_default;
795
1163
  exports.range = range_default;