UNPKG

@corentinth/chisels

Version:

Collection of utilities for JavaScript and TypeScript, lightweight and tree-shakable.

197 lines (191 loc) 4.67 kB
//#region src/bytes.ts const unitsByBase = { 1e3: [ "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ], 1024: [ "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" ] }; /** * Formats a number of bytes into a human-readable string. * * @example * ```typescript * const formatted = formatBytes({ bytes: 4194304 }); * * console.log(formatted); // 4 MiB * ``` */ function formatBytes({ bytes, decimals = 2, base = 1024, units = unitsByBase[base] }) { if (units === void 0 || units.length === 0) throw new Error(`No units defined for base ${base}`); if (bytes === 0) return `0 ${units[0]}`; const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(base)), units.length - 1); return `${(bytes / base ** exponent).toFixed(decimals)} ${units[exponent]}`; } //#endregion //#region src/errors.ts /** * Casts an unknown value to an Error. * * @example * ```typescript * try { * // ... * } catch (rawError) { * const error = castError(rawError); * * // Do something with a proper Error instance * } * ``` */ function castError(error) { if (error instanceof Error) return error; if (error === null || error === void 0) return /* @__PURE__ */ new Error("Unknown error"); if (typeof error === "object") return Object.assign(/* @__PURE__ */ new Error("Unknown error"), error); return new Error(String(error)); } //#endregion //#region src/injection.ts /** * Injects arguments into a set of functions. Useful for DI of repositories, services, etc. * * @example * ```typescript * const functions = { * getUser: ({ userId, db }) => db.users.find({ id: userId }), * removeUser: ({ userId, db }) => db.users.remove({ id: userId }), * }; * * const { getUser, removeUser } = injectArguments(functions, { db }); * * getUser({ userId: 1 }); * removeUser({ userId: 1 }); * ``` */ function injectArguments(functions, injectedArgs) { return Object.fromEntries(Object.entries(functions).map(([key, fn]) => [key, (args) => fn({ ...args, ...injectedArgs })])); } //#endregion //#region src/memo.ts /** * This function takes a function that returns a value and returns a new function that caches the result of the first call. Basically a argument-less memoization. * * @example * ```typescript * const getCwd = memoizeOnce(() => process.cwd()); * * // process.cwd() is only called once * console.log(getCwd()); * console.log(getCwd()); * ``` */ function memoizeOnce(value) { let isCalled = false; let cache; return () => { if (!isCalled) { isCalled = true; cache = value(); } return cache; }; } //#endregion //#region src/safely.ts /** * Safely executes an async function or promise and return a tuple with the result and an error if any. * * @example * ```typescript * const [result, error] = await safely(myFunction); * * if (error) { * console.error(error); * } * * console.log(result); * ``` */ async function safely(fn) { try { return [typeof fn === "function" ? await fn() : await fn, null]; } catch (error) { return [null, castError(error)]; } } /** * Safely executes a function and return a tuple with the result and an error if any. * * @example * ```typescript * const [result, error] = safelySync(myFunction); * * if (error) { * console.error(error); * } * * console.log(result); * ``` */ function safelySync(fn) { try { return [fn(), null]; } catch (error) { return [null, castError(error)]; } } //#endregion //#region src/url.ts /** * Join URL parts and trim slashes. * * @example * ```typescript * const url = joinUrlPaths('/part1/', '/part2/', 'part3', 'part4/'); * * console.log(url); // 'part1/part2/part3/part4' * ``` */ function joinUrlPaths(...parts) { return parts.map((part) => part?.replace(/^\/|\/$/g, "")).filter(Boolean).join("/"); } /** * Functional wrapper around URL constructor to build an URL string from a base URL and optional path, query params and hash. * * @example * ```typescript * const url = buildUrl({ baseUrl: 'https://example.com', path: 'foo', queryParams: { a: '1', b: '2' }, hash: 'hash' }); * * console.log(url); // 'https://example.com/foo?a=1&b=2#hash' * ``` */ function buildUrl({ path: pathOrPaths = "", baseUrl, queryParams, hash }) { const path = Array.isArray(pathOrPaths) ? joinUrlPaths(...pathOrPaths) : pathOrPaths; const url = new URL(path, baseUrl); if (queryParams) if (queryParams instanceof URLSearchParams) url.search = queryParams.toString(); else url.search = new URLSearchParams(queryParams).toString(); if (hash !== void 0) url.hash = hash; return url.toString(); } //#endregion export { buildUrl, castError, formatBytes, injectArguments, joinUrlPaths, memoizeOnce, safely, safelySync };