From df3ed062068808f8d766ae7222387c33e607647e Mon Sep 17 00:00:00 2001 From: Dmitrii Paskhin Date: Sat, 5 Oct 2024 20:26:14 +0200 Subject: [PATCH] docs: add initial docs (#6) --- .changeset/proud-icons-sparkle.md | 5 ++ README.md | 128 +++++++++++++++++++++++++++++- src/main/index.ts | 107 +++++++++++++++++++++---- 3 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 .changeset/proud-icons-sparkle.md diff --git a/.changeset/proud-icons-sparkle.md b/.changeset/proud-icons-sparkle.md new file mode 100644 index 0000000..e1b74b1 --- /dev/null +++ b/.changeset/proud-icons-sparkle.md @@ -0,0 +1,5 @@ +--- +'@dpaskhin/unique': patch +--- + +Added initial docs diff --git a/README.md b/README.md index bccd58d..7a49dac 100644 --- a/README.md +++ b/README.md @@ -1 +1,127 @@ -**@dpaskhin/unique** +# @dpaskhin/unique + +**@dpaskhin/unique** is a TypeScript library that ensures the uniqueness of generated values. It wraps any function to +reject +duplicate values and generate new ones until a unique result is produced. Useful for cases where you need unique random +values or want to prevent repeated results. + +## Installation + +To install **@dpaskhin/unique**, run: + +```shell +npm install --save-dev @dpaskhin/unique +``` + +## Features + +- Ensures uniqueness of generated values by using a custom or global store. +- Configurable with options like maximum retries, timeouts, and exclusion of specific values. + +## Usage + +#### Basic Example + +Here’s a quick example using **@dpaskhin/unique** with a custom function: + +```ts +import { unique } from '@dpaskhin/unique'; + +const randomNumber = () => Math.floor(Math.random() * 100); + +const uniqueRandomNumber = unique(randomNumber, [], { maxRetries: 5 }); + +console.log(uniqueRandomNumber); // Outputs a unique random number each time +``` + +#### Example with Faker.js + +**@dpaskhin/unique** works well with libraries like Faker.js for generating unique random data. + +```ts +import { unique } from '@dpaskhin/unique'; +import { faker } from '@faker-js/faker'; + +const uniqueName = unique(faker.person.firstName, ['male'], { maxRetries: 10 }); + +console.log(uniqueName); // Outputs a unique first name +``` + +## API Reference + +### uniqueFactory(fn, options) + +Creates a function that ensures unique results based on the provided function fn. + +#### Parameters + +- fn - The function used to generate values. +- options - Optional. An object containing configuration options: + - store (Set) - A custom store to track unique values. Defaults to a new Set. + - maxRetries (number) - The maximum number of retries for unique values. Defaults to 50. + - maxTime (number) - The maximum allowed time (in ms) for generating a unique value. Defaults to 50ms. + - exclude (Array) - Values to exclude from the result set. + +#### Returns + +A function that generates unique values based on fn with the same signature. + +#### Example + +```ts +import { uniqueFactory } from '@dpaskhin/unique'; +import { faker } from '@faker-js/faker'; + +const uniqueAddress = uniqueFactory(faker.location.city, { maxRetries: 5 }); + +console.log(uniqueAddress()); // Outputs a unique city name +``` + +### unique(fn, args, options) + +Generates a unique value by running fn and ensuring uniqueness via either a provided or global store. + +#### Parameters + +- fn - The function used to generate values. +- args - Optional. An array of arguments to be passed to fn. +- options - Optional. An object containing configuration options: + - store (Set) - A custom store to track unique values. Defaults to the global store. + - maxRetries (number) - The maximum number of retries for unique values. Defaults to 50. + - maxTime (number) - The maximum allowed time (in ms) for generating a unique value. Defaults to 50ms. + - exclude (Array) - Values to exclude from the result set. + +#### Returns + +A unique value generated by fn. + +#### Example + +```ts +import { unique } from '@dpaskhin/unique'; +import { faker } from '@faker-js/faker'; + +const uniqueEmail = unique(faker.internet.email, [ + { + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + }, +]); + +console.log(uniqueEmail); // Outputs a unique email address +``` + +### Best Practices + +- Avoid Global Store for Local Uniqueness: If you need to ensure uniqueness only within a specific context or function, + use a custom store to avoid unexpected results from shared global state. +- Configure Max Retries and Timeouts: Customize maxRetries and maxTime based on the expected uniqueness and complexity + of generated values. + +### License + +**@dpaskhin/unique** is licensed under the MIT License. + +### Contributing + +Contributions are welcome! If you have ideas or improvements, feel free to submit a pull request. diff --git a/src/main/index.ts b/src/main/index.ts index bf0631d..19cfd7f 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,3 +1,13 @@ +/** + * Configuration options for the unique generation process. + * + * @template Result The type of the result generated by the function. + * + * @property {Set} [store] - Optional store to keep track of unique values. Defaults to a new Set. + * @property {number} [maxRetries=50] - The maximum number of retries to generate a unique value. Defaults to 50. + * @property {number} [maxTime=50] - The maximum time (in ms) allowed for generating a unique value before throwing an error. Defaults to 50ms. + * @property {Result[]} [exclude] - List of values that should be excluded from the result set. + */ interface IOptions { store?: Set; maxRetries?: number; @@ -5,23 +15,33 @@ interface IOptions { exclude?: Result[]; } -function createErrorMessage( - code: string, - storeSize: number, - duration: number, - currentIterations: number -): string { - return ` - ${code} for uniqueness check. - -Found ${storeSize} unique entries before throwing error. -retried: ${currentIterations} -total time: ${duration}ms - -May not be able to generate any more unique values with current settings. -Try adjusting maxTime or maxRetries parameters.`; -} - +/** + * Creates a function that generates unique values based on a passed function `fn`. + * Ensures uniqueness by storing generated values and retrying if duplicates are found. + * + * @template Args The type of the arguments that the function takes. + * @template Result The type of the result generated by the function. + * + * @param {(...args: Args[]) => Result} fn - The function to generate values. + * @param {IOptions} [options={}] - Optional configuration for controlling the uniqueness generation process. + * @returns {(...args: Args[]) => Result} A new function that generates unique values based on `fn`. + * + * @throws {Error} Throws an error if the max retries or max time is exceeded. + * + * @example + * ```ts + * import { uniqueFactory } from '@dpaskhin/unique'; + * import { faker } from '@faker-js/faker'; + * + * // Create a unique generator + * const uniqueNameGen = uniqueFactory(faker.person.firstName); + * + * const name1 = uniqueNameGen(); // Generate a unique name + * const name2 = uniqueNameGen(); // Generate another unique name + * + * console.log(name1, name2); // Two different names + * ``` + */ export function uniqueFactory( fn: (...args: Args[]) => Result, options: IOptions = {} @@ -77,8 +97,44 @@ export function uniqueFactory( }; } +/** + * A global store to track unique values across multiple invocations of the `unique` function. + * This can be shared across different parts of the code to ensure unique values globally. + */ export const GLOBAL_STORE = new Set(); +/** + * Generates a unique value using the provided function `fn`. It ensures uniqueness by checking + * against previous results and values stored either in the provided `store` or the global store. + * + * **Note:** The global store is shared across multiple invocations, and values will persist globally. + * If you need isolation between different parts of your application, you should provide a custom `store` in the options. + * + * **Best Practice:** Avoid using the global store in environments where global uniqueness is not needed, + * as it may lead to unexpected results due to shared state. + * + * @template Args The type of the arguments that the function takes. + * @template Result The type of the result generated by the function. + * + * @param {(...args: Args[]) => Result} fn - The function to generate values. + * @param {Args[]} [args=[]] - The arguments to be passed to `fn`. + * @param {IOptions} [options={}] - Optional configuration for controlling the uniqueness generation process. + * When no `store` is provided, the function will default to using the global store. + * @returns {Result} The unique value generated by the function `fn`. + * + * @throws {Error} Throws an error if the max retries or max time is exceeded. + * + * @example + * ```ts + * import { unique } from '@dpaskhin/unique'; + * import { faker } from '@faker-js/faker'; + * + * const phone1 = unique(faker.phone.number); // Generate a unique phone number + * const phone2 = unique(faker.phone.number); // Generate another unique phone number + * + * console.log(phone1, phone2); // Two different phone numbers + * ``` + */ export function unique( fn: (...args: Args[]) => Result, args: Args[] = [], @@ -89,3 +145,20 @@ export function unique( Object.assign(options, { store: options.store || GLOBAL_STORE }) ).apply(null, args); } + +function createErrorMessage( + code: string, + storeSize: number, + duration: number, + currentIterations: number +): string { + return ` + ${code} for uniqueness check. + +Found ${storeSize} unique entries before throwing error. +retried: ${currentIterations} +total time: ${duration}ms + +May not be able to generate any more unique values with current settings. +Try adjusting maxTime or maxRetries parameters.`; +}