@corentinth/chisels
Version:
Collection of utilities for JavaScript and TypeScript, lightweight and tree-shakable.
197 lines (191 loc) • 4.67 kB
JavaScript
//#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 };