{"id":22944444,"url":"https://github.com/hqoss/utils","last_synced_at":"2025-08-12T22:32:00.049Z","repository":{"id":44177646,"uuid":"98724284","full_name":"hqoss/utils","owner":"hqoss","description":"🛠 A collection of light-weight methods and helpers for defensive programming","archived":false,"fork":false,"pushed_at":"2023-01-04T21:37:01.000Z","size":1372,"stargazers_count":15,"open_issues_count":12,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-28T21:18:14.663Z","etag":null,"topics":["async","defensive-programming","helpers","javascript","light-weight","nodejs","typescript","utilities"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hqoss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2017-07-29T10:01:11.000Z","updated_at":"2023-09-06T09:13:37.000Z","dependencies_parsed_at":"2023-02-02T20:46:14.304Z","dependency_job_id":null,"html_url":"https://github.com/hqoss/utils","commit_stats":null,"previous_names":["litchi-io/utils","openmaths/mod-utils"],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hqoss%2Futils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hqoss%2Futils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hqoss%2Futils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hqoss%2Futils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hqoss","download_url":"https://codeload.github.com/hqoss/utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229711362,"owners_count":18112118,"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":["async","defensive-programming","helpers","javascript","light-weight","nodejs","typescript","utilities"],"created_at":"2024-12-14T14:18:39.409Z","updated_at":"2024-12-14T14:18:40.033Z","avatar_url":"https://github.com/hqoss.png","language":"TypeScript","readme":"[![CircleCI](https://circleci.com/gh/litchi-io/utils.svg?style=svg)](https://circleci.com/gh/litchi-io/utils)\n[![codecov](https://codecov.io/gh/litchi-io/utils/branch/master/graph/badge.svg)](https://codecov.io/gh/litchi-io/utils)\n[![npm version](https://img.shields.io/npm/v/@usefultools/utils.svg)](https://www.npmjs.com/package/@usefultools/utils)\n[![GuardRails](https://badges.production.guardrails.io/litchi-io/utils.svg)](https://www.guardrails.io)\n[![Security Responsible Disclosure](https://img.shields.io/badge/Security-Responsible%20Disclosure-yellow.svg)](https://github.com/litchi-io/utils/blob/master/SECURITY.md)\n\n# JavaScript / TypeScript Utilities\n\nA collection of light-weight methods and helpers for defensive programming.\n\n## Prereqs \u0026 Install\n\n* Node \u003e=9.10.0\n* npm \u003e=6.1.0\n\nPlease note that the **TypeScript target is ES6**.\n\n```sh\nnpm install @usefultools/utils\n```\n\n## Usage\n\nThere are 6 main modules available:\n\n* [Async](https://github.com/litchi-io/mod-utils#async)\n* [Conditionals](https://github.com/litchi-io/mod-utils#conditionals)\n* [Env](https://github.com/litchi-io/mod-utils#env)\n* [Helpers](https://github.com/litchi-io/mod-utils#helpers)\n* [Match](https://github.com/litchi-io/mod-utils#match)\n* [ThrowIf](https://github.com/litchi-io/mod-utils#throwif)\n\n## Async\n\nAvailable methods:\n\n* `withTimeout`\n* `timeout`\n* `makeRecoverable`\n\n### Examples\n\n#### `withTimeout`\n\nThe below will resolve source after 750ms.\n\n```typescript\nfunction findUserById(id: number) {\n  const source = () =\u003e http.get(`/api/users/${id}`)\n  return withTimeout(source, 750)\n}\n\n```\n\n#### `timeout`\n\nThe below will reject if asyncOperation takes more than 0.5 seconds.\n\n```typescript\nfunction work() {\n  const source = asyncOperation() // can take 0-2 seconds\n  return timeout(source, 500)\n}\n\n```\n\n#### `makeRecoverable`\n\nThe below will retry 5 times.\n\n```typescript\nfunction getUsers() {\n  const source = () =\u003e http.get(\"/api/users\")\n  return makeRecoverable(source, 5)\n}\n\n```\n\nThe below will retry 3 times, each time with a delay of 250ms.\n\n```typescript\nfunction getUsers() {\n  const source = () =\u003e http.get(\"/api/users\")\n  return makeRecoverable(source, 3, 250)\n}\n\n```\n\nThe below will retry thrice if the error caught is a `SyntaxError`.\n\n```typescript\nfunction initService() {\n  const source = () =\u003e service.init()\n  return makeRecoverable(source, 3, 0, SyntaxError)\n}\n\n```\n\n**Full test Docs [here](https://github.com/litchi-io/mod-utils/blob/master/src/Async/main.spec.ts).**\n\n---\n\n## Conditionals\n\nAvailable methods:\n\n* `isNull`\n* `isUndefined`\n* `isMissing`\n* `isPresent`\n* `isBoolean`\n* `isArray`\n* `isObject`\n* `isString`\n* `isNumber`\n* `isInteger`\n* `isFunction`\n* `isNonEmptyString`\n* `isNonEmptyArray`\n* `isTrue`\n* `isFalse`\n* `isPositiveInteger`\n* `isNonNegativeInteger`\n* `hasOneItem`\n* `hasMultipleItems`\n* `isConstructable`\n* `hasOnlyKeys`\n* `isEqual`\n\n### Examples\n\n#### `isNull`\n\nFind out whether value is null\n\n```typescript\nisNull(null) // true\n\nisNull(undefined) // false\nisNull(0) // false\nisNull(NaN) // false\n\n```\n\n#### `isUndefined`\n\nFind out whether type of value is undefined\n\n```typescript\nisUndefined(undefined) // true\n\nisUndefined(null) // false\nisUndefined(0) // false\n\n```\n\n#### `isMissing`\n\nFind out whether value is null or undefined, therefore \"missing\"\n\n```typescript\nisMissing(null) // true\nisMissing(undefined) // true\n\nisMissing(0) // false\nisMissing(NaN) // false\nisMissing(\"\") // false\n\n```\n\n#### `isPresent`\n\nFind out whether value is not null and not undefined, therefore \"present\"\n\n```typescript\nisPresent(0) // true\nisPresent(NaN) // true\nisPresent(\"\") // true\n\nisPresent(null) // false\nisPresent(undefined) // false\n\n```\n\n#### `isBoolean`\n\nFind out whether value is of type Boolean\n\n```typescript\nisBoolean(true) // true\nisBoolean(false) // true\n\nisBoolean(0) // false\n\n```\n\n#### `isArray`\n\nFind out whether value is of type Array\n\n```typescript\nisArray([]) // true\nisArray([null, undefined]) // true\n\nisArray({}) // false\n\n```\n\n#### `isObject`\n\nFind out whether value is of type Object\n\n```typescript\nisObject({}) // true\n\nisObject(new Function()) // false\nisObject([]) // false\n\n```\n\n#### `isString`\n\nFind out whether value is of type String\n\n```typescript\nisString(\"\") // true\n\nisString(new String()) // false\n\n```\n\n#### `isNumber`\n\nFind out whether value is of type Number\n\n```typescript\nisNumber(42) // true\nisNumber(Math.PI) // true\nisNumber(Infinity) // true\n\nisNumber(NaN) // false\n\n```\n\n#### `isInteger`\n\nFind out whether value is of type Number and is an Integer\n\n```typescript\nisInteger(42) // true\n\nisInteger(Math.PI) // false\nisInteger(Infinity) // false\nisInteger(NaN) // false\n\n```\n\n#### `isFunction`\n\nFind out whether value is of type Function\n\n```typescript\nisFunction(() =\u003e {}) // true\nisFunction(ReferenceError) // true\n\nisFunction(new ReferenceError()) // false\n\n```\n\n#### `isNonEmptyString`\n\nFind out whether value is of type String, and has at least 1 character\n\n```typescript\nisNonEmptyString(\"Hello, World!\") // true\n\nisNonEmptyString(\"\") // false\n\n```\n\n#### `isNonEmptyArray`\n\nFind out whether value is of type Array and has at least one element\n\n```typescript\nisNonEmptyArray([null]) // true\n\nisNonEmptyArray([]) // false\n\n```\n\n#### `isTrue`\n\nFind out whether value is of type Boolean and is true\n\n```typescript\nisTrue(true) // true\n\nisTrue(1) // false\nisTrue(false) // false\n\n```\n\n#### `isFalse`\n\nFind out whether value is of type Boolean and is false\n\n```typescript\nisFalse(false) // true\n\nisFalse(0) // false\nisFalse(true) // false\n\n```\n\n#### `isPositiveInteger`\n\nFind out whether value is an Integer and greater than 0\n\n```typescript\nisPositiveInteger(42) // true\n\nisPositiveInteger(0) // false\nisPositiveInteger(-42) // false\n\n```\n\n#### `isNonNegativeInteger`\n\nFind out whether value is an Integer and greater or equal to 0\n\n```typescript\nisNonNegativeInteger(42) // true\nisNonNegativeInteger(0) // true\n\nisNonNegativeInteger(-42) // false\n\n```\n\n#### `hasOneItem`\n\nFind out whether value is an Array and its length is 1\n\n```typescript\nhasOneItem([null]) // true\n\nhasOneItem([]) // false\nhasOneItem([42, Math.PI]) // false\n\n```\n\n#### `hasMultipleItems`\n\nFind out whether value is an Array and its length is more than 1\n\n```typescript\nhasMultipleItems([42, Infinity]) // true\n\nhasMultipleItems([]) // false\nhasMultipleItems([\"Hello, World\"]) // false\n\n```\n\n#### `isConstructable`\n\nFind out whether value is Constructable\n\n```typescript\nisConstructable(new Function()) // true\nisConstructable(function a() {}) // true\nisConstructable(class {}) // true\nisConstructable(class ClassName {}) // true\n\nisConstructable(() =\u003e {}) // false\n\n```\n\n#### `hasOnlyKeys`\n\nFind out whether value has only the keys provided\n\n```typescript\nhasOnlyKeys({ a: \"b\", c: \"d\" }, [\"a\", \"c\"]) // true\nhasOnlyKeys({ a: \"b\" }, [\"a\"]) // true\nhasOnlyKeys({}, []) // true\n\nhasOnlyKeys({ a: \"b\" }, [\"c\"]) // false\nhasOnlyKeys({ a: \"b\", c: \"d\" }, [\"a\"]) // false\n\n```\n\n#### `isEqual`\n\nFind out whether value 1 and value 2 are equal (shallow)\n\n```typescript\nisEqual(\"Hello, World!\", \"Hello, World!\") // true\nisEqual(null, null) // true\nisEqual(false, false) // true\nisEqual(Math.PI, Math.PI) // true\nisEqual(Infinity, Infinity) // true\n\nisEqual([], []) // false\nisEqual({}, {}) // false\nisEqual(false, true) // false\n\n```\n\n**Full test Docs [here](https://github.com/litchi-io/mod-utils/blob/master/src/Conditionals/main.spec.ts).**\n\n---\n\n## Env\n\nAvailable methods:\n\n* `getAsBool`\n* `getAsInt`\n* `getAsStr`\n\nNOTE: These methods are namespaced under `env`. The usage is therefore\n\n```typescript\nimport { env } from \"@usefultools/utils\"\n\nenv.getAsBool(...)\nenv.getAsInt(...)\nenv.getAsStr(...)\n\n```\n\n### Examples\n\nAssuming your `process.env` has loaded the following `.env`.\n\n```\nIS_PROD=true\nASYNC_MAX_TIMEOUT=2500\nAPI_KEY=0351f02f-0be2-49d1-bfed-5c45275d4fd2\n\n```\n\n#### `env.getAsBool`\n\nTo retrieve the Boolean value of `\"IS_PROD\"` from `process.env`, you can use the following method.\n\n```typescript\nenv.getAsBool(\"IS_PROD\") // true\n\n```\n\nIf the raw value cannot be found, or the parsed value is not a Boolean, **this function will throw** a `ReferenceError` or a `TypeError` respectively.\n\n#### `env.getAsInt`\n\nTo retrieve the Integer value of `\"ASYNC_MAX_TIMEOUT\"` from `process.env`, you can use the following method.\n\n```typescript\nenv.getAsInt(\"ASYNC_MAX_TIMEOUT\") // 2500\n\n```\n\nIf the raw value cannot be found, or the parsed value is not an Integer, **this function will throw** a `ReferenceError` or a `TypeError` respectively.\n\n#### `env.getAsStr`\n\nTo retrieve the String value of `\"API_KEY\"` from `process.env`, you can use the following method.\n\n```typescript\nenv.getAsStr(\"API_KEY\") // \"0351f02f-0be2-49d1-bfed-5c45275d4fd2\"\n\n```\n\nIf the raw value cannot be found, **this function will throw** a `ReferenceError`.\n\nIn all of the above, you can also use your own env object like so:\n\n```typescript\n// const env = { \"IS_DEV\": \"false\" }\n\nenv.getAsBool(\"IS_DEV\", env) // false\n\n```\n\n**Full test Docs [here](https://github.com/litchi-io/mod-utils/blob/master/src/Env/main.spec.ts).**\n\n---\n\n## Helpers\n\nAvailable methods:\n\n* `noop`\n* `identity`\n* `getRandomIntInclusive`\n* `generateId`\n* `isValidId`\n* `generateUUID`\n* `isValidUUID`\n* `fill`\n\n### Examples\n\n#### `noop`\n\nSometimes you might want to provide a default callback parameter to some of your functions to prevent the application from crashing (on the off-chance someone or something accidentally calls them without any parameters). You can use the `noop` helper as shown below.\n\n```typescript\nfunction doSomething(cb = noop) {\n  let res: string\n\n  try {\n    await http.get(\"/api/healthcheck\")\n    res = \"All works!\"\n  } catch (_err) {\n    res = \"There was an error!\"\n  }\n\n  cb(res)\n}\n\n```\n\n#### `identity`\n\nLet's assume that `doSomething` prints its result (`String`) into the console, but applies `onSuccess` for a Ok result, and `onError` for a Err result. You might want to uppercase the success result, but leave the error message in its original form. You can use the identity helper as shown below.\n\n```typescript\nfunction onSuccess(res: string) {\n   return res.toUpperCase()\n}\n\ndoSomething(onSuccess, identity)\n\n```\n\n#### `getRandomIntInclusive`\n\nTo get a random integer within a specified range, you can use the following:\n\n```typescript\ngetRandomIntInclusive(10, 99) // Yields integers between 10 and 99\n\n```\n\n#### `generateId`\n\nTo get a random id (underlying is the `shortid` library) use:\n\n```typescript\ngenerateId() // \"HJ5fy5p3G\"\ngenerateId() // \"Byij0Ka3z\"\n\n```\n\n#### `isValidId`\n\nTo confirm whether a value is a valid id (underlying is the `shortid` library) use:\n\n```typescript\nisValidId(\"HJ5fy5p3G\") // true\nisValidId(\"foo\") // false\n\n```\n\n#### `generateUUID`\n\nTo get a random UUID v4 (underlying is the `uuid` library) use:\n\n```typescript\ngenerateUUID() // \"b98c5086-1dcc-4822-9fa4-8f343f18e8de\"\ngenerateUUID() // \"7118f7d9-70b1-4cb2-97da-3fe272bed7e8\"\n\n```\n\n#### `isValidId`\n\nTo confirm whether a value is a valid UUID v4 (underlying is the `uuid` library) use:\n\n```typescript\nisValidUUID(\"1ad006bf-00c0-49de-bcf0-7c5eb2f83241\") // true\nisValidUUID(\"foo\") // false\n\n```\n\n#### `fill`\n\nTo fill an array, use:\n\n```typescript\nfill(4) // [0, 1, 2, 3]\n\n```\n\n**Full test Docs [here](https://github.com/litchi-io/mod-utils/blob/master/src/Helpers/main.spec.ts).**\n\n---\n\n## Match\n\nAvailable methods:\n\n* `match`\n\nOther exports:\n\n* `_def`\n\n### Examples\n\n#### `match`\n\nA basic pattern match:\n\n```typescript\nconst getMessage = (year: number): string =\u003e match(year)({\n  [1984]: \"The year is 1984.\",\n  [_def]: \"Unfortunately, we cannot tell what year it is.\"\n})\n\ngetMessage(1984) // \"The year is 1984.\"\ngetMessage(1994) // \"Unfortunately, we cannot tell what year it is.\"\ngetMessage(2024) // \"Unfortunately, we cannot tell what year it is.\"\n\n```\n\nAdvanced pattern matching, including assertions:\n\n```typescript\nfunction isFutureYear(year) {\n  return isPositiveInteger(year)\n  \u0026\u0026 year \u003e new Date().getFullYear()\n}\n\nfunction isCurrentYear(year) {\n  return isPositiveInteger(year)\n  \u0026\u0026 year === new Date().getFullYear()\n}\n\nconst getMessage = (year: number): string =\u003e match(year)(\n  [1984, \"The year is 1984.\"],\n  [isCurrentYear, x =\u003e `The year ${x} is up-to-date.`],\n  [isFutureYear, x =\u003e `The year ${x} is in the future...`],\n  [_def, \"Unfortunately, we cannot tell what year it is.\"],\n)\n\ngetMessage(1984) // \"The year is 1984.\"\ngetMessage(2018) // \"The year 2018 is up-to-date.\"\ngetMessage(2024) // \"The year 2024 is in the future...\"\ngetMessage(1333) // \"Unfortunately, we cannot tell what year it is.\"\n\n```\n\n**Full test Docs [here](https://github.com/litchi-io/mod-utils/blob/master/src/Match/main.spec.ts).**\n\n---\n\n## ThrowIf\n\nA collection of simple throwable assertions, all of which throw if the assertion fails.\n\nAvailable methods:\n\n* `throwIfMissing`\n* `throwIfPresent`\n* `throwIfNotBoolean`\n* `throwIfNotArray`\n* `throwIfNotObject`\n* `throwIfNotString`\n* `throwIfNotNumber`\n* `throwIfNotInteger`\n* `throwIfNotFunction`\n* `throwIfFalse`\n* `throwIfEmptyString`\n* `throwIfEmptyArray`\n* `throwIfNotPositiveInteger`\n* `throwIfNegativeInteger`\n* `throwIfNotConstructable`\n\n### Examples\n\n```typescript\nthrowIfNotObject({}); // void\nthrowIfNotObject([]); // throws Error\nthrowIfNotObject(null); // throws Error\nthrowIfNotObject(undefined); // throws Error\n\n```\n\nYou can also provide your own error messages, and errors.\n\n```typescript\nthrowIfMissing(someValue, '`someValue` missing!'); // throws Error('`someValue` missing!')\nthrowIfMissing(someValue, '`someValue` missing!', ReferenceError); // throws ReferenceError('`someValue` missing!')\n\n```\n\n**Full test Docs [here](https://github.com/litchi-io/mod-utils/blob/master/src/ThrowIf/main.spec.ts).**\n\n---\n\n## Development\n\n1) Install dependencies:\n\n```sh\nnpm install\n```\n\n2) Compile:\n\n```sh\nmake compile\n```\n\n3) Test:\n\n```sh\nmake test # watch mode\nmake test-ci # CI mode / single run\n```\n\n4) Format the codebase:\n\n```sh\nmake format\n```\n\n## Contributing\n\nIf you have comments, complaints, or ideas for improvements, feel free to open an issue or a pull request! See [Contributing guide](./CONTRIBUTING.md) for details about project setup, testing, etc.\n\n## Author and license\n\nThis library was created by [@LITCHI.IO](https://github.com/litchi-io). Main author and maintainer is [Slavo Vojacek](https://github.com/slavovojacek).\n\nContributors: [Slavo Vojacek](https://github.com/slavovojacek)\n\n`@usefultools/utils` is available under the ISC license. See the [LICENSE file](./LICENSE.txt) for more info.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhqoss%2Futils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhqoss%2Futils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhqoss%2Futils/lists"}