1
0
mirror of https://github.com/robonen/tools.git synced 2026-03-20 10:54:44 +00:00

refactor: change separate tools by category

This commit is contained in:
2025-05-19 17:43:42 +07:00
parent d55737df2f
commit 78fb4da82a
158 changed files with 32 additions and 24 deletions

View File

@@ -0,0 +1,2 @@
export * from './sleep';
export * from './tryIt';

View File

@@ -0,0 +1,3 @@
export type AsyncPoolOptions = {
concurrency?: number;
}

View File

@@ -0,0 +1,38 @@
export interface RetryOptions {
times?: number;
delay?: number;
backoff: (options: RetryOptions & { count: number }) => number;
}
/**
* @name retry
* @category Async
* @description Retries a function a specified number of times with a delay between each retry
*
* @param {Promise<unknown>} fn - The function to retry
* @param {RetryOptions} options - The options for the retry
* @returns {Promise<unknown>} - The result of the function
*
* @example
* const result = await retry(() => {
* return fetch('https://jsonplaceholder.typicode.com/todos/1')
* .then(response => response.json())
* });
*
* @example
* const result = await retry(() => {
* return fetch('https://jsonplaceholder.typicode.com/todos/1')
* .then(response => response.json())
* }, { times: 3, delay: 1000 });
*
*/
export async function retry<Return>(
fn: () => Promise<Return>,
options: RetryOptions
) {
const {
times = 3,
} = options;
let count = 0;
}

View File

@@ -0,0 +1,19 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { sleep } from '.';
describe('sleep', () => {
beforeEach(() => {
vi.useFakeTimers({ shouldAdvanceTime: true });
});
it('delay execution by the specified amount of time', async () => {
const start = performance.now();
const delay = 100;
await sleep(delay);
const end = performance.now();
expect(end - start).toBeGreaterThan(delay - 5);
});
});

View File

@@ -0,0 +1,21 @@
/**
* @name sleep
* @category Async
* @description Delays the execution of the current function by the specified amount of time
*
* @param {number} ms - The amount of time to delay the execution of the current function
* @returns {Promise<void>} - A promise that resolves after the specified amount of time
*
* @example
* await sleep(1000);
*
* @example
* sleep(1000).then(() => {
* console.log('Hello, World!');
* });
*
* @since 0.0.3
*/
export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

View File

@@ -0,0 +1,67 @@
import { describe, it, expect } from 'vitest';
import { tryIt } from '.';
describe('tryIt', () => {
it('handle synchronous functions without errors', () => {
const syncFn = (x: number) => x * 2;
const wrappedSyncFn = tryIt(syncFn);
const [error, result] = wrappedSyncFn(2);
expect(error).toBeUndefined();
expect(result).toBe(4);
});
it('handle synchronous functions with errors', () => {
const syncFn = (): void => { throw new Error('Test error') };
const wrappedSyncFn = tryIt(syncFn);
const [error, result] = wrappedSyncFn();
expect(error).toBeInstanceOf(Error);
expect(error?.message).toBe('Test error');
expect(result).toBeUndefined();
});
it('handle asynchronous functions without errors', async () => {
const asyncFn = async (x: number) => x * 2;
const wrappedAsyncFn = tryIt(asyncFn);
const [error, result] = await wrappedAsyncFn(2);
expect(error).toBeUndefined();
expect(result).toBe(4);
});
it('handle asynchronous functions with errors', async () => {
const asyncFn = async () => { throw new Error('Test error') };
const wrappedAsyncFn = tryIt(asyncFn);
const [error, result] = await wrappedAsyncFn();
expect(error).toBeInstanceOf(Error);
expect(error?.message).toBe('Test error');
expect(result).toBeUndefined();
});
it('handle promise-based functions without errors', async () => {
const promiseFn = (x: number) => Promise.resolve(x * 2);
const wrappedPromiseFn = tryIt(promiseFn);
const [error, result] = await wrappedPromiseFn(2);
expect(error).toBeUndefined();
expect(result).toBe(4);
});
it('handle promise-based functions with errors', async () => {
const promiseFn = () => Promise.reject(new Error('Test error'));
const wrappedPromiseFn = tryIt(promiseFn);
const [error, result] = await wrappedPromiseFn();
expect(error).toBeInstanceOf(Error);
expect(error?.message).toBe('Test error');
expect(result).toBeUndefined();
});
});

View File

@@ -0,0 +1,41 @@
import { isPromise } from '../../types';
export type TryItReturn<Return> = Return extends Promise<any>
? Promise<[Error, undefined] | [undefined, Awaited<Return>]>
: [Error, undefined] | [undefined, Return];
/**
* @name tryIt
* @category Async
* @description Wraps promise-based code in a try/catch block without forking the control flow
*
* @param {Function} fn - The function to try
* @returns {Function} - The function that will return a tuple with the error and the result
*
* @example
* const wrappedFetch = tryIt(fetch);
* const [error, result] = await wrappedFetch('https://jsonplaceholder.typicode.com/todos/1');
*
* @example
* const [error, result] = await tryIt(fetch)('https://jsonplaceholder.typicode.com/todos/1');
*
* @since 0.0.3
*/
export function tryIt<Args extends any[], Return>(
fn: (...args: Args) => Return,
) {
return (...args: Args): TryItReturn<Return> => {
try {
const result = fn(...args);
if (isPromise(result))
return result
.then((value) => [undefined, value])
.catch((error) => [error, undefined]) as TryItReturn<Return>;
return [undefined, result] as TryItReturn<Return>;
} catch (error) {
return [error, undefined] as TryItReturn<Return>;
}
};
}