misc.ts 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. /** Represents any value that is either a string itself or can be converted to one (implicitly or explicitly) because it has a toString() method */
  2. export type Stringifiable = string | { toString(): string };
  3. /**
  4. * Automatically appends an `s` to the passed `word`, if `num` is not equal to 1
  5. * @param word A word in singular form, to auto-convert to plural
  6. * @param num If this is an array or NodeList, the amount of items is used
  7. */
  8. export function autoPlural(word: Stringifiable, num: number | unknown[] | NodeList) {
  9. if(Array.isArray(num) || num instanceof NodeList)
  10. num = num.length;
  11. return `${word}${num === 1 ? "" : "s"}`;
  12. }
  13. /** Pauses async execution for the specified time in ms */
  14. export function pauseFor(time: number) {
  15. return new Promise<void>((res) => {
  16. setTimeout(() => res(), time);
  17. });
  18. }
  19. /**
  20. * Calls the passed `func` after the specified `timeout` in ms (defaults to 300).
  21. * Any subsequent calls to this function will reset the timer and discard previous calls.
  22. */
  23. export function debounce<TFunc extends (...args: TArgs[]) => void, TArgs = any>(func: TFunc, timeout = 300) { // eslint-disable-line @typescript-eslint/no-explicit-any
  24. let timer: number | undefined;
  25. return function(...args: TArgs[]) {
  26. clearTimeout(timer);
  27. timer = setTimeout(() => func.apply(this, args), timeout) as unknown as number;
  28. };
  29. }
  30. /** Options for the `fetchAdvanced()` function */
  31. export type FetchAdvancedOpts = RequestInit & Partial<{
  32. /** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
  33. timeout: number;
  34. }>;
  35. /** Calls the fetch API with special options like a timeout */
  36. export async function fetchAdvanced(url: string, options: FetchAdvancedOpts = {}) {
  37. const { timeout = 10000 } = options;
  38. const controller = new AbortController();
  39. const id = setTimeout(() => controller.abort(), timeout);
  40. const res = await fetch(url, {
  41. ...options,
  42. signal: controller.signal,
  43. });
  44. clearTimeout(id);
  45. return res;
  46. }
  47. /**
  48. * Inserts the passed values into a string at the respective placeholders.
  49. * The placeholder format is `%n`, where `n` is the 1-indexed argument number.
  50. * @param str The string to insert the values into
  51. * @param values The values to insert, in order, starting at `%1`
  52. */
  53. export function insertValues(str: string, ...values: Stringifiable[]) {
  54. return str.replace(/%\d/gm, (match) => {
  55. const argIndex = Number(match.substring(1)) - 1;
  56. return (values[argIndex] ?? match)?.toString();
  57. });
  58. }