diff --git a/package.json b/package.json index 7598f619d..5c6e07fef 100644 --- a/package.json +++ b/package.json @@ -1,83 +1,87 @@ { - "name": "radashi", - "version": "12.1.0", - "type": "module", - "description": "The modern, community-first TypeScript toolkit with all of the fast, readable, and minimal utility functions you need. Type-safe, dependency-free, tree-shakeable, fully tested.", - "repository": { - "url": "git+https://github.com/radashi-org/radashi.git" - }, - "homepage": "https://radashi.js.org", - "author": "Alec Larson", - "contributors": ["Ray Epps"], - "license": "MIT", - "packageManager": "pnpm@9.1.3", - "engines": { - "node": ">=16.0.0" - }, - "main": "dist/radashi.cjs", - "module": "dist/radashi.js", - "exports": { - "require": { - "types": "./dist/radashi.d.cts", - "default": "./dist/radashi.cjs" - }, - "types": "./dist/radashi.d.ts", - "default": "./dist/radashi.js" - }, - "types": "dist/radashi.d.cts", - "files": ["dist"], - "scripts": { - "add-function": "bash ./scripts/add-function.sh", - "bench": "vitest bench", - "build": "tsup --clean", - "bundle-impact": "bash ./scripts/bundle-impact.sh", - "dev": "tsup --clean --watch --sourcemap", - "format": "bash ./scripts/format.sh", - "lint": "bash ./scripts/lint.sh", - "move-function": "bash ./scripts/move-function.sh", - "prepublishOnly": "tsc && biome check --fix && pnpm -s build", - "release": "bash ./scripts/release.sh", - "test": "vitest run --coverage", - "test-branch": "bash ./scripts/test-branch.sh", - "test-single": "bash ./scripts/test-single.sh", - "update-browserslist": "bash ./scripts/update-browserslist.sh" - }, - "devDependencies": { - "@biomejs/biome": "^1.8.3", - "@vitest/coverage-v8": "2.0.5", - "cspell": "^8.13.3", - "prettier": "^3.3.2", - "prettier-plugin-pkg": "^0.18.1", - "prettier-plugin-sh": "^0.14.0", - "tsup": "^8.1.0", - "typescript": "^5.5.2", - "vitest": "2.0.5" - }, - "sideEffects": false, - "browserslist": [ - "and_chr >= 57", - "chrome >= 57", - "and_ff >= 52", - "android >= 127", - "edge >= 15", - "samsung >= 7.4", - "safari >= 10.1", - "ios_saf >= 10.3", - "opera >= 44", - "firefox >= 52", - "unreleased and_chr versions", - "unreleased chrome versions", - "unreleased and_ff versions", - "unreleased android versions", - "unreleased edge versions", - "unreleased samsung versions", - "unreleased safari versions", - "unreleased ios_saf versions", - "unreleased opera versions", - "unreleased firefox versions", - "node >= 16" - ], - "dependencies": { - "@radashi-org/biome-config": "link:scripts/biome-config" - } + "name": "radashi", + "version": "12.1.0", + "type": "module", + "description": "The modern, community-first TypeScript toolkit with all of the fast, readable, and minimal utility functions you need. Type-safe, dependency-free, tree-shakeable, fully tested.", + "repository": { + "url": "git+https://github.com/radashi-org/radashi.git" + }, + "homepage": "https://radashi.js.org", + "author": "Alec Larson", + "contributors": [ + "Ray Epps" + ], + "license": "MIT", + "packageManager": "pnpm@9.1.3", + "engines": { + "node": ">=16.0.0" + }, + "main": "dist/radashi.cjs", + "module": "dist/radashi.js", + "exports": { + "require": { + "types": "./dist/radashi.d.cts", + "default": "./dist/radashi.cjs" + }, + "types": "./dist/radashi.d.ts", + "default": "./dist/radashi.js" + }, + "types": "dist/radashi.d.cts", + "files": [ + "dist" + ], + "scripts": { + "add-function": "bash ./scripts/add-function.sh", + "bench": "vitest bench", + "build": "tsup --clean", + "bundle-impact": "bash ./scripts/bundle-impact.sh", + "dev": "tsup --clean --watch --sourcemap", + "format": "bash ./scripts/format.sh", + "lint": "bash ./scripts/lint.sh", + "move-function": "bash ./scripts/move-function.sh", + "prepublishOnly": "tsc && biome check --fix && pnpm -s build", + "release": "bash ./scripts/release.sh", + "test": "vitest run --coverage", + "test-branch": "bash ./scripts/test-branch.sh", + "test-single": "bash ./scripts/test-single.sh", + "update-browserslist": "bash ./scripts/update-browserslist.sh" + }, + "dependencies": { + "@radashi-org/biome-config": "link:scripts/biome-config" + }, + "devDependencies": { + "@biomejs/biome": "^1.8.3", + "@vitest/coverage-v8": "2.0.5", + "cspell": "^8.13.3", + "prettier": "^3.3.2", + "prettier-plugin-pkg": "^0.18.1", + "prettier-plugin-sh": "^0.14.0", + "tsup": "^8.1.0", + "typescript": "^5.5.2", + "vitest": "2.0.5" + }, + "sideEffects": false, + "browserslist": [ + "and_chr >= 57", + "chrome >= 57", + "and_ff >= 52", + "android >= 127", + "edge >= 15", + "samsung >= 7.4", + "safari >= 10.1", + "ios_saf >= 10.3", + "opera >= 44", + "firefox >= 52", + "unreleased and_chr versions", + "unreleased chrome versions", + "unreleased and_ff versions", + "unreleased android versions", + "unreleased edge versions", + "unreleased samsung versions", + "unreleased safari versions", + "unreleased ios_saf versions", + "unreleased opera versions", + "unreleased firefox versions", + "node >= 16" + ] } diff --git a/scripts/benchmarks/src/dedent.ts b/scripts/benchmarks/src/dedent.ts index 2e1dbdcc8..dc9742552 100644 --- a/scripts/benchmarks/src/dedent.ts +++ b/scripts/benchmarks/src/dedent.ts @@ -1,4 +1,4 @@ -import { isArray } from "radashi/typed/isArray.js"; +import { isArray } from 'radashi/typed/isArray.js' /** * Remove indentation from a string. The given string is expected to @@ -36,51 +36,51 @@ import { isArray } from "radashi/typed/isArray.js"; * ``` */ export function dedent( - template: TemplateStringsArray, - ...values: unknown[] -): string; + template: TemplateStringsArray, + ...values: unknown[] +): string -export function dedent(text: string, indent?: string | null): string; +export function dedent(text: string, indent?: string | null): string export function dedent( - text: string | TemplateStringsArray, - ...values: unknown[] + text: string | TemplateStringsArray, + ...values: unknown[] ): string { - // Support tagged template strings - if (isArray(text)) { - if (values.length > 0) { - return dedent( - text.reduce((acc, input, i) => { - let value = String(values[i] ?? ""); + // Support tagged template strings + if (isArray(text)) { + if (values.length > 0) { + return dedent( + text.reduce((acc, input, i) => { + let value = String(values[i] ?? '') - // Detect the indentation before this embedded string. - const indent = - value.includes("\n") && input.match(/[ \t]*(?=[^\n]*$)/)?.[0]; + // Detect the indentation before this embedded string. + const indent = + value.includes('\n') && input.match(/[ \t]*(?=[^\n]*$)/)?.[0] - // Ensure the multi-line, embedded string can be correctly - // dedented. - if (indent) { - value = value.replace(/\n(?=[^\n]*?\S)/g, "\n" + indent); - } + // Ensure the multi-line, embedded string can be correctly + // dedented. + if (indent) { + value = value.replace(/\n(?=[^\n]*?\S)/g, '\n' + indent) + } - return acc + input + value; - }, ""), - ); - } + return acc + input + value + }, ''), + ) + } - text = text[0]; - } + text = text[0] + } - const indent = values[0] ?? detectIndent(text); - const output = indent - ? text.replace(new RegExp(`^${indent}`, "gm"), "") - : text; + const indent = values[0] ?? detectIndent(text) + const output = indent + ? text.replace(new RegExp(`^${indent}`, 'gm'), '') + : text - // Remove the first and last lines (if empty). - return output.replace(/^[ \t]*\n|\n[ \t]*$/g, ""); + // Remove the first and last lines (if empty). + return output.replace(/^[ \t]*\n|\n[ \t]*$/g, '') } // Find the indentation of the first non-empty line. function detectIndent(text: string) { - return text.match(/^[ \t]*(?=\S)/m)?.[0]; + return text.match(/^[ \t]*(?=\S)/m)?.[0] } diff --git a/scripts/biome-config/package.json b/scripts/biome-config/package.json index d79e665ce..1d6847449 100644 --- a/scripts/biome-config/package.json +++ b/scripts/biome-config/package.json @@ -1,31 +1,35 @@ { - "name": "@radashi-org/biome-config", - "version": "1.0.0", - "description": "Shared Biome config for Radashi projects", - "keywords": [ - "radashi", - "biome", - "biomejs", - "config", - "configuration", - "formatter", - "linter" - ], - "repository": { - "url": "git+https://github.com/radashi-org/radashi.git" - }, - "homepage": "https://radashi.js.org", - "license": "MIT", - "author": { - "name": "Alec Larson" - }, - "exports": { - ".": "./biome.json" - }, - "main": "biome.json", - "files": ["biome.json"], - "peerDependencies": { - "@biomejs/biome": "^1.8.3" - }, - "trustedDependencies": ["@biomejs/biome"] + "name": "@radashi-org/biome-config", + "version": "1.0.0", + "description": "Shared Biome config for Radashi projects", + "repository": { + "url": "git+https://github.com/radashi-org/radashi.git" + }, + "homepage": "https://radashi.js.org", + "author": { + "name": "Alec Larson" + }, + "license": "MIT", + "main": "biome.json", + "exports": { + ".": "./biome.json" + }, + "files": [ + "biome.json" + ], + "keywords": [ + "radashi", + "biome", + "biomejs", + "config", + "configuration", + "formatter", + "linter" + ], + "peerDependencies": { + "@biomejs/biome": "^1.8.3" + }, + "trustedDependencies": [ + "@biomejs/biome" + ] } diff --git a/scripts/bundle-impact/src/dedent.ts b/scripts/bundle-impact/src/dedent.ts index 2e1dbdcc8..dc9742552 100644 --- a/scripts/bundle-impact/src/dedent.ts +++ b/scripts/bundle-impact/src/dedent.ts @@ -1,4 +1,4 @@ -import { isArray } from "radashi/typed/isArray.js"; +import { isArray } from 'radashi/typed/isArray.js' /** * Remove indentation from a string. The given string is expected to @@ -36,51 +36,51 @@ import { isArray } from "radashi/typed/isArray.js"; * ``` */ export function dedent( - template: TemplateStringsArray, - ...values: unknown[] -): string; + template: TemplateStringsArray, + ...values: unknown[] +): string -export function dedent(text: string, indent?: string | null): string; +export function dedent(text: string, indent?: string | null): string export function dedent( - text: string | TemplateStringsArray, - ...values: unknown[] + text: string | TemplateStringsArray, + ...values: unknown[] ): string { - // Support tagged template strings - if (isArray(text)) { - if (values.length > 0) { - return dedent( - text.reduce((acc, input, i) => { - let value = String(values[i] ?? ""); + // Support tagged template strings + if (isArray(text)) { + if (values.length > 0) { + return dedent( + text.reduce((acc, input, i) => { + let value = String(values[i] ?? '') - // Detect the indentation before this embedded string. - const indent = - value.includes("\n") && input.match(/[ \t]*(?=[^\n]*$)/)?.[0]; + // Detect the indentation before this embedded string. + const indent = + value.includes('\n') && input.match(/[ \t]*(?=[^\n]*$)/)?.[0] - // Ensure the multi-line, embedded string can be correctly - // dedented. - if (indent) { - value = value.replace(/\n(?=[^\n]*?\S)/g, "\n" + indent); - } + // Ensure the multi-line, embedded string can be correctly + // dedented. + if (indent) { + value = value.replace(/\n(?=[^\n]*?\S)/g, '\n' + indent) + } - return acc + input + value; - }, ""), - ); - } + return acc + input + value + }, ''), + ) + } - text = text[0]; - } + text = text[0] + } - const indent = values[0] ?? detectIndent(text); - const output = indent - ? text.replace(new RegExp(`^${indent}`, "gm"), "") - : text; + const indent = values[0] ?? detectIndent(text) + const output = indent + ? text.replace(new RegExp(`^${indent}`, 'gm'), '') + : text - // Remove the first and last lines (if empty). - return output.replace(/^[ \t]*\n|\n[ \t]*$/g, ""); + // Remove the first and last lines (if empty). + return output.replace(/^[ \t]*\n|\n[ \t]*$/g, '') } // Find the indentation of the first non-empty line. function detectIndent(text: string) { - return text.match(/^[ \t]*(?=\S)/m)?.[0]; + return text.match(/^[ \t]*(?=\S)/m)?.[0] } diff --git a/scripts/docs/package.json b/scripts/docs/package.json index c0d02c2d4..61ad97c5f 100644 --- a/scripts/docs/package.json +++ b/scripts/docs/package.json @@ -1,6 +1,6 @@ { - "private": true, "type": "module", + "private": true, "dependencies": { "@types/node": "^22.3.0", "execa": "^9.3.1", @@ -11,4 +11,4 @@ "radashi-db": "link:../radashi-db", "tsx": "^4.17.0" } -} \ No newline at end of file +} diff --git a/scripts/functions/src/util/bottleneck.ts b/scripts/functions/src/util/bottleneck.ts index 93e691c7d..5a3944265 100644 --- a/scripts/functions/src/util/bottleneck.ts +++ b/scripts/functions/src/util/bottleneck.ts @@ -1,4 +1,4 @@ -declare const setTimeout: (callback: () => void, delay: number) => unknown; +declare const setTimeout: (callback: () => void, delay: number) => unknown /** * The options for the `bottleneck` function. @@ -6,22 +6,22 @@ declare const setTimeout: (callback: () => void, delay: number) => unknown; * @see https://radashi.js.org/reference/async/bottleneck */ export interface BottleneckOptions { - /** - * The maximum number of calls to allow per interval. - * - * @default 1 - */ - max?: number; - /** - * The interval at which to allow the maximum number of calls. - */ - interval: number; - /** - * The maximum number of calls to allow at once. - * - * @default Infinity - */ - concurrency?: number; + /** + * The maximum number of calls to allow per interval. + * + * @default 1 + */ + max?: number + /** + * The interval at which to allow the maximum number of calls. + */ + interval: number + /** + * The maximum number of calls to allow at once. + * + * @default Infinity + */ + concurrency?: number } /** @@ -30,23 +30,23 @@ export interface BottleneckOptions { * @see https://radashi.js.org/reference/async/bottleneck */ export type BottledFunction any> = Fn & { - /** - * Prevent any throttled calls from ever running. - * - * Currently executing calls are not affected. - * - * @example - * ```ts - * const fn = bottleneck({ interval: 1000 }, () => console.log('hello')) - * fn() // <- Runs immediately - * fn() // <- Queued - * - * fn.cancel() - * // Now, your function won't run until another call. - * ``` - */ - cancel(): void; -}; + /** + * Prevent any throttled calls from ever running. + * + * Currently executing calls are not affected. + * + * @example + * ```ts + * const fn = bottleneck({ interval: 1000 }, () => console.log('hello')) + * fn() // <- Runs immediately + * fn() // <- Queued + * + * fn.cancel() + * // Now, your function won't run until another call. + * ``` + */ + cancel(): void +} /** * Limit the rate at which a function is called. @@ -79,83 +79,83 @@ export type BottledFunction any> = Fn & { * ``` */ export function bottleneck any>( - { - max = 1, - interval, - concurrency = Number.POSITIVE_INFINITY, - }: BottleneckOptions, - fn: Fn, + { + max = 1, + interval, + concurrency = Number.POSITIVE_INFINITY, + }: BottleneckOptions, + fn: Fn, ): BottledFunction { - let numCalls = 0; - let numRunning = 0; - let startTime: number | undefined; - - type TArgs = Parameters; - type TReturn = Awaited>; - - type QueueItem = { - args: TArgs; - resolve: (value: TReturn | PromiseLike) => void; - reject: (error: any) => void; - }; - - const queue: QueueItem[] = []; - - async function run(input: TArgs | QueueItem) { - const now = Date.now(); - startTime ??= now; - - if (now - startTime >= interval) { - startTime = now; - numCalls = 0; - } - - if (numCalls < max && numRunning < concurrency) { - // If this is the first call, schedule the flush. - if (!numCalls && Number.isFinite(interval)) { - setTimeout(next, interval); - } - - let result: any; - - numCalls++; - numRunning++; - try { - const args = Array.isArray(input) ? input : input.args; - result = await fn(...args); - } catch (error) { - if (Array.isArray(input)) { - throw error; - } - return input.reject(error); - } finally { - numRunning--; - next(); - } - - return Array.isArray(input) ? result : input.resolve(result); - } - - if (Array.isArray(input)) { - // Return a queue promise for the throttled call. - return new Promise((resolve, reject) => { - queue.push({ args: input, resolve, reject }); - }); - } - - // Return the unused queue item to the queue. - queue.unshift(input); - } - - // This function is called when the interval has elapsed and after - // every finished call. - const next = () => queue.length && run(queue.shift()!); - - const bottled = ((...args: TArgs) => run(args)) as BottledFunction; - - bottled.cancel = () => { - queue.length = 0; - }; - - return bottled; + let numCalls = 0 + let numRunning = 0 + let startTime: number | undefined + + type TArgs = Parameters + type TReturn = Awaited> + + type QueueItem = { + args: TArgs + resolve: (value: TReturn | PromiseLike) => void + reject: (error: any) => void + } + + const queue: QueueItem[] = [] + + async function run(input: TArgs | QueueItem) { + const now = Date.now() + startTime ??= now + + if (now - startTime >= interval) { + startTime = now + numCalls = 0 + } + + if (numCalls < max && numRunning < concurrency) { + // If this is the first call, schedule the flush. + if (!numCalls && Number.isFinite(interval)) { + setTimeout(next, interval) + } + + let result: any + + numCalls++ + numRunning++ + try { + const args = Array.isArray(input) ? input : input.args + result = await fn(...args) + } catch (error) { + if (Array.isArray(input)) { + throw error + } + return input.reject(error) + } finally { + numRunning-- + next() + } + + return Array.isArray(input) ? result : input.resolve(result) + } + + if (Array.isArray(input)) { + // Return a queue promise for the throttled call. + return new Promise((resolve, reject) => { + queue.push({ args: input, resolve, reject }) + }) + } + + // Return the unused queue item to the queue. + queue.unshift(input) + } + + // This function is called when the interval has elapsed and after + // every finished call. + const next = () => queue.length && run(queue.shift()!) + + const bottled = ((...args: TArgs) => run(args)) as BottledFunction + + bottled.cancel = () => { + queue.length = 0 + } + + return bottled } diff --git a/scripts/release-notes/dedent.ts b/scripts/release-notes/dedent.ts index 2e1dbdcc8..dc9742552 100644 --- a/scripts/release-notes/dedent.ts +++ b/scripts/release-notes/dedent.ts @@ -1,4 +1,4 @@ -import { isArray } from "radashi/typed/isArray.js"; +import { isArray } from 'radashi/typed/isArray.js' /** * Remove indentation from a string. The given string is expected to @@ -36,51 +36,51 @@ import { isArray } from "radashi/typed/isArray.js"; * ``` */ export function dedent( - template: TemplateStringsArray, - ...values: unknown[] -): string; + template: TemplateStringsArray, + ...values: unknown[] +): string -export function dedent(text: string, indent?: string | null): string; +export function dedent(text: string, indent?: string | null): string export function dedent( - text: string | TemplateStringsArray, - ...values: unknown[] + text: string | TemplateStringsArray, + ...values: unknown[] ): string { - // Support tagged template strings - if (isArray(text)) { - if (values.length > 0) { - return dedent( - text.reduce((acc, input, i) => { - let value = String(values[i] ?? ""); + // Support tagged template strings + if (isArray(text)) { + if (values.length > 0) { + return dedent( + text.reduce((acc, input, i) => { + let value = String(values[i] ?? '') - // Detect the indentation before this embedded string. - const indent = - value.includes("\n") && input.match(/[ \t]*(?=[^\n]*$)/)?.[0]; + // Detect the indentation before this embedded string. + const indent = + value.includes('\n') && input.match(/[ \t]*(?=[^\n]*$)/)?.[0] - // Ensure the multi-line, embedded string can be correctly - // dedented. - if (indent) { - value = value.replace(/\n(?=[^\n]*?\S)/g, "\n" + indent); - } + // Ensure the multi-line, embedded string can be correctly + // dedented. + if (indent) { + value = value.replace(/\n(?=[^\n]*?\S)/g, '\n' + indent) + } - return acc + input + value; - }, ""), - ); - } + return acc + input + value + }, ''), + ) + } - text = text[0]; - } + text = text[0] + } - const indent = values[0] ?? detectIndent(text); - const output = indent - ? text.replace(new RegExp(`^${indent}`, "gm"), "") - : text; + const indent = values[0] ?? detectIndent(text) + const output = indent + ? text.replace(new RegExp(`^${indent}`, 'gm'), '') + : text - // Remove the first and last lines (if empty). - return output.replace(/^[ \t]*\n|\n[ \t]*$/g, ""); + // Remove the first and last lines (if empty). + return output.replace(/^[ \t]*\n|\n[ \t]*$/g, '') } // Find the indentation of the first non-empty line. function detectIndent(text: string) { - return text.match(/^[ \t]*(?=\S)/m)?.[0]; + return text.match(/^[ \t]*(?=\S)/m)?.[0] } diff --git a/scripts/versions/src/dedent.ts b/scripts/versions/src/dedent.ts index 2e1dbdcc8..dc9742552 100644 --- a/scripts/versions/src/dedent.ts +++ b/scripts/versions/src/dedent.ts @@ -1,4 +1,4 @@ -import { isArray } from "radashi/typed/isArray.js"; +import { isArray } from 'radashi/typed/isArray.js' /** * Remove indentation from a string. The given string is expected to @@ -36,51 +36,51 @@ import { isArray } from "radashi/typed/isArray.js"; * ``` */ export function dedent( - template: TemplateStringsArray, - ...values: unknown[] -): string; + template: TemplateStringsArray, + ...values: unknown[] +): string -export function dedent(text: string, indent?: string | null): string; +export function dedent(text: string, indent?: string | null): string export function dedent( - text: string | TemplateStringsArray, - ...values: unknown[] + text: string | TemplateStringsArray, + ...values: unknown[] ): string { - // Support tagged template strings - if (isArray(text)) { - if (values.length > 0) { - return dedent( - text.reduce((acc, input, i) => { - let value = String(values[i] ?? ""); + // Support tagged template strings + if (isArray(text)) { + if (values.length > 0) { + return dedent( + text.reduce((acc, input, i) => { + let value = String(values[i] ?? '') - // Detect the indentation before this embedded string. - const indent = - value.includes("\n") && input.match(/[ \t]*(?=[^\n]*$)/)?.[0]; + // Detect the indentation before this embedded string. + const indent = + value.includes('\n') && input.match(/[ \t]*(?=[^\n]*$)/)?.[0] - // Ensure the multi-line, embedded string can be correctly - // dedented. - if (indent) { - value = value.replace(/\n(?=[^\n]*?\S)/g, "\n" + indent); - } + // Ensure the multi-line, embedded string can be correctly + // dedented. + if (indent) { + value = value.replace(/\n(?=[^\n]*?\S)/g, '\n' + indent) + } - return acc + input + value; - }, ""), - ); - } + return acc + input + value + }, ''), + ) + } - text = text[0]; - } + text = text[0] + } - const indent = values[0] ?? detectIndent(text); - const output = indent - ? text.replace(new RegExp(`^${indent}`, "gm"), "") - : text; + const indent = values[0] ?? detectIndent(text) + const output = indent + ? text.replace(new RegExp(`^${indent}`, 'gm'), '') + : text - // Remove the first and last lines (if empty). - return output.replace(/^[ \t]*\n|\n[ \t]*$/g, ""); + // Remove the first and last lines (if empty). + return output.replace(/^[ \t]*\n|\n[ \t]*$/g, '') } // Find the indentation of the first non-empty line. function detectIndent(text: string) { - return text.match(/^[ \t]*(?=\S)/m)?.[0]; + return text.match(/^[ \t]*(?=\S)/m)?.[0] } diff --git a/src/array/alphabetical.ts b/src/array/alphabetical.ts index 0072cd697..79ddbcb35 100644 --- a/src/array/alphabetical.ts +++ b/src/array/alphabetical.ts @@ -5,14 +5,14 @@ * @see https://radashi.js.org/reference/array/alphabetical */ export function alphabetical( - array: readonly T[], - getter: (item: T) => string, - direction: "asc" | "desc" = "asc", + array: readonly T[], + getter: (item: T) => string, + direction: 'asc' | 'desc' = 'asc', ): T[] { - if (!array) { - return []; - } - const asc = (a: T, b: T) => `${getter(a)}`.localeCompare(getter(b)); - const dsc = (a: T, b: T) => `${getter(b)}`.localeCompare(getter(a)); - return array.slice().sort(direction === "desc" ? dsc : asc); + if (!array) { + return [] + } + const asc = (a: T, b: T) => `${getter(a)}`.localeCompare(getter(b)) + const dsc = (a: T, b: T) => `${getter(b)}`.localeCompare(getter(a)) + return array.slice().sort(direction === 'desc' ? dsc : asc) } diff --git a/src/array/boil.ts b/src/array/boil.ts index 781e197f2..f477c94c9 100644 --- a/src/array/boil.ts +++ b/src/array/boil.ts @@ -10,11 +10,11 @@ * ``` */ export function boil( - array: readonly T[], - compareFunc: (a: T, b: T) => T, + array: readonly T[], + compareFunc: (a: T, b: T) => T, ): T | null { - if (!array || (array.length ?? 0) === 0) { - return null; - } - return array.reduce(compareFunc); + if (!array || (array.length ?? 0) === 0) { + return null + } + return array.reduce(compareFunc) } diff --git a/src/array/castArray.ts b/src/array/castArray.ts index 57ba2a8c6..cf9c87783 100644 --- a/src/array/castArray.ts +++ b/src/array/castArray.ts @@ -12,9 +12,9 @@ * castArray(undefined) // => [undefined] * ``` */ -export function castArray(value: T): CastArray; +export function castArray(value: T): CastArray export function castArray(value: unknown): unknown { - return Array.isArray(value) ? value.slice() : [value]; + return Array.isArray(value) ? value.slice() : [value] } /** @@ -23,15 +23,15 @@ export function castArray(value: unknown): unknown { * @see https://radashi.js.org/reference/array/castArray */ export type CastArray = [T] extends [never] - ? never[] - : [unknown] extends [T] - ? unknown[] - : - | (T extends any - ? T extends readonly (infer U)[] - ? U[] - : never - : never) - | (Exclude extends never - ? never - : Exclude[]); + ? never[] + : [unknown] extends [T] + ? unknown[] + : + | (T extends any + ? T extends readonly (infer U)[] + ? U[] + : never + : never) + | (Exclude extends never + ? never + : Exclude[]) diff --git a/src/array/castArrayIfExists.ts b/src/array/castArrayIfExists.ts index 24359f168..8c70d9430 100644 --- a/src/array/castArrayIfExists.ts +++ b/src/array/castArrayIfExists.ts @@ -12,9 +12,9 @@ * castArrayIfExists([1, 2, 3]) // => [1, 2, 3] * ``` */ -export function castArrayIfExists(value: T): CastArrayIfExists; +export function castArrayIfExists(value: T): CastArrayIfExists export function castArrayIfExists(value: unknown): unknown { - return Array.isArray(value) ? value.slice() : value != null ? [value] : value; + return Array.isArray(value) ? value.slice() : value != null ? [value] : value } /** @@ -23,16 +23,16 @@ export function castArrayIfExists(value: unknown): unknown { * @see https://radashi.js.org/reference/array/castArrayIfExists */ export type CastArrayIfExists = [T] extends [never] - ? never[] - : [unknown] extends [T] - ? unknown[] | null | undefined - : - | (T extends any - ? T extends readonly (infer U)[] - ? U[] - : never - : never) - | (Exclude extends never - ? never - : Exclude[]) - | Extract; + ? never[] + : [unknown] extends [T] + ? unknown[] | null | undefined + : + | (T extends any + ? T extends readonly (infer U)[] + ? U[] + : never + : never) + | (Exclude extends never + ? never + : Exclude[]) + | Extract diff --git a/src/array/cluster.ts b/src/array/cluster.ts index 3b5200cc6..6ac0a7199 100644 --- a/src/array/cluster.ts +++ b/src/array/cluster.ts @@ -9,9 +9,9 @@ * ``` */ export function cluster(array: readonly T[], size = 2): T[][] { - const clusters: T[][] = []; - for (let i = 0; i < array.length; i += size) { - clusters.push(array.slice(i, i + size)); - } - return clusters; + const clusters: T[][] = [] + for (let i = 0; i < array.length; i += size) { + clusters.push(array.slice(i, i + size)) + } + return clusters } diff --git a/src/array/counting.ts b/src/array/counting.ts index 2642ca6d7..f74238823 100644 --- a/src/array/counting.ts +++ b/src/array/counting.ts @@ -10,18 +10,18 @@ * ``` */ export function counting( - array: readonly T[], - identity: (item: T) => TId, + array: readonly T[], + identity: (item: T) => TId, ): Record { - if (!array) { - return {} as Record; - } - return array.reduce( - (acc, item) => { - const id = identity(item); - acc[id] = (acc[id] ?? 0) + 1; - return acc; - }, - {} as Record, - ); + if (!array) { + return {} as Record + } + return array.reduce( + (acc, item) => { + const id = identity(item) + acc[id] = (acc[id] ?? 0) + 1 + return acc + }, + {} as Record, + ) } diff --git a/src/array/diff.ts b/src/array/diff.ts index 74560463d..2404c67f2 100644 --- a/src/array/diff.ts +++ b/src/array/diff.ts @@ -13,26 +13,26 @@ * ``` */ export function diff( - root: readonly T[], - other: readonly T[], - identity: (item: T) => string | number | symbol = (t: T) => - t as unknown as string | number | symbol, + root: readonly T[], + other: readonly T[], + identity: (item: T) => string | number | symbol = (t: T) => + t as unknown as string | number | symbol, ): T[] { - if (!root?.length && !other?.length) { - return []; - } - if (root?.length === undefined) { - return [...other]; - } - if (!other?.length) { - return [...root]; - } - const bKeys = other.reduce( - (acc, item) => { - acc[identity(item)] = true; - return acc; - }, - {} as Record, - ); - return root.filter((a) => !bKeys[identity(a)]); + if (!root?.length && !other?.length) { + return [] + } + if (root?.length === undefined) { + return [...other] + } + if (!other?.length) { + return [...root] + } + const bKeys = other.reduce( + (acc, item) => { + acc[identity(item)] = true + return acc + }, + {} as Record, + ) + return root.filter(a => !bKeys[identity(a)]) } diff --git a/src/array/first.ts b/src/array/first.ts index 4c5c1ebfb..da29d4855 100644 --- a/src/array/first.ts +++ b/src/array/first.ts @@ -11,10 +11,10 @@ * // 0 * ``` */ -export function first(array: readonly T[]): T | undefined; +export function first(array: readonly T[]): T | undefined -export function first(array: readonly T[], defaultValue: U): T | U; +export function first(array: readonly T[], defaultValue: U): T | U export function first(array: readonly unknown[], defaultValue?: unknown) { - return array?.length > 0 ? array[0] : defaultValue; + return array?.length > 0 ? array[0] : defaultValue } diff --git a/src/array/flat.ts b/src/array/flat.ts index 048e02826..7a5a06d15 100644 --- a/src/array/flat.ts +++ b/src/array/flat.ts @@ -10,8 +10,8 @@ * ``` */ export function flat(lists: readonly T[][]): T[] { - return lists.reduce((acc, list) => { - acc.push(...list); - return acc; - }, []); + return lists.reduce((acc, list) => { + acc.push(...list) + return acc + }, []) } diff --git a/src/array/fork.ts b/src/array/fork.ts index b133ab996..8fc0cddef 100644 --- a/src/array/fork.ts +++ b/src/array/fork.ts @@ -10,14 +10,14 @@ * ``` */ export function fork( - array: readonly T[], - condition: (item: T) => boolean, + array: readonly T[], + condition: (item: T) => boolean, ): [T[], T[]] { - const forked: [T[], T[]] = [[], []]; - if (array) { - for (const item of array) { - forked[condition(item) ? 0 : 1].push(item); - } - } - return forked; + const forked: [T[], T[]] = [[], []] + if (array) { + for (const item of array) { + forked[condition(item) ? 0 : 1].push(item) + } + } + return forked } diff --git a/src/array/group.ts b/src/array/group.ts index 6560b7926..bfff84eef 100644 --- a/src/array/group.ts +++ b/src/array/group.ts @@ -11,18 +11,18 @@ * ``` */ export function group( - array: readonly T[], - getGroupId: (item: T) => Key, + array: readonly T[], + getGroupId: (item: T) => Key, ): { [K in Key]?: T[] } { - return array.reduce( - (acc, item) => { - const groupId = getGroupId(item); - if (!acc[groupId]) { - acc[groupId] = []; - } - acc[groupId].push(item); - return acc; - }, - {} as Record, - ); + return array.reduce( + (acc, item) => { + const groupId = getGroupId(item) + if (!acc[groupId]) { + acc[groupId] = [] + } + acc[groupId].push(item) + return acc + }, + {} as Record, + ) } diff --git a/src/array/intersects.ts b/src/array/intersects.ts index e388a6d88..32c9cebc9 100644 --- a/src/array/intersects.ts +++ b/src/array/intersects.ts @@ -12,16 +12,16 @@ * ``` */ export function intersects( - listA: readonly T[], - listB: readonly T[], - identity?: (t: T) => K, + listA: readonly T[], + listB: readonly T[], + identity?: (t: T) => K, ): boolean { - if (!listA || !listB) { - return false; - } - if (identity) { - const known = new Set(listA.map(identity)); - return listB.some((item) => known.has(identity(item))); - } - return listB.some((item) => listA.includes(item)); + if (!listA || !listB) { + return false + } + if (identity) { + const known = new Set(listA.map(identity)) + return listB.some(item => known.has(identity(item))) + } + return listB.some(item => listA.includes(item)) } diff --git a/src/array/iterate.ts b/src/array/iterate.ts index fe728e573..ab944a3c2 100644 --- a/src/array/iterate.ts +++ b/src/array/iterate.ts @@ -13,13 +13,13 @@ * ``` */ export function iterate( - count: number, - func: (currentValue: T, iteration: number) => T, - initValue: T, + count: number, + func: (currentValue: T, iteration: number) => T, + initValue: T, ): T { - let value = initValue; - for (let i = 1; i <= count; i++) { - value = func(value, i); - } - return value; + let value = initValue + for (let i = 1; i <= count; i++) { + value = func(value, i) + } + return value } diff --git a/src/array/last.ts b/src/array/last.ts index 94a08b8aa..e47d34f2d 100644 --- a/src/array/last.ts +++ b/src/array/last.ts @@ -11,10 +11,10 @@ * // 0 * ``` */ -export function last(array: readonly T[]): T | undefined; +export function last(array: readonly T[]): T | undefined -export function last(array: readonly T[], defaultValue: U): T | U; +export function last(array: readonly T[], defaultValue: U): T | U export function last(array: readonly unknown[], defaultValue?: unknown) { - return array?.length > 0 ? array[array.length - 1] : defaultValue; + return array?.length > 0 ? array[array.length - 1] : defaultValue } diff --git a/src/array/list.ts b/src/array/list.ts index 7d422c85e..10fcc872b 100644 --- a/src/array/list.ts +++ b/src/array/list.ts @@ -1,4 +1,4 @@ -import { range } from "radashi"; +import { range } from 'radashi' /** * Creates a list of given start, end, value, and step parameters. @@ -17,10 +17,10 @@ import { range } from "radashi"; * ``` */ export function list( - startOrLength: number, - end?: number, - valueOrMapper?: T | ((i: number) => T), - step?: number, + startOrLength: number, + end?: number, + valueOrMapper?: T | ((i: number) => T), + step?: number, ): T[] { - return Array.from(range(startOrLength, end, valueOrMapper, step)); + return Array.from(range(startOrLength, end, valueOrMapper, step)) } diff --git a/src/array/mapify.ts b/src/array/mapify.ts index b0db58041..f3280a279 100644 --- a/src/array/mapify.ts +++ b/src/array/mapify.ts @@ -18,14 +18,14 @@ * ``` */ export function mapify( - array: readonly T[], - getKey: (item: T, index: number) => Key, - getValue: (item: T, index: number) => Value = (item) => - item as unknown as Value, + array: readonly T[], + getKey: (item: T, index: number) => Key, + getValue: (item: T, index: number) => Value = item => + item as unknown as Value, ): Map { - const map: Map = new Map(); - for (const item of array) { - map.set(getKey(item, map.size), getValue(item, map.size)); - } - return map; + const map: Map = new Map() + for (const item of array) { + map.set(getKey(item, map.size), getValue(item, map.size)) + } + return map } diff --git a/src/array/merge.ts b/src/array/merge.ts index 6acd85108..8a7f2b7a3 100644 --- a/src/array/merge.ts +++ b/src/array/merge.ts @@ -15,25 +15,25 @@ * ``` */ export function merge( - prev: readonly T[], - array: readonly T[], - toKey: (item: T) => any, + prev: readonly T[], + array: readonly T[], + toKey: (item: T) => any, ): T[] { - if (!array && !prev) { - return []; - } - if (!array) { - return [...prev]; - } - if (!prev) { - return []; - } - if (!toKey) { - return [...prev]; - } - const keys = array.map(toKey); - return prev.map((prevItem) => { - const index = keys.indexOf(toKey(prevItem)); - return index > -1 ? array[index] : prevItem; - }); + if (!array && !prev) { + return [] + } + if (!array) { + return [...prev] + } + if (!prev) { + return [] + } + if (!toKey) { + return [...prev] + } + const keys = array.map(toKey) + return prev.map(prevItem => { + const index = keys.indexOf(toKey(prevItem)) + return index > -1 ? array[index] : prevItem + }) } diff --git a/src/array/objectify.ts b/src/array/objectify.ts index c51f454df..019664d3f 100644 --- a/src/array/objectify.ts +++ b/src/array/objectify.ts @@ -17,15 +17,15 @@ * ``` */ export function objectify( - array: readonly T[], - getKey: (item: T) => Key, - getValue: (item: T) => Value = (item) => item as unknown as Value, + array: readonly T[], + getKey: (item: T) => Key, + getValue: (item: T) => Value = item => item as unknown as Value, ): Record { - return array.reduce( - (acc, item) => { - acc[getKey(item)] = getValue(item); - return acc; - }, - {} as Record, - ); + return array.reduce( + (acc, item) => { + acc[getKey(item)] = getValue(item) + return acc + }, + {} as Record, + ) } diff --git a/src/array/replace.ts b/src/array/replace.ts index 6bbcbf205..a2bc6274e 100644 --- a/src/array/replace.ts +++ b/src/array/replace.ts @@ -10,22 +10,22 @@ * ``` */ export function replace( - array: readonly T[], - newItem: T, - match: (item: T, idx: number) => boolean, + array: readonly T[], + newItem: T, + match: (item: T, idx: number) => boolean, ): T[] { - if (!array) { - return []; - } - if (newItem === undefined) { - return [...array]; - } - const out = array.slice(); - for (let index = 0; index < array.length; index++) { - if (match(array[index], index)) { - out[index] = newItem; - break; - } - } - return out; + if (!array) { + return [] + } + if (newItem === undefined) { + return [...array] + } + const out = array.slice() + for (let index = 0; index < array.length; index++) { + if (match(array[index], index)) { + out[index] = newItem + break + } + } + return out } diff --git a/src/array/replaceOrAppend.ts b/src/array/replaceOrAppend.ts index f568e7360..1d876541c 100644 --- a/src/array/replaceOrAppend.ts +++ b/src/array/replaceOrAppend.ts @@ -14,26 +14,26 @@ * ``` */ export function replaceOrAppend( - array: readonly T[], - newItem: T, - match: (a: T, idx: number) => boolean, + array: readonly T[], + newItem: T, + match: (a: T, idx: number) => boolean, ): T[] { - if (!array && !newItem) { - return []; - } - if (!newItem) { - return [...array]; - } - if (!array) { - return [newItem]; - } - const out = array.slice(); - for (let index = 0; index < array.length; index++) { - if (match(array[index], index)) { - out[index] = newItem; - return out; - } - } - out.push(newItem); - return out; + if (!array && !newItem) { + return [] + } + if (!newItem) { + return [...array] + } + if (!array) { + return [newItem] + } + const out = array.slice() + for (let index = 0; index < array.length; index++) { + if (match(array[index], index)) { + out[index] = newItem + return out + } + } + out.push(newItem) + return out } diff --git a/src/array/select.ts b/src/array/select.ts index 8b5762454..f8cf3762f 100644 --- a/src/array/select.ts +++ b/src/array/select.ts @@ -15,31 +15,31 @@ * ``` */ export function select( - array: readonly T[], - mapper: (item: T, index: number) => U, - condition: ((item: T, index: number) => boolean) | null | undefined, -): U[]; + array: readonly T[], + mapper: (item: T, index: number) => U, + condition: ((item: T, index: number) => boolean) | null | undefined, +): U[] export function select( - array: readonly T[], - mapper: (item: T, index: number) => U | null | undefined, -): U[]; + array: readonly T[], + mapper: (item: T, index: number) => U | null | undefined, +): U[] export function select( - array: readonly T[], - mapper: (item: T, index: number) => U, - condition?: ((item: T, index: number) => boolean) | null, + array: readonly T[], + mapper: (item: T, index: number) => U, + condition?: ((item: T, index: number) => boolean) | null, ): U[] { - if (!array) { - return []; - } - let mapped: U; - return array.reduce((acc, item, index) => { - if (condition) { - condition(item, index) && acc.push(mapper(item, index)); - } else if ((mapped = mapper(item, index)) != null) { - acc.push(mapped); - } - return acc; - }, [] as U[]); + if (!array) { + return [] + } + let mapped: U + return array.reduce((acc, item, index) => { + if (condition) { + condition(item, index) && acc.push(mapper(item, index)) + } else if ((mapped = mapper(item, index)) != null) { + acc.push(mapped) + } + return acc + }, [] as U[]) } diff --git a/src/array/selectFirst.ts b/src/array/selectFirst.ts index d47a80670..6ae61896f 100644 --- a/src/array/selectFirst.ts +++ b/src/array/selectFirst.ts @@ -15,17 +15,17 @@ * ``` */ export function selectFirst( - array: readonly T[], - mapper: (item: T, index: number) => U, - condition?: (item: T, index: number) => boolean, + array: readonly T[], + mapper: (item: T, index: number) => U, + condition?: (item: T, index: number) => boolean, ): U | undefined { - if (!array) { - return undefined; - } - let foundIndex = -1; - const found = array.find((item, index) => { - foundIndex = index; - return condition ? condition(item, index) : mapper(item, index) != null; - }); - return found === undefined ? undefined : mapper(found, foundIndex); + if (!array) { + return undefined + } + let foundIndex = -1 + const found = array.find((item, index) => { + foundIndex = index + return condition ? condition(item, index) : mapper(item, index) != null + }) + return found === undefined ? undefined : mapper(found, foundIndex) } diff --git a/src/array/shift.ts b/src/array/shift.ts index c47b49bfb..4ece0f4a4 100644 --- a/src/array/shift.ts +++ b/src/array/shift.ts @@ -11,18 +11,15 @@ * ``` */ export function shift(arr: readonly T[], n: number): T[] { - if (arr.length === 0) { - return [...arr]; - } + if (arr.length === 0) { + return [...arr] + } - const shiftNumber = n % arr.length; + const shiftNumber = n % arr.length - if (shiftNumber === 0) { - return [...arr]; - } + if (shiftNumber === 0) { + return [...arr] + } - return [ - ...arr.slice(-shiftNumber, arr.length), - ...arr.slice(0, -shiftNumber), - ]; + return [...arr.slice(-shiftNumber, arr.length), ...arr.slice(0, -shiftNumber)] } diff --git a/src/array/sift.ts b/src/array/sift.ts index bdd382765..1edd9ede2 100644 --- a/src/array/sift.ts +++ b/src/array/sift.ts @@ -1,4 +1,4 @@ -type Falsy = null | undefined | false | "" | 0 | 0n; +type Falsy = null | undefined | false | '' | 0 | 0n /** * Given a list returns a new list with only truthy values. @@ -11,5 +11,5 @@ type Falsy = null | undefined | false | "" | 0 | 0n; * ``` */ export function sift(array: readonly (T | Falsy)[]): T[] { - return (array?.filter((x) => !!x) as T[]) ?? []; + return (array?.filter(x => !!x) as T[]) ?? [] } diff --git a/src/array/sort.ts b/src/array/sort.ts index 80320f615..b44e9b67f 100644 --- a/src/array/sort.ts +++ b/src/array/sort.ts @@ -16,14 +16,14 @@ * ``` */ export function sort( - array: readonly T[], - getter: (item: T) => number, - desc = false, + array: readonly T[], + getter: (item: T) => number, + desc = false, ): T[] { - if (!array) { - return []; - } - const asc = (a: T, b: T) => getter(a) - getter(b); - const dsc = (a: T, b: T) => getter(b) - getter(a); - return array.slice().sort(desc === true ? dsc : asc); + if (!array) { + return [] + } + const asc = (a: T, b: T) => getter(a) - getter(b) + const dsc = (a: T, b: T) => getter(b) - getter(a) + return array.slice().sort(desc === true ? dsc : asc) } diff --git a/src/array/toggle.ts b/src/array/toggle.ts index 9cdafb5a3..2f879215b 100644 --- a/src/array/toggle.ts +++ b/src/array/toggle.ts @@ -34,35 +34,35 @@ * ``` */ export function toggle( - array: readonly T[], - item: T, - toKey?: ((item: T, idx: number) => number | string | symbol) | null, - options?: { - strategy?: "prepend" | "append"; - }, + array: readonly T[], + item: T, + toKey?: ((item: T, idx: number) => number | string | symbol) | null, + options?: { + strategy?: 'prepend' | 'append' + }, ): T[] { - if (!array) { - return item !== undefined ? [item] : []; - } - if (item === undefined) { - return [...array]; - } + if (!array) { + return item !== undefined ? [item] : [] + } + if (item === undefined) { + return [...array] + } - let matcher: (item: T, idx: number) => boolean; + let matcher: (item: T, idx: number) => boolean - if (toKey) { - const key = toKey(item, -1); + if (toKey) { + const key = toKey(item, -1) - matcher = (x: T, idx: number) => toKey(x, idx) === key; - } else { - matcher = (x: T) => x === item; - } + matcher = (x: T, idx: number) => toKey(x, idx) === key + } else { + matcher = (x: T) => x === item + } - const existing = array.find(matcher); + const existing = array.find(matcher) - if (existing !== undefined) { - return array.filter((x, idx) => !matcher(x, idx)); - } + if (existing !== undefined) { + return array.filter((x, idx) => !matcher(x, idx)) + } - return options?.strategy === "prepend" ? [item, ...array] : [...array, item]; + return options?.strategy === 'prepend' ? [item, ...array] : [...array, item] } diff --git a/src/array/unique.ts b/src/array/unique.ts index 71b14fd16..c1d4c3d73 100644 --- a/src/array/unique.ts +++ b/src/array/unique.ts @@ -11,19 +11,19 @@ * ``` */ export function unique( - array: readonly T[], - toKey?: (item: T) => K, + array: readonly T[], + toKey?: (item: T) => K, ): T[] { - if (toKey) { - const keys = new Set(); - return array.reduce((acc, item) => { - const key = toKey(item); - if (!keys.has(key)) { - keys.add(key); - acc.push(item); - } - return acc; - }, [] as T[]); - } - return [...new Set(array)]; + if (toKey) { + const keys = new Set() + return array.reduce((acc, item) => { + const key = toKey(item) + if (!keys.has(key)) { + keys.add(key) + acc.push(item) + } + return acc + }, [] as T[]) + } + return [...new Set(array)] } diff --git a/src/array/unzip.ts b/src/array/unzip.ts index 86dfead1d..fced0013f 100644 --- a/src/array/unzip.ts +++ b/src/array/unzip.ts @@ -12,16 +12,16 @@ * ``` */ export function unzip(arrays: readonly (readonly T[])[]): T[][] { - if (!arrays || !arrays.length) { - return []; - } - const out = new Array( - arrays.reduce((max, arr) => Math.max(max, arr.length), 0), - ); - let index = 0; - const get = (array: T[]) => array[index]; - for (; index < out.length; index++) { - out[index] = Array.from(arrays as { length: number }, get); - } - return out; + if (!arrays || !arrays.length) { + return [] + } + const out = new Array( + arrays.reduce((max, arr) => Math.max(max, arr.length), 0), + ) + let index = 0 + const get = (array: T[]) => array[index] + for (; index < out.length; index++) { + out[index] = Array.from(arrays as { length: number }, get) + } + return out } diff --git a/src/array/zip.ts b/src/array/zip.ts index a83209547..e5bc30cc3 100644 --- a/src/array/zip.ts +++ b/src/array/zip.ts @@ -1,4 +1,4 @@ -import { unzip } from "radashi"; +import { unzip } from 'radashi' /** * Creates an array of grouped elements, the first of which contains @@ -13,27 +13,27 @@ import { unzip } from "radashi"; * ``` */ export function zip( - array1: readonly T1[], - array2: readonly T2[], - array3: readonly T3[], - array4: readonly T4[], - array5: readonly T5[], -): [T1, T2, T3, T4, T5][]; + array1: readonly T1[], + array2: readonly T2[], + array3: readonly T3[], + array4: readonly T4[], + array5: readonly T5[], +): [T1, T2, T3, T4, T5][] export function zip( - array1: readonly T1[], - array2: readonly T2[], - array3: readonly T3[], - array4: readonly T4[], -): [T1, T2, T3, T4][]; + array1: readonly T1[], + array2: readonly T2[], + array3: readonly T3[], + array4: readonly T4[], +): [T1, T2, T3, T4][] export function zip( - array1: readonly T1[], - array2: readonly T2[], - array3: readonly T3[], -): [T1, T2, T3][]; + array1: readonly T1[], + array2: readonly T2[], + array3: readonly T3[], +): [T1, T2, T3][] export function zip( - array1: readonly T1[], - array2: readonly T2[], -): [T1, T2][]; + array1: readonly T1[], + array2: readonly T2[], +): [T1, T2][] export function zip(...arrays: (readonly T[])[]): T[][] { - return unzip(arrays); + return unzip(arrays) } diff --git a/src/array/zipToObject.ts b/src/array/zipToObject.ts index 716a1bd9d..c76709ee7 100644 --- a/src/array/zipToObject.ts +++ b/src/array/zipToObject.ts @@ -1,4 +1,4 @@ -import { isArray, isFunction } from "radashi"; +import { isArray, isFunction } from 'radashi' /** * Creates an object mapping the specified keys to their corresponding @@ -18,24 +18,24 @@ import { isArray, isFunction } from "radashi"; * ``` */ export function zipToObject( - keys: K[], - values: V | ((key: K, idx: number) => V) | V[], + keys: K[], + values: V | ((key: K, idx: number) => V) | V[], ): Record { - if (!keys || !keys.length) { - return {} as Record; - } + if (!keys || !keys.length) { + return {} as Record + } - const getValue = isFunction(values) - ? values - : isArray(values) - ? (_k: K, i: number) => values[i] - : (_k: K, _i: number) => values; + const getValue = isFunction(values) + ? values + : isArray(values) + ? (_k: K, i: number) => values[i] + : (_k: K, _i: number) => values - return keys.reduce( - (acc, key, idx) => { - acc[key] = getValue(key, idx); - return acc; - }, - {} as Record, - ); + return keys.reduce( + (acc, key, idx) => { + acc[key] = getValue(key, idx) + return acc + }, + {} as Record, + ) } diff --git a/src/async/all.ts b/src/async/all.ts index 30b0bebb7..3960530b4 100644 --- a/src/async/all.ts +++ b/src/async/all.ts @@ -1,8 +1,8 @@ -import { AggregateError, isArray } from "radashi"; +import { AggregateError, isArray } from 'radashi' type PromiseValues[]> = { - [K in keyof T]: T[K] extends Promise ? U : never; -}; + [K in keyof T]: T[K] extends Promise ? U : never +} /** * Functionally similar to `Promise.all` or `Promise.allSettled`. If @@ -20,12 +20,12 @@ type PromiseValues[]> = { * ``` */ export async function all, ...Promise[]]>( - promises: T, -): Promise>; + promises: T, +): Promise> export async function all[]>( - promises: T, -): Promise>; + promises: T, +): Promise> /** * Functionally similar to `Promise.all` or `Promise.allSettled`. If @@ -43,38 +43,38 @@ export async function all[]>( * ``` */ export async function all>>( - promises: T, -): Promise<{ [K in keyof T]: Awaited }>; + promises: T, +): Promise<{ [K in keyof T]: Awaited }> export async function all( - promises: Record> | Promise[], + promises: Record> | Promise[], ): Promise { - const entries = isArray(promises) - ? promises.map((p) => [null, p] as const) - : Object.entries(promises); + const entries = isArray(promises) + ? promises.map(p => [null, p] as const) + : Object.entries(promises) - const results = await Promise.all( - entries.map(([key, value]) => - value - .then((result) => ({ result, exc: null, key })) - .catch((exc) => ({ result: null, exc, key })), - ), - ); + const results = await Promise.all( + entries.map(([key, value]) => + value + .then(result => ({ result, exc: null, key })) + .catch(exc => ({ result: null, exc, key })), + ), + ) - const exceptions = results.filter((r) => r.exc); - if (exceptions.length > 0) { - throw new AggregateError(exceptions.map((e) => e.exc)); - } + const exceptions = results.filter(r => r.exc) + if (exceptions.length > 0) { + throw new AggregateError(exceptions.map(e => e.exc)) + } - if (isArray(promises)) { - return results.map((r) => r.result); - } + if (isArray(promises)) { + return results.map(r => r.result) + } - return results.reduce( - (acc, item) => { - acc[item.key!] = item.result; - return acc; - }, - {} as Record, - ); + return results.reduce( + (acc, item) => { + acc[item.key!] = item.result + return acc + }, + {} as Record, + ) } diff --git a/src/async/defer.ts b/src/async/defer.ts index 11d7f2d32..6bf67c74c 100644 --- a/src/async/defer.ts +++ b/src/async/defer.ts @@ -1,4 +1,4 @@ -import { tryit } from "radashi"; +import { tryit } from 'radashi' /** * Useful when for script like things where cleanup should be done on @@ -20,34 +20,34 @@ import { tryit } from "radashi"; * ``` */ export async function defer( - func: ( - register: ( - fn: (error?: any) => any, - options?: { rethrow?: boolean }, - ) => void, - ) => Promise, + func: ( + register: ( + fn: (error?: any) => any, + options?: { rethrow?: boolean }, + ) => void, + ) => Promise, ): Promise { - const callbacks: { - fn: (error?: any) => any; - rethrow: boolean; - }[] = []; - const register = ( - fn: (error?: any) => any, - options?: { rethrow?: boolean }, - ) => - callbacks.push({ - fn, - rethrow: options?.rethrow ?? false, - }); - const [err, response] = await tryit(func)(register); - for (const { fn, rethrow } of callbacks) { - const [rethrown] = await tryit(fn)(err); - if (rethrown && rethrow) { - throw rethrown; - } - } - if (err) { - throw err; - } - return response; + const callbacks: { + fn: (error?: any) => any + rethrow: boolean + }[] = [] + const register = ( + fn: (error?: any) => any, + options?: { rethrow?: boolean }, + ) => + callbacks.push({ + fn, + rethrow: options?.rethrow ?? false, + }) + const [err, response] = await tryit(func)(register) + for (const { fn, rethrow } of callbacks) { + const [rethrown] = await tryit(fn)(err) + if (rethrown && rethrow) { + throw rethrown + } + } + if (err) { + throw err + } + return response } diff --git a/src/async/guard.ts b/src/async/guard.ts index 17d7fed5d..e46eee81b 100644 --- a/src/async/guard.ts +++ b/src/async/guard.ts @@ -9,21 +9,21 @@ * ``` */ export function guard any>( - func: TFunction, - shouldGuard?: (err: any) => boolean, + func: TFunction, + shouldGuard?: (err: any) => boolean, ): ReturnType extends Promise - ? Promise> | undefined> - : ReturnType | undefined { - const _guard = (err: any) => { - if (shouldGuard && !shouldGuard(err)) { - throw err; - } - return undefined as any; - }; - try { - const result = func(); - return result instanceof Promise ? result.catch(_guard) : result; - } catch (err) { - return _guard(err); - } + ? Promise> | undefined> + : ReturnType | undefined { + const _guard = (err: any) => { + if (shouldGuard && !shouldGuard(err)) { + throw err + } + return undefined as any + } + try { + const result = func() + return result instanceof Promise ? result.catch(_guard) : result + } catch (err) { + return _guard(err) + } } diff --git a/src/async/map.ts b/src/async/map.ts index f70b8d1d6..84f05d17b 100644 --- a/src/async/map.ts +++ b/src/async/map.ts @@ -13,17 +13,17 @@ * ``` */ export async function map( - array: readonly T[], - asyncMapFunc: (item: T, index: number) => Promise, + array: readonly T[], + asyncMapFunc: (item: T, index: number) => Promise, ): Promise { - if (!array) { - return []; - } - const result = []; - let index = 0; - for (const value of array) { - const newValue = await asyncMapFunc(value, index++); - result.push(newValue); - } - return result; + if (!array) { + return [] + } + const result = [] + let index = 0 + for (const value of array) { + const newValue = await asyncMapFunc(value, index++) + result.push(newValue) + } + return result } diff --git a/src/async/parallel.ts b/src/async/parallel.ts index 3ff568b68..de76023f0 100644 --- a/src/async/parallel.ts +++ b/src/async/parallel.ts @@ -1,10 +1,10 @@ -import { AggregateError, flat, fork, list, sort, tryit } from "radashi"; +import { AggregateError, flat, fork, list, sort, tryit } from 'radashi' type WorkItemResult = { - index: number; - result: K; - error: any; -}; + index: number + result: K + error: any +} /** * Executes many async functions in parallel. Returns the results from * all functions as an array. After all functions have resolved, if @@ -21,40 +21,40 @@ type WorkItemResult = { * ``` */ export async function parallel( - limit: number, - array: readonly T[], - func: (item: T) => Promise, + limit: number, + array: readonly T[], + func: (item: T) => Promise, ): Promise { - const work = array.map((item, index) => ({ - index, - item, - })); - // Process array items - const processor = async (res: (value: WorkItemResult[]) => void) => { - const results: WorkItemResult[] = []; - while (true) { - const next = work.pop(); - if (!next) { - return res(results); - } - const [error, result] = await tryit(func)(next.item); - results.push({ - error, - result: result as K, - index: next.index, - }); - } - }; - // Create queues - const queues = list(1, limit).map(() => new Promise(processor)); - // Wait for all queues to complete - const itemResults = (await Promise.all(queues)) as WorkItemResult[][]; - const [errors, results] = fork( - sort(flat(itemResults), (r) => r.index), - (x) => !!x.error, - ); - if (errors.length > 0) { - throw new AggregateError(errors.map((error) => error.error)); - } - return results.map((r) => r.result); + const work = array.map((item, index) => ({ + index, + item, + })) + // Process array items + const processor = async (res: (value: WorkItemResult[]) => void) => { + const results: WorkItemResult[] = [] + while (true) { + const next = work.pop() + if (!next) { + return res(results) + } + const [error, result] = await tryit(func)(next.item) + results.push({ + error, + result: result as K, + index: next.index, + }) + } + } + // Create queues + const queues = list(1, limit).map(() => new Promise(processor)) + // Wait for all queues to complete + const itemResults = (await Promise.all(queues)) as WorkItemResult[][] + const [errors, results] = fork( + sort(flat(itemResults), r => r.index), + x => !!x.error, + ) + if (errors.length > 0) { + throw new AggregateError(errors.map(error => error.error)) + } + return results.map(r => r.result) } diff --git a/src/async/reduce.ts b/src/async/reduce.ts index ee0ff7af9..90d7b3761 100644 --- a/src/async/reduce.ts +++ b/src/async/reduce.ts @@ -11,18 +11,18 @@ * ``` */ export async function reduce( - array: readonly T[], - asyncReducer: (acc: K, item: T, index: number) => Promise, - initValue?: K, + array: readonly T[], + asyncReducer: (acc: K, item: T, index: number) => Promise, + initValue?: K, ): Promise { - const initProvided = initValue !== undefined; - if (!initProvided && array?.length < 1) { - throw new Error("Cannot reduce empty array with no init value"); - } - const iter = initProvided ? array : array.slice(1); - let value: any = initProvided ? initValue : array[0]; - for (const [i, item] of iter.entries()) { - value = await asyncReducer(value, item, i); - } - return value; + const initProvided = initValue !== undefined + if (!initProvided && array?.length < 1) { + throw new Error('Cannot reduce empty array with no init value') + } + const iter = initProvided ? array : array.slice(1) + let value: any = initProvided ? initValue : array[0] + for (const [i, item] of iter.entries()) { + value = await asyncReducer(value, item, i) + } + return value } diff --git a/src/async/retry.ts b/src/async/retry.ts index dd7ba59b9..cde7d1dd6 100644 --- a/src/async/retry.ts +++ b/src/async/retry.ts @@ -1,10 +1,10 @@ -import { sleep, tryit } from "radashi"; +import { sleep, tryit } from 'radashi' export type RetryOptions = { - times?: number; - delay?: number | null; - backoff?: (count: number) => number; -}; + times?: number + delay?: number | null + backoff?: (count: number) => number +} /** * Retries the given function the specified number of times. @@ -18,31 +18,31 @@ export type RetryOptions = { * ``` */ export async function retry( - options: RetryOptions, - func: (exit: (err: any) => void) => Promise, + options: RetryOptions, + func: (exit: (err: any) => void) => Promise, ): Promise { - const times = options?.times ?? 3; - const delay = options?.delay; - const backoff = options?.backoff ?? null; - let i = 0; - while (true) { - const [err, result] = (await tryit(func)((err: any) => { - throw { _exited: err }; - })) as [any, TResponse]; - if (!err) { - return result; - } - if (err._exited) { - throw err._exited; - } - if (++i >= times) { - throw err; - } - if (delay) { - await sleep(delay); - } - if (backoff) { - await sleep(backoff(i)); - } - } + const times = options?.times ?? 3 + const delay = options?.delay + const backoff = options?.backoff ?? null + let i = 0 + while (true) { + const [err, result] = (await tryit(func)((err: any) => { + throw { _exited: err } + })) as [any, TResponse] + if (!err) { + return result + } + if (err._exited) { + throw err._exited + } + if (++i >= times) { + throw err + } + if (delay) { + await sleep(delay) + } + if (backoff) { + await sleep(backoff(i)) + } + } } diff --git a/src/async/sleep.ts b/src/async/sleep.ts index c056477cf..fc706151c 100644 --- a/src/async/sleep.ts +++ b/src/async/sleep.ts @@ -1,4 +1,4 @@ -declare const setTimeout: (fn: () => void, ms: number) => unknown; +declare const setTimeout: (fn: () => void, ms: number) => unknown /** * Create a promise that resolves after a given amount of time. @@ -10,5 +10,5 @@ declare const setTimeout: (fn: () => void, ms: number) => unknown; * ``` */ export function sleep(milliseconds: number): Promise { - return new Promise((res) => setTimeout(res, milliseconds)); + return new Promise(res => setTimeout(res, milliseconds)) } diff --git a/src/async/tryit.ts b/src/async/tryit.ts index d7d1e9cd9..4958a30dd 100644 --- a/src/async/tryit.ts +++ b/src/async/tryit.ts @@ -1,4 +1,4 @@ -import { isPromise, type Result, type ResultPromise } from "radashi"; +import { isPromise, type Result, type ResultPromise } from 'radashi' /** * The result of a `tryit` function. @@ -19,11 +19,11 @@ import { isPromise, type Result, type ResultPromise } from "radashi"; * ``` */ export type TryitResult< - TReturn, - TError extends Error = Error, + TReturn, + TError extends Error = Error, > = TReturn extends PromiseLike - ? ResultPromise - : Result; + ? ResultPromise + : Result /** * A helper to try an async function without forking the control flow. @@ -31,25 +31,25 @@ export type TryitResult< * result]` */ export function tryit< - TArgs extends any[], - TReturn, - TError extends Error = Error, + TArgs extends any[], + TReturn, + TError extends Error = Error, >( - func: (...args: TArgs) => TReturn, + func: (...args: TArgs) => TReturn, ): (...args: TArgs) => TryitResult { - return (...args): any => { - try { - const result = func(...args); - return isPromise(result) - ? result.then( - (value) => [undefined, value], - (err) => [err, undefined], - ) - : [undefined, result]; - } catch (err) { - return [err, undefined]; - } - }; + return (...args): any => { + try { + const result = func(...args) + return isPromise(result) + ? result.then( + value => [undefined, value], + err => [err, undefined], + ) + : [undefined, result] + } catch (err) { + return [err, undefined] + } + } } -export { tryit as try }; +export { tryit as try } diff --git a/src/async/withResolvers.ts b/src/async/withResolvers.ts index 471767f58..db2d1c73c 100644 --- a/src/async/withResolvers.ts +++ b/src/async/withResolvers.ts @@ -1,7 +1,7 @@ interface PromiseWithResolvers { - promise: Promise; - resolve: (value: T | PromiseLike) => void; - reject: (reason?: any) => void; + promise: Promise + resolve: (value: T | PromiseLike) => void + reject: (reason?: any) => void } /** @@ -18,13 +18,13 @@ interface PromiseWithResolvers { * ``` */ export function withResolvers(): PromiseWithResolvers { - let resolve: any; - let reject: any; + let resolve: any + let reject: any - const promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); + const promise = new Promise((res, rej) => { + resolve = res + reject = rej + }) - return { resolve, reject, promise }; + return { resolve, reject, promise } } diff --git a/src/curry/callable.ts b/src/curry/callable.ts index 2c3c47576..118a09cac 100644 --- a/src/curry/callable.ts +++ b/src/curry/callable.ts @@ -16,16 +16,16 @@ * ``` */ export function callable< - TValue, - TObj extends Record, - TFunc extends (...args: any) => any, + TValue, + TObj extends Record, + TFunc extends (...args: any) => any, >(obj: TObj, fn: (self: TObj) => TFunc): TObj & TFunc { - return new Proxy(Object.assign(fn.bind(null), obj), { - get: (target, key: string) => target[key], - set: (target, key: string, value: any) => { - (target as any)[key] = value; - return true; - }, - apply: (target, _, args) => fn(Object.assign({}, target))(...args), - }) as unknown as TObj & TFunc; + return new Proxy(Object.assign(fn.bind(null), obj), { + get: (target, key: string) => target[key], + set: (target, key: string, value: any) => { + ;(target as any)[key] = value + return true + }, + apply: (target, _, args) => fn(Object.assign({}, target))(...args), + }) as unknown as TObj & TFunc } diff --git a/src/curry/chain.ts b/src/curry/chain.ts index 6a3589a36..47090f497 100644 --- a/src/curry/chain.ts +++ b/src/curry/chain.ts @@ -16,91 +16,91 @@ * ``` */ export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, -): (...arg: T1) => T3; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, +): (...arg: T1) => T3 export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, -): (...arg: T1) => T4; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, +): (...arg: T1) => T4 export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, - f4: (arg: T3) => T5, -): (...arg: T1) => T5; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, + f4: (arg: T3) => T5, +): (...arg: T1) => T5 export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, - f4: (arg: T3) => T5, - f5: (arg: T3) => T6, -): (...arg: T1) => T6; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, + f4: (arg: T3) => T5, + f5: (arg: T3) => T6, +): (...arg: T1) => T6 export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, - f4: (arg: T3) => T5, - f5: (arg: T3) => T6, - f6: (arg: T3) => T7, -): (...arg: T1) => T7; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, + f4: (arg: T3) => T5, + f5: (arg: T3) => T6, + f6: (arg: T3) => T7, +): (...arg: T1) => T7 export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, - f4: (arg: T3) => T5, - f5: (arg: T3) => T6, - f6: (arg: T3) => T7, - f7: (arg: T3) => T8, -): (...arg: T1) => T8; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, + f4: (arg: T3) => T5, + f5: (arg: T3) => T6, + f6: (arg: T3) => T7, + f7: (arg: T3) => T8, +): (...arg: T1) => T8 export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, - f4: (arg: T3) => T5, - f5: (arg: T3) => T6, - f6: (arg: T3) => T7, - f7: (arg: T3) => T8, - f8: (arg: T3) => T9, -): (...arg: T1) => T9; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, + f4: (arg: T3) => T5, + f5: (arg: T3) => T6, + f6: (arg: T3) => T7, + f7: (arg: T3) => T8, + f8: (arg: T3) => T9, +): (...arg: T1) => T9 export function chain( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, - f4: (arg: T3) => T5, - f5: (arg: T3) => T6, - f6: (arg: T3) => T7, - f7: (arg: T3) => T8, - f8: (arg: T3) => T9, - f9: (arg: T3) => T10, -): (...arg: T1) => T10; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, + f4: (arg: T3) => T5, + f5: (arg: T3) => T6, + f6: (arg: T3) => T7, + f7: (arg: T3) => T8, + f8: (arg: T3) => T9, + f9: (arg: T3) => T10, +): (...arg: T1) => T10 export function chain< - T1 extends any[], - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, + T1 extends any[], + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, >( - f1: (...arg: T1) => T2, - f2: (arg: T2) => T3, - f3: (arg: T3) => T4, - f4: (arg: T3) => T5, - f5: (arg: T3) => T6, - f6: (arg: T3) => T7, - f7: (arg: T3) => T8, - f8: (arg: T3) => T9, - f9: (arg: T3) => T10, - f10: (arg: T3) => T11, -): (...arg: T1) => T11; + f1: (...arg: T1) => T2, + f2: (arg: T2) => T3, + f3: (arg: T3) => T4, + f4: (arg: T3) => T5, + f5: (arg: T3) => T6, + f6: (arg: T3) => T7, + f7: (arg: T3) => T8, + f8: (arg: T3) => T9, + f9: (arg: T3) => T10, + f10: (arg: T3) => T11, +): (...arg: T1) => T11 export function chain(...funcs: ((...args: any[]) => any)[]) { - return (...args: any[]) => { - return funcs.slice(1).reduce((acc, fn) => fn(acc), funcs[0](...args)); - }; + return (...args: any[]) => { + return funcs.slice(1).reduce((acc, fn) => fn(acc), funcs[0](...args)) + } } diff --git a/src/curry/compose.ts b/src/curry/compose.ts index 967765311..ba6e92154 100644 --- a/src/curry/compose.ts +++ b/src/curry/compose.ts @@ -16,293 +16,293 @@ * ``` */ export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => LastResult, - ) => (...args: F1Args) => F1Result, - last: (...args: F1NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => LastResult, + ) => (...args: F1Args) => F1Result, + last: (...args: F1NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2Result, - F2NextArgs extends any[], - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2Result, + F2NextArgs extends any[], + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => LastResult, - ) => (...args: F1NextArgs) => F2Result, - last: (...args: F2NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => LastResult, + ) => (...args: F1NextArgs) => F2Result, + last: (...args: F2NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2NextArgs extends any[], - F2Result, - F3NextArgs extends any[], - F3Result, - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2NextArgs extends any[], + F2Result, + F3NextArgs extends any[], + F3Result, + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => F3Result, - ) => (...args: F1NextArgs) => F2Result, - f3: ( - next: (...args: F3NextArgs) => LastResult, - ) => (...args: F2NextArgs) => F3Result, - last: (...args: F3NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => F3Result, + ) => (...args: F1NextArgs) => F2Result, + f3: ( + next: (...args: F3NextArgs) => LastResult, + ) => (...args: F2NextArgs) => F3Result, + last: (...args: F3NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2NextArgs extends any[], - F2Result, - F3NextArgs extends any[], - F3Result, - F4NextArgs extends any[], - F4Result, - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2NextArgs extends any[], + F2Result, + F3NextArgs extends any[], + F3Result, + F4NextArgs extends any[], + F4Result, + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => F3Result, - ) => (...args: F1NextArgs) => F2Result, - f3: ( - next: (...args: F3NextArgs) => F4Result, - ) => (...args: F2NextArgs) => F3Result, - f4: ( - next: (...args: F4NextArgs) => LastResult, - ) => (...args: F3NextArgs) => F4Result, - last: (...args: F4NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => F3Result, + ) => (...args: F1NextArgs) => F2Result, + f3: ( + next: (...args: F3NextArgs) => F4Result, + ) => (...args: F2NextArgs) => F3Result, + f4: ( + next: (...args: F4NextArgs) => LastResult, + ) => (...args: F3NextArgs) => F4Result, + last: (...args: F4NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2NextArgs extends any[], - F2Result, - F3NextArgs extends any[], - F3Result, - F4NextArgs extends any[], - F4Result, - F5NextArgs extends any[], - F5Result, - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2NextArgs extends any[], + F2Result, + F3NextArgs extends any[], + F3Result, + F4NextArgs extends any[], + F4Result, + F5NextArgs extends any[], + F5Result, + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => F3Result, - ) => (...args: F1NextArgs) => F2Result, - f3: ( - next: (...args: F3NextArgs) => F4Result, - ) => (...args: F2NextArgs) => F3Result, - f4: ( - next: (...args: F4NextArgs) => F5Result, - ) => (...args: F3NextArgs) => F4Result, - f5: ( - next: (...args: F5NextArgs) => LastResult, - ) => (...args: F4NextArgs) => F5Result, - last: (...args: F5NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => F3Result, + ) => (...args: F1NextArgs) => F2Result, + f3: ( + next: (...args: F3NextArgs) => F4Result, + ) => (...args: F2NextArgs) => F3Result, + f4: ( + next: (...args: F4NextArgs) => F5Result, + ) => (...args: F3NextArgs) => F4Result, + f5: ( + next: (...args: F5NextArgs) => LastResult, + ) => (...args: F4NextArgs) => F5Result, + last: (...args: F5NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2NextArgs extends any[], - F2Result, - F3NextArgs extends any[], - F3Result, - F4NextArgs extends any[], - F4Result, - F5NextArgs extends any[], - F5Result, - F6NextArgs extends any[], - F6Result, - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2NextArgs extends any[], + F2Result, + F3NextArgs extends any[], + F3Result, + F4NextArgs extends any[], + F4Result, + F5NextArgs extends any[], + F5Result, + F6NextArgs extends any[], + F6Result, + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => F3Result, - ) => (...args: F1NextArgs) => F2Result, - f3: ( - next: (...args: F3NextArgs) => F4Result, - ) => (...args: F2NextArgs) => F3Result, - f4: ( - next: (...args: F4NextArgs) => F5Result, - ) => (...args: F3NextArgs) => F4Result, - f5: ( - next: (...args: F5NextArgs) => F6Result, - ) => (...args: F4NextArgs) => F5Result, - f6: ( - next: (...args: F6NextArgs) => LastResult, - ) => (...args: F5NextArgs) => F6Result, - last: (...args: F6NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => F3Result, + ) => (...args: F1NextArgs) => F2Result, + f3: ( + next: (...args: F3NextArgs) => F4Result, + ) => (...args: F2NextArgs) => F3Result, + f4: ( + next: (...args: F4NextArgs) => F5Result, + ) => (...args: F3NextArgs) => F4Result, + f5: ( + next: (...args: F5NextArgs) => F6Result, + ) => (...args: F4NextArgs) => F5Result, + f6: ( + next: (...args: F6NextArgs) => LastResult, + ) => (...args: F5NextArgs) => F6Result, + last: (...args: F6NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2NextArgs extends any[], - F2Result, - F3NextArgs extends any[], - F3Result, - F4NextArgs extends any[], - F4Result, - F5NextArgs extends any[], - F5Result, - F6NextArgs extends any[], - F6Result, - F7NextArgs extends any[], - F7Result, - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2NextArgs extends any[], + F2Result, + F3NextArgs extends any[], + F3Result, + F4NextArgs extends any[], + F4Result, + F5NextArgs extends any[], + F5Result, + F6NextArgs extends any[], + F6Result, + F7NextArgs extends any[], + F7Result, + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => F3Result, - ) => (...args: F1NextArgs) => F2Result, - f3: ( - next: (...args: F3NextArgs) => F4Result, - ) => (...args: F2NextArgs) => F3Result, - f4: ( - next: (...args: F4NextArgs) => F5Result, - ) => (...args: F3NextArgs) => F4Result, - f5: ( - next: (...args: F5NextArgs) => F6Result, - ) => (...args: F4NextArgs) => F5Result, - f6: ( - next: (...args: F6NextArgs) => F7Result, - ) => (...args: F5NextArgs) => F6Result, - f7: ( - next: (...args: F7NextArgs) => LastResult, - ) => (...args: F6NextArgs) => F7Result, - last: (...args: F7NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => F3Result, + ) => (...args: F1NextArgs) => F2Result, + f3: ( + next: (...args: F3NextArgs) => F4Result, + ) => (...args: F2NextArgs) => F3Result, + f4: ( + next: (...args: F4NextArgs) => F5Result, + ) => (...args: F3NextArgs) => F4Result, + f5: ( + next: (...args: F5NextArgs) => F6Result, + ) => (...args: F4NextArgs) => F5Result, + f6: ( + next: (...args: F6NextArgs) => F7Result, + ) => (...args: F5NextArgs) => F6Result, + f7: ( + next: (...args: F7NextArgs) => LastResult, + ) => (...args: F6NextArgs) => F7Result, + last: (...args: F7NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2NextArgs extends any[], - F2Result, - F3NextArgs extends any[], - F3Result, - F4NextArgs extends any[], - F4Result, - F5NextArgs extends any[], - F5Result, - F6NextArgs extends any[], - F6Result, - F7NextArgs extends any[], - F7Result, - F8NextArgs extends any[], - F8Result, - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2NextArgs extends any[], + F2Result, + F3NextArgs extends any[], + F3Result, + F4NextArgs extends any[], + F4Result, + F5NextArgs extends any[], + F5Result, + F6NextArgs extends any[], + F6Result, + F7NextArgs extends any[], + F7Result, + F8NextArgs extends any[], + F8Result, + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => F3Result, - ) => (...args: F1NextArgs) => F2Result, - f3: ( - next: (...args: F3NextArgs) => F4Result, - ) => (...args: F2NextArgs) => F3Result, - f4: ( - next: (...args: F4NextArgs) => F5Result, - ) => (...args: F3NextArgs) => F4Result, - f5: ( - next: (...args: F5NextArgs) => F6Result, - ) => (...args: F4NextArgs) => F5Result, - f6: ( - next: (...args: F6NextArgs) => F7Result, - ) => (...args: F5NextArgs) => F6Result, - f7: ( - next: (...args: F7NextArgs) => LastResult, - ) => (...args: F6NextArgs) => F7Result, - f8: ( - next: (...args: F8NextArgs) => LastResult, - ) => (...args: F7NextArgs) => F8Result, - last: (...args: F8NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => F3Result, + ) => (...args: F1NextArgs) => F2Result, + f3: ( + next: (...args: F3NextArgs) => F4Result, + ) => (...args: F2NextArgs) => F3Result, + f4: ( + next: (...args: F4NextArgs) => F5Result, + ) => (...args: F3NextArgs) => F4Result, + f5: ( + next: (...args: F5NextArgs) => F6Result, + ) => (...args: F4NextArgs) => F5Result, + f6: ( + next: (...args: F6NextArgs) => F7Result, + ) => (...args: F5NextArgs) => F6Result, + f7: ( + next: (...args: F7NextArgs) => LastResult, + ) => (...args: F6NextArgs) => F7Result, + f8: ( + next: (...args: F8NextArgs) => LastResult, + ) => (...args: F7NextArgs) => F8Result, + last: (...args: F8NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose< - F1Result, - F1Args extends any[], - F1NextArgs extends any[], - F2NextArgs extends any[], - F2Result, - F3NextArgs extends any[], - F3Result, - F4NextArgs extends any[], - F4Result, - F5NextArgs extends any[], - F5Result, - F6NextArgs extends any[], - F6Result, - F7NextArgs extends any[], - F7Result, - F8NextArgs extends any[], - F8Result, - F9NextArgs extends any[], - F9Result, - LastResult, + F1Result, + F1Args extends any[], + F1NextArgs extends any[], + F2NextArgs extends any[], + F2Result, + F3NextArgs extends any[], + F3Result, + F4NextArgs extends any[], + F4Result, + F5NextArgs extends any[], + F5Result, + F6NextArgs extends any[], + F6Result, + F7NextArgs extends any[], + F7Result, + F8NextArgs extends any[], + F8Result, + F9NextArgs extends any[], + F9Result, + LastResult, >( - f1: ( - next: (...args: F1NextArgs) => F2Result, - ) => (...args: F1Args) => F1Result, - f2: ( - next: (...args: F2NextArgs) => F3Result, - ) => (...args: F1NextArgs) => F2Result, - f3: ( - next: (...args: F3NextArgs) => F4Result, - ) => (...args: F2NextArgs) => F3Result, - f4: ( - next: (...args: F4NextArgs) => F5Result, - ) => (...args: F3NextArgs) => F4Result, - f5: ( - next: (...args: F5NextArgs) => F6Result, - ) => (...args: F4NextArgs) => F5Result, - f6: ( - next: (...args: F6NextArgs) => F7Result, - ) => (...args: F5NextArgs) => F6Result, - f7: ( - next: (...args: F7NextArgs) => LastResult, - ) => (...args: F6NextArgs) => F7Result, - f8: ( - next: (...args: F8NextArgs) => LastResult, - ) => (...args: F7NextArgs) => F8Result, - f9: ( - next: (...args: F9NextArgs) => LastResult, - ) => (...args: F8NextArgs) => F9Result, - last: (...args: F9NextArgs) => LastResult, -): (...args: F1Args) => F1Result; + f1: ( + next: (...args: F1NextArgs) => F2Result, + ) => (...args: F1Args) => F1Result, + f2: ( + next: (...args: F2NextArgs) => F3Result, + ) => (...args: F1NextArgs) => F2Result, + f3: ( + next: (...args: F3NextArgs) => F4Result, + ) => (...args: F2NextArgs) => F3Result, + f4: ( + next: (...args: F4NextArgs) => F5Result, + ) => (...args: F3NextArgs) => F4Result, + f5: ( + next: (...args: F5NextArgs) => F6Result, + ) => (...args: F4NextArgs) => F5Result, + f6: ( + next: (...args: F6NextArgs) => F7Result, + ) => (...args: F5NextArgs) => F6Result, + f7: ( + next: (...args: F7NextArgs) => LastResult, + ) => (...args: F6NextArgs) => F7Result, + f8: ( + next: (...args: F8NextArgs) => LastResult, + ) => (...args: F7NextArgs) => F8Result, + f9: ( + next: (...args: F9NextArgs) => LastResult, + ) => (...args: F8NextArgs) => F9Result, + last: (...args: F9NextArgs) => LastResult, +): (...args: F1Args) => F1Result export function compose(...funcs: ((...args: any[]) => any)[]) { - return funcs.reverse().reduce((acc, fn) => fn(acc)); + return funcs.reverse().reduce((acc, fn) => fn(acc)) } diff --git a/src/curry/debounce.ts b/src/curry/debounce.ts index 036538db0..7fda3a1e2 100644 --- a/src/curry/debounce.ts +++ b/src/curry/debounce.ts @@ -1,34 +1,34 @@ -declare const setTimeout: (fn: () => void, ms: number) => unknown; -declare const clearTimeout: (timer: unknown) => void; +declare const setTimeout: (fn: () => void, ms: number) => unknown +declare const clearTimeout: (timer: unknown) => void export type DebounceFunction = { - (...args: TArgs): void; - /** - * When called, future invocations of the debounced function are - * no longer delayed and are instead executed immediately. - */ - cancel(): void; - /** - * Returns `true` if the underlying function is scheduled to be - * called once the delay has passed. - */ - isPending(): boolean; - /** - * Invoke the underlying function immediately. - */ - flush(...args: TArgs): void; -}; + (...args: TArgs): void + /** + * When called, future invocations of the debounced function are + * no longer delayed and are instead executed immediately. + */ + cancel(): void + /** + * Returns `true` if the underlying function is scheduled to be + * called once the delay has passed. + */ + isPending(): boolean + /** + * Invoke the underlying function immediately. + */ + flush(...args: TArgs): void +} export interface DebounceOptions { - delay: number; - /** - * When true, your callback is invoked immediately the very first - * time the debounced function is called. After that, the debounced - * function works as if `leading` was `false`. - * - * @default false - */ - leading?: boolean; + delay: number + /** + * When true, your callback is invoked immediately the very first + * time the debounced function is called. After that, the debounced + * function works as if `leading` was `false`. + * + * @default false + */ + leading?: boolean } /** @@ -51,34 +51,34 @@ export interface DebounceOptions { * ``` */ export function debounce( - { delay, leading }: DebounceOptions, - func: (...args: TArgs) => any, + { delay, leading }: DebounceOptions, + func: (...args: TArgs) => any, ): DebounceFunction { - let timer: unknown = undefined; - let active = true; + let timer: unknown = undefined + let active = true - const debounced: DebounceFunction = (...args: TArgs) => { - if (active) { - clearTimeout(timer); - timer = setTimeout(() => { - active && func(...args); - timer = undefined; - }, delay); - if (leading) { - func(...args); - leading = false; - } - } else { - func(...args); - } - }; - debounced.isPending = () => { - return timer !== undefined; - }; - debounced.cancel = () => { - active = false; - }; - debounced.flush = (...args: TArgs) => func(...args); + const debounced: DebounceFunction = (...args: TArgs) => { + if (active) { + clearTimeout(timer) + timer = setTimeout(() => { + active && func(...args) + timer = undefined + }, delay) + if (leading) { + func(...args) + leading = false + } + } else { + func(...args) + } + } + debounced.isPending = () => { + return timer !== undefined + } + debounced.cancel = () => { + active = false + } + debounced.flush = (...args: TArgs) => func(...args) - return debounced; + return debounced } diff --git a/src/curry/flip.ts b/src/curry/flip.ts index 376e340da..e0110487b 100644 --- a/src/curry/flip.ts +++ b/src/curry/flip.ts @@ -14,11 +14,11 @@ * ``` */ export function flip( - fn: (...args: Args) => Result, + fn: (...args: Args) => Result, ): (...args: Flip) => Result { - return (arg2, arg1, ...args) => (fn as any)(arg1, arg2, ...args); + return (arg2, arg1, ...args) => (fn as any)(arg1, arg2, ...args) } export type Flip = T extends [infer A, infer B, ...infer R] - ? [B, A, ...R] - : never; + ? [B, A, ...R] + : never diff --git a/src/curry/memo.ts b/src/curry/memo.ts index 67bd09cd8..363e338ff 100644 --- a/src/curry/memo.ts +++ b/src/curry/memo.ts @@ -1,34 +1,34 @@ -type Cache = Record; +type Cache = Record function memoize( - cache: Cache, - func: (...args: TArgs) => TResult, - keyFunc: ((...args: TArgs) => string) | null, - ttl: number | null, + cache: Cache, + func: (...args: TArgs) => TResult, + keyFunc: ((...args: TArgs) => string) | null, + ttl: number | null, ) { - return function callWithMemo(...args: any): TResult { - const key = keyFunc ? keyFunc(...args) : JSON.stringify({ args }); - const existing = cache[key]; - if (existing !== undefined) { - if (!existing.exp) { - return existing.value; - } - if (existing.exp > new Date().getTime()) { - return existing.value; - } - } - const result = func(...args); - cache[key] = { - exp: ttl ? new Date().getTime() + ttl : null, - value: result, - }; - return result; - }; + return function callWithMemo(...args: any): TResult { + const key = keyFunc ? keyFunc(...args) : JSON.stringify({ args }) + const existing = cache[key] + if (existing !== undefined) { + if (!existing.exp) { + return existing.value + } + if (existing.exp > new Date().getTime()) { + return existing.value + } + } + const result = func(...args) + cache[key] = { + exp: ttl ? new Date().getTime() + ttl : null, + value: result, + } + return result + } } export interface MemoOptions { - key?: (...args: TArgs) => string; - ttl?: number; + key?: (...args: TArgs) => string + ttl?: number } /** @@ -55,8 +55,8 @@ export interface MemoOptions { * ``` */ export function memo( - func: (...args: TArgs) => TResult, - options: MemoOptions = {}, + func: (...args: TArgs) => TResult, + options: MemoOptions = {}, ): (...args: TArgs) => TResult { - return memoize({}, func, options.key ?? null, options.ttl ?? null); + return memoize({}, func, options.key ?? null, options.ttl ?? null) } diff --git a/src/curry/once.ts b/src/curry/once.ts index 1d819813a..1af1d85c2 100644 --- a/src/curry/once.ts +++ b/src/curry/once.ts @@ -1,37 +1,37 @@ -const onceSymbol: unique symbol = Symbol(); +const onceSymbol: unique symbol = Symbol() /** * The type of a function wrapped with `once`. */ export interface OnceFunction< - Args extends unknown[] = unknown[], - Return = unknown, - This = unknown, + Args extends unknown[] = unknown[], + Return = unknown, + This = unknown, > { - (this: This, ...args: Args): Return; - [onceSymbol]?: Return | typeof onceSymbol; + (this: This, ...args: Args): Return + [onceSymbol]?: Return | typeof onceSymbol } type OnceImplementation = { - ( - fn: (this: This, ...args: Args) => Return, - ): (this: This, ...args: Args) => Return; + ( + fn: (this: This, ...args: Args) => Return, + ): (this: This, ...args: Args) => Return - /** - * Reset the result of a function that was created with `once`, - * allowing it to be called again. - * - * ```ts - * const fn = once(() => Math.random()) - * fn() // 0.5 - * fn() // 0.5 - * once.reset(fn) - * fn() // 0.3 - * fn() // 0.3 - * ``` - */ - reset(fn: OnceFunction): void; -}; + /** + * Reset the result of a function that was created with `once`, + * allowing it to be called again. + * + * ```ts + * const fn = once(() => Math.random()) + * fn() // 0.5 + * fn() // 0.5 + * once.reset(fn) + * fn() // 0.3 + * fn() // 0.3 + * ``` + */ + reset(fn: OnceFunction): void +} /** * Create a function that runs at most once, no matter how many times @@ -50,19 +50,19 @@ type OnceImplementation = { * ``` */ export const once: OnceImplementation = /* @__PURE__ */ (() => { - const once: OnceImplementation = (fn) => { - const onceFn = function (...args: any) { - if (onceFn[onceSymbol] === onceSymbol) { - onceFn[onceSymbol] = fn.apply(this as any, args); - } - return onceFn[onceSymbol]; - } as OnceFunction; + const once: OnceImplementation = fn => { + const onceFn = function (...args: any) { + if (onceFn[onceSymbol] === onceSymbol) { + onceFn[onceSymbol] = fn.apply(this as any, args) + } + return onceFn[onceSymbol] + } as OnceFunction - onceFn[onceSymbol] = onceSymbol; - return onceFn as typeof fn; - }; - once.reset = (fn: OnceFunction): void => { - fn[onceSymbol] = onceSymbol; - }; - return once; -})(); + onceFn[onceSymbol] = onceSymbol + return onceFn as typeof fn + } + once.reset = (fn: OnceFunction): void => { + fn[onceSymbol] = onceSymbol + } + return once +})() diff --git a/src/curry/partial.ts b/src/curry/partial.ts index e6d46aa7f..a303fde6d 100644 --- a/src/curry/partial.ts +++ b/src/curry/partial.ts @@ -11,9 +11,9 @@ * ``` */ type RemoveItemsInFront< - TItems extends any[], - TItemsToRemove extends any[], -> = TItems extends [...TItemsToRemove, ...infer TRest] ? TRest : TItems; + TItems extends any[], + TItemsToRemove extends any[], +> = TItems extends [...TItemsToRemove, ...infer TRest] ? TRest : TItems /** * Create a partial function by providing some (or all) of the @@ -30,8 +30,8 @@ type RemoveItemsInFront< * ``` */ export function partial, R>( - fn: (...args: T) => R, - ...args: TA + fn: (...args: T) => R, + ...args: TA ): (...rest: RemoveItemsInFront) => R { - return (...rest) => fn(...([...args, ...rest] as T)); + return (...rest) => fn(...([...args, ...rest] as T)) } diff --git a/src/curry/partob.ts b/src/curry/partob.ts index 42a2626ce..b8b38d058 100644 --- a/src/curry/partob.ts +++ b/src/curry/partob.ts @@ -19,8 +19,8 @@ * ``` */ export function partob>( - fn: (args: T) => K, - argObj: PartialArgs, + fn: (args: T) => K, + argObj: PartialArgs, ): (restObj: Omit) => K { - return (restObj) => fn({ ...argObj, ...restObj } as T); + return restObj => fn({ ...argObj, ...restObj } as T) } diff --git a/src/curry/proxied.ts b/src/curry/proxied.ts index 32ac70d55..92bdd0023 100644 --- a/src/curry/proxied.ts +++ b/src/curry/proxied.ts @@ -10,12 +10,12 @@ * ``` */ export function proxied( - handler: (propertyName: T) => K, + handler: (propertyName: T) => K, ): Record { - return new Proxy( - {}, - { - get: (target, propertyName: any) => handler(propertyName), - }, - ); + return new Proxy( + {}, + { + get: (target, propertyName: any) => handler(propertyName), + }, + ) } diff --git a/src/curry/throttle.ts b/src/curry/throttle.ts index e4978805e..d50f20cd8 100644 --- a/src/curry/throttle.ts +++ b/src/curry/throttle.ts @@ -1,36 +1,36 @@ -declare const setTimeout: (fn: () => void, ms: number) => unknown; -declare const clearTimeout: (timer: unknown) => void; +declare const setTimeout: (fn: () => void, ms: number) => unknown +declare const clearTimeout: (timer: unknown) => void export type ThrottledFunction = { - (...args: TArgs): void; - /** - * Checks if there is any invocation throttled - */ - isThrottled(): boolean; - /** - * Call the throttled function immediately, ignoring any throttling - * that may be in effect. After, a new throttled call will be allowed - * after the interval has passed. - * - * @example - * ```ts - * const logMessage = (message: string) => { - * console.log(`Message: ${message}`) - * } - * const throttledLog = throttle({ interval: 1000 }, logMessage) - * - * throttledLog('First call') // Logs immediately - * throttledLog('Throttled') // Doesn't log (throttled) - * - * // Force a log, bypassing the throttle - * throttledLog.trigger('Forced log') // Logs immediately - * - * // Check if it's still throttled - * throttledLog.isThrottled() // => true - * ``` - */ - trigger(...args: TArgs): void; -}; + (...args: TArgs): void + /** + * Checks if there is any invocation throttled + */ + isThrottled(): boolean + /** + * Call the throttled function immediately, ignoring any throttling + * that may be in effect. After, a new throttled call will be allowed + * after the interval has passed. + * + * @example + * ```ts + * const logMessage = (message: string) => { + * console.log(`Message: ${message}`) + * } + * const throttledLog = throttle({ interval: 1000 }, logMessage) + * + * throttledLog('First call') // Logs immediately + * throttledLog('Throttled') // Doesn't log (throttled) + * + * // Force a log, bypassing the throttle + * throttledLog.trigger('Forced log') // Logs immediately + * + * // Check if it's still throttled + * throttledLog.isThrottled() // => true + * ``` + */ + trigger(...args: TArgs): void +} /** * Given an interval and a function returns a new function that will @@ -50,38 +50,38 @@ export type ThrottledFunction = { * ``` */ export function throttle( - { interval, trailing }: { interval: number; trailing?: boolean }, - func: (...args: TArgs) => any, + { interval, trailing }: { interval: number; trailing?: boolean }, + func: (...args: TArgs) => any, ): ThrottledFunction { - let timer: unknown; - let lastCalled = 0; - let trailingArgs: TArgs | undefined; + let timer: unknown + let lastCalled = 0 + let trailingArgs: TArgs | undefined - const throttled: ThrottledFunction = (...args: TArgs) => { - if (!isThrottled()) { - trigger(...args); - } else if (trailing) { - trailingArgs = args; - } - }; + const throttled: ThrottledFunction = (...args: TArgs) => { + if (!isThrottled()) { + trigger(...args) + } else if (trailing) { + trailingArgs = args + } + } - const isThrottled = () => Date.now() - lastCalled < interval; - throttled.isThrottled = isThrottled; + const isThrottled = () => Date.now() - lastCalled < interval + throttled.isThrottled = isThrottled - const trigger = (throttled.trigger = (...args: TArgs) => { - func(...args); - lastCalled = Date.now(); + const trigger = (throttled.trigger = (...args: TArgs) => { + func(...args) + lastCalled = Date.now() - if (trailing) { - trailingArgs = undefined; + if (trailing) { + trailingArgs = undefined - clearTimeout(timer); - timer = setTimeout( - () => trailingArgs && trigger(...trailingArgs), - interval, - ); - } - }); + clearTimeout(timer) + timer = setTimeout( + () => trailingArgs && trigger(...trailingArgs), + interval, + ) + } + }) - return throttled; + return throttled } diff --git a/src/function/castComparator.ts b/src/function/castComparator.ts index 9a42ec264..f9b56ec33 100644 --- a/src/function/castComparator.ts +++ b/src/function/castComparator.ts @@ -1,12 +1,12 @@ import { - type Comparable, - type Comparator, - flip, - isFunction, - type MappedInput, - type MappedOutput, - type Mapping, -} from "radashi"; + type Comparable, + type Comparator, + flip, + isFunction, + type MappedInput, + type MappedOutput, + type Mapping, +} from 'radashi' /** * Cast a value into a comparator function. @@ -45,57 +45,57 @@ import { // Support property name: // castComparator('name') export function castComparator( - mapping: TMapping, - compare?: null | undefined, - reverse?: boolean, -): Comparator>; + mapping: TMapping, + compare?: null | undefined, + reverse?: boolean, +): Comparator> // Support property name and compare fn: // castComparator('name', (a: number, b: number) => {…}) export function castComparator>( - mapping: TMapping, - compare: Comparator, - reverse?: boolean, -): Comparator>; + mapping: TMapping, + compare: Comparator, + reverse?: boolean, +): Comparator> // Support explicit function type: // castComparator((data: TInput) => {…}) export function castComparator( - mapping: (data: TInput) => TOutput, - compare?: Comparator | null, - reverse?: boolean, -): Comparator; + mapping: (data: TInput) => TOutput, + compare?: Comparator | null, + reverse?: boolean, +): Comparator // Support explicit input type parameter: // castComparator(…) export function castComparator( - mapping: ComparatorMapping, - compare?: null | undefined, - reverse?: boolean, -): Comparator; + mapping: ComparatorMapping, + compare?: null | undefined, + reverse?: boolean, +): Comparator // Handle everything else with this signature. export function castComparator( - mapping: TMapping, - compare?: Comparator> | null, - reverse?: boolean, -): Comparator>; + mapping: TMapping, + compare?: Comparator> | null, + reverse?: boolean, +): Comparator> export function castComparator( - mapping: ComparatorMapping, - compare?: Comparator | null, - reverse?: boolean, + mapping: ComparatorMapping, + compare?: Comparator | null, + reverse?: boolean, ) { - const map = isFunction(mapping) ? mapping : (obj: any) => obj[mapping]; - const comparator: Comparator = (left, right) => { - const mappedLeft = map(left); - const mappedRight = map(right); - if (compare) { - return compare(mappedLeft, mappedRight); - } - return mappedLeft > mappedRight ? 1 : mappedLeft < mappedRight ? -1 : 0; - }; - return reverse ? flip(comparator) : comparator; + const map = isFunction(mapping) ? mapping : (obj: any) => obj[mapping] + const comparator: Comparator = (left, right) => { + const mappedLeft = map(left) + const mappedRight = map(right) + if (compare) { + return compare(mappedLeft, mappedRight) + } + return mappedLeft > mappedRight ? 1 : mappedLeft < mappedRight ? -1 : 0 + } + return reverse ? flip(comparator) : comparator } /** @@ -105,6 +105,6 @@ export function castComparator( * @see https://radashi.js.org/reference/function/castComparator */ export type ComparatorMapping< - T = any, - Compared extends Comparable = Comparable, -> = Mapping; + T = any, + Compared extends Comparable = Comparable, +> = Mapping diff --git a/src/function/castMapping.ts b/src/function/castMapping.ts index 4e65d77ea..89e103a60 100644 --- a/src/function/castMapping.ts +++ b/src/function/castMapping.ts @@ -1,4 +1,4 @@ -import { type Any, type CompatibleProperty, isFunction } from "radashi"; +import { type Any, type CompatibleProperty, isFunction } from 'radashi' /** * Cast the `mapping` value into a mapping function. @@ -21,14 +21,14 @@ import { type Any, type CompatibleProperty, isFunction } from "radashi"; * ``` */ export function castMapping( - mapping: TMapping, + mapping: TMapping, ): MappingFunction { - return isFunction(mapping) - ? mapping - : mapping != null - ? >(input: TInput) => - input[mapping as keyof object] as MappedOutput - : (input) => input as MappedOutput; + return isFunction(mapping) + ? mapping + : mapping != null + ? >(input: TInput) => + input[mapping as keyof object] as MappedOutput + : input => input as MappedOutput } /** @@ -37,18 +37,15 @@ export function castMapping( * @see https://radashi.js.org/reference/function/castMapping */ export type Mapping = - | ((arg: T) => U) - | CompatibleProperty; + | ((arg: T) => U) + | CompatibleProperty /** * A value that can be casted with `castMapping`. * * @see https://radashi.js.org/reference/function/castMapping */ -export type OptionalMapping = - | Mapping - | null - | undefined; +export type OptionalMapping = Mapping | null | undefined /** * The input type of a mapping function created with `castMapping`. @@ -56,16 +53,16 @@ export type OptionalMapping = * @see https://radashi.js.org/reference/function/castMapping */ export type MappedInput = TMapping extends ( - arg: infer Arg, + arg: infer Arg, ) => any - ? [Arg] extends [Any] - ? unknown - : Arg - : TMapping extends keyof any - ? - | { [P in TMapping]: TPropertyValue } - | (TMapping extends number ? readonly TPropertyValue[] : never) - : unknown; + ? [Arg] extends [Any] + ? unknown + : Arg + : TMapping extends keyof any + ? + | { [P in TMapping]: TPropertyValue } + | (TMapping extends number ? readonly TPropertyValue[] : never) + : unknown /** * The return type of a mapping function created with `castMapping`. @@ -73,18 +70,18 @@ export type MappedInput = TMapping extends ( * @see https://radashi.js.org/reference/function/castMapping */ export type MappedOutput = TMapping extends ( - data: TInput, + data: TInput, ) => infer Result - ? [Result] extends [Any] - ? unknown - : Result - : [TInput] extends [Any] - ? unknown - : TMapping extends null | undefined - ? TInput - : TMapping extends keyof TInput - ? TInput[TMapping] - : never; + ? [Result] extends [Any] + ? unknown + : Result + : [TInput] extends [Any] + ? unknown + : TMapping extends null | undefined + ? TInput + : TMapping extends keyof TInput + ? TInput[TMapping] + : never /** * A mapping function created with `castMapping`. @@ -92,7 +89,7 @@ export type MappedOutput = TMapping extends ( * @see https://radashi.js.org/reference/function/castMapping */ export type MappingFunction = < - TInput extends MappedInput, + TInput extends MappedInput, >( - input: TInput, -) => MappedOutput; + input: TInput, +) => MappedOutput diff --git a/src/number/clamp.ts b/src/number/clamp.ts index 37d5abb73..03880cd75 100644 --- a/src/number/clamp.ts +++ b/src/number/clamp.ts @@ -18,12 +18,12 @@ * ``` */ export function clamp( - n: number, - min: number | null | undefined, - max: number | null | undefined, + n: number, + min: number | null | undefined, + max: number | null | undefined, ): number { - if (max != null && min != null && min > max) { - throw new Error("invalid clamp range"); - } - return max != null && n > max ? max : min != null && n < min ? min : n; + if (max != null && min != null && min > max) { + throw new Error('invalid clamp range') + } + return max != null && n > max ? max : min != null && n < min ? min : n } diff --git a/src/number/inRange.ts b/src/number/inRange.ts index 3b44f7703..223964c9c 100644 --- a/src/number/inRange.ts +++ b/src/number/inRange.ts @@ -13,7 +13,7 @@ * inRange(10, 10) // => false * ``` */ -export function inRange(number: number, end: number): boolean; +export function inRange(number: number, end: number): boolean /** * Checks if the given number is between two numbers. @@ -32,21 +32,21 @@ export function inRange(number: number, end: number): boolean; * inRange(10, 0, 10) // => false * ``` */ -export function inRange(number: number, start: number, end: number): boolean; +export function inRange(number: number, start: number, end: number): boolean export function inRange(number: number, start: number, end?: number): boolean { - const isTypeSafe = - typeof number === "number" && - typeof start === "number" && - (typeof end === "undefined" || typeof end === "number"); + const isTypeSafe = + typeof number === 'number' && + typeof start === 'number' && + (typeof end === 'undefined' || typeof end === 'number') - if (!isTypeSafe) { - return false; - } + if (!isTypeSafe) { + return false + } - if (typeof end === "undefined") { - end = start; - start = 0; - } + if (typeof end === 'undefined') { + end = start + start = 0 + } - return number >= Math.min(start, end) && number < Math.max(start, end); + return number >= Math.min(start, end) && number < Math.max(start, end) } diff --git a/src/number/lerp.ts b/src/number/lerp.ts index 1a2913a2e..417741c34 100644 --- a/src/number/lerp.ts +++ b/src/number/lerp.ts @@ -10,5 +10,5 @@ * ``` */ export function lerp(from: number, to: number, amount: number): number { - return from + (to - from) * amount; + return from + (to - from) * amount } diff --git a/src/number/max.ts b/src/number/max.ts index aeaf6c66a..e5373e8a4 100644 --- a/src/number/max.ts +++ b/src/number/max.ts @@ -8,19 +8,19 @@ * max([{ num: 1 }, { num: 2 }], x => x.num) // => { num: 2 } * ``` */ -export function max(array: readonly [number, ...number[]]): number; -export function max(array: readonly number[]): number | null; +export function max(array: readonly [number, ...number[]]): number +export function max(array: readonly number[]): number | null export function max( - array: readonly T[], - getter: (item: T) => number, -): T | null; + array: readonly T[], + getter: (item: T) => number, +): T | null export function max( - array: readonly T[], - getter?: (item: T) => number, + array: readonly T[], + getter?: (item: T) => number, ): T | null { - if (!array || (array.length ?? 0) === 0) { - return null; - } - const get = getter ?? ((v: any) => v); - return array.reduce((a, b) => (get(a) > get(b) ? a : b)); + if (!array || (array.length ?? 0) === 0) { + return null + } + const get = getter ?? ((v: any) => v) + return array.reduce((a, b) => (get(a) > get(b) ? a : b)) } diff --git a/src/number/min.ts b/src/number/min.ts index 018367f0e..73b65e0f6 100644 --- a/src/number/min.ts +++ b/src/number/min.ts @@ -8,19 +8,19 @@ * min([{ num: 1 }, { num: 2 }], x => x.num) // => { num: 1 } * ``` */ -export function min(array: readonly [number, ...number[]]): number; -export function min(array: readonly number[]): number | null; +export function min(array: readonly [number, ...number[]]): number +export function min(array: readonly number[]): number | null export function min( - array: readonly T[], - getter: (item: T) => number, -): T | null; + array: readonly T[], + getter: (item: T) => number, +): T | null export function min( - array: readonly T[], - getter?: (item: T) => number, + array: readonly T[], + getter?: (item: T) => number, ): T | null { - if (!array || (array.length ?? 0) === 0) { - return null; - } - const get = getter ?? ((v: any) => v); - return array.reduce((a, b) => (get(a) < get(b) ? a : b)); + if (!array || (array.length ?? 0) === 0) { + return null + } + const get = getter ?? ((v: any) => v) + return array.reduce((a, b) => (get(a) < get(b) ? a : b)) } diff --git a/src/number/range.ts b/src/number/range.ts index 7c1049cf8..779deed6e 100644 --- a/src/number/range.ts +++ b/src/number/range.ts @@ -1,4 +1,4 @@ -import { isFunction } from "radashi"; +import { isFunction } from 'radashi' /** * Creates a generator that will produce an iteration through the @@ -18,20 +18,18 @@ import { isFunction } from "radashi"; * ``` */ export function* range( - startOrLength: number, - end?: number, - valueOrMapper: T | ((i: number) => T) = (i) => i as T, - step = 1, + startOrLength: number, + end?: number, + valueOrMapper: T | ((i: number) => T) = i => i as T, + step = 1, ): Generator { - const mapper = isFunction(valueOrMapper) - ? valueOrMapper - : () => valueOrMapper; - const start = end ? startOrLength : 0; - const final = end ?? startOrLength; - for (let i = start; i <= final; i += step) { - yield mapper(i); - if (i + step > final) { - break; - } - } + const mapper = isFunction(valueOrMapper) ? valueOrMapper : () => valueOrMapper + const start = end ? startOrLength : 0 + const final = end ?? startOrLength + for (let i = start; i <= final; i += step) { + yield mapper(i) + if (i + step > final) { + break + } + } } diff --git a/src/number/round.ts b/src/number/round.ts index 15a6a6b11..4e1f71920 100644 --- a/src/number/round.ts +++ b/src/number/round.ts @@ -24,21 +24,21 @@ * ``` */ export function round( - value: number, - precision?: number, - toInteger: (value: number) => number = Math.round, + value: number, + precision?: number, + toInteger: (value: number) => number = Math.round, ): number { - if (precision) { - // Limit the precision to avoid NaN results. - const p = - precision > 0 ? Math.min(precision, 292) : Math.max(precision, -323); + if (precision) { + // Limit the precision to avoid NaN results. + const p = + precision > 0 ? Math.min(precision, 292) : Math.max(precision, -323) - // By using exponential notation, we can avoid floating-point - // precision issues. The "q" is quantity, "e" is exponent. - let [q, e] = `${value}e`.split("e"); - [q, e] = `${toInteger(+`${q}e${+e + p}`)}e`.split("e"); - return +`${q}e${+e - p}`; - } + // By using exponential notation, we can avoid floating-point + // precision issues. The "q" is quantity, "e" is exponent. + let [q, e] = `${value}e`.split('e') + ;[q, e] = `${toInteger(+`${q}e${+e + p}`)}e`.split('e') + return +`${q}e${+e - p}` + } - return toInteger(value); + return toInteger(value) } diff --git a/src/number/sum.ts b/src/number/sum.ts index 56e353843..dc28cd227 100644 --- a/src/number/sum.ts +++ b/src/number/sum.ts @@ -21,11 +21,11 @@ * // => 2 * ``` */ -export function sum(array: readonly number[]): number; -export function sum(array: readonly T[], fn: (item: T) => number): number; +export function sum(array: readonly number[]): number +export function sum(array: readonly T[], fn: (item: T) => number): number export function sum( - array: readonly any[], - fn?: (item: T) => number, + array: readonly any[], + fn?: (item: T) => number, ): number { - return (array || []).reduce((acc, item) => acc + (fn ? fn(item) : item), 0); + return (array || []).reduce((acc, item) => acc + (fn ? fn(item) : item), 0) } diff --git a/src/number/toFloat.ts b/src/number/toFloat.ts index 0055d1b31..d03317bf7 100644 --- a/src/number/toFloat.ts +++ b/src/number/toFloat.ts @@ -1,4 +1,4 @@ -import { isSymbol } from "radashi"; +import { isSymbol } from 'radashi' /** * Combines `Number.parseFloat` with NaN handling. By default, a zero @@ -13,22 +13,22 @@ import { isSymbol } from "radashi"; * toFloat("foo", 1) // => 1 * ``` */ -export function toFloat(value: unknown): number; +export function toFloat(value: unknown): number export function toFloat( - value: unknown, - defaultValue: T | undefined, -): number | T; + value: unknown, + defaultValue: T | undefined, +): number | T export function toFloat( - value: any, - defaultValue?: T, + value: any, + defaultValue?: T, ): number | Exclude { - // Symbols throw on string coercion, which parseFloat does. - const parsedValue = isSymbol(value) ? Number.NaN : Number.parseFloat(value); - return Number.isNaN(parsedValue) - ? defaultValue !== undefined - ? (defaultValue as Exclude) - : 0 - : parsedValue; + // Symbols throw on string coercion, which parseFloat does. + const parsedValue = isSymbol(value) ? Number.NaN : Number.parseFloat(value) + return Number.isNaN(parsedValue) + ? defaultValue !== undefined + ? (defaultValue as Exclude) + : 0 + : parsedValue } diff --git a/src/number/toInt.ts b/src/number/toInt.ts index 1695da913..ec273c967 100644 --- a/src/number/toInt.ts +++ b/src/number/toInt.ts @@ -1,4 +1,4 @@ -import { isSymbol } from "radashi"; +import { isSymbol } from 'radashi' /** * Combines `Number.parseInt` with NaN handling. By default, a zero @@ -13,22 +13,22 @@ import { isSymbol } from "radashi"; * toInt("foo", -1) // => -1 * ``` */ -export function toInt(value: unknown): number; +export function toInt(value: unknown): number export function toInt( - value: unknown, - defaultValue: T | undefined, -): number | T; + value: unknown, + defaultValue: T | undefined, +): number | T export function toInt( - value: any, - defaultValue?: T, + value: any, + defaultValue?: T, ): number | Exclude { - // Symbols throw on string coercion, which parseInt does. - const parsedValue = isSymbol(value) ? Number.NaN : Number.parseInt(value); - return Number.isNaN(parsedValue) - ? defaultValue !== undefined - ? (defaultValue as Exclude) - : 0 - : parsedValue; + // Symbols throw on string coercion, which parseInt does. + const parsedValue = isSymbol(value) ? Number.NaN : Number.parseInt(value) + return Number.isNaN(parsedValue) + ? defaultValue !== undefined + ? (defaultValue as Exclude) + : 0 + : parsedValue } diff --git a/src/object/assign.ts b/src/object/assign.ts index 9f0f4c867..16e21d030 100644 --- a/src/object/assign.ts +++ b/src/object/assign.ts @@ -1,12 +1,12 @@ import { - isPlainObject, - type BoxedPrimitive, - type BuiltInType, - type CustomClass, - type IsExactType, - type OptionalKeys, - type RequiredKeys, -} from "radashi"; + isPlainObject, + type BoxedPrimitive, + type BuiltInType, + type CustomClass, + type IsExactType, + type OptionalKeys, + type RequiredKeys, +} from 'radashi' /** * Create a copy of the first object, and then merge the second object @@ -23,23 +23,23 @@ import { * ``` */ export function assign< - TInitial extends Record, - TOverride extends Record, + TInitial extends Record, + TOverride extends Record, >(initial: TInitial, override: TOverride): Assign { - if (!initial || !override) { - return (initial ?? override ?? {}) as any; - } - const proto = Object.getPrototypeOf(initial); - const merged = proto - ? { ...initial } - : Object.assign(Object.create(proto), initial); - for (const key of Object.keys(override)) { - merged[key] = - isPlainObject(initial[key]) && isPlainObject(override[key]) - ? assign(initial[key], override[key]) - : override[key]; - } - return merged; + if (!initial || !override) { + return (initial ?? override ?? {}) as any + } + const proto = Object.getPrototypeOf(initial) + const merged = proto + ? { ...initial } + : Object.assign(Object.create(proto), initial) + for (const key of Object.keys(override)) { + merged[key] = + isPlainObject(initial[key]) && isPlainObject(override[key]) + ? assign(initial[key], override[key]) + : override[key] + } + return merged } /** @@ -51,59 +51,59 @@ export function assign< * @see https://radashi.js.org/reference/object/assign */ export type Assign< - TInitial extends object, - TOverride extends object, + TInitial extends object, + TOverride extends object, > = TInitial extends any - ? TOverride extends any - ? SimplifyMutable< - Omit & - Omit & - (Pick< - TInitial, - keyof TInitial & keyof TOverride - > extends infer TConflictInitial - ? Pick< - TOverride, - keyof TInitial & keyof TOverride - > extends infer TConflictOverride - ? { - [K in RequiredKeys]: AssignDeep< - TConflictInitial[K & keyof TConflictInitial], - TConflictOverride[K] - >; - } & { - [K in RequiredKeys & - OptionalKeys]: AssignDeep< - TConflictInitial[K], - TConflictOverride[K], - true - >; - } & { - [K in OptionalKeys & - OptionalKeys]?: AssignDeep< - TConflictInitial[K], - TConflictOverride[K], - true - >; - } - : unknown - : unknown) - > - : never - : never; + ? TOverride extends any + ? SimplifyMutable< + Omit & + Omit & + (Pick< + TInitial, + keyof TInitial & keyof TOverride + > extends infer TConflictInitial + ? Pick< + TOverride, + keyof TInitial & keyof TOverride + > extends infer TConflictOverride + ? { + [K in RequiredKeys]: AssignDeep< + TConflictInitial[K & keyof TConflictInitial], + TConflictOverride[K] + > + } & { + [K in RequiredKeys & + OptionalKeys]: AssignDeep< + TConflictInitial[K], + TConflictOverride[K], + true + > + } & { + [K in OptionalKeys & + OptionalKeys]?: AssignDeep< + TConflictInitial[K], + TConflictOverride[K], + true + > + } + : unknown + : unknown) + > + : never + : never /** * Mimic the `Simplify` type and also remove `readonly` modifiers. */ type SimplifyMutable = {} & { - -readonly [P in keyof T]: T[P]; -}; + -readonly [P in keyof T]: T[P] +} /** * This represents a value that should only be replaced if it exists * as an initial value; never deeply assigned into. */ -type AtomicValue = BuiltInType | CustomClass | BoxedPrimitive; +type AtomicValue = BuiltInType | CustomClass | BoxedPrimitive /** * Handle mixed types when merging nested plain objects. @@ -113,45 +113,45 @@ type AtomicValue = BuiltInType | CustomClass | BoxedPrimitive; * unmergeable and `{ n: number }` as mergeable. */ type AssignDeep = - | never // ← Fixes auto-formatting of the comment below. - /** - * When a native type is found in TInitial, it will only exist in - * the result type if the override is optional. - */ - | (TInitial extends AtomicValue - ? IsOptional extends true - ? TInitial - : never - : never) - /** - * When a native type is found in TOverride, it will always exists - * in the result type. - */ - | (TOverride extends AtomicValue ? TOverride : never) - /** - * Deep assignment is handled in this branch. - * - * 1. Exclude any native types from TInitial and TOverride - * 2. If a non-native object type is not found in TInitial, simply - * replace TInitial (or use "A | B" if the override is optional) - * 3. For each non-native object type in TOverride, deep assign to - * every non-native object in TInitial - * 4. For each non-object type in TOverride, simply replace TInitial - * (or use "A | B" if the override is optional) - */ - | (Exclude extends infer TOverride // 1. - ? Exclude> extends infer TInitial - ? [Extract] extends [never] // 2. - ? TOverride | (IsOptional extends true ? TInitial : never) - : TInitial extends object - ? TOverride extends object - ? IsExactType extends true - ? TOverride - : Assign // 3. - : // 4. - TOverride | (IsOptional extends true ? TInitial : never) - : - | Extract - | (IsOptional extends true ? TInitial : never) - : never - : never); + | never // ← Fixes auto-formatting of the comment below. + /** + * When a native type is found in TInitial, it will only exist in + * the result type if the override is optional. + */ + | (TInitial extends AtomicValue + ? IsOptional extends true + ? TInitial + : never + : never) + /** + * When a native type is found in TOverride, it will always exists + * in the result type. + */ + | (TOverride extends AtomicValue ? TOverride : never) + /** + * Deep assignment is handled in this branch. + * + * 1. Exclude any native types from TInitial and TOverride + * 2. If a non-native object type is not found in TInitial, simply + * replace TInitial (or use "A | B" if the override is optional) + * 3. For each non-native object type in TOverride, deep assign to + * every non-native object in TInitial + * 4. For each non-object type in TOverride, simply replace TInitial + * (or use "A | B" if the override is optional) + */ + | (Exclude extends infer TOverride // 1. + ? Exclude> extends infer TInitial + ? [Extract] extends [never] // 2. + ? TOverride | (IsOptional extends true ? TInitial : never) + : TInitial extends object + ? TOverride extends object + ? IsExactType extends true + ? TOverride + : Assign // 3. + : // 4. + TOverride | (IsOptional extends true ? TInitial : never) + : + | Extract + | (IsOptional extends true ? TInitial : never) + : never + : never) diff --git a/src/object/clone.ts b/src/object/clone.ts index dba342a5b..bd71ca2f7 100644 --- a/src/object/clone.ts +++ b/src/object/clone.ts @@ -1,4 +1,4 @@ -import { isPrimitive } from "radashi"; +import { isPrimitive } from 'radashi' /** * Creates a shallow copy of the given object/value. @@ -16,25 +16,25 @@ import { isPrimitive } from "radashi"; * ``` */ export function clone(obj: T): T { - // Primitive values do not need cloning. - if (isPrimitive(obj)) { - return obj; - } + // Primitive values do not need cloning. + if (isPrimitive(obj)) { + return obj + } - // Binding a function to an empty object creates a copy function. - if (typeof obj === "function") { - return obj.bind({}); - } + // Binding a function to an empty object creates a copy function. + if (typeof obj === 'function') { + return obj.bind({}) + } - const proto = Object.getPrototypeOf(obj); - const newObj = - typeof proto?.constructor === "function" - ? new proto.constructor() - : Object.create(proto); + const proto = Object.getPrototypeOf(obj) + const newObj = + typeof proto?.constructor === 'function' + ? new proto.constructor() + : Object.create(proto) - for (const key of Object.getOwnPropertyNames(obj)) { - newObj[key] = obj[key as keyof T]; - } + for (const key of Object.getOwnPropertyNames(obj)) { + newObj[key] = obj[key as keyof T] + } - return newObj; + return newObj } diff --git a/src/object/construct.ts b/src/object/construct.ts index 7b0f44430..4f5774fbf 100644 --- a/src/object/construct.ts +++ b/src/object/construct.ts @@ -1,4 +1,4 @@ -import { set } from "radashi"; +import { set } from 'radashi' /** * The opposite of crush, given an object that was crushed into key @@ -12,10 +12,10 @@ import { set } from "radashi"; * ``` */ export function construct(obj: TObject): object { - if (!obj) { - return {}; - } - return Object.keys(obj).reduce((acc, path) => { - return set(acc, path, (obj as any)[path]); - }, {}); + if (!obj) { + return {} + } + return Object.keys(obj).reduce((acc, path) => { + return set(acc, path, (obj as any)[path]) + }, {}) } diff --git a/src/object/crush.ts b/src/object/crush.ts index b8c5c1693..87da4bdd8 100644 --- a/src/object/crush.ts +++ b/src/object/crush.ts @@ -1,4 +1,4 @@ -import { type Intersect, isArray, isObject, type Simplify } from "radashi"; +import { type Intersect, isArray, isObject, type Simplify } from 'radashi' /** * Flattens a deep object to a single dimension, converting the keys @@ -12,23 +12,23 @@ import { type Intersect, isArray, isObject, type Simplify } from "radashi"; * ``` */ export function crush(value: T): Crush { - if (!value) { - return {} as Crush; - } - return (function crushReducer( - crushed: Crush, - value: unknown, - path: string, - ) { - if (isObject(value) || isArray(value)) { - for (const [prop, propValue] of Object.entries(value)) { - crushReducer(crushed, propValue, path ? `${path}.${prop}` : prop); - } - } else { - crushed[path as keyof Crush] = value as Crush[keyof Crush]; - } - return crushed; - })({} as Crush, value, ""); + if (!value) { + return {} as Crush + } + return (function crushReducer( + crushed: Crush, + value: unknown, + path: string, + ) { + if (isObject(value) || isArray(value)) { + for (const [prop, propValue] of Object.entries(value)) { + crushReducer(crushed, propValue, path ? `${path}.${prop}` : prop) + } + } else { + crushed[path as keyof Crush] = value as Crush[keyof Crush] + } + return crushed + })({} as Crush, value, '') } /** @@ -42,23 +42,23 @@ export function crush(value: T): Crush { * @see https://radashi.js.org/reference/object/crush */ export type Crush = T extends readonly (infer U)[] - ? Record - : Simplify< - Intersect< - keyof T extends infer Prop - ? Prop extends keyof T - ? T[Prop] extends infer Value - ? - | ([Extract] extends [never] - ? never - : Record) - | ([Exclude] extends [never] - ? never - : [Extract] extends [never] - ? { [P in Prop]: Value } - : Record) - : never - : never - : never - > - >; + ? Record + : Simplify< + Intersect< + keyof T extends infer Prop + ? Prop extends keyof T + ? T[Prop] extends infer Value + ? + | ([Extract] extends [never] + ? never + : Record) + | ([Exclude] extends [never] + ? never + : [Extract] extends [never] + ? { [P in Prop]: Value } + : Record) + : never + : never + : never + > + > diff --git a/src/object/filterKey.ts b/src/object/filterKey.ts index bb7f4b1f2..30587bb87 100644 --- a/src/object/filterKey.ts +++ b/src/object/filterKey.ts @@ -1,30 +1,30 @@ -import { isArray } from "radashi"; +import { isArray } from 'radashi' -type KeyOf = object extends T ? keyof any : keyof T; -type ValueOf = object extends T ? unknown : T[keyof T]; +type KeyOf = object extends T ? keyof any : keyof T +type ValueOf = object extends T ? unknown : T[keyof T] export type KeyFilterFunction = ( - value: ValueOf, - key: KeyOf, - obj: T, -) => boolean; + value: ValueOf, + key: KeyOf, + obj: T, +) => boolean /** * Functions can use this type to accept either an array of keys or a * filter function. */ export type KeyFilter< - T extends object = object, - Key extends keyof any = keyof any, -> = KeyFilterFunction | readonly Key[]; + T extends object = object, + Key extends keyof any = keyof any, +> = KeyFilterFunction | readonly Key[] /** * Extract the keys of an object that pass a filter. */ export type FilteredKeys< - T extends object, - F extends KeyFilter | null | undefined, -> = Extract; + T extends object, + F extends KeyFilter | null | undefined, +> = Extract /** * Returns true if the key is in the “keys array” or if the “filter @@ -44,27 +44,27 @@ export type FilteredKeys< * ``` */ export function filterKey( - obj: T, - key: keyof T, - filter: KeyFilter | null | undefined, -): boolean; + obj: T, + key: keyof T, + filter: KeyFilter | null | undefined, +): boolean export function filterKey( - obj: object, - key: keyof any, - filter: KeyFilter | null | undefined, -): boolean; + obj: object, + key: keyof any, + filter: KeyFilter | null | undefined, +): boolean export function filterKey( - obj: object, - key: keyof any, - filter: KeyFilter | null | undefined, + obj: object, + key: keyof any, + filter: KeyFilter | null | undefined, ): boolean { - return ( - Object.hasOwnProperty.call(obj, key) && - (filter == null || - (isArray(filter) - ? filter.includes(key) - : filter((obj as any)[key], key, obj))) - ); + return ( + Object.hasOwnProperty.call(obj, key) && + (filter == null || + (isArray(filter) + ? filter.includes(key) + : filter((obj as any)[key], key, obj))) + ) } diff --git a/src/object/get.ts b/src/object/get.ts index 91e0f32f2..a8205370b 100644 --- a/src/object/get.ts +++ b/src/object/get.ts @@ -15,27 +15,27 @@ * ``` */ export function get( - value: any, - path: string, - defaultValue?: TDefault, + value: any, + path: string, + defaultValue?: TDefault, ): TDefault { - const segments = path.split(/[\.\[\]]/g); - let current: any = value; - for (const key of segments) { - if (current === null) { - return defaultValue as TDefault; - } - if (current === undefined) { - return defaultValue as TDefault; - } - const unquotedKey = key.replace(/['"]/g, ""); - if (unquotedKey.trim() === "") { - continue; - } - current = current[unquotedKey]; - } - if (current === undefined) { - return defaultValue as TDefault; - } - return current; + const segments = path.split(/[\.\[\]]/g) + let current: any = value + for (const key of segments) { + if (current === null) { + return defaultValue as TDefault + } + if (current === undefined) { + return defaultValue as TDefault + } + const unquotedKey = key.replace(/['"]/g, '') + if (unquotedKey.trim() === '') { + continue + } + current = current[unquotedKey] + } + if (current === undefined) { + return defaultValue as TDefault + } + return current } diff --git a/src/object/invert.ts b/src/object/invert.ts index c4c760df9..487a733a9 100644 --- a/src/object/invert.ts +++ b/src/object/invert.ts @@ -11,18 +11,18 @@ * ``` */ export function invert< - TKey extends string | number | symbol, - TValue extends string | number | symbol, + TKey extends string | number | symbol, + TValue extends string | number | symbol, >(obj: Record): Record { - if (!obj) { - return {} as Record; - } - const keys = Object.keys(obj) as TKey[]; - return keys.reduce( - (acc, key) => { - acc[obj[key]] = key; - return acc; - }, - {} as Record, - ); + if (!obj) { + return {} as Record + } + const keys = Object.keys(obj) as TKey[] + return keys.reduce( + (acc, key) => { + acc[obj[key]] = key + return acc + }, + {} as Record, + ) } diff --git a/src/object/keys.ts b/src/object/keys.ts index b46b705c7..62d85538f 100644 --- a/src/object/keys.ts +++ b/src/object/keys.ts @@ -1,4 +1,4 @@ -import { isArray, isPlainObject } from "radashi"; +import { isArray, isPlainObject } from 'radashi' /** * Get a string list of all key names that exist in an object (deep). @@ -13,28 +13,28 @@ import { isArray, isPlainObject } from "radashi"; * ``` */ export function keys(value: object): string[] { - if (!value) { - return []; - } - const keys: string[] = []; - const keyPath: (string | number)[] = []; - const recurse = (value: any) => { - if (isPlainObject(value)) { - for (const [prop, propValue] of Object.entries(value)) { - keyPath.push(prop); - recurse(propValue); - keyPath.pop(); - } - } else if (isArray(value)) { - value.forEach((item, index) => { - keyPath.push(index); - recurse(item); - keyPath.pop(); - }); - } else { - keys.push(keyPath.join(".")); - } - }; - recurse(value); - return keys; + if (!value) { + return [] + } + const keys: string[] = [] + const keyPath: (string | number)[] = [] + const recurse = (value: any) => { + if (isPlainObject(value)) { + for (const [prop, propValue] of Object.entries(value)) { + keyPath.push(prop) + recurse(propValue) + keyPath.pop() + } + } else if (isArray(value)) { + value.forEach((item, index) => { + keyPath.push(index) + recurse(item) + keyPath.pop() + }) + } else { + keys.push(keyPath.join('.')) + } + } + recurse(value) + return keys } diff --git a/src/object/listify.ts b/src/object/listify.ts index 36a3af73e..ea5a57629 100644 --- a/src/object/listify.ts +++ b/src/object/listify.ts @@ -14,18 +14,18 @@ * ``` */ export function listify( - obj: Record, - toItem: (key: Key, value: Value) => Item, + obj: Record, + toItem: (key: Key, value: Value) => Item, ): Item[] { - if (!obj) { - return []; - } - const entries = Object.entries(obj); - if (entries.length === 0) { - return []; - } - return entries.reduce((acc, entry) => { - acc.push(toItem(entry[0] as Key, entry[1] as Value)); - return acc; - }, [] as Item[]); + if (!obj) { + return [] + } + const entries = Object.entries(obj) + if (entries.length === 0) { + return [] + } + return entries.reduce((acc, entry) => { + acc.push(toItem(entry[0] as Key, entry[1] as Value)) + return acc + }, [] as Item[]) } diff --git a/src/object/lowerize.ts b/src/object/lowerize.ts index f64a3f395..02be46ea5 100644 --- a/src/object/lowerize.ts +++ b/src/object/lowerize.ts @@ -1,8 +1,8 @@ -import { mapKeys } from "radashi"; +import { mapKeys } from 'radashi' export type LowercaseKeys> = { - [P in keyof T & string as Lowercase

]: T[P]; -}; + [P in keyof T & string as Lowercase

]: T[P] +} /** * Convert all keys in an object to lower case. @@ -16,7 +16,7 @@ export type LowercaseKeys> = { * ``` */ export function lowerize>( - obj: T, + obj: T, ): LowercaseKeys { - return mapKeys(obj, (k) => k.toLowerCase()) as LowercaseKeys; + return mapKeys(obj, k => k.toLowerCase()) as LowercaseKeys } diff --git a/src/object/mapEntries.ts b/src/object/mapEntries.ts index ca61ba845..357991628 100644 --- a/src/object/mapEntries.ts +++ b/src/object/mapEntries.ts @@ -10,23 +10,23 @@ * ``` */ export function mapEntries< - TKey extends string | number | symbol, - TValue, - TNewKey extends string | number | symbol, - TNewValue, + TKey extends string | number | symbol, + TValue, + TNewKey extends string | number | symbol, + TNewValue, >( - obj: Record, - toEntry: (key: TKey, value: TValue) => [TNewKey, TNewValue], + obj: Record, + toEntry: (key: TKey, value: TValue) => [TNewKey, TNewValue], ): Record { - if (!obj) { - return {} as Record; - } - return Object.entries(obj).reduce( - (acc, [key, value]) => { - const [newKey, newValue] = toEntry(key as TKey, value as TValue); - acc[newKey] = newValue; - return acc; - }, - {} as Record, - ); + if (!obj) { + return {} as Record + } + return Object.entries(obj).reduce( + (acc, [key, value]) => { + const [newKey, newValue] = toEntry(key as TKey, value as TValue) + acc[newKey] = newValue + return acc + }, + {} as Record, + ) } diff --git a/src/object/mapKeys.ts b/src/object/mapKeys.ts index 720c90173..b01e6ef71 100644 --- a/src/object/mapKeys.ts +++ b/src/object/mapKeys.ts @@ -10,19 +10,19 @@ * ``` */ export function mapKeys< - TValue, - TKey extends string | number | symbol, - TNewKey extends string | number | symbol, + TValue, + TKey extends string | number | symbol, + TNewKey extends string | number | symbol, >( - obj: Record, - mapFunc: (key: TKey, value: TValue) => TNewKey, + obj: Record, + mapFunc: (key: TKey, value: TValue) => TNewKey, ): Record { - const keys = Object.keys(obj) as TKey[]; - return keys.reduce( - (acc, key) => { - acc[mapFunc(key as TKey, obj[key])] = obj[key]; - return acc; - }, - {} as Record, - ); + const keys = Object.keys(obj) as TKey[] + return keys.reduce( + (acc, key) => { + acc[mapFunc(key as TKey, obj[key])] = obj[key] + return acc + }, + {} as Record, + ) } diff --git a/src/object/mapValues.ts b/src/object/mapValues.ts index 22b26f973..aca0a3d63 100644 --- a/src/object/mapValues.ts +++ b/src/object/mapValues.ts @@ -10,41 +10,41 @@ * ``` */ export function mapValues< - TValue, - TKey extends string | number | symbol, - TNewValue, + TValue, + TKey extends string | number | symbol, + TNewValue, >( - obj: { [K in TKey]: TValue }, - mapFunc: (value: TValue, key: TKey) => TNewValue, -): { [K in TKey]: TNewValue }; + obj: { [K in TKey]: TValue }, + mapFunc: (value: TValue, key: TKey) => TNewValue, +): { [K in TKey]: TNewValue } // This overload exists to support cases where `obj` is a partial // object whose values are never undefined when the key is also // defined. For example: // { [key: string]?: number } versus { [key: string]: number | undefined } export function mapValues< - TValue, - TKey extends string | number | symbol, - TNewValue, + TValue, + TKey extends string | number | symbol, + TNewValue, >( - obj: { [K in TKey]?: TValue }, - mapFunc: (value: TValue, key: TKey) => TNewValue, -): { [K in TKey]?: TNewValue }; + obj: { [K in TKey]?: TValue }, + mapFunc: (value: TValue, key: TKey) => TNewValue, +): { [K in TKey]?: TNewValue } export function mapValues< - TValue, - TKey extends string | number | symbol, - TNewValue, + TValue, + TKey extends string | number | symbol, + TNewValue, >( - obj: { [K in TKey]?: TValue }, - mapFunc: (value: TValue, key: TKey) => TNewValue, + obj: { [K in TKey]?: TValue }, + mapFunc: (value: TValue, key: TKey) => TNewValue, ): Record { - const keys = Object.keys(obj) as TKey[]; - return keys.reduce( - (acc, key) => { - acc[key] = mapFunc(obj[key]!, key); - return acc; - }, - {} as Record, - ); + const keys = Object.keys(obj) as TKey[] + return keys.reduce( + (acc, key) => { + acc[key] = mapFunc(obj[key]!, key) + return acc + }, + {} as Record, + ) } diff --git a/src/object/omit.ts b/src/object/omit.ts index c8768af84..1d027f4ba 100644 --- a/src/object/omit.ts +++ b/src/object/omit.ts @@ -11,24 +11,24 @@ * ``` */ export function omit( - obj: T, - keys: TKeys[], + obj: T, + keys: TKeys[], ): Omit { - if (!obj) { - return {} as Omit; - } - if (!keys || keys.length === 0) { - return obj as Omit; - } - return keys.reduce( - (acc, key) => { - // Gross, I know, it's mutating the object, but we are allowing - // it in this very limited scope due to the performance - // implications of an omit func. Not a pattern or practice to - // use elsewhere. - delete acc[key]; - return acc; - }, - { ...obj }, - ); + if (!obj) { + return {} as Omit + } + if (!keys || keys.length === 0) { + return obj as Omit + } + return keys.reduce( + (acc, key) => { + // Gross, I know, it's mutating the object, but we are allowing + // it in this very limited scope due to the performance + // implications of an omit func. Not a pattern or practice to + // use elsewhere. + delete acc[key] + return acc + }, + { ...obj }, + ) } diff --git a/src/object/pick.ts b/src/object/pick.ts index 7b6958a46..114f3e254 100644 --- a/src/object/pick.ts +++ b/src/object/pick.ts @@ -1,4 +1,4 @@ -import { type FilteredKeys, filterKey, isArray, type KeyFilter } from "radashi"; +import { type FilteredKeys, filterKey, isArray, type KeyFilter } from 'radashi' /** * Pick a list of properties from an object into a new object. @@ -22,27 +22,27 @@ import { type FilteredKeys, filterKey, isArray, type KeyFilter } from "radashi"; * ``` */ export function pick>( - obj: T, - filter: F, -): Pick>; + obj: T, + filter: F, +): Pick> export function pick( - obj: T, - filter: KeyFilter | null, + obj: T, + filter: KeyFilter | null, ) { - if (!obj) { - return {}; - } - let keys: (keyof T)[] = filter as any; - if (isArray(filter)) { - filter = null; - } else { - keys = Reflect.ownKeys(obj) as (keyof T)[]; - } - return keys.reduce((acc, key) => { - if (filterKey(obj, key, filter)) { - acc[key] = obj[key]; - } - return acc; - }, {} as T); + if (!obj) { + return {} + } + let keys: (keyof T)[] = filter as any + if (isArray(filter)) { + filter = null + } else { + keys = Reflect.ownKeys(obj) as (keyof T)[] + } + return keys.reduce((acc, key) => { + if (filterKey(obj, key, filter)) { + acc[key] = obj[key] + } + return acc + }, {} as T) } diff --git a/src/object/set.ts b/src/object/set.ts index 80c5170fb..0c22d41bc 100644 --- a/src/object/set.ts +++ b/src/object/set.ts @@ -1,4 +1,4 @@ -import { clone, isIntString } from "radashi"; +import { clone, isIntString } from 'radashi' /** * Opposite of get, dynamically set a nested value into an object @@ -12,28 +12,28 @@ import { clone, isIntString } from "radashi"; * ``` */ export function set( - initial: T, - path: string, - value: K, + initial: T, + path: string, + value: K, ): T { - if (!initial) { - return {} as T; - } - if (!path || value === undefined) { - return initial; - } + if (!initial) { + return {} as T + } + if (!path || value === undefined) { + return initial + } - const root: any = clone(initial); - const keys = path.match(/[^.[\]]+/g); - if (keys) { - keys.reduce( - (object, key, i) => - i < keys.length - 1 - ? (object[key] ??= isIntString(keys[i + 1]) ? [] : {}) - : (object[key] = value), - root, - ); - } + const root: any = clone(initial) + const keys = path.match(/[^.[\]]+/g) + if (keys) { + keys.reduce( + (object, key, i) => + i < keys.length - 1 + ? (object[key] ??= isIntString(keys[i + 1]) ? [] : {}) + : (object[key] = value), + root, + ) + } - return root; + return root } diff --git a/src/object/shake.ts b/src/object/shake.ts index 5d4c669c6..c3db5cbd7 100644 --- a/src/object/shake.ts +++ b/src/object/shake.ts @@ -11,17 +11,17 @@ * ``` */ export function shake( - obj: T, - filter: (value: T[keyof T]) => boolean = (value) => value === undefined, + obj: T, + filter: (value: T[keyof T]) => boolean = value => value === undefined, ): T { - if (!obj) { - return {} as T; - } - const keys = Object.keys(obj) as (keyof T)[]; - return keys.reduce((acc, key) => { - if (!filter(obj[key])) { - acc[key] = obj[key]; - } - return acc; - }, {} as T); + if (!obj) { + return {} as T + } + const keys = Object.keys(obj) as (keyof T)[] + return keys.reduce((acc, key) => { + if (!filter(obj[key])) { + acc[key] = obj[key] + } + return acc + }, {} as T) } diff --git a/src/object/traverse.ts b/src/object/traverse.ts index d62799ae2..4ccc184f8 100644 --- a/src/object/traverse.ts +++ b/src/object/traverse.ts @@ -1,18 +1,18 @@ -import { isArray, isFunction, isIterable, isPlainObject, last } from "radashi"; +import { isArray, isFunction, isIterable, isPlainObject, last } from 'radashi' export interface TraverseOptions { - /** - * A function that returns the keys of the object to be traversed. - * - * @default Object.keys - */ - ownKeys?: ((parent: object) => Iterable) | null; - /** - * When true, the visitor callback will be invoked for the root object. - * - * @default false - */ - rootNeedsVisit?: boolean | null; + /** + * A function that returns the keys of the object to be traversed. + * + * @default Object.keys + */ + ownKeys?: ((parent: object) => Iterable) | null + /** + * When true, the visitor callback will be invoked for the root object. + * + * @default false + */ + rootNeedsVisit?: boolean | null } /** @@ -40,224 +40,224 @@ export interface TraverseOptions { * ``` */ export function traverse( - root: object, - visitor: TraverseVisitor, - options?: (TraverseOptions & { rootNeedsVisit?: null }) | null, - outerContext?: TraverseContext, -): boolean; + root: object, + visitor: TraverseVisitor, + options?: (TraverseOptions & { rootNeedsVisit?: null }) | null, + outerContext?: TraverseContext, +): boolean export function traverse( - root: object, - visitor: TraverseVisitor, - options?: TraverseOptions | null, - outerContext?: TraverseContext, -): boolean; + root: object, + visitor: TraverseVisitor, + options?: TraverseOptions | null, + outerContext?: TraverseContext, +): boolean export function traverse( - root: object, - visitor: TraverseVisitor, - options?: TraverseOptions | null, - outerContext?: TraverseContext | null, + root: object, + visitor: TraverseVisitor, + options?: TraverseOptions | null, + outerContext?: TraverseContext | null, ): boolean { - const context = (outerContext ?? { - value: null, - key: null, - parent: null, - parents: [], - path: [], - skipped: new Set(), - skip(obj) { - context.skipped.add(obj ?? context.value); - }, - }) as TraverseContext & { - value: unknown; - key: keyof any | null; - parent: any; - parents: object[]; - path: (keyof any)[]; - skipped: Set; - }; + const context = (outerContext ?? { + value: null, + key: null, + parent: null, + parents: [], + path: [], + skipped: new Set(), + skip(obj) { + context.skipped.add(obj ?? context.value) + }, + }) as TraverseContext & { + value: unknown + key: keyof any | null + parent: any + parents: object[] + path: (keyof any)[] + skipped: Set + } - const { rootNeedsVisit } = (options ??= {}); - const ownKeys = options.ownKeys ?? Object.keys; - const nestedOptions = { - ...options, - rootNeedsVisit: null, - }; + const { rootNeedsVisit } = (options ??= {}) + const ownKeys = options.ownKeys ?? Object.keys + const nestedOptions = { + ...options, + rootNeedsVisit: null, + } - let ok = true; + let ok = true - // This is called for each value in an object or iterable. - const visit = (value: unknown, key: keyof any): boolean => { - // Map entries are destructured into value and key. - if (context.parent.constructor === Map) { - [key, value] = value as [keyof any, unknown]; - } + // This is called for each value in an object or iterable. + const visit = (value: unknown, key: keyof any): boolean => { + // Map entries are destructured into value and key. + if (context.parent.constructor === Map) { + ;[key, value] = value as [keyof any, unknown] + } - context.path.push(key); - const result = visitor( - (context.value = value), - (context.key = key), - context.parent, - context, - nestedOptions, - ); + context.path.push(key) + const result = visitor( + (context.value = value), + (context.key = key), + context.parent, + context, + nestedOptions, + ) - if (result === false) { - return (ok = false); - } + if (result === false) { + return (ok = false) + } - // Traverse nested plain objects and arrays that haven't been - // skipped and aren't a circular reference. - if ( - value !== null && - typeof value === "object" && - (isArray(value) || isPlainObject(value)) && - !context.skipped.has(value) && - !context.parents.includes(value) - ) { - traverse(value, result); - } + // Traverse nested plain objects and arrays that haven't been + // skipped and aren't a circular reference. + if ( + value !== null && + typeof value === 'object' && + (isArray(value) || isPlainObject(value)) && + !context.skipped.has(value) && + !context.parents.includes(value) + ) { + traverse(value, result) + } - context.path.pop(); - return ok; - }; + context.path.pop() + return ok + } - const traverse = ( - parent: object, - parentResult?: ReturnType, - ): boolean => { - context.parents.push(parent); - context.parent = parent; + const traverse = ( + parent: object, + parentResult?: ReturnType, + ): boolean => { + context.parents.push(parent) + context.parent = parent - if (rootNeedsVisit && parent === root) { - parentResult = visitor( - (context.value = parent), - (context.key = null), - context.parent, - context, - nestedOptions, - ); - if (parentResult === false) { - return ok; - } - } + if (rootNeedsVisit && parent === root) { + parentResult = visitor( + (context.value = parent), + (context.key = null), + context.parent, + context, + nestedOptions, + ) + if (parentResult === false) { + return ok + } + } - if (isArray(parent)) { - // Use Array.prototype.forEach for arrays so that sparse arrays - // are efficiently traversed. The array must be cloned so it can - // be cleared if the visitor returns false. - parent.slice().forEach((value, index, values) => { - if (visit(value, index) === false) { - values.length = 0; // Stop further traversal. - } - }); - } - // Allow an iterable (e.g. a Map or a Set) to be passed in as the - // root object. - else if (parent === root && isIterable(parent)) { - let index = 0; - for (const value of parent) { - if (visit(value, index) === false) { - return ok; - } - index++; - } - } - // Traverse the object's properties. - else { - for (const key of ownKeys(parent)) { - if (visit(parent[key as keyof object], key) === false) { - return ok; - } - } - } + if (isArray(parent)) { + // Use Array.prototype.forEach for arrays so that sparse arrays + // are efficiently traversed. The array must be cloned so it can + // be cleared if the visitor returns false. + parent.slice().forEach((value, index, values) => { + if (visit(value, index) === false) { + values.length = 0 // Stop further traversal. + } + }) + } + // Allow an iterable (e.g. a Map or a Set) to be passed in as the + // root object. + else if (parent === root && isIterable(parent)) { + let index = 0 + for (const value of parent) { + if (visit(value, index) === false) { + return ok + } + index++ + } + } + // Traverse the object's properties. + else { + for (const key of ownKeys(parent)) { + if (visit(parent[key as keyof object], key) === false) { + return ok + } + } + } - context.parents.pop(); - context.parent = last(context.parents); + context.parents.pop() + context.parent = last(context.parents) - // Invoke the leave callback for the completed parent. - if (ok && isFunction(parentResult)) { - ok = parentResult() !== false; - } + // Invoke the leave callback for the completed parent. + if (ok && isFunction(parentResult)) { + ok = parentResult() !== false + } - return ok; - }; + return ok + } - if (outerContext) { - // If this is a recursive call, it's possible that the root object - // was skipped earlier. Check for that here so the caller doesn't - // have to check for it. - if (outerContext.skipped.has(root)) { - return true; - } + if (outerContext) { + // If this is a recursive call, it's possible that the root object + // was skipped earlier. Check for that here so the caller doesn't + // have to check for it. + if (outerContext.skipped.has(root)) { + return true + } - // We'll have to restore the context after the traversal because - // it might be used by the caller. - const { value, key } = context; + // We'll have to restore the context after the traversal because + // it might be used by the caller. + const { value, key } = context - traverse(root); + traverse(root) - context.value = value; - context.key = key; - return ok; - } + context.value = value + context.key = key + return ok + } - return traverse(root); + return traverse(root) } /** * The visitor callback for the `traverse` function. */ export type TraverseVisitor = ( - value: unknown, - key: Key, - parent: object, - context: TraverseContext, - options: TraverseOptions & { rootNeedsVisit?: null }, -) => (() => boolean | void) | boolean | void; + value: unknown, + key: Key, + parent: object, + context: TraverseContext, + options: TraverseOptions & { rootNeedsVisit?: null }, +) => (() => boolean | void) | boolean | void /** * The context object for the `traverse` function. */ export interface TraverseContext { - /** - * The current value being traversed. - */ - readonly value: unknown; - /** - * The property key or index with which the current value was found. - */ - readonly key: Key; - /** - * The parent object of the current value. - */ - readonly parent: object; - /** - * The stack of parent objects. The last object is the current - * parent. - * - * ⚠️ This array must not be mutated directly or referenced outside - * the `visitor` callback. If that's necessary, you'll want to clone - * it first. - */ - readonly parents: readonly object[]; - /** - * The path to the `parent` object. The last key is the current key. - * - * ⚠️ This array must not be mutated directly or referenced outside - * the `visitor` callback. If that's necessary, you'll want to clone - * it first. - */ - readonly path: readonly (keyof any)[]; - /** - * When the current value is a traversable object/iterable, this - * function can be used to skip traversing it altogether. - * - * If the `obj` argument is provided, it marks the given object as - * skipped (instead of the current value), preventing it from being - * traversed. - */ - readonly skip: (obj?: object) => void; - readonly skipped: ReadonlySet; + /** + * The current value being traversed. + */ + readonly value: unknown + /** + * The property key or index with which the current value was found. + */ + readonly key: Key + /** + * The parent object of the current value. + */ + readonly parent: object + /** + * The stack of parent objects. The last object is the current + * parent. + * + * ⚠️ This array must not be mutated directly or referenced outside + * the `visitor` callback. If that's necessary, you'll want to clone + * it first. + */ + readonly parents: readonly object[] + /** + * The path to the `parent` object. The last key is the current key. + * + * ⚠️ This array must not be mutated directly or referenced outside + * the `visitor` callback. If that's necessary, you'll want to clone + * it first. + */ + readonly path: readonly (keyof any)[] + /** + * When the current value is a traversable object/iterable, this + * function can be used to skip traversing it altogether. + * + * If the `obj` argument is provided, it marks the given object as + * skipped (instead of the current value), preventing it from being + * traversed. + */ + readonly skip: (obj?: object) => void + readonly skipped: ReadonlySet } diff --git a/src/object/upperize.ts b/src/object/upperize.ts index dbca37fa3..6398e125c 100644 --- a/src/object/upperize.ts +++ b/src/object/upperize.ts @@ -1,8 +1,8 @@ -import { mapKeys } from "radashi"; +import { mapKeys } from 'radashi' export type UppercaseKeys> = { - [P in keyof T & string as Uppercase

]: T[P]; -}; + [P in keyof T & string as Uppercase

]: T[P] +} /** * Convert all keys in an object to upper case. @@ -16,7 +16,7 @@ export type UppercaseKeys> = { * ``` */ export function upperize>( - obj: T, + obj: T, ): UppercaseKeys { - return mapKeys(obj, (k) => k.toUpperCase()) as UppercaseKeys; + return mapKeys(obj, k => k.toUpperCase()) as UppercaseKeys } diff --git a/src/random/draw.ts b/src/random/draw.ts index 5f646fdb5..b68dda2cf 100644 --- a/src/random/draw.ts +++ b/src/random/draw.ts @@ -1,4 +1,4 @@ -import { random } from "radashi"; +import { random } from 'radashi' /** * “Draw” a random item from an array. The item is not removed from @@ -16,10 +16,10 @@ import { random } from "radashi"; * ``` */ export function draw(array: readonly T[]): T | null { - const max = array.length; - if (max === 0) { - return null; - } - const index = random(0, max - 1); - return array[index]; + const max = array.length + if (max === 0) { + return null + } + const index = random(0, max - 1) + return array[index] } diff --git a/src/random/random.ts b/src/random/random.ts index a749ad322..27930cdb1 100644 --- a/src/random/random.ts +++ b/src/random/random.ts @@ -10,5 +10,5 @@ * ``` */ export function random(min: number, max: number): number { - return Math.floor(Math.random() * (max - min + 1) + min); + return Math.floor(Math.random() * (max - min + 1) + min) } diff --git a/src/random/shuffle.ts b/src/random/shuffle.ts index c1e3cfbb8..7dce58e83 100644 --- a/src/random/shuffle.ts +++ b/src/random/shuffle.ts @@ -1,4 +1,4 @@ -import * as _ from "radashi"; +import * as _ from 'radashi' /** * Clone an array and shuffle its items randomly. @@ -14,15 +14,15 @@ import * as _ from "radashi"; * ``` */ export function shuffle( - array: readonly T[], - random: (min: number, max: number) => number = _.random, + array: readonly T[], + random: (min: number, max: number) => number = _.random, ): T[] { - const newArray = array.slice(); - for (let idx = 0, randomIdx: number, item: T; idx < array.length; idx++) { - randomIdx = random(0, array.length - 1); - item = newArray[randomIdx]; - newArray[randomIdx] = newArray[idx]; - newArray[idx] = item; - } - return newArray; + const newArray = array.slice() + for (let idx = 0, randomIdx: number, item: T; idx < array.length; idx++) { + randomIdx = random(0, array.length - 1) + item = newArray[randomIdx] + newArray[randomIdx] = newArray[idx] + newArray[idx] = item + } + return newArray } diff --git a/src/random/uid.ts b/src/random/uid.ts index cb8a1c7a7..01890eadb 100644 --- a/src/random/uid.ts +++ b/src/random/uid.ts @@ -1,4 +1,4 @@ -import { iterate, random } from "radashi"; +import { iterate, random } from 'radashi' /** * Generate a random string of a given length. @@ -10,14 +10,14 @@ import { iterate, random } from "radashi"; * // => "a3fSDf32" * ``` */ -export function uid(length: number, specials = ""): string { - const characters = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + specials; - return iterate( - length, - (acc) => { - return acc + characters.charAt(random(0, characters.length - 1)); - }, - "", - ); +export function uid(length: number, specials = ''): string { + const characters = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + specials + return iterate( + length, + acc => { + return acc + characters.charAt(random(0, characters.length - 1)) + }, + '', + ) } diff --git a/src/series/series.ts b/src/series/series.ts index 5ebfe47b8..12d79e47a 100644 --- a/src/series/series.ts +++ b/src/series/series.ts @@ -1,13 +1,13 @@ -import { list, range } from "radashi"; +import { list, range } from 'radashi' export interface Series { - min: (a: T, b: T) => T; - max: (a: T, b: T) => T; - first: () => T; - last: () => T; - next: (current: T, defaultValue?: T) => T; - previous: (current: T, defaultValue?: T) => T; - spin: (current: T, num: number) => T; + min: (a: T, b: T) => T + max: (a: T, b: T) => T + first: () => T + last: () => T + next: (current: T, defaultValue?: T) => T + previous: (current: T, defaultValue?: T) => T + spin: (current: T, num: number) => T } /** @@ -28,81 +28,81 @@ export interface Series { * ``` */ export const series = ( - items: readonly T[], - toKey: (item: T) => string | symbol = (item) => `${item}`, + items: readonly T[], + toKey: (item: T) => string | symbol = item => `${item}`, ): Series => { - const indexesByKey: Record = {}; - const itemsByIndex: Record = {}; + const indexesByKey: Record = {} + const itemsByIndex: Record = {} - for (const idx of range(items.length - 1)) { - const item = items[idx]; - indexesByKey[toKey(item)] = idx; - itemsByIndex[idx] = item; - } + for (const idx of range(items.length - 1)) { + const item = items[idx] + indexesByKey[toKey(item)] = idx + itemsByIndex[idx] = item + } - /** - * Returns the first item from the series. - */ - const first = (): T => itemsByIndex[0]; + /** + * Returns the first item from the series. + */ + const first = (): T => itemsByIndex[0] - /** - * Returns the last item in the series. - */ - const last = (): T => itemsByIndex[items.length - 1]; + /** + * Returns the last item in the series. + */ + const last = (): T => itemsByIndex[items.length - 1] - /** - * Given an item in the series, returns the next item in the series - * or `defaultValue` if the given value is the last item in the series. - */ - const next = (current: T, defaultValue?: T): T => - itemsByIndex[indexesByKey[toKey(current)] + 1] ?? defaultValue ?? first(); + /** + * Given an item in the series, returns the next item in the series + * or `defaultValue` if the given value is the last item in the series. + */ + const next = (current: T, defaultValue?: T): T => + itemsByIndex[indexesByKey[toKey(current)] + 1] ?? defaultValue ?? first() - /** - * Given an item in the series, returns the previous item in the - * series or `defaultValue` if the given value is the first item in - * the series. - */ - const previous = (current: T, defaultValue?: T): T => - itemsByIndex[indexesByKey[toKey(current)] - 1] ?? defaultValue ?? last(); + /** + * Given an item in the series, returns the previous item in the + * series or `defaultValue` if the given value is the first item in + * the series. + */ + const previous = (current: T, defaultValue?: T): T => + itemsByIndex[indexesByKey[toKey(current)] - 1] ?? defaultValue ?? last() - return { - /** - * Given two values in the series, returns the value that occurs - * earlier in the series. - */ - min(a, b) { - return indexesByKey[toKey(a)] < indexesByKey[toKey(b)] ? a : b; - }, - /** - * Given two values in the series, returns the value that occurs - * later in the series. - */ - max(a, b) { - return indexesByKey[toKey(a)] > indexesByKey[toKey(b)] ? a : b; - }, - first, - last, - next, - previous, - /** - * A more dynamic method than `next` and `previous` that lets you move - * many times in either direction. - * - * ```ts - * series(weekdays).spin('wednesday', 3) // => 'monday' - * series(weekdays).spin('wednesday', -3) // => 'friday' - * ``` - */ - spin(current, num) { - if (num === 0) { - return current; - } - const abs = Math.abs(num); - const rel = abs > items.length ? abs % items.length : abs; - return list(0, rel - 1).reduce( - (acc) => (num > 0 ? next(acc) : previous(acc)), - current, - ); - }, - }; -}; + return { + /** + * Given two values in the series, returns the value that occurs + * earlier in the series. + */ + min(a, b) { + return indexesByKey[toKey(a)] < indexesByKey[toKey(b)] ? a : b + }, + /** + * Given two values in the series, returns the value that occurs + * later in the series. + */ + max(a, b) { + return indexesByKey[toKey(a)] > indexesByKey[toKey(b)] ? a : b + }, + first, + last, + next, + previous, + /** + * A more dynamic method than `next` and `previous` that lets you move + * many times in either direction. + * + * ```ts + * series(weekdays).spin('wednesday', 3) // => 'monday' + * series(weekdays).spin('wednesday', -3) // => 'friday' + * ``` + */ + spin(current, num) { + if (num === 0) { + return current + } + const abs = Math.abs(num) + const rel = abs > items.length ? abs % items.length : abs + return list(0, rel - 1).reduce( + acc => (num > 0 ? next(acc) : previous(acc)), + current, + ) + }, + } +} diff --git a/src/string/camel.ts b/src/string/camel.ts index 9862d38f2..ea4b6a718 100644 --- a/src/string/camel.ts +++ b/src/string/camel.ts @@ -1,4 +1,4 @@ -import { capitalize } from "radashi"; +import { capitalize } from 'radashi' /** * Formats the given string in camel case fashion. @@ -12,18 +12,18 @@ import { capitalize } from "radashi"; * ``` */ export function camel(str: string): string { - const parts = - str - ?.replace(/([A-Z])+/g, capitalize) - ?.split(/(?=[A-Z])|[\.\-\s_]/) - .map((x) => x.toLowerCase()) ?? []; - if (parts.length === 0) { - return ""; - } - if (parts.length === 1) { - return parts[0]; - } - return parts.reduce((acc, part) => { - return `${acc}${part.charAt(0).toUpperCase()}${part.slice(1)}`; - }); + const parts = + str + ?.replace(/([A-Z])+/g, capitalize) + ?.split(/(?=[A-Z])|[\.\-\s_]/) + .map(x => x.toLowerCase()) ?? [] + if (parts.length === 0) { + return '' + } + if (parts.length === 1) { + return parts[0] + } + return parts.reduce((acc, part) => { + return `${acc}${part.charAt(0).toUpperCase()}${part.slice(1)}` + }) } diff --git a/src/string/capitalize.ts b/src/string/capitalize.ts index 95e1452c2..3c8b353f9 100644 --- a/src/string/capitalize.ts +++ b/src/string/capitalize.ts @@ -9,9 +9,9 @@ * ``` */ export function capitalize(str: string): string { - if (!str || str.length === 0) { - return ""; - } - const lower = str.toLowerCase(); - return lower.substring(0, 1).toUpperCase() + lower.substring(1, lower.length); + if (!str || str.length === 0) { + return '' + } + const lower = str.toLowerCase() + return lower.substring(0, 1).toUpperCase() + lower.substring(1, lower.length) } diff --git a/src/string/dash.ts b/src/string/dash.ts index 24e98eda1..085fa65e1 100644 --- a/src/string/dash.ts +++ b/src/string/dash.ts @@ -1,4 +1,4 @@ -import { capitalize } from "radashi"; +import { capitalize } from 'radashi' /** * Formats the given string in dash case fashion. @@ -12,18 +12,18 @@ import { capitalize } from "radashi"; * ``` */ export function dash(str: string): string { - const parts = - str - ?.replace(/([A-Z])+/g, capitalize) - ?.split(/(?=[A-Z])|[\.\-\s_]/) - .map((x) => x.toLowerCase()) ?? []; - if (parts.length === 0) { - return ""; - } - if (parts.length === 1) { - return parts[0]; - } - return parts.reduce((acc, part) => { - return `${acc}-${part.toLowerCase()}`; - }); + const parts = + str + ?.replace(/([A-Z])+/g, capitalize) + ?.split(/(?=[A-Z])|[\.\-\s_]/) + .map(x => x.toLowerCase()) ?? [] + if (parts.length === 0) { + return '' + } + if (parts.length === 1) { + return parts[0] + } + return parts.reduce((acc, part) => { + return `${acc}-${part.toLowerCase()}` + }) } diff --git a/src/string/pascal.ts b/src/string/pascal.ts index f5bd38b34..b9580701e 100644 --- a/src/string/pascal.ts +++ b/src/string/pascal.ts @@ -10,19 +10,19 @@ * ``` */ export function pascal(str: string): string { - if (!str) { - return ""; - } + if (!str) { + return '' + } - const result = str.replace( - /(?:[^\w\d]|_|\s)+(\w)([A-Z]+)?/g, - (_, firstCharacter, capitalizedLetters) => { - if (capitalizedLetters) { - return firstCharacter.toUpperCase() + capitalizedLetters.toLowerCase(); - } - return firstCharacter.toUpperCase(); - }, - ); + const result = str.replace( + /(?:[^\w\d]|_|\s)+(\w)([A-Z]+)?/g, + (_, firstCharacter, capitalizedLetters) => { + if (capitalizedLetters) { + return firstCharacter.toUpperCase() + capitalizedLetters.toLowerCase() + } + return firstCharacter.toUpperCase() + }, + ) - return result[0].toUpperCase() + result.substring(1); + return result[0].toUpperCase() + result.substring(1) } diff --git a/src/string/similarity.ts b/src/string/similarity.ts index da6fffedf..72f1fb08b 100644 --- a/src/string/similarity.ts +++ b/src/string/similarity.ts @@ -24,64 +24,64 @@ * ``` */ export function similarity(str1: string, str2: string): number { - // Early return if strings are identical - if (str1 === str2) { - return 0; - } + // Early return if strings are identical + if (str1 === str2) { + return 0 + } - // Find common prefix and suffix - let start = 0; - let end1 = str1.length - 1; - let end2 = str2.length - 1; + // Find common prefix and suffix + let start = 0 + let end1 = str1.length - 1 + let end2 = str2.length - 1 - while (start <= end1 && start <= end2 && str1[start] === str2[start]) { - start++; - } + while (start <= end1 && start <= end2 && str1[start] === str2[start]) { + start++ + } - while (end1 >= start && end2 >= start && str1[end1] === str2[end2]) { - end1--; - end2--; - } + while (end1 >= start && end2 >= start && str1[end1] === str2[end2]) { + end1-- + end2-- + } - // Calculate lengths of trimmed strings - const length1 = end1 - start + 1; - const length2 = end2 - start + 1; + // Calculate lengths of trimmed strings + const length1 = end1 - start + 1 + const length2 = end2 - start + 1 - // Handle cases where one string is a substring of the other - if (length1 === 0) { - return length2; - } - if (length2 === 0) { - return length1; - } + // Handle cases where one string is a substring of the other + if (length1 === 0) { + return length2 + } + if (length2 === 0) { + return length1 + } - const numRows = length1 + 1; - const numColumns = length2 + 1; + const numRows = length1 + 1 + const numColumns = length2 + 1 - const distances = new Array(numRows * numColumns).fill(0); + const distances = new Array(numRows * numColumns).fill(0) - for (let x = 1; x < numColumns; x++) { - distances[x] = x; - } - for (let y = 1; y < numRows; y++) { - distances[y * numColumns] = y; - } + for (let x = 1; x < numColumns; x++) { + distances[x] = x + } + for (let y = 1; y < numRows; y++) { + distances[y * numColumns] = y + } - for (let x = 1; x < numColumns; x++) { - for (let y = 1; y < numRows; y++) { - const i = y * numColumns + x; - distances[i] = Math.min( - // Cost of a deletion. - distances[i - numColumns] + 1, - // Cost of an insertion. - distances[i - 1] + 1, - // Cost of a substitution. - distances[i - numColumns - 1] + - (str1[start + y - 1] === str2[start + x - 1] ? 0 : 1), - ); - } - } + for (let x = 1; x < numColumns; x++) { + for (let y = 1; y < numRows; y++) { + const i = y * numColumns + x + distances[i] = Math.min( + // Cost of a deletion. + distances[i - numColumns] + 1, + // Cost of an insertion. + distances[i - 1] + 1, + // Cost of a substitution. + distances[i - numColumns - 1] + + (str1[start + y - 1] === str2[start + x - 1] ? 0 : 1), + ) + } + } - // Return the Levenshtein distance - return distances[length1 * numColumns + length2]; + // Return the Levenshtein distance + return distances[length1 * numColumns + length2] } diff --git a/src/string/snake.ts b/src/string/snake.ts index 73bbb5b7c..424e2c918 100644 --- a/src/string/snake.ts +++ b/src/string/snake.ts @@ -1,4 +1,4 @@ -import { capitalize } from "radashi"; +import { capitalize } from 'radashi' /** * Formats the given string in snake case fashion. @@ -12,26 +12,26 @@ import { capitalize } from "radashi"; * ``` */ export function snake( - str: string, - options?: { - splitOnNumber?: boolean; - }, + str: string, + options?: { + splitOnNumber?: boolean + }, ): string { - const parts = - str - ?.replace(/([A-Z])+/g, capitalize) - .split(/(?=[A-Z])|[\.\-\s_]/) - .map((x) => x.toLowerCase()) ?? []; - if (parts.length === 0) { - return ""; - } - if (parts.length === 1) { - return parts[0]; - } - const result = parts.reduce((acc, part) => { - return `${acc}_${part.toLowerCase()}`; - }); - return options?.splitOnNumber === false - ? result - : result.replace(/([A-Za-z]{1}[0-9]{1})/, (val) => `${val[0]!}_${val[1]!}`); + const parts = + str + ?.replace(/([A-Z])+/g, capitalize) + .split(/(?=[A-Z])|[\.\-\s_]/) + .map(x => x.toLowerCase()) ?? [] + if (parts.length === 0) { + return '' + } + if (parts.length === 1) { + return parts[0] + } + const result = parts.reduce((acc, part) => { + return `${acc}_${part.toLowerCase()}` + }) + return options?.splitOnNumber === false + ? result + : result.replace(/([A-Za-z]{1}[0-9]{1})/, val => `${val[0]!}_${val[1]!}`) } diff --git a/src/string/template.ts b/src/string/template.ts index 79d2b0f94..7f9227c28 100644 --- a/src/string/template.ts +++ b/src/string/template.ts @@ -13,16 +13,16 @@ * ``` */ export function template( - str: string, - data: Record, - regex: RegExp = /\{\{(.+?)\}\}/g, + str: string, + data: Record, + regex: RegExp = /\{\{(.+?)\}\}/g, ): string { - let result = ""; - let from = 0; - let match: RegExpExecArray | null; - while ((match = regex.exec(str))) { - result += str.slice(from, match.index) + data[match[1]]; - from = regex.lastIndex; - } - return result + str.slice(from); + let result = '' + let from = 0 + let match: RegExpExecArray | null + while ((match = regex.exec(str))) { + result += str.slice(from, match.index) + data[match[1]] + from = regex.lastIndex + } + return result + str.slice(from) } diff --git a/src/string/title.ts b/src/string/title.ts index fa471e9ca..f18648a98 100644 --- a/src/string/title.ts +++ b/src/string/title.ts @@ -1,4 +1,4 @@ -import { capitalize } from "radashi"; +import { capitalize } from 'radashi' /** * Formats the given string in title case fashion. @@ -13,13 +13,13 @@ import { capitalize } from "radashi"; * ``` */ export function title(str: string | null | undefined): string { - if (!str) { - return ""; - } - return str - .split(/(?=[A-Z])|[\.\-\s_]/) - .map((s) => s.trim()) - .filter((s) => !!s) - .map((s) => capitalize(s.toLowerCase())) - .join(" "); + if (!str) { + return '' + } + return str + .split(/(?=[A-Z])|[\.\-\s_]/) + .map(s => s.trim()) + .filter(s => !!s) + .map(s => capitalize(s.toLowerCase())) + .join(' ') } diff --git a/src/string/trim.ts b/src/string/trim.ts index bb1bae2a1..4b4732c66 100644 --- a/src/string/trim.ts +++ b/src/string/trim.ts @@ -13,13 +13,13 @@ * ``` */ export function trim( - str: string | null | undefined, - charsToTrim = " ", + str: string | null | undefined, + charsToTrim = ' ', ): string { - if (!str) { - return ""; - } - const toTrim = charsToTrim.replace(/[\W]{1}/g, "\\$&"); - const regex = new RegExp(`^[${toTrim}]+|[${toTrim}]+$`, "g"); - return str.replace(regex, ""); + if (!str) { + return '' + } + const toTrim = charsToTrim.replace(/[\W]{1}/g, '\\$&') + const regex = new RegExp(`^[${toTrim}]+|[${toTrim}]+$`, 'g') + return str.replace(regex, '') } diff --git a/src/typed/isArray.ts b/src/typed/isArray.ts index c075972ce..8d124cb7d 100644 --- a/src/typed/isArray.ts +++ b/src/typed/isArray.ts @@ -1,4 +1,4 @@ -import type { StrictExtract } from "radashi"; +import type { StrictExtract } from 'radashi' /** * Literally just `Array.isArray` but with better type inference. @@ -11,8 +11,8 @@ import type { StrictExtract } from "radashi"; * ``` */ export const isArray = /* @__PURE__ */ (() => Array.isArray)() as ( - value: Input, -) => value is ExtractArray; + value: Input, +) => value is ExtractArray /** * An absurdly complicated but accurate type for extracting Array types. @@ -20,11 +20,11 @@ export const isArray = /* @__PURE__ */ (() => Array.isArray)() as ( * It's like `Extract` but better with edge cases. */ export type ExtractArray = T extends any - ? [StrictExtract] extends [readonly any[]] - ? Extract - : [StrictExtract] extends [any[]] - ? Extract - : unknown[] extends T - ? unknown[] - : never - : never; + ? [StrictExtract] extends [readonly any[]] + ? Extract + : [StrictExtract] extends [any[]] + ? Extract + : unknown[] extends T + ? unknown[] + : never + : never diff --git a/src/typed/isDate.ts b/src/typed/isDate.ts index 76191de47..0a1f227ca 100644 --- a/src/typed/isDate.ts +++ b/src/typed/isDate.ts @@ -1,4 +1,4 @@ -import { isTagged } from "radashi"; +import { isTagged } from 'radashi' /** * Return true if the given value is a Date object. @@ -15,5 +15,5 @@ import { isTagged } from "radashi"; * ``` */ export function isDate(value: unknown): value is Date { - return isTagged(value, "[object Date]"); + return isTagged(value, '[object Date]') } diff --git a/src/typed/isEmpty.ts b/src/typed/isEmpty.ts index 33ba0afe3..fb573813e 100644 --- a/src/typed/isEmpty.ts +++ b/src/typed/isEmpty.ts @@ -1,4 +1,4 @@ -import { isDate, isFunction, isNumber, isSymbol } from "radashi"; +import { isDate, isFunction, isNumber, isSymbol } from 'radashi' /** * Return true if the given value is empty. @@ -27,32 +27,32 @@ import { isDate, isFunction, isNumber, isSymbol } from "radashi"; * ``` */ export function isEmpty(value: any): boolean { - if (value === true || value === false) { - return true; - } - if (value === null || value === undefined) { - return true; - } - if (isNumber(value)) { - return value === 0; - } - if (isDate(value)) { - return Number.isNaN(value.getTime()); - } - if (isFunction(value)) { - return false; - } - if (isSymbol(value)) { - return false; - } - const length = (value as any).length; - if (isNumber(length)) { - return length === 0; - } - const size = (value as any).size; - if (isNumber(size)) { - return size === 0; - } - const keys = Object.keys(value).length; - return keys === 0; + if (value === true || value === false) { + return true + } + if (value === null || value === undefined) { + return true + } + if (isNumber(value)) { + return value === 0 + } + if (isDate(value)) { + return Number.isNaN(value.getTime()) + } + if (isFunction(value)) { + return false + } + if (isSymbol(value)) { + return false + } + const length = (value as any).length + if (isNumber(length)) { + return length === 0 + } + const size = (value as any).size + if (isNumber(size)) { + return size === 0 + } + const keys = Object.keys(value).length + return keys === 0 } diff --git a/src/typed/isEqual.ts b/src/typed/isEqual.ts index edbd184db..f029162d6 100644 --- a/src/typed/isEqual.ts +++ b/src/typed/isEqual.ts @@ -15,35 +15,35 @@ * ``` */ export function isEqual(x: TType, y: TType): boolean { - if (Object.is(x, y)) { - return true; - } - if (x instanceof Date && y instanceof Date) { - return x.getTime() === y.getTime(); - } - if (x instanceof RegExp && y instanceof RegExp) { - return x.toString() === y.toString(); - } - if ( - typeof x !== "object" || - x === null || - typeof y !== "object" || - y === null - ) { - return false; - } - const keysX = Reflect.ownKeys(x as unknown as object) as (keyof typeof x)[]; - const keysY = Reflect.ownKeys(y as unknown as object); - if (keysX.length !== keysY.length) { - return false; - } - for (let i = 0; i < keysX.length; i++) { - if (!Reflect.has(y as unknown as object, keysX[i])) { - return false; - } - if (!isEqual(x[keysX[i]], y[keysX[i]])) { - return false; - } - } - return true; + if (Object.is(x, y)) { + return true + } + if (x instanceof Date && y instanceof Date) { + return x.getTime() === y.getTime() + } + if (x instanceof RegExp && y instanceof RegExp) { + return x.toString() === y.toString() + } + if ( + typeof x !== 'object' || + x === null || + typeof y !== 'object' || + y === null + ) { + return false + } + const keysX = Reflect.ownKeys(x as unknown as object) as (keyof typeof x)[] + const keysY = Reflect.ownKeys(y as unknown as object) + if (keysX.length !== keysY.length) { + return false + } + for (let i = 0; i < keysX.length; i++) { + if (!Reflect.has(y as unknown as object, keysX[i])) { + return false + } + if (!isEqual(x[keysX[i]], y[keysX[i]])) { + return false + } + } + return true } diff --git a/src/typed/isError.ts b/src/typed/isError.ts index 8197c2959..d79f5ec9b 100644 --- a/src/typed/isError.ts +++ b/src/typed/isError.ts @@ -1,4 +1,4 @@ -import { isTagged } from "radashi"; +import { isTagged } from 'radashi' /** * Return true if the given value is an Error object. @@ -15,5 +15,5 @@ import { isTagged } from "radashi"; * ``` */ export function isError(value: unknown): value is Error { - return isTagged(value, "[object Error]"); + return isTagged(value, '[object Error]') } diff --git a/src/typed/isFloat.ts b/src/typed/isFloat.ts index 600bf8ad5..fa44892f4 100644 --- a/src/typed/isFloat.ts +++ b/src/typed/isFloat.ts @@ -1,4 +1,4 @@ -import { isNumber } from "radashi"; +import { isNumber } from 'radashi' /** * Return true if the given value is a number that is not an integer. @@ -11,5 +11,5 @@ import { isNumber } from "radashi"; * ``` */ export function isFloat(value: any): value is number { - return isNumber(value) && value % 1 !== 0; + return isNumber(value) && value % 1 !== 0 } diff --git a/src/typed/isFunction.ts b/src/typed/isFunction.ts index 53ebdd6d6..781e157c0 100644 --- a/src/typed/isFunction.ts +++ b/src/typed/isFunction.ts @@ -13,5 +13,5 @@ */ // biome-ignore lint/complexity/noBannedTypes: export function isFunction(value: any): value is Function { - return typeof value === "function"; + return typeof value === 'function' } diff --git a/src/typed/isInt.ts b/src/typed/isInt.ts index 089c43465..883da6b87 100644 --- a/src/typed/isInt.ts +++ b/src/typed/isInt.ts @@ -9,5 +9,5 @@ * ``` */ export const isInt = /* @__PURE__ */ (() => Number.isInteger)() as ( - value: unknown, -) => value is number; + value: unknown, +) => value is number diff --git a/src/typed/isIntString.ts b/src/typed/isIntString.ts index 94a349ec6..3a2af517e 100644 --- a/src/typed/isIntString.ts +++ b/src/typed/isIntString.ts @@ -1,4 +1,4 @@ -import { isString } from "radashi"; +import { isString } from 'radashi' /** * Return true if the given value is a string that can be parsed as an @@ -13,9 +13,9 @@ import { isString } from "radashi"; * ``` */ export function isIntString(value: any): value is string { - if (!isString(value)) { - return false; - } - const num = +value; - return Number.isInteger(num) && `${num}` === value; + if (!isString(value)) { + return false + } + const num = +value + return Number.isInteger(num) && `${num}` === value } diff --git a/src/typed/isMap.ts b/src/typed/isMap.ts index f55ab6511..3eebcafc8 100644 --- a/src/typed/isMap.ts +++ b/src/typed/isMap.ts @@ -1,4 +1,4 @@ -import { isTagged, type StrictExtract } from "radashi"; +import { isTagged, type StrictExtract } from 'radashi' /** * Return true if the given value is a Map. @@ -15,7 +15,7 @@ import { isTagged, type StrictExtract } from "radashi"; * ``` */ export function isMap(value: Input): value is ExtractMap { - return isTagged(value, "[object Map]"); + return isTagged(value, '[object Map]') } /** @@ -24,13 +24,13 @@ export function isMap(value: Input): value is ExtractMap { * It's like `Extract>` but better with edge cases. */ export type ExtractMap = T extends any - ? [StrictExtract>] extends [ - ReadonlyMap, - ] - ? Extract> - : [StrictExtract>] extends [Map] - ? Extract> - : Map extends T - ? Map - : never - : never; + ? [StrictExtract>] extends [ + ReadonlyMap, + ] + ? Extract> + : [StrictExtract>] extends [Map] + ? Extract> + : Map extends T + ? Map + : never + : never diff --git a/src/typed/isNumber.ts b/src/typed/isNumber.ts index ebba21157..2bc475a1f 100644 --- a/src/typed/isNumber.ts +++ b/src/typed/isNumber.ts @@ -10,5 +10,5 @@ * ``` */ export function isNumber(value: unknown): value is number { - return typeof value === "number" && !Number.isNaN(value); + return typeof value === 'number' && !Number.isNaN(value) } diff --git a/src/typed/isObject.ts b/src/typed/isObject.ts index 6b3130734..d5b87ec7d 100644 --- a/src/typed/isObject.ts +++ b/src/typed/isObject.ts @@ -1,4 +1,4 @@ -import { isTagged } from "radashi"; +import { isTagged } from 'radashi' /** * Returns true if `value` is a plain object, a class instance @@ -24,5 +24,5 @@ import { isTagged } from "radashi"; * ``` */ export function isObject(value: unknown): value is object { - return isTagged(value, "[object Object]"); + return isTagged(value, '[object Object]') } diff --git a/src/typed/isPlainObject.ts b/src/typed/isPlainObject.ts index 2a199360a..563db7c08 100644 --- a/src/typed/isPlainObject.ts +++ b/src/typed/isPlainObject.ts @@ -12,17 +12,17 @@ * ``` */ export function isPlainObject(value: any): value is object { - if (typeof value !== "object" || value === null) { - return false; - } + if (typeof value !== 'object' || value === null) { + return false + } - const prototype = Object.getPrototypeOf(value); - return ( - // Fast path for most common objects. - prototype === Object.prototype || - // Support objects created without a prototype. - prototype === null || - // Support plain objects from other realms. - Object.getPrototypeOf(prototype) === null - ); + const prototype = Object.getPrototypeOf(value) + return ( + // Fast path for most common objects. + prototype === Object.prototype || + // Support objects created without a prototype. + prototype === null || + // Support plain objects from other realms. + Object.getPrototypeOf(prototype) === null + ) } diff --git a/src/typed/isPrimitive.ts b/src/typed/isPrimitive.ts index 87c5da453..28f50a43c 100644 --- a/src/typed/isPrimitive.ts +++ b/src/typed/isPrimitive.ts @@ -20,9 +20,9 @@ * ``` */ export function isPrimitive(value: any): boolean { - return ( - value === undefined || - value === null || - (typeof value !== "object" && typeof value !== "function") - ); + return ( + value === undefined || + value === null || + (typeof value !== 'object' && typeof value !== 'function') + ) } diff --git a/src/typed/isPromise.ts b/src/typed/isPromise.ts index b0fda0c0c..b15e8b921 100644 --- a/src/typed/isPromise.ts +++ b/src/typed/isPromise.ts @@ -1,4 +1,4 @@ -import { isFunction } from "radashi"; +import { isFunction } from 'radashi' /** * Returns true if the value is a Promise or has a `then` method. @@ -12,5 +12,5 @@ import { isFunction } from "radashi"; * ``` */ export function isPromise(value: any): value is PromiseLike { - return !!value && isFunction(value.then); + return !!value && isFunction(value.then) } diff --git a/src/typed/isRegExp.ts b/src/typed/isRegExp.ts index e57bed890..b8640583a 100644 --- a/src/typed/isRegExp.ts +++ b/src/typed/isRegExp.ts @@ -1,4 +1,4 @@ -import { isTagged } from "radashi"; +import { isTagged } from 'radashi' /** * Checks if the given value is a RegExp. @@ -15,5 +15,5 @@ import { isTagged } from "radashi"; * ``` */ export function isRegExp(value: unknown): value is RegExp { - return isTagged(value, "[object RegExp]"); + return isTagged(value, '[object RegExp]') } diff --git a/src/typed/isResult.ts b/src/typed/isResult.ts index e92c5ae1f..afb0ccb83 100644 --- a/src/typed/isResult.ts +++ b/src/typed/isResult.ts @@ -1,4 +1,4 @@ -import { isArray, isError, type Result } from "radashi"; +import { isArray, isError, type Result } from 'radashi' /** * Returns true if the value is a `Result` tuple. @@ -23,9 +23,9 @@ import { isArray, isError, type Result } from "radashi"; * ``` */ export function isResult(value: unknown): value is Result { - return ( - isArray(value) && - value.length === 2 && - (isError(value[0]) ? value[1] : value[0]) === undefined - ); + return ( + isArray(value) && + value.length === 2 && + (isError(value[0]) ? value[1] : value[0]) === undefined + ) } diff --git a/src/typed/isResultErr.ts b/src/typed/isResultErr.ts index c5fdefe4c..7f2eee66e 100644 --- a/src/typed/isResultErr.ts +++ b/src/typed/isResultErr.ts @@ -1,4 +1,4 @@ -import { type Err, isResult } from "radashi"; +import { type Err, isResult } from 'radashi' /** * Returns true if the value is an `Err` result. @@ -11,7 +11,7 @@ import { type Err, isResult } from "radashi"; * ``` */ export function isResultErr( - value: unknown, + value: unknown, ): value is Err { - return isResult(value) && value[0] !== undefined; + return isResult(value) && value[0] !== undefined } diff --git a/src/typed/isResultOk.ts b/src/typed/isResultOk.ts index 059aa2d52..cc192bdae 100644 --- a/src/typed/isResultOk.ts +++ b/src/typed/isResultOk.ts @@ -1,4 +1,4 @@ -import { isResult, type Ok } from "radashi"; +import { isResult, type Ok } from 'radashi' /** * Returns true if the value is an `Ok` result. @@ -11,7 +11,7 @@ import { isResult, type Ok } from "radashi"; * ``` */ export function isResultOk( - value: unknown, + value: unknown, ): value is Ok { - return isResult(value) && value[0] === undefined; + return isResult(value) && value[0] === undefined } diff --git a/src/typed/isSet.ts b/src/typed/isSet.ts index 63612f07a..c2c0572ee 100644 --- a/src/typed/isSet.ts +++ b/src/typed/isSet.ts @@ -1,4 +1,4 @@ -import { isTagged, type StrictExtract } from "radashi"; +import { isTagged, type StrictExtract } from 'radashi' /** * Checks if the given value is a Set. @@ -15,7 +15,7 @@ import { isTagged, type StrictExtract } from "radashi"; * ``` */ export function isSet(value: Input): value is ExtractSet { - return isTagged(value, "[object Set]"); + return isTagged(value, '[object Set]') } /** @@ -24,11 +24,11 @@ export function isSet(value: Input): value is ExtractSet { * It's like `Extract>` but better with edge cases. */ export type ExtractSet = T extends any - ? [StrictExtract>] extends [ReadonlySet] - ? Extract> - : [StrictExtract>] extends [Set] - ? Extract> - : Set extends T - ? Set - : never - : never; + ? [StrictExtract>] extends [ReadonlySet] + ? Extract> + : [StrictExtract>] extends [Set] + ? Extract> + : Set extends T + ? Set + : never + : never diff --git a/src/typed/isString.ts b/src/typed/isString.ts index 41d16df10..67e5ec977 100644 --- a/src/typed/isString.ts +++ b/src/typed/isString.ts @@ -9,5 +9,5 @@ * ``` */ export function isString(value: unknown): value is string { - return typeof value === "string"; + return typeof value === 'string' } diff --git a/src/typed/isSymbol.ts b/src/typed/isSymbol.ts index 4423213cb..5bc360c9f 100644 --- a/src/typed/isSymbol.ts +++ b/src/typed/isSymbol.ts @@ -9,5 +9,5 @@ * ``` */ export function isSymbol(value: unknown): value is symbol { - return typeof value === "symbol"; + return typeof value === 'symbol' } diff --git a/src/typed/isWeakMap.ts b/src/typed/isWeakMap.ts index 0cd67af0e..b2c2b82af 100644 --- a/src/typed/isWeakMap.ts +++ b/src/typed/isWeakMap.ts @@ -1,4 +1,4 @@ -import { isTagged } from "radashi"; +import { isTagged } from 'radashi' /** * Checks if the given value is a WeakMap. @@ -15,7 +15,7 @@ import { isTagged } from "radashi"; * ``` */ export function isWeakMap( - value: unknown, + value: unknown, ): value is WeakMap { - return isTagged(value, "[object WeakMap]"); + return isTagged(value, '[object WeakMap]') } diff --git a/src/typed/isWeakSet.ts b/src/typed/isWeakSet.ts index c22addfd4..efe241a8c 100644 --- a/src/typed/isWeakSet.ts +++ b/src/typed/isWeakSet.ts @@ -1,4 +1,4 @@ -import { isTagged } from "radashi"; +import { isTagged } from 'radashi' /** * Checks if the given value is a WeakSet. @@ -16,7 +16,7 @@ import { isTagged } from "radashi"; * ``` */ export function isWeakSet( - value: unknown, + value: unknown, ): value is WeakSet { - return isTagged(value, "[object WeakSet]"); + return isTagged(value, '[object WeakSet]') }