init; collecting some of my commonly used utils

This commit is contained in:
2024-04-01 17:31:33 -05:00
commit a09a7d7337
13 changed files with 322 additions and 0 deletions

14
pkg/async.ts Normal file
View File

@@ -0,0 +1,14 @@
export async function promiseAllSafe<T>(tasks: Promise<T>[]) {
return await Promise.allSettled(tasks)
.then(res => {
const fulfilled: NonNullable<T>[] = [];
res.forEach(r => {
if (r.status == 'fulfilled' && r.value) {
fulfilled.push(r.value);
}
});
return fulfilled;
}) satisfies Awaited<NonNullable<T>[]>;
}

28
pkg/csv.ts Normal file
View File

@@ -0,0 +1,28 @@
import { Options, parse, Parser } from "csv-parse";
import { z } from "zod";
export async function readCSVToType<
TData extends Record<string, unknown>
>(
text: string,
validator: z.ZodType<TData>,
options?: Options
) {
options ??= {
columns: true,
ignore_last_delimiters: true,
skip_empty_lines: true,
relax_column_count: true
}
const parser = parse(text, options);
const records: TData[] = [];
for await (const record of parser as (Parser & AsyncIterable<never>)) {
records.push(
validator.parse(record)
)
}
return records;
}

21
pkg/dom.ts Normal file
View File

@@ -0,0 +1,21 @@
import React from 'react';
export type PickElementProps<
TElement extends keyof React.JSX.IntrinsicElements,
TProps extends keyof React.ComponentProps<TElement>
> = Pick<React.ComponentProps<TElement>, TProps>;
export function clickVirtualDownloadLink(
url: string,
filename: string,
) {
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.target = "_blank";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}

53
pkg/obj.ts Normal file
View File

@@ -0,0 +1,53 @@
/**
* Given an object, return a copy of the object with the specified properties removed.
*
* @param obj - the object to strip properties from
* @param keys - the properties to remove from the object
* @returns - the new object with the specified properties removed
*/
export function excludeFromObject<
TObj extends Record<string, unknown>
>(
obj: TObj,
...keys: (keyof TObj)[]
) {
const copy = { ...obj }
for (const key of keys) {
delete copy[key];
}
return copy satisfies Omit<TObj, typeof keys[number]>;
}
/** The functional opposite of `excludeFromObject` */
export function pickFromObject<
TObj extends Record<string, unknown>
>(
obj: TObj,
...keys: (keyof TObj)[]
) {
const copy = {} as Pick<TObj, keyof TObj>;
for (const key of keys) {
copy[key] = obj[key];
}
return copy;
}
export function hasAllKeys<
TObj extends Record<string, unknown>
>(obj: TObj, ...keys: (keyof TObj)[]) {
for (const key of keys) {
if (!obj[key]) return false;
}
return true;
}
export default class Obj {
static exclude = excludeFromObject;
static pick = pickFromObject;
static hasAllKeys = hasAllKeys;
}

40
pkg/queue.ts Normal file
View File

@@ -0,0 +1,40 @@
export default class Queue<TData> extends Array<TData> {
constructor(...items: TData[]) {
super(...items);
}
public get isEmpty() {
return this.length == 0;
}
public get isNotEmpty() {
return this.length > 0;
}
public enqueue(item: TData) {
this.push(item);
return this;
}
public dequeue() {
return this.shift();
}
public async* walk({ interval = 1000, chunkSize = 1 }) {
while (this.isNotEmpty) {
const item = this.getChunk(chunkSize);
await new Promise(resolve => setTimeout(resolve, interval));
yield item;
}
}
private getChunk(length: number) {
const chunk = [];
while (chunk.length < length && this.isNotEmpty) {
chunk.push(this.dequeue());
}
return chunk;
}
}

17
pkg/time.ts Normal file
View File

@@ -0,0 +1,17 @@
export default class Time {
static SECOND = 1000;
static MINUTE = this.SECOND * 60;
static HOUR = this.MINUTE * 60;
static DAY = this.HOUR * 24;
static WEEK = this.DAY * 7;
static MONTH = this.DAY * 30;
static YEAR = this.DAY * 365;
static seconds = (n: number) => n * this.SECOND;
static minutes = (n: number) => n * this.MINUTE;
static hours = (n: number) => n * this.HOUR;
static days = (n: number) => n * this.DAY;
static weeks = (n: number) => n * this.WEEK;
static months = (n: number) => n * this.MONTH;
static years = (n: number) => n * this.YEAR;
}

6
pkg/types.ts Normal file
View File

@@ -0,0 +1,6 @@
export type Callable<
TReturn = void,
TArgs extends unknown[] = unknown[]
> = (...args: TArgs) => TReturn;
export type Maybe<T> = T | null | undefined;

7
pkg/validators.ts Normal file
View File

@@ -0,0 +1,7 @@
export function must<T = unknown>(
evaluation: T,
errorMessage = "Failed to fulfill requirements for function"
): NonNullable<T> | never {
if (!evaluation) throw new Error(errorMessage);
return evaluation;
}