{"id":16974627,"url":"https://github.com/alttiri/util-js","last_synced_at":"2026-04-13T16:35:18.906Z","repository":{"id":37498237,"uuid":"487366138","full_name":"AlttiRi/util-js","owner":"AlttiRi","description":"Some JavaScript util functions. Mostly it's a draft version for personal use.","archived":false,"fork":false,"pushed_at":"2023-07-02T11:14:10.000Z","size":41,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-05-09T18:29:58.122Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AlttiRi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-30T19:39:59.000Z","updated_at":"2024-05-31T01:16:56.708Z","dependencies_parsed_at":"2024-05-31T01:16:54.937Z","dependency_job_id":"6651b7c5-a88d-4f02-ae26-c244cfbdd6a3","html_url":"https://github.com/AlttiRi/util-js","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlttiRi%2Futil-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlttiRi%2Futil-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlttiRi%2Futil-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlttiRi%2Futil-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AlttiRi","download_url":"https://codeload.github.com/AlttiRi/util-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244868032,"owners_count":20523581,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T01:07:20.276Z","updated_at":"2026-04-13T16:35:18.899Z","avatar_url":"https://github.com/AlttiRi.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [util-js](https://github.com/AlttiRi/util-js)\n\nSome JavaScript util functions.\n\nMostly it's a draft version for personal use.\n\n## *.d.ts\n\n```ts\n/**\n * Formats bytes EXACTLY like Windows File Explorer does.\n * Check the file with tests.\n * @see bsc--format-size-win-like.t.ts\n * @alias bytesToSizeWinLike\n * @alias formatSizeWinLike\n * @param {number} bytes\n * @return {string}\n */\nexport declare function formatFileSizeWinLike(bytes: number): string;\n/**\n * Formats bytes mostly like Windows File Explorer does,\n * but in some rare cases the result is different.\n * The old implementation of `formatFileSizeWinLike`.\n * It produces the more accurate result, but not like Windows does.\n * See \"inaccurate\" tests.\n * @see bsc--format-size-win-like.t.ts\n * @param {number} bytes\n * @return {string}\n */\nexport declare function formatFileSize(bytes: number): string;\n/**\n * @example\n * 10.1005859375 -\u003e \"10.1\"\n * 9.99902343750 -\u003e \"9.99\"\n * 836.966796875 -\u003e \"836\"\n * 0.08   -\u003e \"0.08\"\n * 0.099  -\u003e \"0.09\"\n * 0.0099 -\u003e \"0\"\n * @param {number} number\n * @return {string}\n */\nexport declare function toTruncPrecision3(number: number): string;\n/**\n * Useful for file byte size formatting:\n * 34456909 -\u003e 34 456 909\n * @alias tripleSizeGroups\n * @param {number} num\n * @return {string}\n * */\nexport declare function formatNumber(num: number): string;\n/** @deprecated Use `formatFileSizeWinLike` */\nexport declare const bytesToSizeWinLike: typeof formatFileSizeWinLike;\n/** @deprecated Use `formatFileSizeWinLike` */\nexport declare const formatSizeWinLike: typeof formatFileSizeWinLike;\n/** @deprecated Use `formatNumber` */\nexport declare const tripleSizeGroups: typeof formatNumber;\n/**\n * \"Sun, 10 Jan 2021 22:22:22 GMT\" -\u003e \"2021.01.10\"\n * @param {Date | string | number?} [dateValue]\n * @param {boolean} [utc = true]\n * @return {string}\n */\nexport declare function dateToDayDateString(dateValue?: Date | string | number, utc?: boolean): string;\n/**\n * \"Sun, 10 Jan 2021 22:22:22 GMT\" -\u003e \"2021.01.10 22:22:22Z\"\n * @param {Date | string | number} [dateValue]\n * @param {boolean?} [utc = true]\n * @return {string}\n */\nexport declare function dateToDayDateTimeString(dateValue?: Date | string | number, utc?: boolean): string;\n/**\n * \"Sun, 10 Jan 2021 22:22:22 GMT\" -\u003e \"2021.01.10\"\n * @param {Date | string | number} [dateValue]\n * @return {string}\n */\nexport declare function localDate(dateValue?: number | string | Date): string;\n/**\n * \"Sun, 10 Jan 2021 22:22:22 GMT\" -\u003e \"2021.01.10 22:22:22\"\n * @param {Date | string | number} [dateValue]\n * @return {string}\n */\nexport declare function localDateTime(dateValue?: number | string | Date): string;\n/**\n * Formats date. Supports: YY.YYYY.MM.DD HH:mm:SS.\n * Default format: \"YYYY.MM.DD\".\n * formatDate() -\u003e \"2022.01.07\"\n * @param {Date | string | number} [dateValue]\n * @param {string}  [pattern = \"YYYY.MM.DD\"]\n * @param {boolean} [utc = true]\n * @return {string}\n */\nexport declare function formatDate(dateValue?: Date | string | number, pattern?: string, utc?: boolean): string;\n/**\n * A classic `debounce` wrap function.\n *\n * Wraps a function to create a debounced version that delays execution until after a specified time has elapsed since the last call.\n * Only the last call within the specified time window is executed.\n *\n * @param runnable - The function to debounce.\n * @param ms - The debounce delay in milliseconds (default: 250).\n * @param scope - Optional context to bind the function to (defaults to the caller's context).\n * @returns A debounced function that delays execution of the provided function.\n * @example\n * const logAny = (i: any) =\u003e console.log(i);\n * const logAnyDebounced = debounce(logAny, 50);\n *\n * // prints `99` after ~1+ second\n * for (let i = 0; i \u003c 100; i++) {\n *     logAnyDebounced(i);\n *     await sleep(10);\n * }\n */\nexport declare function debounce\u003cA extends any[]\u003e(runnable: (...args: A) =\u003e unknown, ms?: number, scope?: any): (...args: A) =\u003e void;\n/**\n * Creates a debounced function that resolves to `false` after a specified delay,\n * or `true` if called again before the delay expires.\n *\n * The function ensures that only the last call within the specified time window resolves to `false`,\n * while earlier calls resolve to `true`.\n *\n * @param ms - The debounce delay in milliseconds (default: 250).\n * @returns An async function that returns a Promise resolving to a boolean indicating\n * whether the call was debounced (`true`) or not (`false`).\n * @example\n * const selfDebounced = getSelfDebounced(300);\n *\n * // prints \"99\" after ~1300 ms\n * for (let i = 0; i \u003c 100; i++) {\n *     selfDebounced().then((debounced) =\u003e {\n *         if (debounced) {\n *             return;\n *         }\n *         console.log(i);\n *     });\n *     await sleep(10);\n * }\n */\nexport declare function getSelfDebounced(ms?: number): () =\u003e Promise\u003cboolean\u003e;\n/**\n * Creates a debounced function that resolves after a specified delay, or rejects if called again before the delay expires.\n * The function ensures that only the last call within the specified time window resolves, while earlier calls reject.\n *\n * @param ms - The debounce delay in milliseconds (default: 250).\n * @returns An async function that returns a Promise that either resolves (for the last call) or rejects (for earlier calls).\n * @example\n * const selfDebouncedReject = getSelfDebouncedReject(300);\n *\n * // prints \"99\" after ~1300 ms\n * for (let i = 0; i \u003c 100; i++) {\n *     selfDebouncedReject().then(() =\u003e {\n *         console.log(i);\n *     }).catch(() =\u003e {});\n *     await sleep(10);\n * }\n */\nexport declare function getSelfDebouncedReject(ms?: number): () =\u003e Promise\u003cvoid\u003e;\n/**\n * A classic `throttle` wrap function.\n *\n * Wraps a function to create a throttled version that executes no more than once per specified time interval.\n * The first call is executed immediately, and if additional calls occur within the interval,\n * the last one is executed after the interval expires.\n *\n * @param runnable - The function to throttle.\n * @param ms - The throttle interval in milliseconds (default: 250).\n * @param scope - Optional context to bind the function to (defaults to the caller's context).\n * @returns A throttled function that limits execution frequency.\n * @example\n * const logAny = (i: any) =\u003e console.log(i);\n * const logAnyThrottled = throttle(logAny, 500);\n *\n * // prints \"0 31 63 96 99\" (intermediate values like \"31 63 96\" may vary)\n * for (let i = 0; i \u003c 100; i++) {\n *     logAnyThrottled(i);\n *     await sleep(10);\n * }\n */\nexport declare function throttle\u003cA extends any[]\u003e(runnable: (...args: A) =\u003e any, ms?: number, scope?: any): (...args: A) =\u003e void;\n/**\n * Creates a throttled function with control methods to execute immediately (`runNow`) or `clear` pending callbacks.\n * The throttled function limits execution to once per specified time interval, with an option to run the first call immediately.\n *\n * @param ms - The throttle interval in milliseconds (default: 250).\n * @param runFirstImmediately - Whether to execute the first call immediately (default: true).\n * @returns An object containing:\n *   - `throttled`: The throttled function that accepts a callback to execute.\n *   - `runNow`: A method to execute the last queued callback immediately.\n *   - `clear`: A method to cancel any pending callback.\n * @example\n * const {throttled, runNow, clear} = getThrottle(300, true);\n *\n * // prints \"0 20 40 60 80 99\"\n * for (let i = 0; i \u003c 100; i++) {\n *     throttled(() =\u003e {\n *         console.log(i);\n *     });\n *     await sleep(10);\n * }\n * runNow(); // run the last callback without delay\n */\nexport declare function getThrottle(ms?: number, runFirstImmediately?: boolean): {\n  throttled: (callback: Function, runNow?: boolean) =\u003e void;\n  runNow: (clearDelayed?: boolean) =\u003e any;\n  clear: () =\u003e void;\n};\n/**\n * Sleeps `ms` milliseconds.\n * If param is `undefined` it sleeps until the next macro-task.\n * Note: With `0` real ms will be `4`+ ms.\n * @param {number?} ms\n * */\nexport declare function sleep(ms?: number): Promise\u003cvoid\u003e;\n/**\n * Interruptible `sleep`.\n * If was interrupted resolves with the interrupt reason (`signal.reason`).\n * @param {number} ms\n * @param {AbortSignal} signal\n */\nexport declare function sleepEx(ms: number, signal: AbortSignal): Promise\u003cvoid | any\u003e;\nexport declare function isString(value: unknown): value is string;\nexport declare function isAnyString(value: unknown): value is (string | String);\n/**\n * Java's `hashCode` like. 32-bits hash.\n * Note: `Math.imul(..., 1)` does the same as  `| 0`, with the same speed.\n * @example\n * hashString(\"Lorem Ipsum\") === -488052133\n * hashString(\"Qwerty\") === -1862984904\n * hashString(\"A\") === 65\n * hashString(\"👾👽💀\") === -2019372252\n * @param {string} str\n * @return {number}\n */\nexport declare function hashString(str: string): number;\n/**\n * Similar to `hashString`, but it always returns a positive number. 31-bits hash.\n * @param {string} str\n */\nexport declare function hashStringPos(str: string): number;\nexport type DownloadBlobOpt = {\n  /** The URL to be added as a hash in the downloaded blob URL. Useful to keep the original file URL. */\n  url?: string;\n  /** The delay before `revokeObjectURL`. 5000 by default. */\n  timeout?: number;\n};\nexport declare function downloadBlob(blob: Blob, name: string, url?: string): void;\nexport declare function downloadBlob(blob: Blob, name: string, opt: DownloadBlobOpt): void;\n```\n\n## *.d.ts (sync)\n\n```ts\n/**\n * Use it when in one place you need to `enqueue()` some `value`, until `close()`.\n * In other place you can iterate over this queue in for-await loop.\n *\n * `enqueue` does not add a value until there is a free space in the queue, you should `await` it.\n * (`size` parameter of `constructor`).\n *\n * Use `close()` after you finished to `enqueue()` data.\n */\nexport declare class AsyncBufferQueue\u003cT\u003e {\n    private values;\n    private done;\n    private promise;\n    private resolve;\n    private semaphore;\n    constructor(size?: number);\n    close(): void;\n    enqueue(value: T): Promise\u003cvoid\u003e;\n    [Symbol.asyncIterator](): AsyncGenerator\u003cT\u003e;\n}\nexport declare class CountLatch {\n    private count;\n    private promise;\n    private resolve;\n    /** @param {number} count = 0 */\n    constructor(count?: number);\n    countDown(): void;\n    countUp(): void;\n    /** Makes this object \"Thenable\" */\n    then(resolve: VoidFunc, reject: VoidFunc): Promise\u003cvoid\u003e;\n}\nexport type Node\u003cT\u003e = {\n    value: T;\n    next: Node\u003cT\u003e | null;\n};\n/** \"LinkedList\" with `Array` interface */\nexport declare class Queue\u003cT\u003e {\n    length: number;\n    private _last;\n    private _first;\n    constructor();\n    push(value: T): void;\n    shift(): T | undefined;\n}\n/** The most simple semaphore implementation. */\nexport declare class Semaphore {\n    private readonly max;\n    private count;\n    private readonly resolveQueue;\n    /** @param {number} [max = 1] - by default, it works as a mutex. */\n    constructor(max?: number);\n    /** @return {Promise\u003cunknown\u003e} */\n    acquire(): Promise\u003cunknown\u003e;\n    /** @return {void} */\n    release(): void;\n}\n/** `resolve`/`reject` of `Promise` with no result. */\nexport type VoidFunc = (value: void) =\u003e void;\n```\n\n## Installation\n\n### From NPM\n\n```bash\nnpm install @alttiri/util-js\n```\n\n### From GitHub repository\n\n```bash\nnpm install git+https://github.com/alttiri/util-js.git\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eMore ways\u003c/summary\u003e\n\n### From GitHub repository (a specific version):\n\n- **Based on SemVer:**\n    ```bash\n    npm install git+https://github.com/alttiri/util-js.git#semver:1.3.0\n    ```\n  Or add\n    ```\n    \"@alttiri/util-js\": \"github:alttiri/util-js#semver:1.3.0\"\n    ```\n  as `dependencies` in `package.json` file.\n\n  See available [tags](https://github.com/AlttiRi/util-js/tags).\n\n- **Based on a commit hash:**\n    ```bash\n    npm install git+https://github.com/alttiri/util-js.git#eea3068f8c70c6a500a44b69aeb0cb65ac8b80a6\n    ```\n  Or add\n    ```\n    \"@alttiri/util-js\": \"github:alttiri/util-js#eea3068f8c70c6a500a44b69aeb0cb65ac8b80a6\"\n    ```\n  as `dependencies` in `package.json` file.\n\n  See available [commits hashes](https://github.com/AlttiRi/util-js/commits/master).\n\n\n### From GitHub Packages:\nTo install you need first to create `.npmrc` file with `@alttiri:registry=https://npm.pkg.github.com` content:\n```bash\necho @alttiri:registry=https://npm.pkg.github.com \u003e\u003e .npmrc\n```\n\nonly then run\n\n```bash\nnpm install @alttiri/util-node-js\n```\nNote, that GitHub Packages requires to have also `~/.npmrc` file (`.npmrc` in your home dir) with `//npm.pkg.github.com/:_authToken=TOKEN` content, where `TOKEN` is a token with the `read:packages` permission, take it here https://github.com/settings/tokens/new.\n\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falttiri%2Futil-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falttiri%2Futil-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falttiri%2Futil-js/lists"}