Last active
July 25, 2023 12:34
-
-
Save navin-moorthy/149a8c850cdca099a4e133e5e131c400 to your computer and use it in GitHub Desktop.
Common Utils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { getErrorMessage } from "./getErrorMessage.js"; | |
/** | |
* Adds additional error message to the existing error message. | |
* @param {unknown} error - The error object. | |
* @param {string} errorMessage - The additional error message to be added. | |
* @returns {string} - The updated error message. | |
*/ | |
export function addAdditionalErrorMessage( | |
error: unknown, | |
errorMessage: string | |
): string { | |
return `${errorMessage} - ${getErrorMessage(error)}`; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Converts a number of seconds to a string in the format "Xh Ym Zs". | |
* @param {number} seconds - The number of seconds to convert. | |
* @returns {string} A string in the format "Xh Ym Zs". | |
*/ | |
export function convertSecondsToTimeString(seconds: number): string { | |
const hours = Math.floor(seconds / 3_600); | |
const minutes = Math.floor((seconds % 3_600) / 60); | |
const remainingSeconds = seconds % 60; | |
return `${hours}h ${minutes}m ${remainingSeconds}s`; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Extracts the DD-MM-YYYY format from a given ISO date string. | |
* | |
* @param isoDate - The ISO date string to extract the date from. | |
* @returns The date in the format "DD-MM-YYYY". | |
*/ | |
function extractIsoDate(isoDate: string): string { | |
const date = new Date(isoDate); | |
const formattedDate = `${date.getUTCDate()}-${ | |
date.getUTCMonth() + 1 | |
}-${date.getUTCFullYear()}`; | |
return formattedDate; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const generateArrayRange = function* ( | |
startArgument: number, | |
end: number, | |
step: number, | |
) { | |
let start = startArgument; | |
while (start < end) { | |
yield start; | |
start += step; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Represents an error object with a message. | |
*/ | |
type ErrorWithMessage = { | |
message: string; | |
}; | |
/** | |
* Determines whether a value is an Error object. | |
* @param {unknown} error - The value to test. | |
* @returns {boolean} True if the value is an Error object, false otherwise. | |
*/ | |
export function isErrorObject(error: unknown): error is Error { | |
return error !== null && typeof error === "object"; | |
} | |
/** | |
* Determines if an object is an ErrorWithMessage. | |
* @param {unknown} error - The object to check. | |
* @returns {boolean} True if the object is an ErrorWithMessage, false otherwise. | |
*/ | |
function isErrorWithMessage(error: unknown): error is ErrorWithMessage { | |
return ( | |
isErrorObject(error) && | |
"message" in error && | |
typeof (error as ErrorWithMessage).message === "string" | |
); | |
} | |
/** | |
* Converts an object to an ErrorWithMessage. | |
* @param {unknown} maybeError - The object to convert. | |
* @returns {ErrorWithMessage} An ErrorWithMessage object. | |
*/ | |
function toErrorWithMessage(maybeError: unknown): ErrorWithMessage { | |
if (isErrorWithMessage(maybeError)) { | |
return maybeError; | |
} | |
try { | |
return new Error(JSON.stringify(maybeError)); | |
} catch { | |
// fallback in case there's an error stringify the maybeError | |
// like with circular references for example. | |
return new Error(String(maybeError)); | |
} | |
} | |
/** | |
* Gets the message property of an ErrorWithMessage object. | |
* @param {unknown} error - The ErrorWithMessage object. | |
* @returns {string} The message property of the ErrorWithMessage object. | |
*/ | |
export function getErrorMessage(error: unknown): string { | |
return toErrorWithMessage(error).message; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/lodash/lodash/blob/master/.internal/getTag.js | |
import { isNullable } from "./isNullable.js"; | |
// eslint-disable-next-line @typescript-eslint/unbound-method | |
const toString = Object.prototype.toString; | |
/** | |
* Gets the `toStringTag` of `value`. | |
* @private | |
* @param {*} value The value to query. | |
* @returns {string} Returns the `toStringTag`. | |
*/ | |
export function getTag(value: unknown): string { | |
if (isNullable(value)) { | |
return value === undefined ? "[object Undefined]" : "[object Null]"; | |
} | |
return toString.call(value); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function handlePromiseAllSettledResults( | |
results: PromiseSettledResult<void>[], | |
) { | |
const isRejected = ( | |
input: PromiseSettledResult<unknown>, | |
): input is PromiseRejectedResult => input.status === "rejected"; | |
const isFulfilled = <T>( | |
input: PromiseSettledResult<T>, | |
): input is PromiseFulfilledResult<T> => input.status === "fulfilled"; | |
// eslint-disable-next-line @typescript-eslint/no-unsafe-return | |
const errors = results.filter(isRejected).map(result => result?.reason); | |
if (errors.length) { | |
// Aggregate all errors into one | |
throw new AggregateError(errors); | |
} | |
return results.filter(isFulfilled).map(result => result.value); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { isNil } from "./isNil"; | |
/** | |
* Determines whether a value is non-null and non-undefined. | |
* @template T - The type of the value to check. | |
* @param value - The value to check. | |
* @returns A boolean indicating whether the value is non-null and non-undefined. | |
*/ | |
export function isDefined<T>(value: T | null | undefined): value is T { | |
return !isNil(value); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Checks if a value is a non-empty string. | |
* @param value - The value to check. | |
* @returns A boolean indicating whether the value is a non-empty string. | |
*/ | |
export function isEmptyString(value: string): value is string { | |
return value === ""; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Checks if a value is nullable (null or undefined). | |
* @template T - The type of the value being checked. | |
* @param {T} value - The value to check. | |
* @returns {value is null | undefined} - Returns true if the value is null or undefined, false otherwise. | |
* @example | |
* isNil(null); // returns true | |
* isNil(undefined); // returns true | |
* isNil('Hello'); // returns false | |
* isNil(42); // returns false | |
*/ | |
export function isNil<T>(value: T): value is Extract<T, null | undefined> { | |
// eslint-disable-next-line no-eq-null, eqeqeq | |
return value == null; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Cannot have isEmptyArray variant because of no NonEmptyArray type guard | |
/** | |
* Represents a non-empty array. | |
* @template T - The type of elements in the array. | |
*/ | |
export type NonEmptyArray<T> = [T, ...T[]]; | |
/** | |
* Checks if the provided array is non-empty. | |
* @template T - The type of elements in the array. | |
* @param {T[]} array - The array to check. | |
* @returns {boolean} - Returns true if the array is non-empty, false otherwise. | |
*/ | |
export function isNonEmptyArray<T>(array: T[]): array is NonEmptyArray<T> { | |
return array.length > 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable eqeqeq */ | |
// https://github.com/lodash/lodash/blob/master/isSymbol.js | |
import { getTag } from "./getTag.js"; | |
import { isNullable } from "./isNullable.js"; | |
/** | |
* Checks if `value` is classified as a `Symbol` primitive or object. | |
* @since 4.0.0 | |
* @param {*} value The value to check. | |
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`. | |
* @example | |
* | |
* isSymbol(Symbol.iterator) | |
* // => true | |
* | |
* isSymbol('abc') | |
* // => false | |
*/ | |
export function isSymbol(value: unknown): value is symbol { | |
const type = typeof value; | |
return ( | |
type == "symbol" || | |
(type === "object" && | |
!isNullable(value) && | |
getTag(value) == "[object Symbol]") | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { type NonEmptyArray } from "../../../utils/isNonEmptyArray"; | |
export const joinArrayStrings = ( | |
array: NonEmptyArray<string>, | |
separator = " · ", | |
) => array.filter((value) => value !== "").join(separator); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { logger } from "./logger.js"; | |
export function log(message: string) { | |
logger.info(message); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { logger } from "./logger.js"; | |
export function logError(message: string, error?: unknown) { | |
logger.error(`Message:: ${message} -`, error); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Export is needed because TypeScript complains about an error otherwise: | |
// Error: …/tailwind-merge/src/config-utils.ts(8,17): semantic error TS4058: Return type of exported function has or is using name 'LruCache' from external module "…/tailwind-merge/src/lru-cache" but cannot be named. | |
export interface LruCache<Key, Value> { | |
get(key: Key): Value | undefined; | |
set(key: Key, value: Value): void; | |
} | |
// LRU cache inspired from hashlru (https://github.com/dominictarr/hashlru/blob/v1.0.4/index.js) but object replaced with Map to improve performance | |
export function getLruCache<Key, Value>( | |
maxCacheSize: number, | |
): LruCache<Key, Value> { | |
if (maxCacheSize < 1) { | |
return { | |
get: () => undefined, | |
set: () => {}, | |
}; | |
} | |
let cacheSize = 0; | |
let cache = new Map<Key, Value>(); | |
let previousCache = new Map<Key, Value>(); | |
function update(key: Key, value: Value) { | |
cache.set(key, value); | |
cacheSize++; | |
if (cacheSize > maxCacheSize) { | |
cacheSize = 0; | |
previousCache = cache; | |
cache = new Map(); | |
} | |
} | |
return { | |
get(key) { | |
let value = cache.get(key); | |
if (value !== undefined) { | |
return value; | |
} | |
if ((value = previousCache.get(key)) !== undefined) { | |
update(key, value); | |
return value; | |
} | |
}, | |
set(key, value) { | |
if (cache.has(key)) { | |
cache.set(key, value); | |
} else { | |
update(key, value); | |
} | |
}, | |
}; | |
} | |
export const cache = getLruCache<string, string>(100); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const noop = (): void => {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Returns an array of key-value pairs for a given object. | |
* @example | |
* const obj = { a: 1, b: 2, c: 3 }; | |
* const result = entries(obj); | |
* // result: [['a', 1], ['b', 2], ['c', 3]] | |
* @example | |
* const obj = { name: 'John', age: 30, city: 'New York' }; | |
* const result = entries(obj); | |
* // result: [['name', 'John'], ['age', 30], ['city', 'New York']] | |
* @param object - The object to get key-value pairs from. | |
* @returns An array of key-value pairs for the given object. | |
*/ | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
export const entries = <T extends Record<string, any>>( | |
object: T, | |
): Array<[keyof T, T[keyof T]]> => Object.entries(object); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Shorten a string to less than maxLen characters without truncating words. | |
export const shortenString = function ( | |
string: string, | |
maxLength: number, | |
separator = " ", | |
) { | |
if (string.length <= maxLength) { | |
return string; | |
} | |
return string.slice(0, Math.max(0, string.lastIndexOf(separator, maxLength))); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { addAdditionalErrorMessage } from "./addAdditionalErrorMessage"; | |
/** | |
* Throws an error with an additional error message. | |
* @param error - The original error. | |
* @param errorMessage - The additional error message. | |
* @returns This function never returns as it always throws an error. | |
*/ | |
export function throwError(error: unknown, errorMessage: string): never { | |
throw new Error(addAdditionalErrorMessage(error, errorMessage), { | |
cause: error, | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable eqeqeq */ | |
// https://github.com/lodash/lodash/blob/master/toString.js | |
import { isNullable } from "./isNullable.js"; | |
import { isSymbol } from "./isSymbol.js"; | |
/** | |
* Used as references for various `Number` constants. | |
*/ | |
const INFINITY = 1 / 0; | |
/** | |
* Converts `value` to a string. An empty string is returned for `null` | |
* and `undefined` values. The sign of `-0` is preserved. | |
* @since 4.0.0 | |
* @param {*} value The value to convert. | |
* @returns {string} Returns the converted string. | |
* @example | |
* | |
* toString(null) | |
* // => '' | |
* | |
* toString(-0) | |
* // => '-0' | |
* | |
* toString([1, 2, 3]) | |
* // => '1,2,3' | |
*/ | |
export function toString(value: unknown): string { | |
if (isNullable(value)) { | |
return ""; | |
} | |
// Exit early for strings to avoid a performance hit in some environments. | |
if (typeof value === "string") { | |
return value; | |
} | |
if (Array.isArray(value)) { | |
// Recursively convert values (susceptible to call stack limits). | |
return `${value.map((other) => | |
isNullable(other) ? other : toString(other), | |
)}`; | |
} | |
if (isSymbol(value)) { | |
return value.toString(); | |
} | |
const result = `${value}`; | |
// @ts-expect-error - TS doesn't like the value to be unknown compare to INFINITY | |
return result == "0" && 1 / value == -INFINITY ? "-0" : result; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/t3-oss/t3-env/blob/main/packages/core/index.ts | |
import { z, type ZodError, type ZodObject, type ZodType } from "zod"; | |
import { type Prettify } from "./Prettify.js"; | |
import { throwError } from "./throwError.js"; | |
const onValidationError = (error: ZodError) => { | |
console.error( | |
"❌ Invalid environment variables:", | |
error.flatten().fieldErrors, | |
); | |
throw new Error("Invalid environment variables"); | |
}; | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
type Impossible<T extends Record<string, any>> = Partial< | |
Record<keyof T, never> | |
>; | |
type InferredSchema<Schema extends Record<string, ZodType>> = Partial<{ | |
[Key in keyof Schema]: Schema[Key]; | |
}>; | |
type ValidateEnvironmentVariablesOptions< | |
Schema extends Record<string, ZodType>, | |
> = Impossible<InferredSchema<never>> | InferredSchema<Schema>; | |
export function validateEnvironmentVariables< | |
Schema extends Record<string, ZodType> = NonNullable<unknown>, | |
>( | |
schemaObject: ValidateEnvironmentVariablesOptions<Schema>, | |
): Prettify<z.infer<ZodObject<Schema>>> { | |
try { | |
const _schemaObject = | |
typeof schemaObject === "object" ? (schemaObject as z.ZodRawShape) : {}; | |
// eslint-disable-next-line node/no-process-env | |
const parsed = z.object(_schemaObject).safeParse(process.env); | |
if (!parsed.success) { | |
return onValidationError(parsed.error); | |
} | |
return parsed.data as unknown as Prettify<z.infer<ZodObject<Schema>>>; | |
} catch (error) { | |
return throwError(error, "Error in validateEnvironmentVariables function"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment