From d9d0505194c2f0cdecbc80d7b36ea2bc97972ea0 Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 09:50:59 -0500 Subject: [PATCH 1/8] ci: added `docs.yml` --- .github/workflows/docs.yml | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..4a56c51 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,53 @@ +name: Publish docs + +on: + push: + branches: [master] + +permissions: + contents: read + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Setup pnpm + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + + - name: Use Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version-file: '.node-version' + cache: 'pnpm' + + - name: Installing dependencies + run: pnpm install --frozen-lockfile + + - name: Build docs + run: pnpm build:docs + + - name: Upload docs artifact + id: deployment + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: docs + + deploy: + needs: build + runs-on: ubuntu-24.04 + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 From 121f48c312822855ce34c76f6759a92b56a99de1 Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 09:52:49 -0500 Subject: [PATCH 2/8] build: updated tsconfig options --- tsconfig.base.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/tsconfig.base.json b/tsconfig.base.json index c32e3b7..fc25f5b 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -13,7 +13,6 @@ "incremental": true, "isolatedModules": true, "lib": ["es2023", "DOM"], - "listEmittedFiles": true, "module": "NodeNext", "moduleResolution": "NodeNext", "noEmit": true, @@ -24,7 +23,6 @@ "noUnusedLocals": true, "noUnusedParameters": true, "outDir": "./dist", - "removeComments": true, "resolveJsonModule": true, "rootDir": "./", "skipLibCheck": true, From 383eb19e0feeaebdf96c56d645fde5ce49b1c11e Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 09:53:36 -0500 Subject: [PATCH 3/8] chore(deps-dev): added `typedoc` --- cspell.json | 1 + package.json | 4 +- pnpm-lock.yaml | 192 ++++++++++++++++++++++++++++++++++++++++++------- typedoc.json | 14 ++++ 4 files changed, 184 insertions(+), 27 deletions(-) create mode 100644 typedoc.json diff --git a/cspell.json b/cspell.json index 85a303e..6e44c4b 100644 --- a/cspell.json +++ b/cspell.json @@ -26,6 +26,7 @@ "tslib", "twasn't", "typecheck", + "typedoc", "unrs-resolver", "Unwritable", "vite", diff --git a/package.json b/package.json index ea1e74c..5b47136 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "clean": "rimraf ./dist/ ./cache/ ./coverage/", "prebuild": "pnpm clean", "build": "tsgo --build tsconfig.cjs.json tsconfig.mjs.json --force", + "build:docs": "typedoc", "postbuild": "echo '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json && echo '{\"type\":\"module\"}' > ./dist/mjs/package.json && pnpm validate", "typecheck": "tsgo --build --verbose --noEmit", "lint": "eslint ./*.{js,cjs,mjs,ts,cts,mts} ./src/ ./bench/ ./test/ --ext .ts,.mjs,.cjs", @@ -104,9 +105,10 @@ "husky": "^9.1.7", "jsdom": "^29.1.1", "lint-staged": "^17.0.8", - "prettier": "^3.9.4", + "prettier": "^3.9.5", "rimraf": "^6.1.3", "semantic-release": "^25.0.5", + "typedoc": "^0.28.20", "validate-package-exports": "^1.2.1", "vitest": "^4.1.10" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f4c38c..3f85aef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,13 +28,13 @@ importers: version: 0.12.1(eslint@8.57.1)(typescript@6.0.3) '@webdeveric/prettier-config': specifier: ^0.4.0 - version: 0.4.0(prettier@3.9.4) + version: 0.4.0(prettier@3.9.5) '@webdeveric/ts-data-structures': specifier: ^1.0.1 version: 1.0.1 commitlint: specifier: ^21.2.1 - version: 21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.0.1)(typescript@6.0.3) + version: 21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.1.0)(typescript@6.0.3) commitlint-plugin-cspell: specifier: ^0.9.3 version: 0.9.3(@commitlint/lint@21.2.0) @@ -66,14 +66,17 @@ importers: specifier: ^17.0.8 version: 17.0.8 prettier: - specifier: ^3.9.4 - version: 3.9.4 + specifier: ^3.9.5 + version: 3.9.5 rimraf: specifier: ^6.1.3 version: 6.1.3 semantic-release: specifier: ^25.0.5 version: 25.0.5(typescript@6.0.3) + typedoc: + specifier: ^0.28.20 + version: 0.28.20(typescript@6.0.3) validate-package-exports: specifier: ^1.2.1 version: 1.2.1 @@ -547,6 +550,9 @@ packages: resolution: {integrity: sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==} engines: {node: ^20.17.0 || >=22.9.0} + '@gerrit0/mini-shiki@3.23.0': + resolution: {integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==} + '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -848,6 +854,21 @@ packages: peerDependencies: semantic-release: '>=20.1.0' + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} + + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} + + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@sigstore/bundle@4.0.0': resolution: {integrity: sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==} engines: {node: ^20.17.0 || >=22.9.0} @@ -915,6 +936,9 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -924,6 +948,9 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@typescript-eslint/eslint-plugin@8.63.0': resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1278,6 +1305,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + argue-cli@3.1.0: + resolution: {integrity: sha512-DhBpBfXL4SS2uC0N922MMajKR3CdrTG0u2or1PNYgXMsrSzViJrbtvT0nCLlLGUI0plam/ZZCs7aAauHtW9thw==} + engines: {node: '>=22'} + argv-formatter@1.0.0: resolution: {integrity: sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==} @@ -1520,6 +1551,11 @@ packages: engines: {node: '>=22'} hasBin: true + conventional-commits-parser@7.1.0: + resolution: {integrity: sha512-DPp6hkUjvwIivxbkrTiLXeRswNv1A/4GFA2X6scXma0AMa9632V3TwxmrlkUIEtUktiM3Ln+RrSH2xlP3/jUTw==} + engines: {node: '>=22'} + hasBin: true + convert-hrtime@5.0.0: resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} engines: {node: '>=12'} @@ -1692,6 +1728,10 @@ packages: emojilib@2.4.0: resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + entities@8.0.0: resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} engines: {node: '>=20.19.0'} @@ -2572,6 +2612,9 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + linkify-it@5.0.2: + resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} + lint-staged@17.0.8: resolution: {integrity: sha512-B2P/d+jVW0UXOQ0MVMLrB/9ydA1P+zz6jYfdrbbEd9ur3S2rcbduFWKiUCC02Sm5hbC8nrm7y24WuYMG54HfxA==} engines: {node: '>=22.22.1'} @@ -2625,6 +2668,9 @@ packages: resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} + lunr@2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2643,6 +2689,10 @@ packages: resolution: {integrity: sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw==} engines: {node: ^20.17.0 || >=22.9.0} + markdown-it@14.3.0: + resolution: {integrity: sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==} + hasBin: true + marked-terminal@7.3.0: resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} engines: {node: '>=16.0.0'} @@ -2661,6 +2711,9 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} @@ -3113,8 +3166,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.9.4: - resolution: {integrity: sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==} + prettier@3.9.5: + resolution: {integrity: sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==} engines: {node: '>=14'} hasBin: true @@ -3155,6 +3208,10 @@ packages: kerberos: optional: true + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -3553,11 +3610,11 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - tldts-core@7.4.7: - resolution: {integrity: sha512-rNlAI8fKn/JckBMUSbNL/ES2kmDiurWaE49l+ikwEc9A6lFR7gMx9AhgQMQKBK4H5w4pKLH64JzZfB99uRsGNQ==} + tldts-core@7.4.8: + resolution: {integrity: sha512-c1P7u0EhACHj7lPy4MJm8iTFEU8+nB0LCtddH0fhP7noaVoXAqafMtOOeX+ulpuPBqnrRgRhw494RICT3mbhnw==} - tldts@7.4.7: - resolution: {integrity: sha512-56L0/9HELHSsG1bFCzay8UoLxzRL7kpFf7Wl5q/kSYwiSJGACvro61xnKzPNM+SadxllzdtXsKDSXE7HPeqIAw==} + tldts@7.4.8: + resolution: {integrity: sha512-htwgN/8KRB3z3vnC0BOETVh2m499g5GmyTK9Wq5JBLX3FNz6tSBveAd+fQhzy9hkjif8vy2jwDMR1sGhLtZl2A==} hasBin: true to-regex-range@5.0.1: @@ -3640,11 +3697,21 @@ packages: resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} + typedoc@0.28.20: + resolution: {integrity: sha512-uSKqkh8Cr48vllnEy+jdaAgOeR6Y+QCBW7usgUsKj7gJEfR7stw9U/fE49LBnj2tPRKPY0c0EBJSWe9Appmplg==} + engines: {node: '>= 18', pnpm: '>= 10'} + hasBin: true + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x + typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -4008,13 +4075,13 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@commitlint/cli@21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.0.1)(typescript@6.0.3)': + '@commitlint/cli@21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.1.0)(typescript@6.0.3)': dependencies: '@commitlint/config-conventional': 21.2.0 '@commitlint/format': 21.2.0 '@commitlint/lint': 21.2.0 '@commitlint/load': 21.2.0(@types/node@24.13.3)(typescript@6.0.3) - '@commitlint/read': 21.2.1(conventional-commits-parser@7.0.1) + '@commitlint/read': 21.2.1(conventional-commits-parser@7.1.0) '@commitlint/types': 21.2.0 tinyexec: 1.2.4 yargs: 18.0.0 @@ -4081,11 +4148,11 @@ snapshots: conventional-changelog-angular: 9.2.1 conventional-commits-parser: 7.0.1 - '@commitlint/read@21.2.1(conventional-commits-parser@7.0.1)': + '@commitlint/read@21.2.1(conventional-commits-parser@7.1.0)': dependencies: '@commitlint/top-level': 21.2.0 '@commitlint/types': 21.2.0 - '@conventional-changelog/git-client': 3.1.0(conventional-commits-parser@7.0.1) + '@conventional-changelog/git-client': 3.1.0(conventional-commits-parser@7.1.0) tinyexec: 1.2.4 transitivePeerDependencies: - conventional-commits-filter @@ -4114,16 +4181,16 @@ snapshots: '@commitlint/types@21.2.0': dependencies: - conventional-commits-parser: 7.0.1 + conventional-commits-parser: 7.1.0 picocolors: 1.1.1 - '@conventional-changelog/git-client@3.1.0(conventional-commits-parser@7.0.1)': + '@conventional-changelog/git-client@3.1.0(conventional-commits-parser@7.1.0)': dependencies: '@simple-libs/child-process-utils': 2.0.0 '@simple-libs/stream-utils': 2.0.0 semver: 7.8.5 optionalDependencies: - conventional-commits-parser: 7.0.1 + conventional-commits-parser: 7.1.0 '@conventional-changelog/template@1.2.1': {} @@ -4432,6 +4499,14 @@ snapshots: '@gar/promise-retry@1.0.3': {} + '@gerrit0/mini-shiki@3.23.0': + dependencies: + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -4805,6 +4880,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@shikijs/engine-oniguruma@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/themes@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/types@3.23.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/vscode-textmate@10.0.2': {} + '@sigstore/bundle@4.0.0': dependencies: '@sigstore/protobuf-specs': 0.5.1 @@ -4872,6 +4967,10 @@ snapshots: '@types/estree@1.0.9': {} + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + '@types/json5@0.0.29': {} '@types/node@24.13.3': @@ -4880,6 +4979,8 @@ snapshots: '@types/normalize-package-data@2.4.4': {} + '@types/unist@3.0.3': {} + '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@8.57.1)(typescript@6.0.3))(eslint@8.57.1)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -5143,9 +5244,9 @@ snapshots: dependencies: eslint: 8.57.1 - '@webdeveric/prettier-config@0.4.0(prettier@3.9.4)': + '@webdeveric/prettier-config@0.4.0(prettier@3.9.5)': dependencies: - prettier: 3.9.4 + prettier: 3.9.5 '@webdeveric/ts-data-structures@1.0.1': {} @@ -5204,6 +5305,8 @@ snapshots: argparse@2.0.1: {} + argue-cli@3.1.0: {} + argv-formatter@1.0.0: {} array-buffer-byte-length@1.0.2: @@ -5429,9 +5532,9 @@ snapshots: '@commitlint/types': 21.2.0 cspell-lib: 10.0.1 - commitlint@21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.0.1)(typescript@6.0.3): + commitlint@21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.1.0)(typescript@6.0.3): dependencies: - '@commitlint/cli': 21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.0.1)(typescript@6.0.3) + '@commitlint/cli': 21.2.1(@types/node@24.13.3)(conventional-commits-parser@7.1.0)(typescript@6.0.3) '@commitlint/types': 21.2.0 transitivePeerDependencies: - '@types/node' @@ -5491,6 +5594,11 @@ snapshots: '@simple-libs/stream-utils': 2.0.0 meow: 14.1.0 + conventional-commits-parser@7.1.0: + dependencies: + '@simple-libs/stream-utils': 2.0.0 + argue-cli: 3.1.0 + convert-hrtime@5.0.0: {} convert-source-map@2.0.0: {} @@ -5705,6 +5813,8 @@ snapshots: emojilib@2.4.0: {} + entities@4.5.0: {} + entities@8.0.0: {} env-ci@11.2.0: @@ -6652,6 +6762,10 @@ snapshots: lines-and-columns@1.2.4: {} + linkify-it@5.0.2: + dependencies: + uc.micro: 2.1.0 + lint-staged@17.0.8: dependencies: listr2: 10.2.2 @@ -6711,6 +6825,8 @@ snapshots: lru-cache@11.5.2: {} + lunr@2.3.9: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -6748,6 +6864,15 @@ snapshots: transitivePeerDependencies: - supports-color + markdown-it@14.3.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.2 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + marked-terminal@7.3.0(marked@15.0.12): dependencies: ansi-escapes: 7.3.0 @@ -6765,6 +6890,8 @@ snapshots: mdn-data@2.27.1: {} + mdurl@2.0.0: {} + meow@13.2.0: {} meow@14.1.0: {} @@ -7170,7 +7297,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.9.4: {} + prettier@3.9.5: {} pretty-ms@9.3.0: dependencies: @@ -7192,6 +7319,8 @@ snapshots: proxy-agent-negotiate@1.1.0: {} + punycode.js@2.3.1: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} @@ -7692,11 +7821,11 @@ snapshots: tinyrainbow@3.1.0: {} - tldts-core@7.4.7: {} + tldts-core@7.4.8: {} - tldts@7.4.7: + tldts@7.4.8: dependencies: - tldts-core: 7.4.7 + tldts-core: 7.4.8 to-regex-range@5.0.1: dependencies: @@ -7704,7 +7833,7 @@ snapshots: tough-cookie@6.0.2: dependencies: - tldts: 7.4.7 + tldts: 7.4.8 tr46@6.0.0: dependencies: @@ -7787,8 +7916,19 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typedoc@0.28.20(typescript@6.0.3): + dependencies: + '@gerrit0/mini-shiki': 3.23.0 + lunr: 2.3.9 + markdown-it: 14.3.0 + minimatch: 10.2.5 + typescript: 6.0.3 + yaml: 2.9.0 + typescript@6.0.3: {} + uc.micro@2.1.0: {} + uglify-js@3.19.3: optional: true diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..e54982c --- /dev/null +++ b/typedoc.json @@ -0,0 +1,14 @@ +{ + "entryPoints": ["src/**/*.ts"], + "out": "docs", + "excludeInternal": true, + "excludeNotDocumented": false, + "cleanOutputDir": true, + "readme": "readme.md", + "gitRevision": "master", + "treatWarningsAsErrors": true, + "validation": { + "notExported": true, + "invalidLink": true + } +} From 0fcabd3c4edfd71d77e65a97462aad45e5169e76 Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 09:53:54 -0500 Subject: [PATCH 4/8] chore: updated git ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 60b84ec..e0899d8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ npm-debug.log cache/ coverage/ +docs/ dist/ dist-mjs/ node_modules/ From 8334200e51029775b65c77ce45f683efea2cde27 Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 09:54:35 -0500 Subject: [PATCH 5/8] docs(readme): updated badge --- readme.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e6024ea..d79dc3b 100644 --- a/readme.md +++ b/readme.md @@ -1,13 +1,23 @@ # @webdeveric/utils -[![NodeJS](https://github.com/webdeveric/utils/actions/workflows/node.js.yml/badge.svg)](https://github.com/webdeveric/utils/actions/workflows/node.js.yml) [![CodeQL Advanced](https://github.com/webdeveric/utils/actions/workflows/codeql.yml/badge.svg)](https://github.com/webdeveric/utils/actions/workflows/codeql.yml) +[![NodeJS](https://github.com/webdeveric/utils/actions/workflows/node.js.yml/badge.svg)](https://github.com/webdeveric/utils/actions/workflows/node.js.yml) [![Release](https://github.com/webdeveric/utils/actions/workflows/release.yml/badge.svg)](https://github.com/webdeveric/utils/actions/workflows/release.yml) ## Install +### `pnpm` + ```shell pnpm add @webdeveric/utils ``` +### `npm` + ```shell npm i @webdeveric/utils --save ``` + +### `yarn` + +```shell +yarn add @webdeveric/utils +``` From 6a7dc95c36d1161e075ac056825018330ab15630 Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 10:09:12 -0500 Subject: [PATCH 6/8] refactor!: removed `isDateString()` BREAKING CHANGE: Use `isDateInputString()` instead. --- src/predicate/index.ts | 1 - src/predicate/isDateString.ts | 10 ---------- 2 files changed, 11 deletions(-) delete mode 100644 src/predicate/isDateString.ts diff --git a/src/predicate/index.ts b/src/predicate/index.ts index b7ae07b..6f75f24 100644 --- a/src/predicate/index.ts +++ b/src/predicate/index.ts @@ -11,7 +11,6 @@ export * from './isBinaryNumberString.js'; export * from './isBoolean.js'; export * from './isBooleanArray.js'; export * from './isDateInputString.js'; -export * from './isDateString.js'; export * from './isDigitsString.js'; export * from './isFiniteNumber.js'; export * from './isFunction.js'; diff --git a/src/predicate/isDateString.ts b/src/predicate/isDateString.ts deleted file mode 100644 index ade9491..0000000 --- a/src/predicate/isDateString.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { isDateInputString } from './isDateInputString.js'; - -import type { TypePredicateFn } from '../types/functions.js'; - -/** - * Determine if `input` is a valid date string. - * - * @deprecated Use `isDateInputString` instead. - */ -export const isDateString: TypePredicateFn = isDateInputString; From 44e7d12f7d6ccaa5ccda0dce10a311be79ff9f31 Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 10:11:52 -0500 Subject: [PATCH 7/8] docs: added docblock comments --- src/asArray.ts | 9 ++++++ src/asError.ts | 9 ++++++ src/assertion/assertExhaustive.ts | 19 ++++++++++++ src/assertion/assertIsAsyncIterable.ts | 13 ++++++++ src/assertion/assertIsBigInt.ts | 9 ++++++ src/assertion/assertIsBigIntArray.ts | 9 ++++++ src/assertion/assertIsBoolean.ts | 9 ++++++ src/assertion/assertIsBooleanArray.ts | 9 ++++++ src/assertion/assertIsDigitsString.ts | 9 ++++++ src/assertion/assertIsFiniteNumber.ts | 9 ++++++ src/assertion/assertIsFunction.ts | 9 ++++++ src/assertion/assertIsInt32.ts | 9 ++++++ src/assertion/assertIsIntString.ts | 9 ++++++ src/assertion/assertIsInteger.ts | 9 ++++++ src/assertion/assertIsIterable.ts | 9 ++++++ src/assertion/assertIsLengthAware.ts | 9 ++++++ src/assertion/assertIsNull.ts | 9 ++++++ src/assertion/assertIsNullArray.ts | 9 ++++++ src/assertion/assertIsNumber.ts | 9 ++++++ src/assertion/assertIsNumberArray.ts | 9 ++++++ src/assertion/assertIsNumberGTEOne.ts | 9 ++++++ src/assertion/assertIsNumericString.ts | 9 ++++++ src/assertion/assertIsNumericValue.ts | 11 +++++++ src/assertion/assertIsNumericValueArray.ts | 9 ++++++ src/assertion/assertIsObject.ts | 10 +++++++ src/assertion/assertIsOptionalBigInt.ts | 10 +++++++ src/assertion/assertIsOptionalBoolean.ts | 10 +++++++ src/assertion/assertIsOptionalNull.ts | 10 +++++++ src/assertion/assertIsOptionalNumber.ts | 10 +++++++ src/assertion/assertIsOptionalString.ts | 10 +++++++ src/assertion/assertIsOptionalSymbol.ts | 10 +++++++ src/assertion/assertIsPositiveFiniteNumber.ts | 9 ++++++ src/assertion/assertIsPositiveInteger.ts | 9 ++++++ src/assertion/assertIsPrimitive.ts | 9 ++++++ .../assertIsPromiseFulfilledResult.ts | 11 +++++++ .../assertIsPromiseRejectedResult.ts | 11 +++++++ src/assertion/assertIsPropertyKey.ts | 11 +++++++ src/assertion/assertIsSafeInteger.ts | 9 ++++++ src/assertion/assertIsSizeAware.ts | 9 ++++++ src/assertion/assertIsString.ts | 9 ++++++ src/assertion/assertIsStringArray.ts | 9 ++++++ src/assertion/assertIsStringMatching.ts | 9 ++++++ src/assertion/assertIsStringRecord.ts | 9 ++++++ src/assertion/assertIsStringWithLength.ts | 9 ++++++ src/assertion/assertIsSymbol.ts | 9 ++++++ src/assertion/assertIsSymbolArray.ts | 9 ++++++ src/assertion/assertIsUndefined.ts | 9 ++++++ src/assertion/assertIsUndefinedArray.ts | 9 ++++++ src/assertion/assertPathExists.ts | 12 ++++++++ src/assertion/assertPredicate.ts | 11 +++++++ src/assertion/getError.ts | 9 ++++++ src/capitalize.ts | 10 ++++++- src/cartesian.ts | 9 +++++- src/chunk.ts | 8 +++++ src/clamp.ts | 9 ++++++ src/combinations.ts | 8 +++++ src/comment.ts | 11 +++++++ src/compose.ts | 11 +++++++ src/convert.ts | 8 +++++ src/countCharCode.ts | 8 +++++ src/countCharacter.ts | 8 +++++ src/counter.ts | 8 +++++ src/deepDecodeURI.ts | 8 +++++ src/deepFreeze.ts | 10 ++++++- src/delay.ts | 6 ++++ src/delayAnimationFrame.ts | 9 ++++++ src/delayAnimationFrames.ts | 9 ++++++ src/describeInput.ts | 10 +++++++ src/escapeRegExp.ts | 8 +++++ src/findIndentation.ts | 5 ++++ src/get.ts | 8 +++++ src/getDateString.ts | 8 +++++ src/getISODateString.ts | 8 +++++ src/getMaxValue.ts | 8 +++++ src/getMilliseconds.ts | 9 ++++++ src/getMinValue.ts | 8 +++++ src/getOwnKeys.ts | 8 +++++ src/getOwnPaths.ts | 8 +++++ src/getOwnProperties.ts | 8 +++++ src/getPackageName.ts | 9 ++++++ src/getPaths.ts | 8 +++++ src/getRandomItem.ts | 8 +++++ src/getSortedObject.ts | 8 +++++ src/getType.ts | 9 ++++++ src/has.ts | 11 +++++-- src/hasAdditionalProperties.ts | 6 ++++ src/inRange.ts | 9 ++++++ src/isEmpty.ts | 9 ++++++ src/iterateForever.ts | 13 ++++++++ src/joinStrings.ts | 8 +++++ src/jsonParse.ts | 8 +++++ src/looksLikeURL.ts | 9 ++++++ src/memo.ts | 11 ++++++- src/normalize.ts | 25 ++++++++-------- src/parseNumber.ts | 9 ++++++ src/pathParts.ts | 8 +++++ src/predicate/assume.ts | 5 ++++ src/predicate/factory/allOf.ts | 8 +++++ src/predicate/factory/anyOf.ts | 8 +++++ src/predicate/factory/everyItem.ts | 11 +++++++ src/predicate/factory/fromEnum.ts | 14 +++++++++ src/predicate/factory/instanceOf.ts | 10 +++++++ src/predicate/factory/is.ts | 7 +++++ src/predicate/factory/literal.ts | 10 +++++++ src/predicate/factory/matching.ts | 10 +++++++ src/predicate/factory/maybeArray.ts | 11 +++++++ src/predicate/factory/nonNullable.ts | 12 +++++++- src/predicate/factory/nullable.ts | 11 +++++++ src/predicate/factory/nullish.ts | 12 ++++++++ src/predicate/factory/optional.ts | 11 +++++++ src/predicate/factory/range.ts | 10 +++++++ src/predicate/factory/shape.ts | 13 ++++++++ src/predicate/factory/simple.ts | 10 +++++++ src/predicate/factory/stringLength.ts | 11 +++++++ src/predicate/factory/tuple.ts | 11 +++++++ src/predicate/factory/typeOf.ts | 11 +++++++ src/predicate/factory/withLength.ts | 15 ++++++++++ src/predicate/factory/withSize.ts | 14 +++++++++ src/predicate/isAny.ts | 9 ++++++ src/predicate/isAnyObject.ts | 6 ++++ src/predicate/isAnyObjectWith.ts | 6 ++++ src/predicate/isAnyObjectWithOwn.ts | 6 ++++ src/predicate/isArray.ts | 6 ++++ src/predicate/isAsyncIterable.ts | 12 ++++++-- src/predicate/isBigInt.ts | 9 ++++++ src/predicate/isBigIntArray.ts | 9 ++++++ src/predicate/isBinaryNumberString.ts | 10 ++++++- src/predicate/isBoolean.ts | 9 ++++++ src/predicate/isBooleanArray.ts | 9 ++++++ src/predicate/isDateInputString.ts | 6 ++++ src/predicate/isDigitsString.ts | 9 ++++++ src/predicate/isFiniteNumber.ts | 9 ++++++ src/predicate/isFunction.ts | 9 ++++++ src/predicate/isHexNumberString.ts | 10 ++++++- src/predicate/isISODateString.ts | 8 ++++- src/predicate/isInt32.ts | 9 ++++++ src/predicate/isIntString.ts | 9 ++++++ src/predicate/isInteger.ts | 9 ++++++ src/predicate/isIterable.ts | 9 ++++++ src/predicate/isJSONable.ts | 9 ++++++ src/predicate/isLengthAware.ts | 9 ++++++ src/predicate/isNonNullable.ts | 9 ++++++ src/predicate/isNull.ts | 9 ++++++ src/predicate/isNullArray.ts | 9 ++++++ src/predicate/isNullish.ts | 9 ++++++ src/predicate/isNumber.ts | 9 ++++++ src/predicate/isNumberArray.ts | 9 ++++++ src/predicate/isNumericString.ts | 9 ++++++ src/predicate/isNumericValue.ts | 9 ++++++ src/predicate/isNumericValueArray.ts | 9 ++++++ src/predicate/isObject.ts | 6 ++++ src/predicate/isObjectLiteral.ts | 6 ++++ src/predicate/isObjectWith.ts | 6 ++++ src/predicate/isOctalNumberString.ts | 10 ++++++- src/predicate/isOptionalArray.ts | 9 ++++++ src/predicate/isOptionalBigInt.ts | 9 ++++++ src/predicate/isOptionalBoolean.ts | 9 ++++++ src/predicate/isOptionalISODateString.ts | 9 ++++++ src/predicate/isOptionalNull.ts | 9 ++++++ src/predicate/isOptionalNumber.ts | 9 ++++++ src/predicate/isOptionalObject.ts | 9 ++++++ src/predicate/isOptionalString.ts | 9 ++++++ src/predicate/isOptionalSymbol.ts | 9 ++++++ src/predicate/isPositiveFiniteNumber.ts | 9 ++++++ src/predicate/isPositiveInteger.ts | 9 ++++++ src/predicate/isPrimitive.ts | 9 ++++++ src/predicate/isPromiseFulfilledResult.ts | 9 ++++++ src/predicate/isPromiseLike.ts | 9 ++++++ src/predicate/isPromiseRejectedResult.ts | 9 ++++++ src/predicate/isPropertyKey.ts | 9 ++++++ src/predicate/isSafeInteger.ts | 9 ++++++ src/predicate/isSizeAware.ts | 9 ++++++ src/predicate/isString.ts | 9 ++++++ src/predicate/isStringArray.ts | 9 ++++++ src/predicate/isStringRecord.ts | 9 ++++++ src/predicate/isStringWithLength.ts | 9 ++++++ src/predicate/isSymbol.ts | 9 ++++++ src/predicate/isSymbolArray.ts | 9 ++++++ src/predicate/isTimeoutError.ts | 6 ++++ src/predicate/isUInt32.ts | 9 ++++++ src/predicate/isUndefined.ts | 9 ++++++ src/predicate/isUndefinedArray.ts | 9 ++++++ src/predicate/isUnknown.ts | 9 ++++++ src/predicate/isUrlString.ts | 9 ++++++ src/prefix.ts | 9 ++++++ src/randomInt.ts | 9 ++++++ src/redactCredentialsInURL.ts | 8 +++++ src/resultify.ts | 25 ++++++++++++++++ src/secToString.ts | 8 +++++ src/set.ts | 14 +++++++-- src/sort/byLocaleCompare.ts | 8 +++++ src/sort/byRandom.ts | 5 ++++ src/sort/bySimpleComparison.ts | 8 +++++ src/sort/bySubtraction.ts | 8 +++++ src/sort/byTimestamp.ts | 8 +++++ src/sort/factory/byProperty.ts | 8 +++++ src/sort/factory/byReverseOf.ts | 8 +++++ src/stripIndent.ts | 5 ++++ src/stripWhitespace.ts | 8 +++++ src/suffix.ts | 9 ++++++ src/toPascalCase.ts | 9 ++++++ src/trimEnd.ts | 9 ++++++ src/trimIndentation.ts | 8 +++++ src/trimStart.ts | 9 ++++++ src/tryFn.ts | 11 +++++++ src/tryIt.ts | 9 ++++++ src/unique.ts | 3 +- src/uniqueItems.ts | 8 +++++ src/until.ts | 30 +++++++++++++++++++ 209 files changed, 1918 insertions(+), 30 deletions(-) diff --git a/src/asArray.ts b/src/asArray.ts index 2a2c0a4..42f0a32 100644 --- a/src/asArray.ts +++ b/src/asArray.ts @@ -1,3 +1,12 @@ +/** + * Ensure `data` is an array, wrapping it in one if it isn't already. + * + * @example + * ```ts + * asArray(1); // [1] + * asArray([1, 2]); // [1, 2] + * ``` + */ export function asArray(data: T | T[]): T[] { return Array.isArray(data) ? data : [data]; } diff --git a/src/asError.ts b/src/asError.ts index 902f000..d0c992c 100644 --- a/src/asError.ts +++ b/src/asError.ts @@ -1,3 +1,12 @@ +/** + * Ensure `input` is an `Error` instance, converting it to one if it isn't already. + * + * @example + * ```ts + * asError('Oops'); // Error('Oops') + * asError(new Error('Oops')); // the same Error instance + * ``` + */ export function asError(input: unknown): Error { return input instanceof Error ? input : new Error(String(input)); } diff --git a/src/assertion/assertExhaustive.ts b/src/assertion/assertExhaustive.ts index 81d9057..c6e1579 100644 --- a/src/assertion/assertExhaustive.ts +++ b/src/assertion/assertExhaustive.ts @@ -1,5 +1,24 @@ import { getError } from './getError.js'; +/** + * Assert that this line is unreachable, useful for exhaustive checks such as a `switch` covering every case of a union. + * + * @example + * ```ts + * type Direction = 'up' | 'down'; + * + * function describe(direction: Direction): string { + * switch (direction) { + * case 'up': + * return 'Going up'; + * case 'down': + * return 'Going down'; + * default: + * assertExhaustive(direction); // throws if a new Direction case isn't handled above + * } + * } + * ``` + */ export function assertExhaustive(_: never, error: string | Error = 'Failed exhaustive check'): never { throw getError(error); } diff --git a/src/assertion/assertIsAsyncIterable.ts b/src/assertion/assertIsAsyncIterable.ts index 6f324f0..e8d1dd3 100644 --- a/src/assertion/assertIsAsyncIterable.ts +++ b/src/assertion/assertIsAsyncIterable.ts @@ -2,6 +2,19 @@ import { isAsyncIterable } from '../predicate/isAsyncIterable.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an `AsyncIterable`. + * + * @example + * ```ts + * async function* gen() { + * yield 1; + * } + * + * assertIsAsyncIterable(gen()); // does not throw + * assertIsAsyncIterable([1, 2, 3]); // throws TypeError: input is not an AsyncIterable + * ``` + */ export function assertIsAsyncIterable( input: unknown, error: string | Error = 'input is not an AsyncIterable', diff --git a/src/assertion/assertIsBigInt.ts b/src/assertion/assertIsBigInt.ts index 19887de..e255aae 100644 --- a/src/assertion/assertIsBigInt.ts +++ b/src/assertion/assertIsBigInt.ts @@ -2,6 +2,15 @@ import { isBigInt } from '../predicate/isBigInt.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a `bigint`. + * + * @example + * ```ts + * assertIsBigInt(10n); // does not throw + * assertIsBigInt(10); // throws TypeError: input is not a bigint + * ``` + */ export function assertIsBigInt( input: unknown, error: string | Error = 'input is not a bigint', diff --git a/src/assertion/assertIsBigIntArray.ts b/src/assertion/assertIsBigIntArray.ts index 97b865f..8e195ec 100644 --- a/src/assertion/assertIsBigIntArray.ts +++ b/src/assertion/assertIsBigIntArray.ts @@ -2,6 +2,15 @@ import { isBigIntArray } from '../predicate/isBigIntArray.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an array of `bigint`. + * + * @example + * ```ts + * assertIsBigIntArray([1n, 2n, 3n]); // does not throw + * assertIsBigIntArray([1, 2, 3]); // throws TypeError: input is not an array of bigint + * ``` + */ export function assertIsBigIntArray( input: unknown, error: string | Error = 'input is not an array of bigint', diff --git a/src/assertion/assertIsBoolean.ts b/src/assertion/assertIsBoolean.ts index 95fa8cb..49fc03e 100644 --- a/src/assertion/assertIsBoolean.ts +++ b/src/assertion/assertIsBoolean.ts @@ -2,6 +2,15 @@ import { isBoolean } from '../predicate/isBoolean.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a boolean. + * + * @example + * ```ts + * assertIsBoolean(true); // does not throw + * assertIsBoolean('true'); // throws TypeError: input is not a boolean + * ``` + */ export function assertIsBoolean( input: unknown, error: string | Error = 'input is not a boolean', diff --git a/src/assertion/assertIsBooleanArray.ts b/src/assertion/assertIsBooleanArray.ts index 7c0009c..7a142ff 100644 --- a/src/assertion/assertIsBooleanArray.ts +++ b/src/assertion/assertIsBooleanArray.ts @@ -2,6 +2,15 @@ import { isBooleanArray } from '../predicate/isBooleanArray.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an array of booleans. + * + * @example + * ```ts + * assertIsBooleanArray([true, false]); // does not throw + * assertIsBooleanArray([true, 'false']); // throws TypeError: input is not an array of boolean + * ``` + */ export function assertIsBooleanArray( input: unknown, error: string | Error = 'input is not an array of boolean', diff --git a/src/assertion/assertIsDigitsString.ts b/src/assertion/assertIsDigitsString.ts index e8692f9..febef75 100644 --- a/src/assertion/assertIsDigitsString.ts +++ b/src/assertion/assertIsDigitsString.ts @@ -4,6 +4,15 @@ import { getError } from './getError.js'; import type { NumericString } from '../types/common.js'; +/** + * Assert that `input` is a string that contains digits only. + * + * @example + * ```ts + * assertIsDigitsString('12345'); // does not throw + * assertIsDigitsString('123.45'); // throws TypeError: input is not a string of integers only + * ``` + */ export function assertIsDigitsString( input: unknown, error: string | Error = 'input is not a string of integers only', diff --git a/src/assertion/assertIsFiniteNumber.ts b/src/assertion/assertIsFiniteNumber.ts index fcb1c45..05448d8 100644 --- a/src/assertion/assertIsFiniteNumber.ts +++ b/src/assertion/assertIsFiniteNumber.ts @@ -2,6 +2,15 @@ import { isFiniteNumber } from '../predicate/isFiniteNumber.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a finite number. + * + * @example + * ```ts + * assertIsFiniteNumber(42); // does not throw + * assertIsFiniteNumber(Infinity); // throws TypeError: input is not a finite number + * ``` + */ export function assertIsFiniteNumber( input: unknown, error: string | Error = 'input is not a finite number', diff --git a/src/assertion/assertIsFunction.ts b/src/assertion/assertIsFunction.ts index 65411b0..e1dab1c 100644 --- a/src/assertion/assertIsFunction.ts +++ b/src/assertion/assertIsFunction.ts @@ -2,6 +2,15 @@ import { isFunction } from '../predicate/isFunction.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a function. + * + * @example + * ```ts + * assertIsFunction(() => {}); // does not throw + * assertIsFunction(42); // throws TypeError: input is not a function + * ``` + */ export function assertIsFunction( input: unknown, error: string | Error = 'input is not a function', diff --git a/src/assertion/assertIsInt32.ts b/src/assertion/assertIsInt32.ts index 2f42f1a..a8c5487 100644 --- a/src/assertion/assertIsInt32.ts +++ b/src/assertion/assertIsInt32.ts @@ -4,6 +4,15 @@ import { getError } from './getError.js'; import type { Int32 } from '../types/numbers.js'; +/** + * Assert that `input` is a 32-bit integer. + * + * @example + * ```ts + * assertIsInt32(42); // does not throw + * assertIsInt32(2 ** 31); // throws TypeError: input is not an Int32 + * ``` + */ export function assertIsInt32(input: unknown, error: string | Error = 'input is not an Int32'): asserts input is Int32 { if (!isInt32(input)) { throw getError(error); diff --git a/src/assertion/assertIsIntString.ts b/src/assertion/assertIsIntString.ts index d5bdda5..3ea5098 100644 --- a/src/assertion/assertIsIntString.ts +++ b/src/assertion/assertIsIntString.ts @@ -4,6 +4,15 @@ import { getError } from './getError.js'; import type { NumericString } from '../types/common.js'; +/** + * Assert that `input` is a string representing an integer. + * + * @example + * ```ts + * assertIsIntString('42'); // does not throw + * assertIsIntString('42.5'); // throws TypeError: input is not an integer string + * ``` + */ export function assertIsIntString( input: unknown, error: string | Error = 'input is not an integer string', diff --git a/src/assertion/assertIsInteger.ts b/src/assertion/assertIsInteger.ts index d3a282b..0c4d0d9 100644 --- a/src/assertion/assertIsInteger.ts +++ b/src/assertion/assertIsInteger.ts @@ -2,6 +2,15 @@ import { isInteger } from '../predicate/isInteger.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an integer. + * + * @example + * ```ts + * assertIsInteger(42); // does not throw + * assertIsInteger(42.5); // throws TypeError: input is not an integer + * ``` + */ export function assertIsInteger( input: unknown, error: string | Error = 'input is not an integer', diff --git a/src/assertion/assertIsIterable.ts b/src/assertion/assertIsIterable.ts index f2a96ba..4342655 100644 --- a/src/assertion/assertIsIterable.ts +++ b/src/assertion/assertIsIterable.ts @@ -2,6 +2,15 @@ import { isIterable } from '../predicate/isIterable.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an `Iterable`. + * + * @example + * ```ts + * assertIsIterable([1, 2, 3]); // does not throw + * assertIsIterable(42); // throws TypeError: input is not an Iterable + * ``` + */ export function assertIsIterable( input: unknown, error: string | Error = 'input is not an Iterable', diff --git a/src/assertion/assertIsLengthAware.ts b/src/assertion/assertIsLengthAware.ts index dd48750..b3b1fb5 100644 --- a/src/assertion/assertIsLengthAware.ts +++ b/src/assertion/assertIsLengthAware.ts @@ -2,6 +2,15 @@ import { isLengthAware } from '../predicate/isLengthAware.js'; import { getError } from './getError.js'; +/** + * Assert that `input` has a numeric `length` property. + * + * @example + * ```ts + * assertIsLengthAware('hello'); // does not throw, strings have a numeric length + * assertIsLengthAware(42); // throws TypeError: input is not length aware + * ``` + */ export function assertIsLengthAware( input: unknown, error: string | Error = 'input is not length aware', diff --git a/src/assertion/assertIsNull.ts b/src/assertion/assertIsNull.ts index 9f8cac9..b4329b4 100644 --- a/src/assertion/assertIsNull.ts +++ b/src/assertion/assertIsNull.ts @@ -2,6 +2,15 @@ import { isNull } from '../predicate/isNull.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is `null`. + * + * @example + * ```ts + * assertIsNull(null); // does not throw + * assertIsNull(undefined); // throws TypeError: input is not null + * ``` + */ export function assertIsNull(input: unknown, error: string | Error = 'input is not null'): asserts input is null { if (!isNull(input)) { throw getError(error); diff --git a/src/assertion/assertIsNullArray.ts b/src/assertion/assertIsNullArray.ts index 95d1d61..76bd5ab 100644 --- a/src/assertion/assertIsNullArray.ts +++ b/src/assertion/assertIsNullArray.ts @@ -2,6 +2,15 @@ import { isNullArray } from '../predicate/isNullArray.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an array of `null` values. + * + * @example + * ```ts + * assertIsNullArray([null, null]); // does not throw + * assertIsNullArray([null, undefined]); // throws TypeError: input is not an array of null + * ``` + */ export function assertIsNullArray( input: unknown, error: string | Error = 'input is not an array of null', diff --git a/src/assertion/assertIsNumber.ts b/src/assertion/assertIsNumber.ts index d0f2d93..0f0f53f 100644 --- a/src/assertion/assertIsNumber.ts +++ b/src/assertion/assertIsNumber.ts @@ -2,6 +2,15 @@ import { isNumber } from '../predicate/isNumber.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a number. + * + * @example + * ```ts + * assertIsNumber(42); // does not throw + * assertIsNumber('42'); // throws TypeError: input is not a number + * ``` + */ export function assertIsNumber( input: unknown, error: string | Error = 'input is not a number', diff --git a/src/assertion/assertIsNumberArray.ts b/src/assertion/assertIsNumberArray.ts index cfa666e..0b93243 100644 --- a/src/assertion/assertIsNumberArray.ts +++ b/src/assertion/assertIsNumberArray.ts @@ -2,6 +2,15 @@ import { isNumberArray } from '../predicate/isNumberArray.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an array of numbers. + * + * @example + * ```ts + * assertIsNumberArray([1, 2, 3]); // does not throw + * assertIsNumberArray([1, '2', 3]); // throws TypeError: input is not an array of number + * ``` + */ export function assertIsNumberArray( input: unknown, error: string | Error = 'input is not an array of number', diff --git a/src/assertion/assertIsNumberGTEOne.ts b/src/assertion/assertIsNumberGTEOne.ts index 4d73ff8..eea1762 100644 --- a/src/assertion/assertIsNumberGTEOne.ts +++ b/src/assertion/assertIsNumberGTEOne.ts @@ -2,6 +2,15 @@ import { isPositiveFiniteNumber } from '../predicate/isPositiveFiniteNumber.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a finite number greater than or equal to 1. + * + * @example + * ```ts + * assertIsNumberGTEOne(1); // does not throw + * assertIsNumberGTEOne(0.5); // throws TypeError: input is not a number >= 1 + * ``` + */ export function assertIsNumberGTEOne( input: unknown, error: string | Error = 'input is not a number >= 1', diff --git a/src/assertion/assertIsNumericString.ts b/src/assertion/assertIsNumericString.ts index b207a66..d6b5e35 100644 --- a/src/assertion/assertIsNumericString.ts +++ b/src/assertion/assertIsNumericString.ts @@ -4,6 +4,15 @@ import { getError } from './getError.js'; import type { NumericString } from '../types/common.js'; +/** + * Assert that `input` is a string representing a numeric value. + * + * @example + * ```ts + * assertIsNumericString('3.14'); // does not throw + * assertIsNumericString('abc'); // throws TypeError: input is not a numeric string + * ``` + */ export function assertIsNumericString( input: unknown, error: string | Error = 'input is not a numeric string', diff --git a/src/assertion/assertIsNumericValue.ts b/src/assertion/assertIsNumericValue.ts index c0d9586..a9eff7f 100644 --- a/src/assertion/assertIsNumericValue.ts +++ b/src/assertion/assertIsNumericValue.ts @@ -4,6 +4,17 @@ import { getError } from './getError.js'; import type { NumericValue } from '../types/common.js'; +/** + * Assert that `input` is a number, bigint, or numeric string. + * + * @example + * ```ts + * assertIsNumericValue(42); // does not throw + * assertIsNumericValue('42'); // does not throw + * assertIsNumericValue(42n); // does not throw + * assertIsNumericValue('abc'); // throws TypeError: input is not a numerical value + * ``` + */ export function assertIsNumericValue( input: unknown, error: string | Error = 'input is not a numerical value', diff --git a/src/assertion/assertIsNumericValueArray.ts b/src/assertion/assertIsNumericValueArray.ts index 90345f0..4710789 100644 --- a/src/assertion/assertIsNumericValueArray.ts +++ b/src/assertion/assertIsNumericValueArray.ts @@ -4,6 +4,15 @@ import { getError } from './getError.js'; import type { NumericValue } from '../types/common.js'; +/** + * Assert that `input` is an array of numbers, bigints, or numeric strings. + * + * @example + * ```ts + * assertIsNumericValueArray([1, '2', 3n]); // does not throw + * assertIsNumericValueArray([1, 'abc']); // throws TypeError: input is not a numerical value array + * ``` + */ export function assertIsNumericValueArray( input: unknown, error: string | Error = 'input is not a numerical value array', diff --git a/src/assertion/assertIsObject.ts b/src/assertion/assertIsObject.ts index 307cd03..cd30e0e 100644 --- a/src/assertion/assertIsObject.ts +++ b/src/assertion/assertIsObject.ts @@ -4,6 +4,16 @@ import { getError } from './getError.js'; import type { UnknownRecord } from '../types/records.js'; +/** + * Assert that `input` is an object. + * + * @example + * ```ts + * assertIsObject({ a: 1 }); // does not throw + * assertIsObject(null); // throws TypeError: input is not an object + * assertIsObject([1, 2, 3]); // throws TypeError: input is not an object + * ``` + */ export function assertIsObject( input: unknown, error: string | Error = 'input is not an object', diff --git a/src/assertion/assertIsOptionalBigInt.ts b/src/assertion/assertIsOptionalBigInt.ts index 977d504..4a81f64 100644 --- a/src/assertion/assertIsOptionalBigInt.ts +++ b/src/assertion/assertIsOptionalBigInt.ts @@ -2,6 +2,16 @@ import { isOptionalBigInt } from '../predicate/isOptionalBigInt.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a `bigint` or `undefined`. + * + * @example + * ```ts + * assertIsOptionalBigInt(10n); // does not throw + * assertIsOptionalBigInt(undefined); // does not throw + * assertIsOptionalBigInt(10); // throws TypeError: input is not an optional bigint + * ``` + */ export function assertIsOptionalBigInt( input: unknown, error: string | Error = 'input is not an optional bigint', diff --git a/src/assertion/assertIsOptionalBoolean.ts b/src/assertion/assertIsOptionalBoolean.ts index 23d5a89..2d110d4 100644 --- a/src/assertion/assertIsOptionalBoolean.ts +++ b/src/assertion/assertIsOptionalBoolean.ts @@ -2,6 +2,16 @@ import { isOptionalBoolean } from '../predicate/isOptionalBoolean.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a boolean or `undefined`. + * + * @example + * ```ts + * assertIsOptionalBoolean(true); // does not throw + * assertIsOptionalBoolean(undefined); // does not throw + * assertIsOptionalBoolean('true'); // throws TypeError: input is not an optional boolean + * ``` + */ export function assertIsOptionalBoolean( input: unknown, error: string | Error = 'input is not an optional boolean', diff --git a/src/assertion/assertIsOptionalNull.ts b/src/assertion/assertIsOptionalNull.ts index b7120e9..e763290 100644 --- a/src/assertion/assertIsOptionalNull.ts +++ b/src/assertion/assertIsOptionalNull.ts @@ -2,6 +2,16 @@ import { isOptionalNull } from '../predicate/isOptionalNull.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is `null` or `undefined`. + * + * @example + * ```ts + * assertIsOptionalNull(null); // does not throw + * assertIsOptionalNull(undefined); // does not throw + * assertIsOptionalNull(0); // throws TypeError: input is not an optional null + * ``` + */ export function assertIsOptionalNull( input: unknown, error: string | Error = 'input is not an optional null', diff --git a/src/assertion/assertIsOptionalNumber.ts b/src/assertion/assertIsOptionalNumber.ts index e7b81a9..b745f09 100644 --- a/src/assertion/assertIsOptionalNumber.ts +++ b/src/assertion/assertIsOptionalNumber.ts @@ -2,6 +2,16 @@ import { isOptionalNumber } from '../predicate/isOptionalNumber.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a number or `undefined`. + * + * @example + * ```ts + * assertIsOptionalNumber(42); // does not throw + * assertIsOptionalNumber(undefined); // does not throw + * assertIsOptionalNumber('42'); // throws TypeError: input is not an optional number + * ``` + */ export function assertIsOptionalNumber( input: unknown, error: string | Error = 'input is not an optional number', diff --git a/src/assertion/assertIsOptionalString.ts b/src/assertion/assertIsOptionalString.ts index c567a4b..a033065 100644 --- a/src/assertion/assertIsOptionalString.ts +++ b/src/assertion/assertIsOptionalString.ts @@ -2,6 +2,16 @@ import { isOptionalString } from '../predicate/isOptionalString.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a string or `undefined`. + * + * @example + * ```ts + * assertIsOptionalString('hello'); // does not throw + * assertIsOptionalString(undefined); // does not throw + * assertIsOptionalString(42); // throws TypeError: input is not an optional string + * ``` + */ export function assertIsOptionalString( input: unknown, error: string | Error = 'input is not an optional string', diff --git a/src/assertion/assertIsOptionalSymbol.ts b/src/assertion/assertIsOptionalSymbol.ts index f3a6c16..1a0d0af 100644 --- a/src/assertion/assertIsOptionalSymbol.ts +++ b/src/assertion/assertIsOptionalSymbol.ts @@ -2,6 +2,16 @@ import { isOptionalSymbol } from '../predicate/isOptionalSymbol.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a symbol or `undefined`. + * + * @example + * ```ts + * assertIsOptionalSymbol(Symbol('id')); // does not throw + * assertIsOptionalSymbol(undefined); // does not throw + * assertIsOptionalSymbol('id'); // throws TypeError: input is not an optional symbol + * ``` + */ export function assertIsOptionalSymbol( input: unknown, error: string | Error = 'input is not an optional symbol', diff --git a/src/assertion/assertIsPositiveFiniteNumber.ts b/src/assertion/assertIsPositiveFiniteNumber.ts index 982dfd5..005e0b4 100644 --- a/src/assertion/assertIsPositiveFiniteNumber.ts +++ b/src/assertion/assertIsPositiveFiniteNumber.ts @@ -2,6 +2,15 @@ import { isPositiveFiniteNumber } from '../predicate/isPositiveFiniteNumber.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a positive, finite number. + * + * @example + * ```ts + * assertIsPositiveFiniteNumber(42); // does not throw + * assertIsPositiveFiniteNumber(-1); // throws TypeError: input is not a positive finite number + * ``` + */ export function assertIsPositiveFiniteNumber( input: unknown, error: string | Error = 'input is not a positive finite number', diff --git a/src/assertion/assertIsPositiveInteger.ts b/src/assertion/assertIsPositiveInteger.ts index 02f07c8..4fe342b 100644 --- a/src/assertion/assertIsPositiveInteger.ts +++ b/src/assertion/assertIsPositiveInteger.ts @@ -2,6 +2,15 @@ import { isPositiveInteger } from '../predicate/isPositiveInteger.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a positive integer. + * + * @example + * ```ts + * assertIsPositiveInteger(42); // does not throw + * assertIsPositiveInteger(-1); // throws TypeError: input is not a positive integer + * ``` + */ export function assertIsPositiveInteger( input: unknown, error: string | Error = 'input is not a positive integer', diff --git a/src/assertion/assertIsPrimitive.ts b/src/assertion/assertIsPrimitive.ts index 3aee408..23ee5ab 100644 --- a/src/assertion/assertIsPrimitive.ts +++ b/src/assertion/assertIsPrimitive.ts @@ -4,6 +4,15 @@ import { getError } from './getError.js'; import type { Primitive } from '../types/common.js'; +/** + * Assert that `input` is a primitive value. + * + * @example + * ```ts + * assertIsPrimitive('hello'); // does not throw + * assertIsPrimitive({}); // throws TypeError: input is not primitive + * ``` + */ export function assertIsPrimitive( input: unknown, error: string | Error = 'input is not primitive', diff --git a/src/assertion/assertIsPromiseFulfilledResult.ts b/src/assertion/assertIsPromiseFulfilledResult.ts index 76125df..6c500fc 100644 --- a/src/assertion/assertIsPromiseFulfilledResult.ts +++ b/src/assertion/assertIsPromiseFulfilledResult.ts @@ -2,6 +2,17 @@ import { isPromiseFulfilledResult } from '../predicate/isPromiseFulfilledResult. import { getError } from './getError.js'; +/** + * Assert that `input` is a fulfilled `Promise` result. + * + * @example + * ```ts + * const [result] = await Promise.allSettled([Promise.resolve(42)]); + * + * assertIsPromiseFulfilledResult(result); // does not throw + * assertIsPromiseFulfilledResult({ status: 'rejected' }); // throws TypeError: input is not a promise fulfilled result + * ``` + */ export function assertIsPromiseFulfilledResult( input: unknown, error: string | Error = 'input is not a promise fulfilled result', diff --git a/src/assertion/assertIsPromiseRejectedResult.ts b/src/assertion/assertIsPromiseRejectedResult.ts index fc223a5..8d2fcec 100644 --- a/src/assertion/assertIsPromiseRejectedResult.ts +++ b/src/assertion/assertIsPromiseRejectedResult.ts @@ -2,6 +2,17 @@ import { isPromiseRejectedResult } from '../predicate/isPromiseRejectedResult.js import { getError } from './getError.js'; +/** + * Assert that `input` is a rejected `Promise` result. + * + * @example + * ```ts + * const [result] = await Promise.allSettled([Promise.reject(new Error('fail'))]); + * + * assertIsPromiseRejectedResult(result); // does not throw + * assertIsPromiseRejectedResult({ status: 'fulfilled' }); // throws TypeError: input is not a promise rejected result + * ``` + */ export function assertIsPromiseRejectedResult( input: unknown, error: string | Error = 'input is not a promise rejected result', diff --git a/src/assertion/assertIsPropertyKey.ts b/src/assertion/assertIsPropertyKey.ts index 923f6ea..c8895b0 100644 --- a/src/assertion/assertIsPropertyKey.ts +++ b/src/assertion/assertIsPropertyKey.ts @@ -2,6 +2,17 @@ import { isPropertyKey } from '../predicate/isPropertyKey.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a valid property key: a string, number, or symbol. + * + * @example + * ```ts + * assertIsPropertyKey('key'); // does not throw + * assertIsPropertyKey(42); // does not throw + * assertIsPropertyKey(Symbol('key')); // does not throw + * assertIsPropertyKey({}); // throws TypeError: input is not a property key + * ``` + */ export function assertIsPropertyKey( input: unknown, error: string | Error = 'input is not a property key', diff --git a/src/assertion/assertIsSafeInteger.ts b/src/assertion/assertIsSafeInteger.ts index 41fd437..8d2d8a9 100644 --- a/src/assertion/assertIsSafeInteger.ts +++ b/src/assertion/assertIsSafeInteger.ts @@ -2,6 +2,15 @@ import { isSafeInteger } from '../predicate/isSafeInteger.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a safe integer. + * + * @example + * ```ts + * assertIsSafeInteger(42); // does not throw + * assertIsSafeInteger(2 ** 53); // throws TypeError: input is not a safe integer + * ``` + */ export function assertIsSafeInteger( input: unknown, error: string | Error = 'input is not a safe integer', diff --git a/src/assertion/assertIsSizeAware.ts b/src/assertion/assertIsSizeAware.ts index 9fa4fef..9247e0b 100644 --- a/src/assertion/assertIsSizeAware.ts +++ b/src/assertion/assertIsSizeAware.ts @@ -2,6 +2,15 @@ import { isSizeAware } from '../predicate/isSizeAware.js'; import { getError } from './getError.js'; +/** + * Assert that `input` has a numeric `size` property. + * + * @example + * ```ts + * assertIsSizeAware(new Set([1, 2, 3])); // does not throw + * assertIsSizeAware(42); // throws TypeError: input is not size aware + * ``` + */ export function assertIsSizeAware( input: unknown, error: string | Error = 'input is not size aware', diff --git a/src/assertion/assertIsString.ts b/src/assertion/assertIsString.ts index 9f2651d..77d64ca 100644 --- a/src/assertion/assertIsString.ts +++ b/src/assertion/assertIsString.ts @@ -2,6 +2,15 @@ import { isString } from '../predicate/isString.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a string. + * + * @example + * ```ts + * assertIsString('hello'); // does not throw + * assertIsString(42); // throws TypeError: input is not a string + * ``` + */ export function assertIsString( input: unknown, error: string | Error = 'input is not a string', diff --git a/src/assertion/assertIsStringArray.ts b/src/assertion/assertIsStringArray.ts index 0c7bb17..d2dd98f 100644 --- a/src/assertion/assertIsStringArray.ts +++ b/src/assertion/assertIsStringArray.ts @@ -2,6 +2,15 @@ import { isStringArray } from '../predicate/isStringArray.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an array of strings. + * + * @example + * ```ts + * assertIsStringArray(['a', 'b']); // does not throw + * assertIsStringArray(['a', 42]); // throws TypeError: input is not an array of string + * ``` + */ export function assertIsStringArray( input: unknown, error: string | Error = 'input is not an array of string', diff --git a/src/assertion/assertIsStringMatching.ts b/src/assertion/assertIsStringMatching.ts index 4d5e600..2e47036 100644 --- a/src/assertion/assertIsStringMatching.ts +++ b/src/assertion/assertIsStringMatching.ts @@ -2,6 +2,15 @@ import { matching } from '../predicate/factory/matching.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a string that matches the given `pattern`. + * + * @example + * ```ts + * assertIsStringMatching('hello', /^h/); // does not throw + * assertIsStringMatching('world', /^h/); // throws TypeError: input is not a string that matches the pattern + * ``` + */ export function assertIsStringMatching( input: unknown, pattern: RegExp, diff --git a/src/assertion/assertIsStringRecord.ts b/src/assertion/assertIsStringRecord.ts index 47a3682..6ae3384 100644 --- a/src/assertion/assertIsStringRecord.ts +++ b/src/assertion/assertIsStringRecord.ts @@ -4,6 +4,15 @@ import { getError } from './getError.js'; import type { StringRecord } from '../types/records.js'; +/** + * Assert that `input` is an object whose own properties all have string values. + * + * @example + * ```ts + * assertIsStringRecord({ a: '1', b: '2' }); // does not throw + * assertIsStringRecord({ a: 1 }); // throws TypeError: input is not a string record + * ``` + */ export function assertIsStringRecord( input: unknown, error: string | Error = 'input is not a string record', diff --git a/src/assertion/assertIsStringWithLength.ts b/src/assertion/assertIsStringWithLength.ts index d04c0ed..4315afc 100644 --- a/src/assertion/assertIsStringWithLength.ts +++ b/src/assertion/assertIsStringWithLength.ts @@ -2,6 +2,15 @@ import { isStringWithLength } from '../predicate/isStringWithLength.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a non-empty string. + * + * @example + * ```ts + * assertIsStringWithLength('hello'); // does not throw + * assertIsStringWithLength(''); // throws TypeError: input is not a string with length + * ``` + */ export function assertIsStringWithLength( input: unknown, error: string | Error = 'input is not a string with length', diff --git a/src/assertion/assertIsSymbol.ts b/src/assertion/assertIsSymbol.ts index 1199639..9f26084 100644 --- a/src/assertion/assertIsSymbol.ts +++ b/src/assertion/assertIsSymbol.ts @@ -2,6 +2,15 @@ import { isSymbol } from '../predicate/isSymbol.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is a symbol. + * + * @example + * ```ts + * assertIsSymbol(Symbol('id')); // does not throw + * assertIsSymbol('id'); // throws TypeError: input is not a symbol + * ``` + */ export function assertIsSymbol( input: unknown, error: string | Error = 'input is not a symbol', diff --git a/src/assertion/assertIsSymbolArray.ts b/src/assertion/assertIsSymbolArray.ts index 924f862..e3cb9e9 100644 --- a/src/assertion/assertIsSymbolArray.ts +++ b/src/assertion/assertIsSymbolArray.ts @@ -2,6 +2,15 @@ import { isSymbolArray } from '../predicate/isSymbolArray.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an array of symbols. + * + * @example + * ```ts + * assertIsSymbolArray([Symbol('a'), Symbol('b')]); // does not throw + * assertIsSymbolArray([Symbol('a'), 'b']); // throws TypeError: input is not an array of symbol + * ``` + */ export function assertIsSymbolArray( input: unknown, error: string | Error = 'input is not an array of symbol', diff --git a/src/assertion/assertIsUndefined.ts b/src/assertion/assertIsUndefined.ts index e6e2317..742cf15 100644 --- a/src/assertion/assertIsUndefined.ts +++ b/src/assertion/assertIsUndefined.ts @@ -2,6 +2,15 @@ import { isUndefined } from '../predicate/isUndefined.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is `undefined`. + * + * @example + * ```ts + * assertIsUndefined(undefined); // does not throw + * assertIsUndefined(null); // throws TypeError: input is not undefined + * ``` + */ export function assertIsUndefined( input: unknown, error: string | Error = 'input is not undefined', diff --git a/src/assertion/assertIsUndefinedArray.ts b/src/assertion/assertIsUndefinedArray.ts index 6a22bf1..86a9fd9 100644 --- a/src/assertion/assertIsUndefinedArray.ts +++ b/src/assertion/assertIsUndefinedArray.ts @@ -2,6 +2,15 @@ import { isUndefinedArray } from '../predicate/isUndefinedArray.js'; import { getError } from './getError.js'; +/** + * Assert that `input` is an array of `undefined` values. + * + * @example + * ```ts + * assertIsUndefinedArray([undefined, undefined]); // does not throw + * assertIsUndefinedArray([undefined, null]); // throws TypeError: input is not an array of undefined + * ``` + */ export function assertIsUndefinedArray( input: unknown, error: string | Error = 'input is not an array of undefined', diff --git a/src/assertion/assertPathExists.ts b/src/assertion/assertPathExists.ts index d3e0fe9..9219ba1 100644 --- a/src/assertion/assertPathExists.ts +++ b/src/assertion/assertPathExists.ts @@ -15,6 +15,18 @@ export function assertPathExists, ): asserts input is Input & WithPath; +/** + * Assert that `path` exists on `input`, optionally checking the value at that path with `predicate`. + * + * @example + * ```ts + * const input = { a: { b: 1 } }; + * + * assertPathExists(input, 'a.b'); // does not throw + * assertPathExists(input, 'a.b', (value): value is number => typeof value === 'number'); // does not throw + * assertPathExists(input, 'c'); // throws Error: object path (c) does not exist on input + * ``` + */ export function assertPathExists( input: Input, path: InputPath, diff --git a/src/assertion/assertPredicate.ts b/src/assertion/assertPredicate.ts index e4651f5..4ebe005 100644 --- a/src/assertion/assertPredicate.ts +++ b/src/assertion/assertPredicate.ts @@ -4,6 +4,17 @@ import type { TypePredicateFn } from '../types/functions.js'; export type ErrorFactory = (input: unknown) => Error; +/** + * Assert that `input` satisfies the given `predicate`. + * + * @example + * ```ts + * const isNumber = (value: unknown): value is number => typeof value === 'number'; + * + * assertPredicate(42, isNumber); // does not throw + * assertPredicate('42', isNumber); // throws TypeError: invalid input + * ``` + */ export function assertPredicate( input: unknown, predicate: TypePredicateFn, diff --git a/src/assertion/getError.ts b/src/assertion/getError.ts index e279288..d2bb369 100644 --- a/src/assertion/getError.ts +++ b/src/assertion/getError.ts @@ -1,3 +1,12 @@ +/** + * Get an `Error` instance from `error`, wrapping a string in a `TypeError`. + * + * @example + * ```ts + * getError('Something went wrong'); // returns new TypeError('Something went wrong') + * getError(new RangeError('Out of range')); // returns the same RangeError instance + * ``` + */ export function getError(error: string | Error): Error { return error instanceof Error ? error : new TypeError(error); } diff --git a/src/capitalize.ts b/src/capitalize.ts index eb475fc..81c10bf 100644 --- a/src/capitalize.ts +++ b/src/capitalize.ts @@ -1,2 +1,10 @@ -export const capitalize = (word: Type): Capitalize => +/** + * Capitalize the first letter of `word`. + * + * @example + * ```ts + * capitalize('hello'); // 'Hello' + * ``` + */ +export const capitalize = (word: Type): Capitalize => (word.substring(0, 1).toUpperCase() + word.substring(1)) as Capitalize; diff --git a/src/cartesian.ts b/src/cartesian.ts index 1161890..fe166dd 100644 --- a/src/cartesian.ts +++ b/src/cartesian.ts @@ -1,5 +1,12 @@ /** - * @see https://en.wikipedia.org/wiki/Cartesian_product + * Lazily yield the Cartesian product of the given arrays. + * + * @see {@link https://en.wikipedia.org/wiki/Cartesian_product} + * + * @example + * ```ts + * [...cartesian([1, 2], ['a', 'b'])]; // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']] + * ``` */ export function* cartesian(...input: T[][]): Generator { const [head, ...tail] = input; diff --git a/src/chunk.ts b/src/chunk.ts index 219e9a2..1e74f1a 100644 --- a/src/chunk.ts +++ b/src/chunk.ts @@ -1,3 +1,11 @@ +/** + * Split `items` into consecutive chunks of at most `chunkSize` items each. + * + * @example + * ```ts + * [...chunk([1, 2, 3, 4, 5], 2)]; // [[1, 2], [3, 4], [5]] + * ``` + */ export function* chunk(items: T[], chunkSize: number): Generator { if (!Number.isSafeInteger(chunkSize) || chunkSize <= 0) { throw new RangeError('Chunk size must be an integer greater than 0'); diff --git a/src/clamp.ts b/src/clamp.ts index d0ba983..085bf60 100644 --- a/src/clamp.ts +++ b/src/clamp.ts @@ -3,6 +3,15 @@ import { getMinValue } from './getMinValue.js'; import type { NumericValue } from './types/common.js'; +/** + * Clamp `value` so it falls between `min` and `max`. + * + * @example + * ```ts + * clamp(0, 15, 10); // 10 + * clamp(0, -5, 10); // 0 + * ``` + */ export function clamp(min: T, value: T, max: T): T { return getMaxValue(min, getMinValue(value, max)); } diff --git a/src/combinations.ts b/src/combinations.ts index d7c3d18..784e531 100644 --- a/src/combinations.ts +++ b/src/combinations.ts @@ -14,6 +14,14 @@ export type CombinationsInput = { export type CombinationsOutput> = Input extends CombinationsInput ? Type : never; +/** + * Generate every combination of `input`'s property values, recursing into nested objects. + * + * @example + * ```ts + * [...combinations({ a: [1, 2], b: 'x' })]; // [{ a: 1, b: 'x' }, { a: 2, b: 'x' }] + * ``` + */ export function* combinations< Type extends object = object, Input extends CombinationsInput = CombinationsInput, diff --git a/src/comment.ts b/src/comment.ts index 9fdf0ad..ef0c318 100644 --- a/src/comment.ts +++ b/src/comment.ts @@ -16,6 +16,9 @@ export type CommentOptions = { type?: CommentType | `${CommentType}`; } & Partial; +/** + * @internal + */ function getCommentParts(type: CommentType | `${CommentType}`): CommentParts { return { [CommentType.Block]: { @@ -45,6 +48,14 @@ function getCommentParts(type: CommentType | `${CommentType}`): CommentParts { }[type]; } +/** + * Wrap `text` in a comment of the given `type`. + * + * @example + * ```ts + * comment('Hello\nWorld'); // '/**\n * Hello\n * World\n *\/' + * ``` + */ export function comment(text: string, options?: CommentOptions): string { if (!text) { return ''; diff --git a/src/compose.ts b/src/compose.ts index 63b8324..c069543 100644 --- a/src/compose.ts +++ b/src/compose.ts @@ -1,5 +1,16 @@ export type ComposeFn = ((data: T) => R) | ((data: T, ...args: A) => R); +/** + * Compose `functions` into a single function that pipes data through each of them in order. + * + * @example + * ```ts + * const addOne = (n: number) => n + 1; + * const double = (n: number) => n * 2; + * + * compose(addOne, double)(3); // 8 + * ``` + */ export function compose(...functions: ComposeFn[]): ComposeFn { return functions.reduce>( (prev, next) => diff --git a/src/convert.ts b/src/convert.ts index 7d72d24..148a817 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -13,6 +13,14 @@ export type ConvertRecord = { export type AnyConverter = ConvertRecord | ConvertFn; +/** + * Convert `input` using `converter`, which may be a function or a record of nested converters. + * + * @example + * ```ts + * convert({ name: 'Andy' }, { greeting: (data) => `Hi, ${data.name}` }); // { greeting: 'Hi, Andy' } + * ``` + */ export const convert = (input: Readonly, converter: AnyConverter): Output => { if (typeof converter === 'function') { return converter(input); diff --git a/src/countCharCode.ts b/src/countCharCode.ts index 04ea186..a3a87f8 100644 --- a/src/countCharCode.ts +++ b/src/countCharCode.ts @@ -1,3 +1,11 @@ +/** + * Count how many times `charCode` occurs in `input`. + * + * @example + * ```ts + * countCharCode('hello', 'l'.charCodeAt(0)); // 2 + * ``` + */ export function countCharCode(input: string, charCode: number): number { let count = 0; diff --git a/src/countCharacter.ts b/src/countCharacter.ts index 098cd52..21c2680 100644 --- a/src/countCharacter.ts +++ b/src/countCharacter.ts @@ -1,5 +1,13 @@ import { countCharCode } from './countCharCode.js'; +/** + * Count how many times `char` occurs in `input`. + * + * @example + * ```ts + * countCharacter('hello', 'l'); // 2 + * ``` + */ export function countCharacter(input: string, char: string): number { if (char.length !== 1) { throw new Error('Expected a single character'); diff --git a/src/counter.ts b/src/counter.ts index 7a0d013..dfd66e2 100644 --- a/src/counter.ts +++ b/src/counter.ts @@ -1,3 +1,11 @@ +/** + * Generate a sequence of numbers from `start` to `end`, incrementing by `step` each time. + * + * @example + * ```ts + * [...counter(1, 5)]; // [1, 2, 3, 4, 5] + * ``` + */ export function* counter(start = 0, end = Infinity, step = 1): Generator { if (step === 0) { throw new TypeError('step cannot be zero'); diff --git a/src/deepDecodeURI.ts b/src/deepDecodeURI.ts index 81f2784..d991500 100644 --- a/src/deepDecodeURI.ts +++ b/src/deepDecodeURI.ts @@ -1,3 +1,11 @@ +/** + * Repeatedly decode `uri` until decoding it no longer changes the value. + * + * @example + * ```ts + * deepDecodeURI('%2520'); // ' ' + * ``` + */ export function deepDecodeURI(uri: string): string { if (!uri.length) { return uri; diff --git a/src/deepFreeze.ts b/src/deepFreeze.ts index 4cb8265..b5006ee 100644 --- a/src/deepFreeze.ts +++ b/src/deepFreeze.ts @@ -9,7 +9,15 @@ export type DeepFreezeOptions = { /** * Deep freeze an object or array. * - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze} + * + * @example + * ```ts + * const frozen = deepFreeze({ nested: { value: 1 } }); + * + * Object.isFrozen(frozen); // true + * Object.isFrozen(frozen.nested); // true + * ``` */ export function deepFreeze( input: Input, diff --git a/src/delay.ts b/src/delay.ts index 5b51a37..6bc1355 100644 --- a/src/delay.ts +++ b/src/delay.ts @@ -12,6 +12,12 @@ export function delay(milliseconds: number, value: T, signal?: AbortSignal): * The `ms` value can be between zero and the max delay value for `setTimeout()`, which is `2 ** 31 - 1`. * * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value} + * + * @example + * ```ts + * await delay(1000); // resolves with `undefined` after 1 second + * await delay(1000, 'done'); // resolves with 'done' after 1 second + * ``` */ export function delay(milliseconds: number, value?: T, signal?: AbortSignal): Promise { return new Promise((resolve, reject) => { diff --git a/src/delayAnimationFrame.ts b/src/delayAnimationFrame.ts index 41f812d..dd3be63 100644 --- a/src/delayAnimationFrame.ts +++ b/src/delayAnimationFrame.ts @@ -2,6 +2,15 @@ export function delayAnimationFrame(): Promise; export function delayAnimationFrame(value: T): Promise; +/** + * Return a Promise that resolves with `value` on the next animation frame. + * + * @example + * ```ts + * await delayAnimationFrame(); // resolves with `undefined` on the next animation frame + * await delayAnimationFrame('done'); // resolves with 'done' on the next animation frame + * ``` + */ export function delayAnimationFrame(value?: T): Promise { return new Promise((resolve) => { window.requestAnimationFrame(() => resolve(value)); diff --git a/src/delayAnimationFrames.ts b/src/delayAnimationFrames.ts index b05188d..f9568af 100644 --- a/src/delayAnimationFrames.ts +++ b/src/delayAnimationFrames.ts @@ -2,6 +2,15 @@ export function delayAnimationFrames(frames: number): Promise; export function delayAnimationFrames(frames: number, value: T): Promise; +/** + * Return a Promise that resolves with `value` after the given number of animation `frames` have elapsed. + * + * @example + * ```ts + * await delayAnimationFrames(5); // resolves with `undefined` after 5 animation frames + * await delayAnimationFrames(5, 'done'); // resolves with 'done' after 5 animation frames + * ``` + */ export function delayAnimationFrames(frames: number, value?: T): Promise { return new Promise((resolve, reject) => { if (!Number.isInteger(frames) || frames < 1) { diff --git a/src/describeInput.ts b/src/describeInput.ts index fe4d9c8..7e6e191 100644 --- a/src/describeInput.ts +++ b/src/describeInput.ts @@ -2,6 +2,16 @@ import { getType } from './getType.js'; import { looksLikeURL } from './looksLikeURL.js'; import { isNumericString } from './predicate/isNumericString.js'; +/** + * Describe `input` with a short, human-readable label based on its type and shape. + * + * @example + * ```ts + * describeInput(true); // 'true' + * describeInput('https://example.com'); // 'https URL' + * describeInput(42); // 'Safe Integer' + * ``` + */ export const describeInput = (input: unknown): string => { switch (typeof input) { case 'boolean': diff --git a/src/escapeRegExp.ts b/src/escapeRegExp.ts index 53ca09d..8c16670 100644 --- a/src/escapeRegExp.ts +++ b/src/escapeRegExp.ts @@ -1,5 +1,13 @@ const pattern = /[.*+?^${}()|[\]\\]/g; +/** + * Escape RegExp special characters in `input`. + * + * @example + * ```ts + * escapeRegExp('a.b*c'); // 'a\\.b\\*c' + * ``` + */ export function escapeRegExp(input: string): string { return input.length ? input.replace(pattern, '\\$&') : input; } diff --git a/src/findIndentation.ts b/src/findIndentation.ts index b45d13b..32e0a5f 100644 --- a/src/findIndentation.ts +++ b/src/findIndentation.ts @@ -2,6 +2,11 @@ import { INDENT_CHAR_RAW_PATTERN, NEWLINE_RAW_PATTERN } from './constants.js'; /** * Find indentation on first line that isn't whitespace only. + * + * @example + * ```ts + * findIndentation([' hello', ' world']); // ' ' + * ``` */ export function findIndentation(lines: readonly string[]): string | undefined { return lines diff --git a/src/get.ts b/src/get.ts index 20c10dc..00f3106 100644 --- a/src/get.ts +++ b/src/get.ts @@ -11,6 +11,14 @@ export function get>( export function get(input: Input, path: InputPath): unknown; +/** + * Get the value at `path` within `input`. + * + * @example + * ```ts + * get({ a: { b: 1 } }, 'a.b'); // 1 + * ``` + */ export function get | PropertyKey>( input: Input, path: InputPath, diff --git a/src/getDateString.ts b/src/getDateString.ts index 09ea02d..130f917 100644 --- a/src/getDateString.ts +++ b/src/getDateString.ts @@ -2,5 +2,13 @@ import { getISODateString } from './getISODateString.js'; import type { DateInput, DateString } from './types/date-time.js'; +/** + * Get the date portion (`YYYY-MM-DD`) of `value` as a date string. + * + * @example + * ```ts + * getDateString(new Date('2024-01-15T10:30:00Z')); // '2024-01-15' + * ``` + */ export const getDateString = (value: DateInput = new Date()): DateString => getISODateString(value).split('T')[0] as DateString; diff --git a/src/getISODateString.ts b/src/getISODateString.ts index df529d0..f6dfe56 100644 --- a/src/getISODateString.ts +++ b/src/getISODateString.ts @@ -1,4 +1,12 @@ import type { DateInput, ISODateString } from './types/date-time.js'; +/** + * Convert `value` to an ISO 8601 date string. + * + * @example + * ```ts + * getISODateString(new Date('2024-01-15T10:30:00Z')); // '2024-01-15T10:30:00.000Z' + * ``` + */ export const getISODateString = (value: DateInput = new Date()): ISODateString => (value instanceof Date ? value : new Date(value)).toISOString() as ISODateString; diff --git a/src/getMaxValue.ts b/src/getMaxValue.ts index 316bf00..4dd49be 100644 --- a/src/getMaxValue.ts +++ b/src/getMaxValue.ts @@ -2,6 +2,14 @@ import { assertIsNumericValueArray } from './assertion/assertIsNumericValueArray import type { NumericValue } from './types/common.js'; +/** + * Get the largest value among `values`. + * + * @example + * ```ts + * getMaxValue(1, 5, 3); // 5 + * ``` + */ export function getMaxValue(...values: [T, ...T[]]): T { if (values.length === 0) { throw new Error('Expected at least one numeric value'); diff --git a/src/getMilliseconds.ts b/src/getMilliseconds.ts index dc7638a..b8537b1 100644 --- a/src/getMilliseconds.ts +++ b/src/getMilliseconds.ts @@ -1,4 +1,13 @@ import { isInteger } from './predicate/isInteger.js'; +/** + * Get the number of milliseconds represented by `input`. + * + * @example + * ```ts + * getMilliseconds(1000); // 1000 + * getMilliseconds(new Date(0)); // 0 + * ``` + */ export const getMilliseconds = (input: string | number | Date): number => input instanceof Date ? input.getTime() : isInteger(input) ? input : Date.parse(input); diff --git a/src/getMinValue.ts b/src/getMinValue.ts index 67f560c..4ca66b6 100644 --- a/src/getMinValue.ts +++ b/src/getMinValue.ts @@ -2,6 +2,14 @@ import { assertIsNumericValueArray } from './assertion/assertIsNumericValueArray import type { NumericValue } from './types/common.js'; +/** + * Get the smallest value among `values`. + * + * @example + * ```ts + * getMinValue(1, 5, 3); // 1 + * ``` + */ export function getMinValue(...values: [T, ...T[]]): T { if (values.length === 0) { throw new Error('Expected at least one numeric value'); diff --git a/src/getOwnKeys.ts b/src/getOwnKeys.ts index 074c642..9d659b7 100644 --- a/src/getOwnKeys.ts +++ b/src/getOwnKeys.ts @@ -1,3 +1,11 @@ +/** + * Get `data`'s own enumerable property keys. + * + * @example + * ```ts + * getOwnKeys({ a: 1, b: 2 }); // ['a', 'b'] + * ``` + */ export function getOwnKeys[0], K extends keyof T>(data: T): K[] { return Object.keys(data) as K[]; } diff --git a/src/getOwnPaths.ts b/src/getOwnPaths.ts index b8d6508..0b4ed82 100644 --- a/src/getOwnPaths.ts +++ b/src/getOwnPaths.ts @@ -1,6 +1,14 @@ import type { Path } from './types/objects.js'; import type { AnyRecord } from './types/records.js'; +/** + * Get all own property paths of `input`, including dot-separated paths for nested objects. + * + * @example + * ```ts + * getOwnPaths({ a: 1, b: { c: 2 } }); // ['a', 'b', 'b.c'] + * ``` + */ export const getOwnPaths = (input: Type): Path[] => { return Object.entries(input).reduce((paths, [key, value]) => { paths.push(key); diff --git a/src/getOwnProperties.ts b/src/getOwnProperties.ts index aeb5241..0855f8a 100644 --- a/src/getOwnProperties.ts +++ b/src/getOwnProperties.ts @@ -1,3 +1,11 @@ +/** + * Get `data`'s own property names and symbols. + * + * @example + * ```ts + * getOwnProperties({ a: 1, b: 2 }); // ['a', 'b'] + * ``` + */ export function getOwnProperties(data: T): K[] { return [...Object.getOwnPropertyNames(data), ...Object.getOwnPropertySymbols(data)] as K[]; } diff --git a/src/getPackageName.ts b/src/getPackageName.ts index e0f73ae..eab22e1 100644 --- a/src/getPackageName.ts +++ b/src/getPackageName.ts @@ -1,3 +1,12 @@ +/** + * Extract the package name, including any scope, from `input`. + * + * @example + * ```ts + * getPackageName('@scope/name/sub/path'); // '@scope/name' + * getPackageName('lodash/fp'); // 'lodash' + * ``` + */ export function getPackageName(input: string): string | undefined { return /^(?(?:(?@[^/]+)\/)?(?[a-z][^/]+))/i.exec(input)?.groups?.['pkg']; } diff --git a/src/getPaths.ts b/src/getPaths.ts index fc78e8f..9f96360 100644 --- a/src/getPaths.ts +++ b/src/getPaths.ts @@ -1,6 +1,14 @@ import type { Path } from './types/objects.js'; import type { AnyRecord } from './types/records.js'; +/** + * Get every property path in `input`, including nested paths. + * + * @example + * ```ts + * getPaths({ a: 1, b: { c: 2 } }); // ['a', 'b', 'b.c'] + * ``` + */ export const getPaths = (input: Type): Path[] => { const paths: string[] = []; diff --git a/src/getRandomItem.ts b/src/getRandomItem.ts index 4a09abc..26d8d3a 100644 --- a/src/getRandomItem.ts +++ b/src/getRandomItem.ts @@ -6,6 +6,14 @@ export function getRandomItem(input: NonEmptyArray): Type; export function getRandomItem(input: Type[]): Type | undefined; +/** + * Get a random item from `input`. + * + * @example + * ```ts + * getRandomItem([1, 2, 3]); // 1, 2, or 3 + * ``` + */ export function getRandomItem(input: Type[]): Type | undefined { switch (input.length) { case 0: diff --git a/src/getSortedObject.ts b/src/getSortedObject.ts index 4edf0a2..8415c42 100644 --- a/src/getSortedObject.ts +++ b/src/getSortedObject.ts @@ -13,6 +13,14 @@ export function getSortedObject( compareFunction?: CompareFn, ): Data[]; +/** + * Recursively sort the keys of `data`, optionally using a custom `compareFunction`. + * + * @example + * ```ts + * getSortedObject({ b: 2, a: 1 }); // { a: 1, b: 2 } + * ``` + */ export function getSortedObject( data: Data | Data[], compareFunction: CompareFn = defaultCompareFunction, diff --git a/src/getType.ts b/src/getType.ts index 2a4c7aa..cdd2b2f 100644 --- a/src/getType.ts +++ b/src/getType.ts @@ -1,3 +1,12 @@ +/** + * Get the internal `[[Class]]` type of `input`, e.g. `'String'`, `'Array'`, `'Null'`. + * + * @example + * ```ts + * getType([]); // 'Array' + * getType(null); // 'Null' + * ``` + */ export function getType(input: unknown): string { return Object.prototype.toString.call(input).slice(8, -1); } diff --git a/src/has.ts b/src/has.ts index 01959e7..df7145a 100644 --- a/src/has.ts +++ b/src/has.ts @@ -4,9 +4,6 @@ import { isAnyObject } from './predicate/isAnyObject.js'; import type { FromPath, Merge, Path, PathValue } from './types/objects.js'; import type { IfNever, Pretty } from './types/utils.js'; -/** - * Determine if the path exists on an object. - */ // Known path so the `Input` type is unchanged export function has>(input: Input, path: InputPath): input is Input; @@ -22,6 +19,14 @@ export function has( path: InputPath, ): input is FromPath; +/** + * Determine if the path exists on an object. + * + * @example + * ```ts + * has({ a: { b: 1 } }, 'a.b'); // true + * ``` + */ export function has | string | number>( input: Input, path: InputPath, diff --git a/src/hasAdditionalProperties.ts b/src/hasAdditionalProperties.ts index a9b2633..c7f9096 100644 --- a/src/hasAdditionalProperties.ts +++ b/src/hasAdditionalProperties.ts @@ -1,5 +1,11 @@ /** * Determine if the `input` object has properties other than the provided `knownProperties`. + * + * @example + * ```ts + * hasAdditionalProperties({ a: 1, b: 2 }, ['a']); // true + * hasAdditionalProperties({ a: 1 }, ['a']); // false + * ``` */ export const hasAdditionalProperties = (input: object, knownProperties: PropertyKey[]): boolean => { const properties = Array.isArray(input) ? [...knownProperties.map(String), 'length'] : knownProperties; diff --git a/src/inRange.ts b/src/inRange.ts index 8f73d93..d98b36b 100644 --- a/src/inRange.ts +++ b/src/inRange.ts @@ -1,2 +1,11 @@ +/** + * Determine if `input` is a number or bigint between `min` and `max`, inclusive. + * + * @example + * ```ts + * inRange(5, 1, 10); // true + * inRange(15, 1, 10); // false + * ``` + */ export const inRange = (input: unknown, min: number | bigint, max: number | bigint): boolean => (typeof input === 'number' || typeof input === 'bigint') && input >= min && input <= max; diff --git a/src/isEmpty.ts b/src/isEmpty.ts index e213453..07971f0 100644 --- a/src/isEmpty.ts +++ b/src/isEmpty.ts @@ -1,5 +1,14 @@ import { isLengthAware } from './predicate/isLengthAware.js'; +/** + * Determine if `input` is empty. + * + * @example + * ```ts + * isEmpty(''); // true + * isEmpty([1]); // false + * ``` + */ export function isEmpty(input: unknown): boolean { if (input == null || (typeof input === 'string' && !input.length)) { return true; diff --git a/src/iterateForever.ts b/src/iterateForever.ts index 6f94cae..99f65f9 100644 --- a/src/iterateForever.ts +++ b/src/iterateForever.ts @@ -1,3 +1,16 @@ +/** + * Repeatedly yield the items in `items`, looping forever. + * + * @example + * ```ts + * const iterator = iterateForever([1, 2, 3]); + * + * iterator.next().value; // 1 + * iterator.next().value; // 2 + * iterator.next().value; // 3 + * iterator.next().value; // 1 + * ``` + */ export function* iterateForever(items: Iterable): Generator { while (true) { yield* items; diff --git a/src/joinStrings.ts b/src/joinStrings.ts index f894de9..c9c86ea 100644 --- a/src/joinStrings.ts +++ b/src/joinStrings.ts @@ -1,6 +1,14 @@ import { trimEnd } from './trimEnd.js'; import { trimStart } from './trimStart.js'; +/** + * Join `left` and `right` with `separator`, without duplicating the separator at the seam. + * + * @example + * ```ts + * joinStrings('a/', '/b'); // 'a/b' + * ``` + */ export function joinStrings(left: string, right: string, separator = '/'): string { return trimEnd(left, separator) + separator + trimStart(right, separator); } diff --git a/src/jsonParse.ts b/src/jsonParse.ts index e308d10..5bd9492 100644 --- a/src/jsonParse.ts +++ b/src/jsonParse.ts @@ -6,6 +6,14 @@ export function jsonParse(input: string, reviver?: JsonReviver): unknown; export function jsonParse(input: string, reviver: JsonReviver | undefined, assertionFn: TypeAssertionFn): T; +/** + * Parse `input` as JSON, optionally asserting the parsed value's type with `assertionFn`. + * + * @example + * ```ts + * jsonParse('{"a":1}'); // { a: 1 } + * ``` + */ export function jsonParse(input: string, reviver?: JsonReviver, assertionFn?: TypeAssertionFn): unknown { const data: unknown = JSON.parse(input, reviver); diff --git a/src/looksLikeURL.ts b/src/looksLikeURL.ts index d2ea85a..7828945 100644 --- a/src/looksLikeURL.ts +++ b/src/looksLikeURL.ts @@ -1,2 +1,11 @@ +/** + * Determine if `input` looks like a URL. + * + * @example + * ```ts + * looksLikeURL('https://example.com'); // true + * looksLikeURL('not a url'); // false + * ``` + */ // eslint-disable-next-line no-control-regex export const looksLikeURL = (input: string): boolean => /^[\x00-\x7F]+:\/\/.+/.test(input); diff --git a/src/memo.ts b/src/memo.ts index 9e9cb99..779df82 100644 --- a/src/memo.ts +++ b/src/memo.ts @@ -11,7 +11,16 @@ export type MemoizedFn> = Fn /** * Memoize a function * - * @todo use `Map.getOrInsertComputed()` once it is widely available. + * @privateRemarks + * TODO: use `Map.getOrInsertComputed()` once it is widely available. + * + * @example + * ```ts + * const square = memo((n: number) => n * n); + * + * square(4); // 16, computed and cached + * square(4); // 16, returned from the cache + * ``` */ export function memo>( fn: Fn, diff --git a/src/normalize.ts b/src/normalize.ts index 747410b..ac233be 100644 --- a/src/normalize.ts +++ b/src/normalize.ts @@ -29,9 +29,21 @@ export type ContextInitializer, ) => ContextData; +export function normalize( + input: Readonly, + normalizers: AnyNormalizer>, // No initializer so data must be partial +): Data; + +export function normalize( + input: Readonly, + normalizers: AnyNormalizer, + initContextData: ContextInitializer, +): Data; + /** - * @example + * Recursively transform the properties of `input` using `normalizers`. * + * @example * ```ts * normalize({ demo: true }, { demo: () => false }); * ``` @@ -44,17 +56,6 @@ export type ContextInitializer false ); * ``` */ -export function normalize( - input: Readonly, - normalizers: AnyNormalizer>, // No initializer so data must be partial -): Data; - -export function normalize( - input: Readonly, - normalizers: AnyNormalizer, - initContextData: ContextInitializer, -): Data; - export function normalize( input: Readonly, normalizers: AnyNormalizer, diff --git a/src/parseNumber.ts b/src/parseNumber.ts index 1c3f6a9..930ce3e 100644 --- a/src/parseNumber.ts +++ b/src/parseNumber.ts @@ -1,5 +1,14 @@ import { isBigInt } from './predicate/isBigInt.js'; import { isNumber } from './predicate/isNumber.js'; +/** + * Convert `input` to a number. + * + * @example + * ```ts + * parseNumber('42'); // 42 + * parseNumber(42n); // 42 + * ``` + */ export const parseNumber = (input: bigint | number | string): number => isNumber(input) ? input : isBigInt(input) ? Number.parseInt(input.toString()) : Number.parseFloat(input); diff --git a/src/pathParts.ts b/src/pathParts.ts index 0461b44..bc1dc0f 100644 --- a/src/pathParts.ts +++ b/src/pathParts.ts @@ -1,3 +1,11 @@ +/** + * Yield each part of `input`, splitting a string path on non-word characters. + * + * @example + * ```ts + * [...pathParts('a.b[0]')]; // ['a', 'b', '0'] + * ``` + */ export function* pathParts(input: PropertyKey): Generator { if (input === '') { return; diff --git a/src/predicate/assume.ts b/src/predicate/assume.ts index 9ae11cf..b1d5101 100644 --- a/src/predicate/assume.ts +++ b/src/predicate/assume.ts @@ -5,6 +5,11 @@ * @privateRemarks * The `is` prefix is omitted because there is not any conditional logic in the function. * It is more of a command to `tsc` to assume the type rather than a check. + * + * @example + * ```ts + * assume(42); // true (no runtime check is performed) + * ``` */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any export const assume = (_input: unknown, ..._args: any[]): _input is Type => true; diff --git a/src/predicate/factory/allOf.ts b/src/predicate/factory/allOf.ts index ee16acd..29d221e 100644 --- a/src/predicate/factory/allOf.ts +++ b/src/predicate/factory/allOf.ts @@ -4,6 +4,14 @@ import type { IntersectionOf } from '../../types/utils.js'; /** * All predicates must pass + * + * @example + * ```ts + * const isPositiveInteger = allOf(isNumber, isInteger, (input: unknown): input is number => (input as number) > 0); + * isPositiveInteger(5); // true + * isPositiveInteger(-5); // false + * isPositiveInteger(1.5); // false + * ``` */ export const allOf = >>( ...predicates: Predicates diff --git a/src/predicate/factory/anyOf.ts b/src/predicate/factory/anyOf.ts index 3f1e276..08ccc73 100644 --- a/src/predicate/factory/anyOf.ts +++ b/src/predicate/factory/anyOf.ts @@ -4,6 +4,14 @@ import type { UnionOf } from '../../types/utils.js'; /** * Any predicate can pass + * + * @example + * ```ts + * const isStringOrNumber = anyOf(isString, isNumber); + * isStringOrNumber('hello'); // true + * isStringOrNumber(5); // true + * isStringOrNumber(true); // false + * ``` */ export const anyOf = >>( ...predicates: Predicates diff --git a/src/predicate/factory/everyItem.ts b/src/predicate/factory/everyItem.ts index e295017..d35aa3a 100644 --- a/src/predicate/factory/everyItem.ts +++ b/src/predicate/factory/everyItem.ts @@ -1,5 +1,16 @@ import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that checks if `input` is an array whose every item passes the given `predicate`. + * + * @example + * ```ts + * const isStringArray = everyItem(isString); + * isStringArray(['a', 'b', 'c']); // true + * isStringArray(['a', 1, 'c']); // false + * isStringArray('a'); // false + * ``` + */ export const everyItem = (predicate: TypePredicateFn): TypePredicateFn => (input: unknown): input is Type[] => diff --git a/src/predicate/factory/fromEnum.ts b/src/predicate/factory/fromEnum.ts index 1cc0500..80b1c0a 100644 --- a/src/predicate/factory/fromEnum.ts +++ b/src/predicate/factory/fromEnum.ts @@ -26,6 +26,20 @@ const getEnumValues = (enumObject: T): Set => { /** * Create a type predicate function that checks if the input is a member of the TypeScript `enum` + * + * @example + * ```ts + * enum Color { + * Red, + * Green, + * Blue, + * } + * + * const isColor = fromEnum(Color); + * isColor(Color.Red); // true + * isColor(0); // true + * isColor(3); // false + * ``` */ export const fromEnum = (enumObject: T): TypePredicateFn => { const values = getEnumValues(enumObject); diff --git a/src/predicate/factory/instanceOf.ts b/src/predicate/factory/instanceOf.ts index 4a537b2..435dc39 100644 --- a/src/predicate/factory/instanceOf.ts +++ b/src/predicate/factory/instanceOf.ts @@ -1,6 +1,16 @@ import type { AnyNewable } from '../../types/common.js'; import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that checks if `input` is an instance of the given `constructor`. + * + * @example + * ```ts + * const isDate = instanceOf(Date); + * isDate(new Date()); // true + * isDate('2024-01-01'); // false + * ``` + */ export const instanceOf = (constructor: T): TypePredicateFn> => (input: unknown): input is InstanceType => diff --git a/src/predicate/factory/is.ts b/src/predicate/factory/is.ts index 896af24..fa55d2b 100644 --- a/src/predicate/factory/is.ts +++ b/src/predicate/factory/is.ts @@ -4,6 +4,13 @@ import type { UnionOf } from '../../types/utils.js'; /** * Use `Object.is()` to compare `input` against allowed values. + * + * @example + * ```ts + * const isRedGreenOrBlue = is('red', 'green', 'blue'); + * isRedGreenOrBlue('red'); // true + * isRedGreenOrBlue('yellow'); // false + * ``` */ export const is = >( ...values: Values diff --git a/src/predicate/factory/literal.ts b/src/predicate/factory/literal.ts index f54e269..b7383df 100644 --- a/src/predicate/factory/literal.ts +++ b/src/predicate/factory/literal.ts @@ -1,5 +1,15 @@ import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that checks if `input` strictly equals the given `value`. + * + * @example + * ```ts + * const isFoo = literal('foo'); + * isFoo('foo'); // true + * isFoo('bar'); // false + * ``` + */ export const literal = (value: Type): TypePredicateFn => (input: unknown): input is Type => diff --git a/src/predicate/factory/matching.ts b/src/predicate/factory/matching.ts index c48f7fd..efbfdc6 100644 --- a/src/predicate/factory/matching.ts +++ b/src/predicate/factory/matching.ts @@ -1,5 +1,15 @@ import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that checks if `input` is a string matching the given `pattern`. + * + * @example + * ```ts + * const isHexColor = matching(/^#[0-9a-f]{6}$/i); + * isHexColor('#ff0000'); // true + * isHexColor('red'); // false + * ``` + */ export const matching = (pattern: RegExp): TypePredicateFn => (input: unknown): input is T => diff --git a/src/predicate/factory/maybeArray.ts b/src/predicate/factory/maybeArray.ts index 269f387..96711b1 100644 --- a/src/predicate/factory/maybeArray.ts +++ b/src/predicate/factory/maybeArray.ts @@ -1,5 +1,16 @@ import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that checks `input` against `predicate`, applying it to every item when `input` is an array. + * + * @example + * ```ts + * const isStringOrStringArray = maybeArray(isString); + * isStringOrStringArray('hello'); // true + * isStringOrStringArray(['a', 'b']); // true + * isStringOrStringArray(['a', 1]); // false + * ``` + */ export const maybeArray = (predicate: TypePredicateFn): TypePredicateFn => (input: unknown): input is T | T[] => diff --git a/src/predicate/factory/nonNullable.ts b/src/predicate/factory/nonNullable.ts index e6bbe1e..8ea3d3c 100644 --- a/src/predicate/factory/nonNullable.ts +++ b/src/predicate/factory/nonNullable.ts @@ -1,7 +1,17 @@ import type { TypePredicateFn } from '../../types/functions.js'; /** - * @see https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype + * Create a type predicate function that passes if `input` is not `null`/`undefined` and passes the given `predicate`. + * + * @see {@link https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype} + * + * @example + * ```ts + * const isNonNullableString = nonNullable(isString); + * isNonNullableString('hello'); // true + * isNonNullableString(null); // false + * isNonNullableString(undefined); // false + * ``` */ export const nonNullable = (predicate: TypePredicateFn): TypePredicateFn> => diff --git a/src/predicate/factory/nullable.ts b/src/predicate/factory/nullable.ts index 0bbab9e..f137f6f 100644 --- a/src/predicate/factory/nullable.ts +++ b/src/predicate/factory/nullable.ts @@ -1,5 +1,16 @@ import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that passes if `input` is `null` or passes the given `predicate`. + * + * @example + * ```ts + * const isNullableString = nullable(isString); + * isNullableString('hello'); // true + * isNullableString(null); // true + * isNullableString(undefined); // false + * ``` + */ export const nullable = (predicate: TypePredicateFn): TypePredicateFn => (input: unknown): input is T | null => diff --git a/src/predicate/factory/nullish.ts b/src/predicate/factory/nullish.ts index 7b3c597..a8ac431 100644 --- a/src/predicate/factory/nullish.ts +++ b/src/predicate/factory/nullish.ts @@ -1,6 +1,18 @@ import type { Nullish } from '../../types/common.js'; import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that passes if `input` is `null`, `undefined`, or passes the given `predicate`. + * + * @example + * ```ts + * const isNullishString = nullish(isString); + * isNullishString('hello'); // true + * isNullishString(null); // true + * isNullishString(undefined); // true + * isNullishString(5); // false + * ``` + */ export const nullish = (predicate: TypePredicateFn): TypePredicateFn> => (input: unknown): input is Nullish => diff --git a/src/predicate/factory/optional.ts b/src/predicate/factory/optional.ts index 4d5e75e..b97c535 100644 --- a/src/predicate/factory/optional.ts +++ b/src/predicate/factory/optional.ts @@ -1,5 +1,16 @@ import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that passes if `input` is `undefined` or passes the given `predicate`. + * + * @example + * ```ts + * const isOptionalString = optional(isString); + * isOptionalString('hello'); // true + * isOptionalString(undefined); // true + * isOptionalString(null); // false + * ``` + */ export const optional = (predicate: TypePredicateFn): TypePredicateFn => (input: unknown): input is T | undefined => diff --git a/src/predicate/factory/range.ts b/src/predicate/factory/range.ts index 1e399c5..5a45046 100644 --- a/src/predicate/factory/range.ts +++ b/src/predicate/factory/range.ts @@ -4,6 +4,16 @@ export function range(min: number, max: number): TypePredicateFn; export function range(min: bigint, max: bigint): TypePredicateFn; +/** + * Create a type predicate function that checks if `input` is a number or `bigint` within the inclusive range from `min` to `max`. + * + * @example + * ```ts + * const isPositive = range(0, Infinity); + * isPositive(5); // true + * isPositive(-1); // false + * ``` + */ export function range(min: number | bigint, max: number | bigint): TypePredicateFn { if (min === Number.NEGATIVE_INFINITY && max === Number.POSITIVE_INFINITY) { throw new RangeError('min and max cannot be -Infinity and Infinity'); diff --git a/src/predicate/factory/shape.ts b/src/predicate/factory/shape.ts index a0a9a71..acc6ab1 100644 --- a/src/predicate/factory/shape.ts +++ b/src/predicate/factory/shape.ts @@ -38,6 +38,19 @@ export type InferTypeFromShape> = { [Property in keyof Shape]: InferTypeFromShapeValue; }; +/** + * Create a type predicate function that checks if `input` is an object matching the given `objectShape`. Set `additionalProperties` to `false` to reject objects with extra properties. + * + * @example + * ```ts + * const isPerson = shape({ name: isString, age: isNumber }); + * isPerson({ name: 'Andy', age: 30 }); // true + * isPerson({ name: 'Andy' }); // false + * + * const isStrictPerson = shape({ name: isString, age: isNumber }, false); + * isStrictPerson({ name: 'Andy', age: 30, extra: true }); // false + * ``` + */ export const shape = = ObjectShapeRecord>( objectShape: Shape, additionalProperties = true, diff --git a/src/predicate/factory/simple.ts b/src/predicate/factory/simple.ts index 3024694..177741c 100644 --- a/src/predicate/factory/simple.ts +++ b/src/predicate/factory/simple.ts @@ -22,6 +22,16 @@ export type Simple = Type extends string ? object : never; +/** + * Create a type predicate function that narrows the result of `fn` down to its simple (non-branded) type. + * + * @example + * ```ts + * const isSimpleNumber = simple(isInt32); // narrows from branded `Int32` down to plain `number` + * isSimpleNumber(5); // true + * isSimpleNumber('5'); // false + * ``` + */ export const simple = >(fn: Fn): TypePredicateFn>> => (input): input is Simple> => diff --git a/src/predicate/factory/stringLength.ts b/src/predicate/factory/stringLength.ts index 88de8a8..0888fa5 100644 --- a/src/predicate/factory/stringLength.ts +++ b/src/predicate/factory/stringLength.ts @@ -1,5 +1,16 @@ import type { TypePredicateFn } from '../../types/functions.js'; +/** + * Create a type predicate function that checks if `input` is a string whose length is between `min` and `max`, inclusive. + * + * @example + * ```ts + * const isShortString = stringLength(1, 10); + * isShortString('hello'); // true + * isShortString(''); // false + * isShortString('this is too long'); // false + * ``` + */ export const stringLength = ( min: number, max: number = Number.POSITIVE_INFINITY, diff --git a/src/predicate/factory/tuple.ts b/src/predicate/factory/tuple.ts index fd1e65f..911904b 100644 --- a/src/predicate/factory/tuple.ts +++ b/src/predicate/factory/tuple.ts @@ -7,6 +7,17 @@ export type GetTupleFromInput = { [Property in keyof Type]: Type[Property] extends TypePredicateFn ? T : Type[Property]; }; +/** + * Create a type predicate function that checks if `input` is an array matching the given `tupleShape`. + * + * @example + * ```ts + * const isNameAgeTuple = tuple([isString, isNumber]); + * isNameAgeTuple(['Andy', 30]); // true + * isNameAgeTuple([30, 'Andy']); // false + * isNameAgeTuple(['Andy', 30, 'extra']); // false + * ``` + */ export const tuple = ( tupleShape: Input, ): TypePredicateFn> => { diff --git a/src/predicate/factory/typeOf.ts b/src/predicate/factory/typeOf.ts index 1ce5077..e8bb57e 100644 --- a/src/predicate/factory/typeOf.ts +++ b/src/predicate/factory/typeOf.ts @@ -1,5 +1,16 @@ import type { TypeOf, TypeOfMapping } from '../../types/common.js'; +/** + * Create a type predicate function that checks if `input`'s `typeof` matches one of the given `types`. + * + * @example + * ```ts + * const isStringOrNumber = typeOf('string', 'number'); + * isStringOrNumber('hello'); // true + * isStringOrNumber(5); // true + * isStringOrNumber(true); // false + * ``` + */ export const typeOf = (...types: T[]) => (input: Input): input is Input & TypeOfMapping[T] => diff --git a/src/predicate/factory/withLength.ts b/src/predicate/factory/withLength.ts index 985c11e..2f8360d 100644 --- a/src/predicate/factory/withLength.ts +++ b/src/predicate/factory/withLength.ts @@ -16,6 +16,21 @@ export function withLength, Range range: Range, ): TypePredicateFn & { length: number }>; +/** + * Create a type predicate function that checks if `input` passes `fn` and has a `length` matching the given `length` or falling within the given range. + * + * @example + * ```ts + * const twoCharString = withLength(isString, 2); + * twoCharString('ab'); // true + * twoCharString('abc'); // false + * + * const stringRange = withLength(isString, [1, 3]); + * stringRange('a'); // true + * stringRange('abc'); // true + * stringRange('abcd'); // false + * ``` + */ export function withLength, LengthOrRange extends number | NumberRange>( fn: Fn, lengthRange: LengthOrRange, diff --git a/src/predicate/factory/withSize.ts b/src/predicate/factory/withSize.ts index 733881d..a5731a4 100644 --- a/src/predicate/factory/withSize.ts +++ b/src/predicate/factory/withSize.ts @@ -16,6 +16,20 @@ export function withSize, Range ext range: Range, ): TypePredicateFn & { size: number }>; +/** + * Create a type predicate function that checks if `input` passes `fn` and has a `size` matching the given `size` or falling within the given range. + * + * @example + * ```ts + * const twoItemSet = withSize(instanceOf(Set), 2); + * twoItemSet(new Set([1, 2])); // true + * twoItemSet(new Set([1])); // false + * + * const setWithRange = withSize(instanceOf(Set), [1, 3]); + * setWithRange(new Set([1, 2])); // true + * setWithRange(new Set()); // false + * ``` + */ export function withSize, SizeOrRange extends number | NumberRange>( fn: Fn, sizeRange: SizeOrRange, diff --git a/src/predicate/isAny.ts b/src/predicate/isAny.ts index f4d7905..621429a 100644 --- a/src/predicate/isAny.ts +++ b/src/predicate/isAny.ts @@ -1,4 +1,13 @@ import { assume } from './assume.js'; /* eslint-disable @typescript-eslint/no-explicit-any */ +/** + * Always determine that `input` matches, regardless of its actual type. + * + * @example + * ```ts + * isAny(42); // true + * isAny('hello'); // true + * ``` + */ export const isAny = assume; diff --git a/src/predicate/isAnyObject.ts b/src/predicate/isAnyObject.ts index 81fb8c6..abe7aaa 100644 --- a/src/predicate/isAnyObject.ts +++ b/src/predicate/isAnyObject.ts @@ -1,4 +1,10 @@ /** * Determine if `input` is any non-null object. + * + * @example + * ```ts + * isAnyObject({}); // true + * isAnyObject(null); // false + * ``` */ export const isAnyObject = (input: unknown): input is object => input !== null && typeof input === 'object'; diff --git a/src/predicate/isAnyObjectWith.ts b/src/predicate/isAnyObjectWith.ts index e62b2e7..6facbfa 100644 --- a/src/predicate/isAnyObjectWith.ts +++ b/src/predicate/isAnyObjectWith.ts @@ -2,6 +2,12 @@ import { isAnyObject } from './isAnyObject.js'; /** * Determine if `input` is an object and has the provided properties. + * + * @example + * ```ts + * isAnyObjectWith({ a: 1, b: 2 }, ['a', 'b']); // true + * isAnyObjectWith({ a: 1 }, ['a', 'b']); // false + * ``` */ export const isAnyObjectWith = ( input: T, diff --git a/src/predicate/isAnyObjectWithOwn.ts b/src/predicate/isAnyObjectWithOwn.ts index 0770297..de43deb 100644 --- a/src/predicate/isAnyObjectWithOwn.ts +++ b/src/predicate/isAnyObjectWithOwn.ts @@ -2,6 +2,12 @@ import { isAnyObject } from './isAnyObject.js'; /** * Determine if `input` is an object and directly has the provided properties. + * + * @example + * ```ts + * isAnyObjectWithOwn({ a: 1 }, ['a']); // true + * isAnyObjectWithOwn(Object.create({ a: 1 }), ['a']); // false + * ``` */ export const isAnyObjectWithOwn = ( input: T, diff --git a/src/predicate/isArray.ts b/src/predicate/isArray.ts index a3a20ed..a1abf74 100644 --- a/src/predicate/isArray.ts +++ b/src/predicate/isArray.ts @@ -1,4 +1,10 @@ /** * Determine if `input` is an array. + * + * @example + * ```ts + * isArray([1, 2, 3]); // true + * isArray('not an array'); // false + * ``` */ export const isArray = (input: unknown): input is unknown[] => Array.isArray(input); diff --git a/src/predicate/isAsyncIterable.ts b/src/predicate/isAsyncIterable.ts index 54c9485..3163244 100644 --- a/src/predicate/isAsyncIterable.ts +++ b/src/predicate/isAsyncIterable.ts @@ -1,6 +1,14 @@ /** - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator + * Determine if `input` is an async iterable. + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols} + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator} + * + * @example + * ```ts + * isAsyncIterable({ [Symbol.asyncIterator]() { return this; } }); // true + * isAsyncIterable([1, 2, 3]); // false + * ``` */ export const isAsyncIterable = (input: unknown): input is AsyncIterable => { return ( diff --git a/src/predicate/isBigInt.ts b/src/predicate/isBigInt.ts index 492f3f6..e25bca6 100644 --- a/src/predicate/isBigInt.ts +++ b/src/predicate/isBigInt.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a bigint. + * + * @example + * ```ts + * isBigInt(42n); // true + * isBigInt(42); // false + * ``` + */ export const isBigInt = (input: unknown): input is bigint => typeof input === 'bigint'; diff --git a/src/predicate/isBigIntArray.ts b/src/predicate/isBigIntArray.ts index 9e50cb2..7a1fe94 100644 --- a/src/predicate/isBigIntArray.ts +++ b/src/predicate/isBigIntArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isBigInt } from './isBigInt.js'; +/** + * Determine if `input` is an array of bigints. + * + * @example + * ```ts + * isBigIntArray([1n, 2n, 3n]); // true + * isBigIntArray([1, 2, 3]); // false + * ``` + */ export const isBigIntArray = everyItem(isBigInt); diff --git a/src/predicate/isBinaryNumberString.ts b/src/predicate/isBinaryNumberString.ts index 706b650..b6b8c57 100644 --- a/src/predicate/isBinaryNumberString.ts +++ b/src/predicate/isBinaryNumberString.ts @@ -3,6 +3,14 @@ import { matching } from './factory/matching.js'; import type { BinaryNumberString } from '../types/numbers.js'; /** - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_strings#binary_numbers + * Determine if `input` is a binary number string. + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_strings#binary_numbers} + * + * @example + * ```ts + * isBinaryNumberString('0b1010'); // true + * isBinaryNumberString('1010'); // false + * ``` */ export const isBinaryNumberString = matching(/^0b[01]+$/i); diff --git a/src/predicate/isBoolean.ts b/src/predicate/isBoolean.ts index b5d4036..9fb2d4a 100644 --- a/src/predicate/isBoolean.ts +++ b/src/predicate/isBoolean.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a boolean. + * + * @example + * ```ts + * isBoolean(true); // true + * isBoolean(1); // false + * ``` + */ export const isBoolean = (input: unknown): input is boolean => typeof input === 'boolean'; diff --git a/src/predicate/isBooleanArray.ts b/src/predicate/isBooleanArray.ts index 597d2f5..dbd1191 100644 --- a/src/predicate/isBooleanArray.ts +++ b/src/predicate/isBooleanArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isBoolean } from './isBoolean.js'; +/** + * Determine if `input` is an array of booleans. + * + * @example + * ```ts + * isBooleanArray([true, false]); // true + * isBooleanArray([true, 1]); // false + * ``` + */ export const isBooleanArray = everyItem(isBoolean); diff --git a/src/predicate/isDateInputString.ts b/src/predicate/isDateInputString.ts index 68deec7..616df9d 100644 --- a/src/predicate/isDateInputString.ts +++ b/src/predicate/isDateInputString.ts @@ -3,6 +3,12 @@ import type { TypePredicateFn } from '../types/functions.js'; /** * Determine if `input` is a valid date string. + * + * @example + * ```ts + * isDateInputString('2024-01-01'); // true + * isDateInputString('not a date'); // false + * ``` */ export const isDateInputString: TypePredicateFn = (input: unknown): input is DateInputString => typeof input === 'string' && !Number.isNaN(Date.parse(input)); diff --git a/src/predicate/isDigitsString.ts b/src/predicate/isDigitsString.ts index 5b79e75..001fc3b 100644 --- a/src/predicate/isDigitsString.ts +++ b/src/predicate/isDigitsString.ts @@ -2,4 +2,13 @@ import { matching } from './factory/matching.js'; import type { NumericString } from '../types/common.js'; +/** + * Determine if `input` is a string containing only digits. + * + * @example + * ```ts + * isDigitsString('12345'); // true + * isDigitsString('12a45'); // false + * ``` + */ export const isDigitsString = matching(/^\d+$/); diff --git a/src/predicate/isFiniteNumber.ts b/src/predicate/isFiniteNumber.ts index 11155c7..6d24813 100644 --- a/src/predicate/isFiniteNumber.ts +++ b/src/predicate/isFiniteNumber.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a finite number. + * + * @example + * ```ts + * isFiniteNumber(42); // true + * isFiniteNumber(Infinity); // false + * ``` + */ export const isFiniteNumber = (input: unknown): input is number => Number.isFinite(input); diff --git a/src/predicate/isFunction.ts b/src/predicate/isFunction.ts index d85cb4a..eff872f 100644 --- a/src/predicate/isFunction.ts +++ b/src/predicate/isFunction.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a function. + * + * @example + * ```ts + * isFunction(() => {}); // true + * isFunction({}); // false + * ``` + */ export const isFunction = (input: unknown): input is Function => typeof input === 'function'; diff --git a/src/predicate/isHexNumberString.ts b/src/predicate/isHexNumberString.ts index 3621195..6fbf85f 100644 --- a/src/predicate/isHexNumberString.ts +++ b/src/predicate/isHexNumberString.ts @@ -3,6 +3,14 @@ import { matching } from './factory/matching.js'; import type { HexNumberString } from '../types/numbers.js'; /** - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_strings#hexadecimal_numbers + * Determine if `input` is a hexadecimal number string. + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_strings#hexadecimal_numbers} + * + * @example + * ```ts + * isHexNumberString('0xff'); // true + * isHexNumberString('ff'); // false + * ``` */ export const isHexNumberString = matching(/^0x[0-9a-f]+$/i); diff --git a/src/predicate/isISODateString.ts b/src/predicate/isISODateString.ts index 607e08a..623ffaa 100644 --- a/src/predicate/isISODateString.ts +++ b/src/predicate/isISODateString.ts @@ -9,6 +9,12 @@ export const ISO_DATE_PATTERN = * This checks to see if the input matches the format that `toISOString()` * returns, which is a simplified format based on ISO 8601. * - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString} + * + * @example + * ```ts + * isISODateString('2024-01-01T00:00:00.000Z'); // true + * isISODateString('2024-01-01'); // false + * ``` */ export const isISODateString = matching(ISO_DATE_PATTERN); diff --git a/src/predicate/isInt32.ts b/src/predicate/isInt32.ts index f16634c..49047f1 100644 --- a/src/predicate/isInt32.ts +++ b/src/predicate/isInt32.ts @@ -2,6 +2,15 @@ import { int32Max, int32Min } from '../numbers.js'; import type { Int32 } from '../types/numbers.js'; +/** + * Determine if `input` is an integer within the 32-bit signed integer range. + * + * @example + * ```ts + * isInt32(42); // true + * isInt32(2 ** 32); // false + * ``` + */ export function isInt32(input: unknown): input is Int32 { return typeof input === 'number' && Number.isInteger(input) && input >= int32Min && input <= int32Max; } diff --git a/src/predicate/isIntString.ts b/src/predicate/isIntString.ts index 25ff9ec..25b5717 100644 --- a/src/predicate/isIntString.ts +++ b/src/predicate/isIntString.ts @@ -2,4 +2,13 @@ import { matching } from './factory/matching.js'; import type { NumericString } from '../types/common.js'; +/** + * Determine if `input` is a string representing an integer. + * + * @example + * ```ts + * isIntString('42'); // true + * isIntString('4.2'); // false + * ``` + */ export const isIntString = matching(/^[-+]?\d+$/); diff --git a/src/predicate/isInteger.ts b/src/predicate/isInteger.ts index c5e2880..aa04e30 100644 --- a/src/predicate/isInteger.ts +++ b/src/predicate/isInteger.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is an integer. + * + * @example + * ```ts + * isInteger(42); // true + * isInteger(4.2); // false + * ``` + */ export const isInteger = (input: unknown): input is number => Number.isInteger(input); diff --git a/src/predicate/isIterable.ts b/src/predicate/isIterable.ts index 6f0de3a..aca22d5 100644 --- a/src/predicate/isIterable.ts +++ b/src/predicate/isIterable.ts @@ -1,3 +1,12 @@ +/** + * Determine if `input` is iterable. + * + * @example + * ```ts + * isIterable([1, 2, 3]); // true + * isIterable({ a: 1 }); // false + * ``` + */ export const isIterable = (input: unknown): input is Iterable => { return ( input !== null && diff --git a/src/predicate/isJSONable.ts b/src/predicate/isJSONable.ts index 84dcf2f..8a4db14 100644 --- a/src/predicate/isJSONable.ts +++ b/src/predicate/isJSONable.ts @@ -1,5 +1,14 @@ import type { JsonValue } from '../types/common.js'; +/** + * Determine if `input` has a `toJSON` method that accepts zero or one arguments. + * + * @example + * ```ts + * isJSONable(new Date()); // true + * isJSONable({}); // false + * ``` + */ export const isJSONable = (input: unknown): input is { toJSON: (key?: string) => JsonValue } => { return ( input !== null && diff --git a/src/predicate/isLengthAware.ts b/src/predicate/isLengthAware.ts index d461d7d..6a1c3fc 100644 --- a/src/predicate/isLengthAware.ts +++ b/src/predicate/isLengthAware.ts @@ -1,2 +1,11 @@ +/** + * Determine if `input` has a numeric `length` property. + * + * @example + * ```ts + * isLengthAware('hello'); // true + * isLengthAware({}); // false + * ``` + */ export const isLengthAware = (input: unknown): input is { length: number } => input !== null && typeof input === 'object' && 'length' in input && typeof input.length === 'number'; diff --git a/src/predicate/isNonNullable.ts b/src/predicate/isNonNullable.ts index 75cd38c..0101e24 100644 --- a/src/predicate/isNonNullable.ts +++ b/src/predicate/isNonNullable.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is not `null` or `undefined`. + * + * @example + * ```ts + * isNonNullable(42); // true + * isNonNullable(null); // false + * ``` + */ export const isNonNullable = (input: T): input is NonNullable => typeof input !== 'undefined' && input !== null; diff --git a/src/predicate/isNull.ts b/src/predicate/isNull.ts index f8abe17..40cceed 100644 --- a/src/predicate/isNull.ts +++ b/src/predicate/isNull.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is `null`. + * + * @example + * ```ts + * isNull(null); // true + * isNull(undefined); // false + * ``` + */ export const isNull = (input: unknown): input is null => input === null; diff --git a/src/predicate/isNullArray.ts b/src/predicate/isNullArray.ts index bf2fa7b..1f9030f 100644 --- a/src/predicate/isNullArray.ts +++ b/src/predicate/isNullArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isNull } from './isNull.js'; +/** + * Determine if `input` is an array containing only `null` values. + * + * @example + * ```ts + * isNullArray([null, null]); // true + * isNullArray([null, undefined]); // false + * ``` + */ export const isNullArray = everyItem(isNull); diff --git a/src/predicate/isNullish.ts b/src/predicate/isNullish.ts index e81b42d..0abc492 100644 --- a/src/predicate/isNullish.ts +++ b/src/predicate/isNullish.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is `null` or `undefined`. + * + * @example + * ```ts + * isNullish(null); // true + * isNullish(0); // false + * ``` + */ export const isNullish = (input: unknown): input is null | undefined => input == null; diff --git a/src/predicate/isNumber.ts b/src/predicate/isNumber.ts index 35c8a13..f0b4401 100644 --- a/src/predicate/isNumber.ts +++ b/src/predicate/isNumber.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a number and not `NaN`. + * + * @example + * ```ts + * isNumber(42); // true + * isNumber(NaN); // false + * ``` + */ export const isNumber = (input: unknown): input is number => typeof input === 'number' && !Number.isNaN(input); diff --git a/src/predicate/isNumberArray.ts b/src/predicate/isNumberArray.ts index b3fd098..0aba67f 100644 --- a/src/predicate/isNumberArray.ts +++ b/src/predicate/isNumberArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isNumber } from './isNumber.js'; +/** + * Determine if `input` is an array of numbers. + * + * @example + * ```ts + * isNumberArray([1, 2, 3]); // true + * isNumberArray([1, '2', 3]); // false + * ``` + */ export const isNumberArray = everyItem(isNumber); diff --git a/src/predicate/isNumericString.ts b/src/predicate/isNumericString.ts index b067793..75666cb 100644 --- a/src/predicate/isNumericString.ts +++ b/src/predicate/isNumericString.ts @@ -2,4 +2,13 @@ import { matching } from './factory/matching.js'; import type { NumericString } from '../types/common.js'; +/** + * Determine if `input` is a string representing a numeric value, including optional sign and decimal point. + * + * @example + * ```ts + * isNumericString('-42.5'); // true + * isNumericString('42a'); // false + * ``` + */ export const isNumericString = matching(/^[-+]?(\d+(\.\d+)?|\.\d+)$/); diff --git a/src/predicate/isNumericValue.ts b/src/predicate/isNumericValue.ts index 56b867d..13558ff 100644 --- a/src/predicate/isNumericValue.ts +++ b/src/predicate/isNumericValue.ts @@ -2,5 +2,14 @@ import { isNumericString } from './isNumericString.js'; import type { NumericValue } from '../types/common.js'; +/** + * Determine if `input` is a number, a bigint, or a numeric string. + * + * @example + * ```ts + * isNumericValue('42'); // true + * isNumericValue('abc'); // false + * ``` + */ export const isNumericValue = (input: unknown): input is NumericValue => (typeof input === 'number' && !Number.isNaN(input)) || typeof input === 'bigint' || isNumericString(input); diff --git a/src/predicate/isNumericValueArray.ts b/src/predicate/isNumericValueArray.ts index bd77446..6064eca 100644 --- a/src/predicate/isNumericValueArray.ts +++ b/src/predicate/isNumericValueArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isNumericValue } from './isNumericValue.js'; +/** + * Determine if `input` is an array of numeric values. + * + * @example + * ```ts + * isNumericValueArray([1, '2', 3n]); // true + * isNumericValueArray([1, 'abc']); // false + * ``` + */ export const isNumericValueArray = everyItem(isNumericValue); diff --git a/src/predicate/isObject.ts b/src/predicate/isObject.ts index 53abe95..edec96c 100644 --- a/src/predicate/isObject.ts +++ b/src/predicate/isObject.ts @@ -2,6 +2,12 @@ import type { UnknownRecord } from '../types/records.js'; /** * Determine if `input` is a non-null object and not an array. + * + * @example + * ```ts + * isObject({}); // true + * isObject([]); // false + * ``` */ export const isObject = (input: unknown): input is UnknownRecord => input !== null && typeof input === 'object' && !Array.isArray(input); diff --git a/src/predicate/isObjectLiteral.ts b/src/predicate/isObjectLiteral.ts index caa852e..8d4e054 100644 --- a/src/predicate/isObjectLiteral.ts +++ b/src/predicate/isObjectLiteral.ts @@ -2,6 +2,12 @@ import type { UnknownRecord } from '../types/records.js'; /** * Determine if `input` is an object literal. + * + * @example + * ```ts + * isObjectLiteral({ a: 1 }); // true + * isObjectLiteral(new Map()); // false + * ``` */ export const isObjectLiteral = (input: unknown): input is UnknownRecord => input !== null && typeof input === 'object' && Object.getPrototypeOf(input) === Object.prototype; diff --git a/src/predicate/isObjectWith.ts b/src/predicate/isObjectWith.ts index d6d5765..6eb16b9 100644 --- a/src/predicate/isObjectWith.ts +++ b/src/predicate/isObjectWith.ts @@ -2,6 +2,12 @@ import { isObject } from './isObject.js'; /** * Determine if `input` is an object and has the provided properties. + * + * @example + * ```ts + * isObjectWith({ a: 1, b: 2 }, ['a', 'b']); // true + * isObjectWith({ a: 1 }, ['a', 'b']); // false + * ``` */ export const isObjectWith = (input: T, properties: P[]): input is T & Record => isObject(input) && properties.every((property) => property in input); diff --git a/src/predicate/isOctalNumberString.ts b/src/predicate/isOctalNumberString.ts index 11d1e2a..2bbf6b3 100644 --- a/src/predicate/isOctalNumberString.ts +++ b/src/predicate/isOctalNumberString.ts @@ -3,6 +3,14 @@ import { matching } from './factory/matching.js'; import type { OctalNumberString } from '../types/numbers.js'; /** - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_strings#octal_numbers + * Determine if `input` is an octal number string. + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_strings#octal_numbers} + * + * @example + * ```ts + * isOctalNumberString('0o17'); // true + * isOctalNumberString('17'); // false + * ``` */ export const isOctalNumberString = matching(/^0o[0-7]+$/i); diff --git a/src/predicate/isOptionalArray.ts b/src/predicate/isOptionalArray.ts index a19350a..b71e2b3 100644 --- a/src/predicate/isOptionalArray.ts +++ b/src/predicate/isOptionalArray.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isArray } from './isArray.js'; +/** + * Determine if `input` is `undefined` or an array. + * + * @example + * ```ts + * isOptionalArray(undefined); // true + * isOptionalArray(null); // false + * ``` + */ export const isOptionalArray = optional(isArray); diff --git a/src/predicate/isOptionalBigInt.ts b/src/predicate/isOptionalBigInt.ts index 0524d12..178637d 100644 --- a/src/predicate/isOptionalBigInt.ts +++ b/src/predicate/isOptionalBigInt.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isBigInt } from './isBigInt.js'; +/** + * Determine if `input` is `undefined` or a bigint. + * + * @example + * ```ts + * isOptionalBigInt(undefined); // true + * isOptionalBigInt(null); // false + * ``` + */ export const isOptionalBigInt = optional(isBigInt); diff --git a/src/predicate/isOptionalBoolean.ts b/src/predicate/isOptionalBoolean.ts index e215096..c754c07 100644 --- a/src/predicate/isOptionalBoolean.ts +++ b/src/predicate/isOptionalBoolean.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isBoolean } from './isBoolean.js'; +/** + * Determine if `input` is `undefined` or a boolean. + * + * @example + * ```ts + * isOptionalBoolean(undefined); // true + * isOptionalBoolean(null); // false + * ``` + */ export const isOptionalBoolean = optional(isBoolean); diff --git a/src/predicate/isOptionalISODateString.ts b/src/predicate/isOptionalISODateString.ts index 94e63ae..8cdfef2 100644 --- a/src/predicate/isOptionalISODateString.ts +++ b/src/predicate/isOptionalISODateString.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isISODateString } from './isISODateString.js'; +/** + * Determine if `input` is `undefined` or an ISO date string. + * + * @example + * ```ts + * isOptionalISODateString(undefined); // true + * isOptionalISODateString('2024-01-01'); // false + * ``` + */ export const isOptionalISODateString = optional(isISODateString); diff --git a/src/predicate/isOptionalNull.ts b/src/predicate/isOptionalNull.ts index a092975..5aefee7 100644 --- a/src/predicate/isOptionalNull.ts +++ b/src/predicate/isOptionalNull.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isNull } from './isNull.js'; +/** + * Determine if `input` is `undefined` or `null`. + * + * @example + * ```ts + * isOptionalNull(undefined); // true + * isOptionalNull(0); // false + * ``` + */ export const isOptionalNull = optional(isNull); diff --git a/src/predicate/isOptionalNumber.ts b/src/predicate/isOptionalNumber.ts index 49bfcc2..36a2ae3 100644 --- a/src/predicate/isOptionalNumber.ts +++ b/src/predicate/isOptionalNumber.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isNumber } from './isNumber.js'; +/** + * Determine if `input` is `undefined` or a number. + * + * @example + * ```ts + * isOptionalNumber(undefined); // true + * isOptionalNumber(null); // false + * ``` + */ export const isOptionalNumber = optional(isNumber); diff --git a/src/predicate/isOptionalObject.ts b/src/predicate/isOptionalObject.ts index 091eb77..e503352 100644 --- a/src/predicate/isOptionalObject.ts +++ b/src/predicate/isOptionalObject.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isObject } from './isObject.js'; +/** + * Determine if `input` is `undefined` or a non-null object. + * + * @example + * ```ts + * isOptionalObject(undefined); // true + * isOptionalObject(null); // false + * ``` + */ export const isOptionalObject = optional(isObject); diff --git a/src/predicate/isOptionalString.ts b/src/predicate/isOptionalString.ts index 520a2dc..9c5b319 100644 --- a/src/predicate/isOptionalString.ts +++ b/src/predicate/isOptionalString.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isString } from './isString.js'; +/** + * Determine if `input` is `undefined` or a string. + * + * @example + * ```ts + * isOptionalString(undefined); // true + * isOptionalString(null); // false + * ``` + */ export const isOptionalString = optional(isString); diff --git a/src/predicate/isOptionalSymbol.ts b/src/predicate/isOptionalSymbol.ts index 4fed21a..2e53999 100644 --- a/src/predicate/isOptionalSymbol.ts +++ b/src/predicate/isOptionalSymbol.ts @@ -1,4 +1,13 @@ import { optional } from './factory/optional.js'; import { isSymbol } from './isSymbol.js'; +/** + * Determine if `input` is `undefined` or a symbol. + * + * @example + * ```ts + * isOptionalSymbol(undefined); // true + * isOptionalSymbol(null); // false + * ``` + */ export const isOptionalSymbol = optional(isSymbol); diff --git a/src/predicate/isPositiveFiniteNumber.ts b/src/predicate/isPositiveFiniteNumber.ts index f660a9f..c31dc7a 100644 --- a/src/predicate/isPositiveFiniteNumber.ts +++ b/src/predicate/isPositiveFiniteNumber.ts @@ -1,3 +1,12 @@ import { isFiniteNumber } from './isFiniteNumber.js'; +/** + * Determine if `input` is a finite number greater than or equal to 0. + * + * @example + * ```ts + * isPositiveFiniteNumber(42); // true + * isPositiveFiniteNumber(-1); // false + * ``` + */ export const isPositiveFiniteNumber = (input: unknown): input is number => isFiniteNumber(input) && input >= 0; diff --git a/src/predicate/isPositiveInteger.ts b/src/predicate/isPositiveInteger.ts index f74dc0b..82877f2 100644 --- a/src/predicate/isPositiveInteger.ts +++ b/src/predicate/isPositiveInteger.ts @@ -1,3 +1,12 @@ import { isInteger } from './isInteger.js'; +/** + * Determine if `input` is an integer greater than or equal to 0. + * + * @example + * ```ts + * isPositiveInteger(42); // true + * isPositiveInteger(-1); // false + * ``` + */ export const isPositiveInteger = (input: unknown): input is number => isInteger(input) && input >= 0; diff --git a/src/predicate/isPrimitive.ts b/src/predicate/isPrimitive.ts index f618fde..f2beb28 100644 --- a/src/predicate/isPrimitive.ts +++ b/src/predicate/isPrimitive.ts @@ -1,5 +1,14 @@ import type { Primitive } from '../types/common.js'; +/** + * Determine if `input` is a primitive value, i.e. `null`, a string, number, bigint, boolean, `undefined`, or symbol. + * + * @example + * ```ts + * isPrimitive('hello'); // true + * isPrimitive({}); // false + * ``` + */ export const isPrimitive = (input: unknown): input is Primitive => input === null || typeof input === 'string' || diff --git a/src/predicate/isPromiseFulfilledResult.ts b/src/predicate/isPromiseFulfilledResult.ts index 7a3c48b..6450c36 100644 --- a/src/predicate/isPromiseFulfilledResult.ts +++ b/src/predicate/isPromiseFulfilledResult.ts @@ -1,6 +1,15 @@ import { shape } from './factory/shape.js'; import { isUnknown } from './isUnknown.js'; +/** + * Determine if `input` has the shape of a fulfilled `PromiseSettledResult`. + * + * @example + * ```ts + * isPromiseFulfilledResult({ status: 'fulfilled', value: 42 }); // true + * isPromiseFulfilledResult({ status: 'rejected', reason: 'error' }); // false + * ``` + */ export const isPromiseFulfilledResult = shape>({ status: 'fulfilled', value: isUnknown, diff --git a/src/predicate/isPromiseLike.ts b/src/predicate/isPromiseLike.ts index 4537a46..e5d06b2 100644 --- a/src/predicate/isPromiseLike.ts +++ b/src/predicate/isPromiseLike.ts @@ -2,6 +2,15 @@ import { shape } from './factory/shape.js'; import { withLength } from './factory/withLength.js'; import { isFunction } from './isFunction.js'; +/** + * Determine if `input` has a `then` function that accepts 2 arguments, matching the shape of a native `Promise`. + * + * @example + * ```ts + * isPromiseLike(Promise.resolve(42)); // true + * isPromiseLike({ then: () => {} }); // false + * ``` + */ export const isPromiseLike = shape>({ then: withLength(isFunction, 2), }); diff --git a/src/predicate/isPromiseRejectedResult.ts b/src/predicate/isPromiseRejectedResult.ts index b8ef977..0077b6d 100644 --- a/src/predicate/isPromiseRejectedResult.ts +++ b/src/predicate/isPromiseRejectedResult.ts @@ -1,6 +1,15 @@ import { shape } from './factory/shape.js'; import { isAny } from './isAny.js'; +/** + * Determine if `input` has the shape of a rejected `PromiseSettledResult`. + * + * @example + * ```ts + * isPromiseRejectedResult({ status: 'rejected', reason: 'error' }); // true + * isPromiseRejectedResult({ status: 'fulfilled', value: 42 }); // false + * ``` + */ export const isPromiseRejectedResult = shape({ status: 'rejected', reason: isAny, diff --git a/src/predicate/isPropertyKey.ts b/src/predicate/isPropertyKey.ts index 4b4ecd1..8d8e8c8 100644 --- a/src/predicate/isPropertyKey.ts +++ b/src/predicate/isPropertyKey.ts @@ -1,2 +1,11 @@ +/** + * Determine if `input` is a string, number, or symbol. + * + * @example + * ```ts + * isPropertyKey('key'); // true + * isPropertyKey({}); // false + * ``` + */ export const isPropertyKey = (input: unknown): input is PropertyKey => typeof input === 'string' || typeof input === 'number' || typeof input === 'symbol'; diff --git a/src/predicate/isSafeInteger.ts b/src/predicate/isSafeInteger.ts index 20874ce..f6118d2 100644 --- a/src/predicate/isSafeInteger.ts +++ b/src/predicate/isSafeInteger.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a safe integer. + * + * @example + * ```ts + * isSafeInteger(42); // true + * isSafeInteger(2 ** 53); // false + * ``` + */ export const isSafeInteger = (input: unknown): input is number => Number.isSafeInteger(input); diff --git a/src/predicate/isSizeAware.ts b/src/predicate/isSizeAware.ts index 387a6d5..8c877b6 100644 --- a/src/predicate/isSizeAware.ts +++ b/src/predicate/isSizeAware.ts @@ -1,2 +1,11 @@ +/** + * Determine if `input` is a non-null object with a numeric `size` property. + * + * @example + * ```ts + * isSizeAware(new Set([1, 2])); // true + * isSizeAware({}); // false + * ``` + */ export const isSizeAware = (input: unknown): input is { size: number } => input !== null && typeof input === 'object' && 'size' in input && typeof input.size === 'number'; diff --git a/src/predicate/isString.ts b/src/predicate/isString.ts index 1fc5b2c..44ec2ee 100644 --- a/src/predicate/isString.ts +++ b/src/predicate/isString.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a string. + * + * @example + * ```ts + * isString('hello'); // true + * isString(42); // false + * ``` + */ export const isString = (input: unknown): input is string => typeof input === 'string'; diff --git a/src/predicate/isStringArray.ts b/src/predicate/isStringArray.ts index ccece31..16fdc85 100644 --- a/src/predicate/isStringArray.ts +++ b/src/predicate/isStringArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isString } from './isString.js'; +/** + * Determine if `input` is an array of strings. + * + * @example + * ```ts + * isStringArray(['a', 'b']); // true + * isStringArray(['a', 1]); // false + * ``` + */ export const isStringArray = everyItem(isString); diff --git a/src/predicate/isStringRecord.ts b/src/predicate/isStringRecord.ts index 7f16382..0df5e82 100644 --- a/src/predicate/isStringRecord.ts +++ b/src/predicate/isStringRecord.ts @@ -3,6 +3,15 @@ import { isStringArray } from './isStringArray.js'; import type { StringRecord } from '../types/records.js'; +/** + * Determine if `input` is an object whose values are all arrays of strings. + * + * @example + * ```ts + * isStringRecord({ a: 'x', b: 'y' }); // true + * isStringRecord({ a: 1 }); // false + * ``` + */ export const isStringRecord = (input: unknown): input is StringRecord => { return isObject(input) && Object.entries(input).every(isStringArray); }; diff --git a/src/predicate/isStringWithLength.ts b/src/predicate/isStringWithLength.ts index 12272d8..963291d 100644 --- a/src/predicate/isStringWithLength.ts +++ b/src/predicate/isStringWithLength.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a string with a length greater than 0. + * + * @example + * ```ts + * isStringWithLength('hello'); // true + * isStringWithLength(''); // false + * ``` + */ export const isStringWithLength = (input: unknown): input is string => typeof input === 'string' && input.length > 0; diff --git a/src/predicate/isSymbol.ts b/src/predicate/isSymbol.ts index e13bb46..af2aa71 100644 --- a/src/predicate/isSymbol.ts +++ b/src/predicate/isSymbol.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is a symbol. + * + * @example + * ```ts + * isSymbol(Symbol('id')); // true + * isSymbol('id'); // false + * ``` + */ export const isSymbol = (input: unknown): input is symbol => typeof input === 'symbol'; diff --git a/src/predicate/isSymbolArray.ts b/src/predicate/isSymbolArray.ts index ed7b11a..6e91886 100644 --- a/src/predicate/isSymbolArray.ts +++ b/src/predicate/isSymbolArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isSymbol } from './isSymbol.js'; +/** + * Determine if `input` is an array of symbols. + * + * @example + * ```ts + * isSymbolArray([Symbol('a'), Symbol('b')]); // true + * isSymbolArray([Symbol('a'), 'b']); // false + * ``` + */ export const isSymbolArray = everyItem(isSymbol); diff --git a/src/predicate/isTimeoutError.ts b/src/predicate/isTimeoutError.ts index 376acf0..1b9a13c 100644 --- a/src/predicate/isTimeoutError.ts +++ b/src/predicate/isTimeoutError.ts @@ -12,6 +12,12 @@ import type { TimeoutError } from '../types/errors.js'; * @privateRemarks * Using `instanceof` is not reliable for cross-realm errors. * We must check the shape of the input instead. 🦆 + * + * @example + * ```ts + * isTimeoutError(new DOMException('Timed out', 'TimeoutError')); // true + * isTimeoutError(new Error('Timed out')); // false + * ``` */ export const isTimeoutError = shape({ name: literal('TimeoutError'), diff --git a/src/predicate/isUInt32.ts b/src/predicate/isUInt32.ts index df27bfc..bf906fb 100644 --- a/src/predicate/isUInt32.ts +++ b/src/predicate/isUInt32.ts @@ -2,6 +2,15 @@ import { uInt32Max, uInt32Min } from '../numbers.js'; import type { UInt32 } from '../types/numbers.js'; +/** + * Determine if `input` is an integer within the unsigned 32-bit integer range. + * + * @example + * ```ts + * isUInt32(42); // true + * isUInt32(-1); // false + * ``` + */ export function isUInt32(input: unknown): input is UInt32 { return typeof input === 'number' && Number.isInteger(input) && input >= uInt32Min && input <= uInt32Max; } diff --git a/src/predicate/isUndefined.ts b/src/predicate/isUndefined.ts index adbc988..38f216a 100644 --- a/src/predicate/isUndefined.ts +++ b/src/predicate/isUndefined.ts @@ -1 +1,10 @@ +/** + * Determine if `input` is `undefined`. + * + * @example + * ```ts + * isUndefined(undefined); // true + * isUndefined(null); // false + * ``` + */ export const isUndefined = (input: unknown): input is undefined => typeof input === 'undefined'; diff --git a/src/predicate/isUndefinedArray.ts b/src/predicate/isUndefinedArray.ts index f53e840..df02429 100644 --- a/src/predicate/isUndefinedArray.ts +++ b/src/predicate/isUndefinedArray.ts @@ -1,4 +1,13 @@ import { everyItem } from './factory/everyItem.js'; import { isUndefined } from './isUndefined.js'; +/** + * Determine if `input` is an array of `undefined` values. + * + * @example + * ```ts + * isUndefinedArray([undefined, undefined]); // true + * isUndefinedArray([undefined, null]); // false + * ``` + */ export const isUndefinedArray = everyItem(isUndefined); diff --git a/src/predicate/isUnknown.ts b/src/predicate/isUnknown.ts index 0d4a78a..3037505 100644 --- a/src/predicate/isUnknown.ts +++ b/src/predicate/isUnknown.ts @@ -1,3 +1,12 @@ import { assume } from './assume.js'; +/** + * Always returns `true`, allowing `input` to be treated as `unknown` without any runtime checks. + * + * @example + * ```ts + * isUnknown(42); // true + * isUnknown('hello'); // true + * ``` + */ export const isUnknown = assume; diff --git a/src/predicate/isUrlString.ts b/src/predicate/isUrlString.ts index 34475b6..ad12304 100644 --- a/src/predicate/isUrlString.ts +++ b/src/predicate/isUrlString.ts @@ -1,3 +1,12 @@ +/** + * Determine if `input` is a string that `URL.canParse()` accepts as a valid URL. + * + * @example + * ```ts + * isUrlString('https://example.com'); // true + * isUrlString('not a url'); // false + * ``` + */ export const isUrlString = (input: unknown): input is string => { return typeof input === 'string' && URL.canParse(input); }; diff --git a/src/prefix.ts b/src/prefix.ts index 7d48b2b..5ad94c9 100644 --- a/src/prefix.ts +++ b/src/prefix.ts @@ -1,5 +1,14 @@ import type { Primitive } from './types/common.js'; +/** + * Prepend `prefixString` to `value`, or return `defaultValue` if `value` is `null`, `undefined`, or an empty string. + * + * @example + * ```ts + * prefix('$', 5); // '$5' + * prefix('$', null, 'N/A'); // 'N/A' + * ``` + */ export const prefix = (prefixString: string, value: Exclude, defaultValue = ''): string => { if (value == null || (typeof value == 'string' && value.length === 0)) { return defaultValue; diff --git a/src/randomInt.ts b/src/randomInt.ts index 8e12ad8..fef0908 100644 --- a/src/randomInt.ts +++ b/src/randomInt.ts @@ -17,6 +17,15 @@ export function randomInt(options?: RandomIntOptions): number; export function randomInt(min: number, max?: number): number; +/** + * Get a cryptographically secure random integer between `min` (inclusive) and `max` (exclusive). + * + * @example + * ```ts + * randomInt(1, 10); // a random integer >= 1 and < 10 + * randomInt({ min: 1, max: 10 }); // a random integer >= 1 and < 10 + * ``` + */ export function randomInt(arg1?: number | RandomIntOptions, arg2?: number): number { const { min = 0, max = Number.MAX_SAFE_INTEGER } = isObject(arg1) ? arg1 : { min: arg1, max: arg2 }; diff --git a/src/redactCredentialsInURL.ts b/src/redactCredentialsInURL.ts index 74b24ff..7a36cd9 100644 --- a/src/redactCredentialsInURL.ts +++ b/src/redactCredentialsInURL.ts @@ -5,6 +5,14 @@ export type URLMaskOptions = password: string; }; +/** + * Replace the username and password in `input`, a URL, with `mask`. + * + * @example + * ```ts + * redactCredentialsInURL('https://user:pass@example.com'); // 'https://REDACTED:REDACTED@example.com/' + * ``` + */ export const redactCredentialsInURL = ( input: ConstructorParameters[0], mask: URLMaskOptions = 'REDACTED', diff --git a/src/resultify.ts b/src/resultify.ts index 25ec9f7..55365ac 100644 --- a/src/resultify.ts +++ b/src/resultify.ts @@ -34,6 +34,17 @@ function errorResult(error: E): ErrorResult { export type ResultifiedSyncFn = (...args: Parameters) => Result, Error>; +/** + * Wrap a synchronous function `fn` so it returns a `Result` instead of throwing. + * + * @example + * ```ts + * const parse = resultify(JSON.parse); + * + * parse('{"a":1}'); // { ok: { a: 1 }, isOk: true, isError: false } + * parse('invalid'); // { error: SyntaxError, isOk: false, isError: true } + * ``` + */ export function resultify(fn: Fn): ResultifiedSyncFn { return (...args) => { try { @@ -48,6 +59,20 @@ export type ResultifiedAsyncFn = ( ...args: Parameters ) => Promise>, Error>>; +/** + * Wrap an async function `fn` so its returned `Promise` resolves with a `Result` instead of rejecting. + * + * @example + * ```ts + * const fetchJson = resultifyAsync(async (url: string) => { + * const response = await fetch(url); + * + * return response.json(); + * }); + * + * await fetchJson('https://example.com'); // { ok: ..., isOk: true, isError: false } + * ``` + */ export const resultifyAsync = (fn: Fn): ResultifiedAsyncFn => (...args) => diff --git a/src/secToString.ts b/src/secToString.ts index 501d23d..0ce3782 100644 --- a/src/secToString.ts +++ b/src/secToString.ts @@ -13,6 +13,14 @@ export enum Seconds { type SecondsTuple = [key: Lowercase, seconds: Seconds]; +/** + * Convert `time`, in seconds, to a human-readable string. + * + * @example + * ```ts + * secToString(90061); // '1 day 1 hour 1 minute 1 second' + * ``` + */ export function secToString(time: number, joinString = ' '): string { const secTime: SecondsTuple[] = [ ['millennium', Seconds.Millennium], diff --git a/src/set.ts b/src/set.ts index a7067f8..1653c63 100644 --- a/src/set.ts +++ b/src/set.ts @@ -2,9 +2,6 @@ import { pathParts } from './pathParts.js'; import type { Path, PathValue } from './types/objects.js'; -/** - * Set the value of a property - */ export function set, Value extends PathValue>( input: Input, path: InputPath, @@ -17,6 +14,17 @@ export function set( value: Value, ): Value; +/** + * Set the value of a property + * + * @example + * ```ts + * const data = { a: { b: 1 } }; + * + * set(data, 'a.b', 2); // 2 + * data; // { a: { b: 2 } } + * ``` + */ export function set | string, Value>( input: Input, path: InputPath, diff --git a/src/sort/byLocaleCompare.ts b/src/sort/byLocaleCompare.ts index d0a5cc3..9aa2ac3 100644 --- a/src/sort/byLocaleCompare.ts +++ b/src/sort/byLocaleCompare.ts @@ -1 +1,9 @@ +/** + * Compare two strings using `localeCompare`. + * + * @example + * ```ts + * ['banana', 'apple', 'cherry'].sort(byLocaleCompare); // ['apple', 'banana', 'cherry'] + * ``` + */ export const byLocaleCompare = (left: string, right: string): number => left.localeCompare(right); diff --git a/src/sort/byRandom.ts b/src/sort/byRandom.ts index d802927..3c585f2 100644 --- a/src/sort/byRandom.ts +++ b/src/sort/byRandom.ts @@ -1,5 +1,10 @@ /** * Randomly return -1, 0, or 1. This is an easy way to shuffle an array. + * + * @example + * ```ts + * [1, 2, 3, 4, 5].sort(byRandom); // shuffled order, e.g. [3, 1, 5, 2, 4] + * ``` */ export const byRandom = (): number => { let value: number; diff --git a/src/sort/bySimpleComparison.ts b/src/sort/bySimpleComparison.ts index acdff77..35589c0 100644 --- a/src/sort/bySimpleComparison.ts +++ b/src/sort/bySimpleComparison.ts @@ -1,3 +1,11 @@ +/** + * Compare two values using `<`, `>`, and `===`. + * + * @example + * ```ts + * [3, 1, 2].sort(bySimpleComparison); // [1, 2, 3] + * ``` + */ export const bySimpleComparison = (left: T, right: T): number => { return left === right ? 0 : left > right ? 1 : -1; }; diff --git a/src/sort/bySubtraction.ts b/src/sort/bySubtraction.ts index 3244c14..02b4551 100644 --- a/src/sort/bySubtraction.ts +++ b/src/sort/bySubtraction.ts @@ -1,4 +1,12 @@ import { parseNumber } from '../parseNumber.js'; +/** + * Compare two numeric-like values by parsing them and subtracting `right` from `left`. + * + * @example + * ```ts + * [10, 2, 1].sort(bySubtraction); // [1, 2, 10] + * ``` + */ export const bySubtraction = (left: T, right: T): number => parseNumber(left) - parseNumber(right); diff --git a/src/sort/byTimestamp.ts b/src/sort/byTimestamp.ts index 84a3930..db06ad6 100644 --- a/src/sort/byTimestamp.ts +++ b/src/sort/byTimestamp.ts @@ -1,5 +1,13 @@ import { getMilliseconds } from '../getMilliseconds.js'; +/** + * Compare two dates, strings, or numbers by their timestamp in milliseconds. + * + * @example + * ```ts + * ['2024-01-02', '2024-01-01'].sort(byTimestamp); // ['2024-01-01', '2024-01-02'] + * ``` + */ export const byTimestamp = (left: T, right: T): number => { const timeDiff = getMilliseconds(left) - getMilliseconds(right); diff --git a/src/sort/factory/byProperty.ts b/src/sort/factory/byProperty.ts index f26d900..5655e3c 100644 --- a/src/sort/factory/byProperty.ts +++ b/src/sort/factory/byProperty.ts @@ -1,5 +1,13 @@ import type { CompareFn } from '../../types/functions.js'; +/** + * Create a comparator that sorts by the value at the given object `property`, using `compareFn` to compare those values. + * + * @example + * ```ts + * [{ age: 30 }, { age: 20 }].sort(byProperty(bySubtraction, 'age')); // [{ age: 20 }, { age: 30 }] + * ``` + */ export const byProperty = (compareFn: CompareFn, property: K): CompareFn => (left, right) => diff --git a/src/sort/factory/byReverseOf.ts b/src/sort/factory/byReverseOf.ts index d65149d..a29d2dd 100644 --- a/src/sort/factory/byReverseOf.ts +++ b/src/sort/factory/byReverseOf.ts @@ -1,5 +1,13 @@ import type { CompareFn } from '../../types/functions.js'; +/** + * Create a comparator that reverses the ordering produced by the given `compareFn`. + * + * @example + * ```ts + * [1, 2, 3].sort(byReverseOf(bySubtraction)); // [3, 2, 1] + * ``` + */ export const byReverseOf = (compareFn: CompareFn): CompareFn => (left, right) => diff --git a/src/stripIndent.ts b/src/stripIndent.ts index a720792..d1912b3 100644 --- a/src/stripIndent.ts +++ b/src/stripIndent.ts @@ -2,6 +2,11 @@ import { NEWLINE_RAW_PATTERN } from './constants.js'; /** * Remove `indent` immediately following every line break in `input`. + * + * @example + * ```ts + * stripIndent('\n foo\n bar', ' '); // '\nfoo\nbar' + * ``` */ export function stripIndent(input: string, indent: string): string { return input.replaceAll(new RegExp(String.raw`(?${NEWLINE_RAW_PATTERN})${indent}`, 'g'), '$'); diff --git a/src/stripWhitespace.ts b/src/stripWhitespace.ts index 1731e17..3568423 100644 --- a/src/stripWhitespace.ts +++ b/src/stripWhitespace.ts @@ -1,4 +1,12 @@ import type { StripWhitespace } from './types/strings.js'; +/** + * Remove all whitespace from `input`. + * + * @example + * ```ts + * stripWhitespace('a b\tc\nd'); // 'abcd' + * ``` + */ export const stripWhitespace = (input: T): StripWhitespace => input.replace(/\s+/g, '') as StripWhitespace; diff --git a/src/suffix.ts b/src/suffix.ts index e43db32..bb7817c 100644 --- a/src/suffix.ts +++ b/src/suffix.ts @@ -1,5 +1,14 @@ import type { Primitive } from './types/common.js'; +/** + * Append `suffixString` to `value`, or return `defaultValue` if `value` is `null`, `undefined`, or an empty string. + * + * @example + * ```ts + * suffix('!', 'Hi'); // 'Hi!' + * suffix('!', null, 'N/A'); // 'N/A' + * ``` + */ export const suffix = (suffixString: string, value: Exclude, defaultValue = ''): string => { if (value == null || (typeof value == 'string' && value.length === 0)) { return defaultValue; diff --git a/src/toPascalCase.ts b/src/toPascalCase.ts index 9fb85eb..cbe7814 100644 --- a/src/toPascalCase.ts +++ b/src/toPascalCase.ts @@ -4,6 +4,15 @@ import type { StringRecord } from './types/records.js'; import type { PascalCase } from './types/strings.js'; import type { KeyValueTuple } from './types/tuples.js'; +/** + * Convert `text` to PascalCase, optionally replacing individual words using `customWords`. + * + * @example + * ```ts + * toPascalCase('hello world'); // 'HelloWorld' + * toPascalCase('foo-bar', { bar: 'BAR' }); // 'FooBAR' + * ``` + */ export function toPascalCase(text: Type, customWords?: StringRecord): PascalCase { let words: string[] = String(text) .replaceAll(/['.]/g, '') diff --git a/src/trimEnd.ts b/src/trimEnd.ts index 6233677..f41819f 100644 --- a/src/trimEnd.ts +++ b/src/trimEnd.ts @@ -1,5 +1,14 @@ import { escapeRegExp } from './escapeRegExp.js'; +/** + * Remove `char` from the end of `str`, or whitespace if `char` isn't provided. + * + * @example + * ```ts + * trimEnd('hello '); // 'hello' + * trimEnd('hello///', '/'); // 'hello' + * ``` + */ export function trimEnd(str: string, char?: string): string { return char ? str.replace(new RegExp(`${escapeRegExp(char)}+$`), '') : str.trimEnd(); } diff --git a/src/trimIndentation.ts b/src/trimIndentation.ts index 3856639..5d8cc2f 100644 --- a/src/trimIndentation.ts +++ b/src/trimIndentation.ts @@ -2,6 +2,14 @@ import { NEWLINE_RAW_PATTERN } from './constants.js'; import { findIndentation } from './findIndentation.js'; import { stripIndent } from './stripIndent.js'; +/** + * Remove common leading indentation from every line in `input` and trim the result. + * + * @example + * ```ts + * trimIndentation(' foo\n bar\n'); // 'foo\nbar' + * ``` + */ export function trimIndentation(input: string): string { const whiteSpace = findIndentation(input.split(new RegExp(NEWLINE_RAW_PATTERN))); diff --git a/src/trimStart.ts b/src/trimStart.ts index 68b4978..9b65fa8 100644 --- a/src/trimStart.ts +++ b/src/trimStart.ts @@ -1,5 +1,14 @@ import { escapeRegExp } from './escapeRegExp.js'; +/** + * Remove `char` from the start of `str`, or whitespace if `char` isn't provided. + * + * @example + * ```ts + * trimStart(' hello'); // 'hello' + * trimStart('///hello', '/'); // 'hello' + * ``` + */ export function trimStart(str: string, char?: string): string { return char ? str.replace(new RegExp(`^${escapeRegExp(char)}+`), '') : str.trimStart(); } diff --git a/src/tryFn.ts b/src/tryFn.ts index b04dec9..10837a3 100644 --- a/src/tryFn.ts +++ b/src/tryFn.ts @@ -7,6 +7,17 @@ export function tryFn( defaultValue: DefaultValue, ): (...args: Parameters) => ReturnType | DefaultValue; +/** + * Wrap `fn` so calling it returns `defaultValue` instead of throwing. + * + * @example + * ```ts + * const parse = tryFn(JSON.parse, {}); + * + * parse('invalid'); // {} + * parse('{"a":1}'); // { a: 1 } + * ``` + */ export function tryFn( fn: Fn, defaultValue?: DefaultType, diff --git a/src/tryIt.ts b/src/tryIt.ts index e63e794..5ac15cf 100644 --- a/src/tryIt.ts +++ b/src/tryIt.ts @@ -4,6 +4,15 @@ export function tryIt(fn: Fn): ReturnType | undefine export function tryIt(fn: Fn, defaultValue: D): ReturnType | D; +/** + * Call `fn` and return `defaultValue` instead of throwing if it fails. + * + * @example + * ```ts + * tryIt(() => JSON.parse('invalid'), {}); // {} + * tryIt(() => JSON.parse('{"a":1}')); // { a: 1 } + * ``` + */ export function tryIt(fn: Fn, defaultValue?: D): ReturnType | D | undefined { try { return fn(); diff --git a/src/unique.ts b/src/unique.ts index b8a1e46..661a263 100644 --- a/src/unique.ts +++ b/src/unique.ts @@ -14,7 +14,8 @@ export type UniqueOptions = { /** * Return `true` to yield the item. * - * @todo Refactor to use `filter` on the (async)iterator when available. + * @privateRemarks + * TODO: Refactor to use `filter` on the (async)iterator when available. * @see https://github.com/tc39/proposal-async-iterator-helpers * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/filter */ diff --git a/src/uniqueItems.ts b/src/uniqueItems.ts index 66388c2..1e90b27 100644 --- a/src/uniqueItems.ts +++ b/src/uniqueItems.ts @@ -1,3 +1,11 @@ +/** + * Get the unique items in `data`. + * + * @example + * ```ts + * uniqueItems([1, 2, 2, 3]); // [1, 2, 3] + * ``` + */ export function uniqueItems(data: T[]): T[] { return [...new Set(data)]; } diff --git a/src/until.ts b/src/until.ts index dc53133..1c9a382 100644 --- a/src/until.ts +++ b/src/until.ts @@ -32,13 +32,43 @@ const defaultOptions: Readonly = { delay: 10, }; +/** + * Determine if `input` is a valid `Delay`. + * + * @example + * ```ts + * isDelay(10); // true + * isDelay(() => 10); // true + * isDelay('10'); // false + * ``` + */ export const isDelay = (input: unknown): input is Delay => Number.isInteger(input) || typeof input === 'function'; +/** + * Resolve `delay` to a number of milliseconds, calling it with `context` if it's a function. + * + * @example + * ```ts + * const context = { callCount: 2, lastCall: Date.now(), data: {}, options: { delay: 100 } }; + * + * getDelay(100, context); // 100 + * getDelay((ctx) => ctx.callCount * 50, context); // 100 + * ``` + */ export const getDelay = (delay: Delay, context: UntilContext): number => typeof delay === 'function' ? delay(context) : delay; /** * Return a Promise that delegates resolving/rejecting to the passed in function. + * + * @example + * ```ts + * await until((resolve, reject, context) => { + * if (context.callCount >= 3) { + * resolve('done'); + * } + * }, { delay: 100, callLimit: 5 }); // resolves with 'done' after being called 3 times + * ``` */ export function until(fn: UntilCallback, options: UntilOptions = defaultOptions): Promise { if (typeof fn !== 'function') { From bd219cc126cb90835ea342e59b8f855a13600175 Mon Sep 17 00:00:00 2001 From: Eric King Date: Sun, 12 Jul 2026 10:28:49 -0500 Subject: [PATCH 8/8] chore(deps-dev): updated dev dependencies --- pnpm-lock.yaml | 54 ++++++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f85aef..3bc7db1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -82,7 +82,7 @@ importers: version: 1.2.1 vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)) + version: 4.1.10(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)) packages: @@ -1057,8 +1057,8 @@ packages: engines: {node: '>=16.20.0'} hasBin: true - '@ungap/structured-clone@1.3.2': - resolution: {integrity: sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA==} + '@ungap/structured-clone@1.3.3': + resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} '@unrs/resolver-binding-android-arm-eabi@1.12.2': resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} @@ -1546,11 +1546,6 @@ packages: engines: {node: '>=18'} hasBin: true - conventional-commits-parser@7.0.1: - resolution: {integrity: sha512-6VtskFpPsNkGVk/TY2RnV/MEdKfvCPBtQZN9x8jh9+k5RWBQ+tiaWn5UFCzTr0Dd88iKx7xghxbjBRp5uIzp3g==} - engines: {node: '>=22'} - hasBin: true - conventional-commits-parser@7.1.0: resolution: {integrity: sha512-DPp6hkUjvwIivxbkrTiLXeRswNv1A/4GFA2X6scXma0AMa9632V3TwxmrlkUIEtUktiM3Ln+RrSH2xlP3/jUTw==} engines: {node: '>=22'} @@ -2225,8 +2220,8 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} engines: {node: '>= 4'} import-fresh@3.3.1: @@ -2718,10 +2713,6 @@ packages: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} - meow@14.1.0: - resolution: {integrity: sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==} - engines: {node: '>=20'} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -3784,8 +3775,8 @@ packages: engines: {node: '>=22.22.2'} hasBin: true - vite@8.1.3: - resolution: {integrity: sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==} + vite@8.1.4: + resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4146,7 +4137,7 @@ snapshots: dependencies: '@commitlint/types': 21.2.0 conventional-changelog-angular: 9.2.1 - conventional-commits-parser: 7.0.1 + conventional-commits-parser: 7.1.0 '@commitlint/read@21.2.1(conventional-commits-parser@7.1.0)': dependencies: @@ -4990,7 +4981,7 @@ snapshots: '@typescript-eslint/utils': 8.63.0(eslint@8.57.1)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.63.0 eslint: 8.57.1 - ignore: 7.0.5 + ignore: 7.0.6 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 @@ -5103,7 +5094,7 @@ snapshots: '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260707.2 '@typescript/native-preview-win32-x64': 7.0.0-dev.20260707.2 - '@ungap/structured-clone@1.3.2': {} + '@ungap/structured-clone@1.3.3': {} '@unrs/resolver-binding-android-arm-eabi@1.12.2': optional: true @@ -5187,7 +5178,7 @@ snapshots: obug: 2.1.3 std-env: 4.2.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)) + vitest: 4.1.10(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)) '@vitest/expect@4.1.10': dependencies: @@ -5198,13 +5189,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0) + vite: 8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0) '@vitest/pretty-format@4.1.10': dependencies: @@ -5589,11 +5580,6 @@ snapshots: '@simple-libs/stream-utils': 1.2.0 meow: 13.2.0 - conventional-commits-parser@7.0.1: - dependencies: - '@simple-libs/stream-utils': 2.0.0 - meow: 14.1.0 - conventional-commits-parser@7.1.0: dependencies: '@simple-libs/stream-utils': 2.0.0 @@ -6030,7 +6016,7 @@ snapshots: '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.2 + '@ungap/structured-clone': 1.3.3 ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 @@ -6418,7 +6404,7 @@ snapshots: ignore@5.3.2: {} - ignore@7.0.5: {} + ignore@7.0.6: {} import-fresh@3.3.1: dependencies: @@ -6894,8 +6880,6 @@ snapshots: meow@13.2.0: {} - meow@14.1.0: {} - merge-stream@2.0.0: {} micromatch@4.0.8: @@ -8011,7 +7995,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite@8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0): + vite@8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.5 @@ -8024,10 +8008,10 @@ snapshots: jiti: 2.6.1 yaml: 2.9.0 - vitest@4.1.10(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)): + vitest@4.1.10(@types/node@24.13.3)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1)(vite@8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(vite@8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -8044,7 +8028,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0) + vite: 8.1.4(@types/node@24.13.3)(jiti@2.6.1)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.13.3