├── .czrc ├── .editorconfig ├── .eslintrc ├── .fossa.yml ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── codeql-analysis.yml │ ├── release-eggs.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .husky ├── .gitignore └── commit-msg ├── .prettierrc ├── .releaserc.json ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── LICENSE ├── README.md ├── SECURITY.md ├── api-extractor.json ├── api.ts ├── commitlint.config.js ├── common ├── head.ts ├── head_test.ts ├── init.ts ├── init_test.ts ├── last.ts ├── last_test.ts ├── mod.ts ├── tail.ts └── tail_test.ts ├── deps.ts ├── dev_deps.ts ├── docs ├── .vitepress │ ├── config.js │ └── theme │ │ ├── custom.css │ │ └── index.ts ├── guide │ └── index.md ├── index.md ├── public │ ├── googlef5dce3c92d21b4b2.html │ ├── icon.gif │ └── logo.png └── views │ └── api.eta ├── egg.json ├── mod.ts ├── package.json ├── rollup.config.ts ├── scripts ├── gen-api-list.ts ├── gen-api-model.ts ├── gen-api.ts ├── gen-full-docs.ts └── gen-relations.ts ├── src ├── F.ts ├── K.ts ├── N.ts ├── NN.ts ├── T.ts ├── _ │ ├── has.ts │ ├── hasPath.ts │ ├── prop.ts │ └── propPath.ts ├── add.ts ├── advance.ts ├── and.ts ├── append.ts ├── chunk.ts ├── constants │ └── index.ts ├── constructorName.ts ├── dec.ts ├── defaultTo.ts ├── divide.ts ├── equal.ts ├── flattenDeep.ts ├── gt.ts ├── gte.ts ├── has.ts ├── identical.ts ├── identity.ts ├── ifElse.ts ├── ifElseFn.ts ├── inc.ts ├── lt.ts ├── lte.ts ├── multiply.ts ├── not.ts ├── or.ts ├── pipe.ts ├── prepend.ts ├── product.ts ├── props.ts ├── subtract.ts ├── sum.ts ├── take.ts ├── takeLast.ts ├── tap.ts ├── tryCatch.ts ├── types │ └── index.ts ├── uniq.ts └── xor.ts ├── test ├── F.test.ts ├── K.test.ts ├── N.test.ts ├── NN.test.ts ├── T.test.ts ├── _ │ ├── has.test.ts │ ├── hasPath.test.ts │ ├── prop.test.ts │ └── propPath.test.ts ├── advance.test.ts ├── and.test.ts ├── append.test.ts ├── asserts.ts ├── chunk.test.ts ├── constants │ └── index.ts ├── constructorName.test.ts ├── dec.test.ts ├── defaultTo.test.ts ├── flattenDeep.test.ts ├── gt.test.ts ├── gte.test.ts ├── has.test.ts ├── identity.test.ts ├── ifElse.test.ts ├── ifElseFn.test.ts ├── inc.test.ts ├── index.ts ├── lt.test.ts ├── lte.test.ts ├── not.test.ts ├── or.test.ts ├── pipe.test.ts ├── prepend.test.ts ├── product.test.ts ├── props.test.ts ├── sum.test.ts ├── tag.test.ts ├── take.test.ts ├── takeLast.test.ts ├── tryCatch.test.ts ├── tsconfig.json ├── uniq.test.ts └── xor.test.ts ├── tsconfig.json ├── tsdoc.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es2021": true, 6 | "node": true 7 | }, 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended" 12 | ], 13 | "parser": "@typescript-eslint/parser", 14 | "parserOptions": { 15 | "ecmaVersion": 12, 16 | "sourceType": "module", 17 | "tsconfigRootDir": "__dirname" 18 | }, 19 | "plugins": [ 20 | "@typescript-eslint", 21 | "simple-import-sort", 22 | "eslint-plugin-tsdoc" 23 | ], 24 | "rules": { 25 | "simple-import-sort/imports": "error", 26 | "simple-import-sort/exports": "error", 27 | "tsdoc/syntax": "error" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | commitlint.config.js linguist-documentation 2 | .husky/commit-msg linguist-documentation 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | 28 | - OS: [e.g. iOS] 29 | - Browser [e.g. chrome, safari] 30 | - Version [e.g. 22] 31 | 32 | **Smartphone (please complete the following information):** 33 | 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: CodeQL 13 | 14 | on: 15 | push: 16 | branches: [main] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [main] 20 | schedule: 21 | - cron: '0 0 * * *' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: ['javascript'] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /.github/workflows/release-eggs.yml: -------------------------------------------------------------------------------- 1 | name: release-eggs 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Setup repo 12 | uses: actions/checkout@v2 13 | 14 | - name: Setup Deno 15 | uses: denolib/setup-deno@v2 16 | with: 17 | deno-version: v1.5.x 18 | 19 | - name: Publish module 20 | run: | 21 | deno install -A --unstable https://x.nest.land/eggs@0.3.2/eggs.ts 22 | eggs link ${{ secrets.NESTAPIKEY }} 23 | eggs publish --yes --no-check --version $(git describe --tags $(git rev-list --tags --max-count=1)) 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | branches: 6 | - beta 7 | - main 8 | paths-ignore: 9 | - examples/** 10 | - docs/** 11 | 12 | jobs: 13 | # audit: 14 | # runs-on: ${{ matrix.os }} 15 | 16 | # strategy: 17 | # matrix: 18 | # os: [ubuntu-latest] 19 | # node: [15] 20 | 21 | # steps: 22 | # - uses: actions/setup-node@v2-beta 23 | # with: 24 | # node-version: ${{ matrix.node }} 25 | 26 | # - name: Checkout 27 | # uses: actions/checkout@v2 28 | 29 | # - name: Audit 30 | # run: yarn audit --level critical 31 | 32 | setup: 33 | runs-on: ${{ matrix.os }} 34 | 35 | strategy: 36 | matrix: 37 | os: [ubuntu-latest] 38 | node: [15] 39 | 40 | steps: 41 | - uses: actions/setup-node@v2-beta 42 | with: 43 | node-version: ${{ matrix.node }} 44 | 45 | - name: Checkout 46 | uses: actions/checkout@v2 47 | 48 | - name: Cache node_modules 49 | id: node_modules_cache_id 50 | uses: actions/cache@v2 51 | with: 52 | path: '**/node_modules' 53 | key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 54 | 55 | - name: Install 56 | if: steps.node_modules_cache_id.outputs.cache-hit != 'true' 57 | run: yarn --check-files --frozen-lockfile --non-interactive 58 | 59 | build: 60 | needs: [setup] 61 | runs-on: ${{ matrix.os }} 62 | 63 | strategy: 64 | matrix: 65 | os: [ubuntu-latest] 66 | node: [15] 67 | 68 | steps: 69 | - uses: actions/setup-node@v2-beta 70 | with: 71 | node-version: ${{ matrix.node }} 72 | 73 | - name: Checkout 74 | uses: actions/checkout@v2 75 | 76 | - name: Restore node_modules 77 | id: node_modules_cache_id 78 | uses: actions/cache@v2 79 | with: 80 | path: '**/node_modules' 81 | key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 82 | 83 | - name: Build 84 | run: yarn build 85 | 86 | - uses: actions/upload-artifact@v2 87 | with: 88 | name: dist 89 | path: dist 90 | 91 | docs: 92 | needs: [build] 93 | runs-on: ${{ matrix.os }} 94 | 95 | strategy: 96 | matrix: 97 | os: [ubuntu-latest] 98 | node: [15] 99 | 100 | steps: 101 | - uses: actions/setup-node@v2-beta 102 | with: 103 | node-version: ${{ matrix.node }} 104 | 105 | - name: Checkout 106 | uses: actions/checkout@v2 107 | 108 | - name: Restore node_modules 109 | id: node_modules_cache_id 110 | uses: actions/cache@v2 111 | with: 112 | path: '**/node_modules' 113 | key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 114 | 115 | - uses: actions/download-artifact@v2 116 | with: 117 | name: dist 118 | path: dist 119 | 120 | - name: Prepare 121 | run: yarn prepare:docs 122 | 123 | - name: Build 124 | run: yarn build:docs 125 | 126 | - name: Deploy 127 | uses: peaceiris/actions-gh-pages@v3 128 | with: 129 | github_token: ${{ secrets.GITHUB_TOKEN }} 130 | publish_dir: docs/.vitepress/dist 131 | 132 | lint: 133 | needs: [setup] 134 | runs-on: ${{ matrix.os }} 135 | 136 | strategy: 137 | matrix: 138 | os: [ubuntu-latest] 139 | node: [15] 140 | 141 | steps: 142 | - uses: actions/setup-node@v2-beta 143 | with: 144 | node-version: ${{ matrix.node }} 145 | 146 | - name: Checkout 147 | uses: actions/checkout@v2 148 | 149 | - name: Restore node_modules 150 | id: node_modules_cache_id 151 | uses: actions/cache@v2 152 | with: 153 | path: '**/node_modules' 154 | key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 155 | 156 | - name: Lint 157 | run: yarn lint 158 | 159 | test: 160 | runs-on: ${{ matrix.os }} 161 | 162 | strategy: 163 | matrix: 164 | os: [ubuntu-latest] 165 | node: [15] 166 | 167 | steps: 168 | - name: Checkout 169 | uses: actions/checkout@v2 170 | 171 | - name: Setup Deno 172 | uses: denolib/setup-deno@v2 173 | with: 174 | deno-version: v1.11.x 175 | 176 | - name: Test 177 | run: yarn test --unstable --coverage=coverage 178 | 179 | - name: Generate coverage report 180 | run: deno --unstable coverage ./coverage --lcov > coverage.lcov 181 | 182 | - uses: actions/upload-artifact@v2 183 | with: 184 | name: coverage 185 | path: coverage.lcov 186 | 187 | report-coverage: 188 | needs: [test] 189 | runs-on: ${{ matrix.os }} 190 | 191 | strategy: 192 | matrix: 193 | os: [ubuntu-latest] 194 | 195 | steps: 196 | - name: Checkout 197 | uses: actions/checkout@v2 198 | 199 | - uses: actions/download-artifact@v2 200 | with: 201 | name: coverage 202 | 203 | - uses: codecov/codecov-action@v1 204 | with: 205 | files: coverage.lcov 206 | 207 | release: 208 | needs: [lint, test, build] 209 | runs-on: ${{ matrix.os }} 210 | 211 | strategy: 212 | matrix: 213 | os: [ubuntu-latest] 214 | node: [15] 215 | steps: 216 | - uses: actions/setup-node@v2-beta 217 | with: 218 | node-version: ${{ matrix.node }} 219 | 220 | - name: Checkout 221 | uses: actions/checkout@v2 222 | 223 | - name: Restore node_modules 224 | id: node_modules_cache_id 225 | uses: actions/cache@v2 226 | with: 227 | path: '**/node_modules' 228 | key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 229 | 230 | - uses: actions/download-artifact@v2 231 | with: 232 | name: dist 233 | path: dist 234 | 235 | - name: Release 236 | run: yarn release 237 | env: 238 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 239 | GH_TOKEN: ${{ secrets.GH_PUBLIC }} 240 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: "0 9 * * *" 8 | 9 | jobs: 10 | stable: 11 | name: Deno Stable 12 | 13 | runs-on: ${{ matrix.os }} 14 | timeout-minutes: 60 15 | 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | os: [macOS-latest, windows-latest, ubuntu-latest] 20 | 21 | steps: 22 | - name: Setup repo 23 | uses: actions/checkout@v2 24 | 25 | - name: Setup Deno 26 | uses: denolib/setup-deno@v2 27 | 28 | - name: Run tests 29 | run: deno test -A --unstable 30 | 31 | nightly: 32 | name: Deno Nightly 33 | 34 | runs-on: ${{ matrix.os }} 35 | timeout-minutes: 60 36 | 37 | strategy: 38 | fail-fast: false 39 | matrix: 40 | os: [macOS-latest, windows-latest, ubuntu-latest] 41 | 42 | steps: 43 | - name: Setup repo 44 | uses: actions/checkout@v2 45 | 46 | - name: Setup Deno 47 | uses: denolib/setup-deno@v2 48 | with: 49 | deno-version: nightly 50 | 51 | - name: Run tests 52 | run: deno test -A --unstable 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | 118 | temp 119 | docs/api/* 120 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": ["main", { "name": "beta", "prerelease": true }], 3 | "plugins": [ 4 | [ 5 | "semantic-release-gitmoji", 6 | { 7 | "releaseRules": { 8 | "major": [":boom:"], 9 | "premajor": [":boom:"], 10 | "minor": [":sparkles:"], 11 | "preminor": [":sparkles:"], 12 | "patch": [":bug:", ":ambulance:", ":lock:"], 13 | "prepatch": [":bug:", ":ambulance:", ":lock:"] 14 | } 15 | } 16 | ], 17 | "@semantic-release/changelog", 18 | "@semantic-release/npm", 19 | "@semantic-release/github", 20 | [ 21 | "@semantic-release/git", 22 | { 23 | "assets": ["CHANGELOG.md", "package.json", "LICENSE"], 24 | "message": ":bookmark: ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 25 | } 26 | ] 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["denoland.vscode-deno"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll": true 6 | }, 7 | "deno.enable": true, 8 | "deno.lint": true, 9 | "deno.unstable": true, 10 | "deno.suggest.completeFunctionCalls": true, 11 | "deno.config": "./tsconfig.json" 12 | } 13 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | . 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | . Translations are available at 128 | . 129 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: TomokiMiyauci 4 | patreon: tomoki_miyauci 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 TomokiMiyauci 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | logo image 3 |

fonction

4 |

5 | 6 |

7 | A modern practical functional library 8 |

9 | 10 |
11 | 12 | [![test](https://github.com/TomokiMiyauci/fonction/actions/workflows/test.yml/badge.svg)](https://github.com/TomokiMiyauci/fonction/actions/workflows/test.yml) 13 | [![GitHub release](https://img.shields.io/github/release/TomokiMiyauci/fonction.svg)](https://github.com/TomokiMiyauci/fonction/releases) 14 | [![deno land](http://img.shields.io/badge/available%20on-deno.land/x-lightgrey.svg?logo=deno&labelColor=black)](https://deno.land/x/fonction) 15 | [![nest badge](https://nest.land/badge.svg)](https://nest.land/package/fonction) 16 | [![deno version](https://img.shields.io/badge/deno-^1.6.0-lightgrey?logo=deno)](https://github.com/denoland/deno) 17 | ![node support version](https://img.shields.io/badge/node-%5E14.16.0-yellow) 18 | ![bundle size](https://img.shields.io/bundlephobia/min/fonction) 19 | 20 | ![GitHub (Pre-)Release Date](https://img.shields.io/github/release-date-pre/TomokiMiyauci/fonction) 21 | [![dependencies Status](https://status.david-dm.org/gh/TomokiMiyauci/fonction.svg)](https://david-dm.org/TomokiMiyauci/fonction) 22 | [![codecov](https://codecov.io/gh/TomokiMiyauci/fonction/branch/main/graph/badge.svg?token=SPAi5Pv2wd)](https://codecov.io/gh/TomokiMiyauci/fonction) 23 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/f43b1c317e11445399d85ce6efc06504)](https://www.codacy.com/gh/TomokiMiyauci/fonction/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TomokiMiyauci/fonction&utm_campaign=Badge_Grade) 24 | ![npm type definitions](https://img.shields.io/npm/types/arithmetic4) 25 | ![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg) 26 | ![Gitmoji](https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg?style=flat) 27 | ![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg) 28 | ![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) 29 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) 30 | [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B26231%2Fgithub.com%2FTomokiMiyauci%2Ffonction.svg?type=small)](https://app.fossa.com/projects/custom%2B26231%2Fgithub.com%2FTomokiMiyauci%2Ffonction?ref=badge_small) 31 | 32 |
33 | 34 | --- 35 | 36 | ## :sparkles: Features 37 | 38 | - :green_heart: Friendly type definition 39 | - :earth_americas: Universal functions providing ESM and Commonjs 40 | - :package: Optimized, super slim size 41 | - :page_facing_up: TSDoc-style comments 42 | - :1234: Bigint support 43 | - 🦕 Deno support 44 | 45 | Fonction (French word for "function", not typo:sweat_smile:) is modern practical functional library. 46 | Special attention is paid to bundle size and strict type definitions. Therefore, you can take out and use only what you want to use without worrying about the size. 47 | 48 | ## :memo: Docs 49 | 50 | [Read the Docs to Learn More.](https://tomokimiyauci.github.io/fonction/) 51 | 52 | ## :green_heart: Supports 53 | 54 | The TypeScript version must be `4.1.0` or higher. 55 | 56 | This project provide `ES modules` and `Commonjs`. 57 | 58 | If you have an opinion about what to support, you can open an [issue](https://github.com/TomokiMiyauci/fonction/issues) to discuss it. 59 | 60 | The `browserslist` has the following settings. 61 | 62 | ```bash 63 | > 0.5% 64 | last 1 version 65 | not IE <= 11 66 | not ie_mob <= 11 67 | node 14 68 | ``` 69 | 70 | | Deno
Deno | Node.js
Node.js | IE / Edge
Edge | Firefox
Firefox | Chrome
Chrome | Safari
Safari | iOS Safari
iOS Safari | Samsung
Samsung | Opera
Opera | 71 | | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | 72 | | `^1.6.0` | `^14.16.0` | `^88` | `^86` | `^87` | `^13.1` | `^13.4` | `^13.0` | `^73` | 73 | 74 | ## :dizzy: Usage 75 | 76 | `fonction` provides multi platform modules. 77 | 78 | You can see all the functions [here](https://tomokimiyauci.github.io/fonction/api/). 79 | 80 | ### 🦕 Deno 81 | 82 | #### deno.land 83 | 84 | ```ts 85 | import { add } from 'https://deno.land/x/fonction/mod.ts' 86 | 87 | add(1, 2) // 3 88 | ``` 89 | 90 | #### nest.land 91 | 92 | ```ts 93 | import { add } from 'https://x.nest.land/fonction@1.5.0/mod.ts' 94 | 95 | add(1, 2) // 3 96 | ``` 97 | 98 | ### :package: Node.js 99 | 100 | #### Install 101 | 102 | ```bash 103 | npm i fonction 104 | or 105 | yarn add fonction 106 | ``` 107 | 108 | #### ESM 109 | 110 | ```ts 111 | import { add } from 'fonction' 112 | 113 | add(1, 2) // 3 114 | ``` 115 | 116 | #### Commonjs 117 | 118 | ```ts 119 | const { add } = require('fonction') 120 | 121 | add(1, 2) // 3 122 | ``` 123 | 124 | ### :globe_with_meridians: CDN 125 | 126 | The module that bundles the dependencies is obtained from [skypack](https://www.skypack.dev/view/fonction). 127 | 128 | ```html 129 | 133 | ``` 134 | 135 | ## :world_map: Loadmap 136 | 137 | For the time being, my goal is to implement the functions implemented in the great starting projects ([lodash](https://github.com/lodash/lodash), [ramda](https://github.com/ramda/ramda), [rambda](https://github.com/ramda/ramda), ... etc). 138 | 139 | The release will be a public release when it is fully tested in the `beta` release and then merged into the main branch. 140 | 141 | You can check the implementation status of all functions [here](https://tomokimiyauci.github.io/fonction/api/). 142 | 143 | You can also try all the features including the `beta` version with the following command or URL. 144 | 145 | ```bash 146 | npm i fonction@beta 147 | or 148 | yarn add fonction@beta 149 | ``` 150 | 151 | ```ts 152 | // deno.land 153 | import { _ } from 'https://deno.land/x/fonction@VERSION/mod.ts' 154 | ``` 155 | 156 | `@VERSION` format is like `v1.5.0-beta.1`. 157 | 158 | ## :star: Other projects 159 | 160 | - [core-fn](https://github.com/TomokiMiyauci/core-fn) 161 | - [is-valid](https://github.com/TomokiMiyauci/is-valid) 162 | 163 | ## :handshake: Contributing 164 | 165 | Contributions, issues and feature requests are welcome!
Feel free to check [issues](https://github.com/TomokiMiyauci/fonction/issues). 166 | 167 | ## :seedling: Show your support 168 | 169 | Give a ⭐️ if this project helped you! 170 | 171 | 172 | 173 | 174 | 175 | ## :bulb: License 176 | 177 | Copyright © 2021-present [TomokiMiyauci](https://github.com/TomokiMiyauci). 178 | 179 | Released under the [MIT](./LICENSE) license 180 | 181 | [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B26231%2Fgithub.com%2FTomokiMiyauci%2Ffonction.svg?type=large)](https://app.fossa.com/projects/custom%2B26231%2Fgithub.com%2FTomokiMiyauci%2Ffonction?ref=badge_large) 182 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", 3 | 4 | "mainEntryPointFilePath": "/dist/index.es.d.ts", 5 | 6 | "bundledPackages": [], 7 | 8 | "compiler": {}, 9 | 10 | "apiReport": { 11 | "enabled": false, 12 | "reportFileName": ".api.md" 13 | }, 14 | 15 | "docModel": { 16 | "enabled": true, 17 | "apiJsonFilePath": "/temp/.api.json" 18 | }, 19 | 20 | "dtsRollup": { 21 | "enabled": false 22 | }, 23 | 24 | "tsdocMetadata": {}, 25 | 26 | "messages": { 27 | "compilerMessageReporting": { 28 | "default": { 29 | "logLevel": "warning" 30 | } 31 | }, 32 | 33 | "extractorMessageReporting": { 34 | "default": { 35 | "logLevel": "warning" 36 | } 37 | }, 38 | 39 | "tsdocMessageReporting": { 40 | "default": { 41 | "logLevel": "warning" 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /api.ts: -------------------------------------------------------------------------------- 1 | type Modules = 'rambda' | 'ramda' | 'lodash' | 'fonction' 2 | type ExcludeModules = Exclude 3 | type Api = { 4 | [k: string]: 5 | | { 6 | [m in Modules]?: string 7 | } 8 | | ExcludeModules[] 9 | } 10 | 11 | const ALL_MODULES: ExcludeModules[] = ['rambda', 'ramda', 'lodash'] 12 | const LAMBDAS: ExcludeModules[] = ['rambda', 'ramda'] 13 | const api: Api = { 14 | advance: {}, 15 | add: ALL_MODULES, 16 | and: LAMBDAS, 17 | chunk: { 18 | lodash: 'chunk' 19 | }, 20 | constructorName: [], 21 | dec: LAMBDAS, 22 | F: LAMBDAS, 23 | head: { 24 | ramda: 'head', 25 | rambda: 'head', 26 | lodash: 'first' 27 | }, 28 | flattenDeep: { 29 | lodash: 'flattenDeep', 30 | rambda: 'flatten', 31 | ramda: 'flatten' 32 | }, 33 | gt: ['ramda', 'lodash'], 34 | gte: ['ramda', 'lodash'], 35 | has: ALL_MODULES, 36 | init: ALL_MODULES, 37 | identity: ALL_MODULES, 38 | inc: LAMBDAS, 39 | K: {}, 40 | lt: ['ramda', 'lodash'], 41 | lte: ['ramda', 'lodash'], 42 | not: LAMBDAS, 43 | N: { 44 | lodash: 'not', 45 | rambda: 'not', 46 | ramda: 'not' 47 | }, 48 | NN: {}, 49 | or: LAMBDAS, 50 | prepend: LAMBDAS, 51 | product: LAMBDAS, 52 | props: { 53 | rambda: 'prop', 54 | ramda: 'prop', 55 | lodash: 'get' 56 | }, 57 | replaceAll: {}, 58 | sum: ALL_MODULES, 59 | T: { 60 | rambda: 'T', 61 | ramda: 'T', 62 | lodash: 'stubTrue' 63 | }, 64 | tail: ALL_MODULES, 65 | xor: LAMBDAS, 66 | subtract: ALL_MODULES, 67 | multiply: ALL_MODULES, 68 | divide: ALL_MODULES, 69 | adjust: { 70 | ramda: 'adjust', 71 | rambda: 'adjust', 72 | fonction: undefined 73 | }, 74 | all: { 75 | ramda: 'all', 76 | rambda: 'all', 77 | fonction: undefined 78 | }, 79 | allPass: { 80 | ramda: 'allPass', 81 | rambda: 'allPass', 82 | fonction: undefined 83 | }, 84 | any: { 85 | ramda: 'any', 86 | rambda: 'any', 87 | fonction: undefined 88 | }, 89 | anyPass: { 90 | ramda: 'anyPass', 91 | rambda: 'anyPass', 92 | fonction: undefined 93 | }, 94 | append: LAMBDAS, 95 | applySpec: { 96 | ramda: 'applySpec', 97 | rambda: 'applySpec', 98 | fonction: undefined 99 | }, 100 | assoc: { 101 | ramda: 'assoc', 102 | rambda: 'assoc', 103 | fonction: undefined 104 | }, 105 | clone: { 106 | ramda: 'clone', 107 | rambda: 'clone', 108 | lodash: 'cloneDeep', 109 | fonction: undefined 110 | }, 111 | compose: { 112 | ramda: 'compose', 113 | rambda: 'compose', 114 | fonction: undefined 115 | }, 116 | converge: { 117 | ramda: 'converge', 118 | rambda: 'converge', 119 | fonction: undefined 120 | }, 121 | curry: ['lodash', 'rambda', 'ramda'], 122 | defaultTo: ['rambda', 'ramda'], 123 | drop: { 124 | ramda: 'drop', 125 | rambda: 'drop', 126 | lodash: 'drop', 127 | fonction: undefined 128 | }, 129 | dropLast: { 130 | ramda: 'dropLast', 131 | rambda: 'dropLast', 132 | lodash: 'dropRight', 133 | fonction: undefined 134 | }, 135 | equal: { 136 | ramda: 'equals', 137 | rambda: 'equals', 138 | lodash: 'isEqual' 139 | }, 140 | filter: { 141 | ramda: 'filter', 142 | rambda: 'filter', 143 | lodash: 'filter', 144 | fonction: undefined 145 | }, 146 | find: { 147 | ramda: 'find', 148 | rambda: 'find', 149 | lodash: 'find', 150 | fonction: undefined 151 | }, 152 | findIndex: { 153 | ramda: 'findIndex', 154 | rambda: 'findIndex', 155 | lodash: 'findIndex', 156 | fonction: undefined 157 | }, 158 | ifElse: {}, 159 | ifElseFn: { 160 | ramda: 'ifElse', 161 | rambda: 'ifElse' 162 | }, 163 | indexOf: { 164 | ramda: 'indexOf', 165 | rambda: 'indexOf', 166 | lodash: 'indexOf', 167 | fonction: undefined 168 | }, 169 | is: { 170 | rambda: 'is', 171 | ramda: 'is', 172 | fonction: undefined 173 | }, 174 | isEmpty: ALL_MODULES, 175 | last: ALL_MODULES, 176 | lastIndexOf: { 177 | ramda: 'lastIndexOf', 178 | rambda: 'lastIndexOf', 179 | lodash: 'lastIndexOf', 180 | fonction: undefined 181 | }, 182 | pipe: ['rambda', 'ramda'], 183 | match: { 184 | ramda: 'match', 185 | rambda: 'match', 186 | fonction: undefined 187 | }, 188 | merge: { 189 | ramda: 'merge', 190 | rambda: 'merge', 191 | lodash: 'merge', 192 | fonction: undefined 193 | }, 194 | none: { 195 | ramda: 'none', 196 | rambda: 'none', 197 | fonction: undefined 198 | }, 199 | omit: { 200 | ramda: 'omit', 201 | rambda: 'omit', 202 | lodash: 'omit', 203 | fonction: undefined 204 | }, 205 | over: { 206 | ramda: 'over', 207 | rambda: 'over', 208 | fonction: undefined 209 | }, 210 | path: { 211 | ramda: 'path', 212 | rambda: 'path', 213 | lodash: 'get', 214 | fonction: 'props' 215 | }, 216 | // pick: { 217 | // fonction: undefined 218 | // }, 219 | // propEq: { 220 | // fonction: undefined 221 | // }, 222 | // range: { 223 | // fonction: undefined 224 | // }, 225 | // reduce: { 226 | // fonction: undefined 227 | // }, 228 | // repeat: { 229 | // fonction: undefined 230 | // }, 231 | // set: { 232 | // fonction: undefined 233 | // }, 234 | // sort: { 235 | // fonction: undefined 236 | // }, 237 | // sortBy: { 238 | // fonction: undefined 239 | // }, 240 | // split: { 241 | // fonction: undefined 242 | // }, 243 | // splitEvery: { 244 | // fonction: undefined 245 | // }, 246 | tap: ['lodash', 'rambda', 'ramda'], 247 | take: ALL_MODULES, 248 | takeLast: { 249 | ramda: 'takeLast', 250 | rambda: 'takeLast', 251 | lodash: 'takeRight' 252 | }, 253 | tryCatch: ['rambda', 'ramda'], 254 | // type: { 255 | // fonction: undefined 256 | // }, 257 | uniq: ['ramda', 'rambda', 'lodash'] 258 | // update: { 259 | // fonction: undefined 260 | // }, 261 | // view: { 262 | // fonction: undefined 263 | // } 264 | } 265 | 266 | export default api 267 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['gitmoji'], 3 | parserPreset: { 4 | parserOpts: { 5 | headerPattern: /^(:\w*:)(?:\s)(?:\((.*?)\))?\s((?:.*(?=\())|.*)(?:\(#(\d*)\))?/, 6 | headerCorrespondence: ['type', 'scope', 'subject', 'ticket'] 7 | } 8 | }, 9 | rules: { 10 | 'type-enum': [ 11 | 2, 12 | 'always', 13 | [ 14 | ':art:', 15 | ':newspaper:', 16 | ':memo:', 17 | ':zap:', 18 | ':fire:', 19 | ':books:', 20 | ':bug:', 21 | ':ambulance:', 22 | ':penguin:', 23 | ':checkered_flag:', 24 | ':robot:', 25 | ':green_ale:', 26 | ':tractor:', 27 | ':recycle:', 28 | ':white_check_mark:', 29 | ':microscope:', 30 | ':green_heart:', 31 | ':lock:', 32 | ':arrow_up:', 33 | ':arrow_down:', 34 | ':fast_forward:', 35 | ':rewind:', 36 | ':rotating_light:', 37 | ':lipstick:', 38 | ':wheelchair:', 39 | ':globe_with_meridians:', 40 | ':construction:', 41 | ':gem:', 42 | ':bookmark:', 43 | ':tada:', 44 | ':loud_sound:', 45 | ':mute:', 46 | ':sparkles:', 47 | ':speech_balloon:', 48 | ':bulb:', 49 | ':construction_worker:', 50 | ':chart_with_upwards_trend:', 51 | ':ribbon:', 52 | ':rocket:', 53 | ':heavy_minus_sign:', 54 | ':heavy_plus_sign:', 55 | ':wrench:', 56 | ':hankey:', 57 | ':leaves:', 58 | ':bank:', 59 | ':whale:', 60 | ':twisted_rightwards_arrows:', 61 | ':pushpin:', 62 | ':busts_in_silhouette:', 63 | ':children_crossing:', 64 | ':iphone:', 65 | ':clown_face:', 66 | ':ok_hand:', 67 | ':boom:', 68 | ':bento:', 69 | ':pencil2:', 70 | ':package:', 71 | ':alien:', 72 | ':truck:', 73 | ':age_facing_up:', 74 | ':busts_in_silhouette:', 75 | ':card_file_box:', 76 | ':loud-sound:', 77 | ':mute:', 78 | ':egg:', 79 | ':see-no-evil:', 80 | ':camera-flash:', 81 | ':alembic:', 82 | ':mag:', 83 | ':wheel-of-dharma:', 84 | ':label:', 85 | ':triangular_flag_on_post:', 86 | ':page_facing_up:' 87 | ] 88 | ], 89 | 'header-max-length': [2, 'always', 75] 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /common/head.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isArray } from '../deps.ts' 3 | import { ifElse } from '../src/ifElse.ts' 4 | import { take } from '../src/take.ts' 5 | 6 | /** 7 | * Infer the head types. 8 | * 9 | * @typeParam T - `string` or any `array` 10 | * @returns Head element of the `T` 11 | * 12 | * @example 13 | * ```ts 14 | * // String 15 | * Head // string 16 | * Head<''> // '' 17 | * Head<'hello'> // 'h' 18 | * ``` 19 | * 20 | * @example 21 | * ```ts 22 | * // Array 23 | * Head<[] | never[] | readonly [] | readonly never[]> // undefined 24 | * Head<['hello', 'world']> // 'hello' 25 | * Head // string | number | undefined 26 | * ``` 27 | * 28 | * @category `Array` `String` 29 | * 30 | * @see Related to {@link Last} 31 | * 32 | * @public 33 | */ 34 | type Head = T extends string 35 | ? T extends `${infer F}${string}` 36 | ? F 37 | : T extends '' 38 | ? '' 39 | : string 40 | : T extends readonly [infer U, ...infer _] 41 | ? U 42 | : T[0] | undefined 43 | 44 | /** 45 | * Infer the head types. 46 | * 47 | * @typeParam T - `string` or any `array` 48 | * @returns Head element of the `T` 49 | * 50 | * @example 51 | * ```ts 52 | * // String 53 | * head<''> // '' 54 | * head<'hello'> // 'hello' 55 | * ``` 56 | * 57 | * @example 58 | * ```ts 59 | * // Array 60 | * head<[]> // undefined 61 | * head<['hello', 'world']> // 'hello' 62 | * ``` 63 | * 64 | * @category `Array` `String` 65 | * 66 | * @see Related to {@link Last} 67 | * 68 | * @public 69 | */ 70 | const head = (val: T): Head => 71 | ifElse( 72 | isArray(val), 73 | () => val[0], 74 | () => take(1, val) 75 | ) as Head 76 | 77 | export { head } 78 | export type { Head } 79 | -------------------------------------------------------------------------------- /common/head_test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals, assertEqualsType } from '../dev_deps.ts' 3 | import { Head, head } from './head.ts' 4 | Deno.test('head', () => { 5 | const table: [string | unknown[], string | undefined | unknown][] = [ 6 | ['', ''], 7 | ['a', 'a'], 8 | [' ab', ' '], 9 | ['abcd', 'a'], 10 | ['abcde ', 'a'], 11 | ['abcd_', 'a'], 12 | [[], undefined], 13 | [[''], ''], 14 | [['hello', 'world'], 'hello'], 15 | [['hello', 'new', 'world'], 'hello'], 16 | [ 17 | [['hello', 'new', 'world'], 'test'], 18 | ['hello', 'new', 'world'] 19 | ], 20 | [ 21 | [ 22 | ['hello', 'new', 'world'], 23 | ['hello2', 'world'] 24 | ], 25 | ['hello', 'new', 'world'] 26 | ], 27 | [[0], 0], 28 | [[0, 3, 6, 9], 0], 29 | [[{}], {}] 30 | ] 31 | table.forEach(([val, expected]) => { 32 | assertEquals(head(val), expected, `head(${val}) -> ${expected}`) 33 | }) 34 | 35 | assertEqualsType(head([])) 36 | assertEqualsType(head([] as const)) 37 | assertEqualsType(head([] as [])) 38 | assertEqualsType(head([''])) 39 | assertEqualsType<''>(head([''] as const)) 40 | assertEqualsType<''>(head([''] as [''])) 41 | assertEqualsType(head([] as string[])) 42 | assertEqualsType(head(['1', 2])) 43 | assertEqualsType<'1'>(head(['1', 2] as const)) 44 | assertEqualsType<100>( 45 | head([100, 200, 'hello', []] as [100, 200, 'hello', []]) 46 | ) 47 | assertEqualsType(head('')) 48 | assertEqualsType(head('hello')) 49 | assertEqualsType(head('hello' as const)) 50 | }) 51 | 52 | Deno.test('Head', () => { 53 | assertEqualsType< 54 | undefined, 55 | Head<[] | never[] | readonly [] | readonly never[]> 56 | >() 57 | assertEqualsType<'', Head<[''] | readonly ['']>>() 58 | assertEqualsType>() 59 | assertEqualsType>() 60 | assertEqualsType<100, Head<[100, 200, 'hello', []]>>() 61 | assertEqualsType>() 62 | assertEqualsType<'', Head<''>>() 63 | assertEqualsType<'h', Head<'hello'>>() 64 | }) 65 | -------------------------------------------------------------------------------- /common/init.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { slice } from '../deps.ts' 3 | 4 | /** 5 | * @example 6 | * ```ts 7 | * InitString // string 8 | * InitString<''> // '' 9 | * InitString<'a'> // '' 10 | * InitString<'ab'> // 'a' 11 | * InitString<'abcd'> // 'abc' 12 | * ``` 13 | * @internal 14 | */ 15 | type InitString = T extends `${infer F}${infer R}` 16 | ? R extends '' 17 | ? '' 18 | : `${F}${InitString}` 19 | : T extends '' 20 | ? '' 21 | : string 22 | 23 | /** 24 | * Infer the init types. 25 | * @typeParam T - `string` or any `array` 26 | * 27 | * @example 28 | * ```ts 29 | * // String 30 | * Init // string 31 | * Init<''> // '' 32 | * Init<'hello'> // 'hell' 33 | * ``` 34 | * 35 | * @example 36 | * ```ts 37 | * // Array 38 | * Init<[] | never[] | readonly [] | readonly never[]> // [] 39 | * Init<['hello']> // [] 40 | * Init<['hello', 'world']> // ['hello'] 41 | * ``` 42 | * 43 | * @category `Array` `String` 44 | * 45 | * @see Related to {@link Tail} 46 | * 47 | * @public 48 | */ 49 | type Init = T extends string 50 | ? InitString 51 | : T extends readonly [...infer I, unknown] 52 | ? I 53 | : T 54 | 55 | /** 56 | * Returns all but the init element of the given list or string. 57 | * @param val - string or any array object 58 | * @returns The result of `val.slice(0, -1)` 59 | * 60 | * @remarks 61 | * The maximum number of characters for the type system to work properly is 16. 62 | * 63 | * @example 64 | * ```ts 65 | * // String 66 | * init('hello') // 'hell' 67 | * init('h') // '' 68 | * init('') // '' 69 | * ``` 70 | * 71 | * @example 72 | * ```ts 73 | * init([1, 2, 3]) // [1, 2] 74 | * init(['hello', 'world']) // ['hello'] 75 | * init(['hello']) // [] 76 | * init([]) // [] 77 | * ``` 78 | * 79 | * @category `Array` `String` 80 | * 81 | * @see Related to {@link tail} 82 | * 83 | * @public 84 | */ 85 | const init = (val: T): Init => 86 | slice(0, -1, val) as Init 87 | 88 | export { init } 89 | export type { Init } 90 | -------------------------------------------------------------------------------- /common/init_test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals, assertEqualsType } from '../dev_deps.ts' 3 | import { Init, init } from './init.ts' 4 | 5 | Deno.test('init', () => { 6 | const tableString: [string, string][] = [ 7 | ['', ''], 8 | ['a', ''], 9 | ['ab', 'a'], 10 | ['abc', 'ab'] 11 | ] 12 | tableString.forEach(([val, expected]) => { 13 | assertEquals(init(val), expected, `init(${val}) -> ${expected}`) 14 | }) 15 | 16 | const tableArray: [unknown[], unknown[]][] = [ 17 | [[], []], 18 | [[''], []], 19 | [[undefined], []], 20 | [[null], []], 21 | [[0], []], 22 | [['', ''], ['']], 23 | [[0, 0], [0]], 24 | [[0, ''], [0]], 25 | [['hello', 'world'], ['hello']], 26 | [ 27 | ['hello', 'new', 'world'], 28 | ['hello', 'new'] 29 | ], 30 | [ 31 | [undefined, null, 'hello', 'world'], 32 | [undefined, null, 'hello'] 33 | ], 34 | [[['hello', 'world']], []] 35 | ] 36 | 37 | tableArray.forEach(([val, expected]) => { 38 | assertEquals(init(val), expected, `init(${val}) -> ${expected}`) 39 | }) 40 | 41 | assertEqualsType<[], Init<[]>>() 42 | assertEqualsType>() 43 | assertEqualsType<[], Init<[1]>>() 44 | assertEqualsType<[1], Init<[1, 2]>>() 45 | assertEqualsType<[1, 2], Init<[1, 2, 3]>>() 46 | assertEqualsType<'', Init<''>>() 47 | assertEqualsType<'', Init<'a'>>() 48 | assertEqualsType<'a', Init<'ab'>>() 49 | assertEqualsType<'abcde', Init<'abcdef'>>() 50 | assertEqualsType<'abcdefghijklmno', Init<'abcdefghijklmnop'>>() 51 | }) 52 | -------------------------------------------------------------------------------- /common/last.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isArray } from '../deps.ts' 3 | import { ifElse } from '../src/ifElse.ts' 4 | import { takeLast } from '../src/takeLast.ts' 5 | 6 | /** 7 | * @example 8 | * ```ts 9 | * LastString<''> // '' 10 | * LastString<'a'> // 'a' 11 | * LastString<'abcdefghijk'> // 'k' 12 | * ``` 13 | * 14 | * @internal 15 | */ 16 | type LastString = T extends `${infer L}${infer R}` 17 | ? R extends '' 18 | ? L 19 | : LastString 20 | : T extends '' 21 | ? '' 22 | : string 23 | 24 | /** 25 | * Infer the last types. 26 | * 27 | * @typeParam T - `string` or any `array` 28 | * 29 | * @example 30 | * ```ts 31 | * // String 32 | * Last // string 33 | * Last<''> // '' 34 | * Last<'hello'> // 'o' 35 | * ``` 36 | * 37 | * @example 38 | * ```ts 39 | * // Array 40 | * Last<[] | never[] | readonly [] | readonly never[]> // undefined 41 | * Last<['hello', 'world']> // 'world' 42 | * Last // string | number | undefined 43 | * ``` 44 | * 45 | * @category `Array` `String` 46 | * 47 | * @see Related to {@link head} 48 | * 49 | * @public 50 | */ 51 | type Last = T extends string 52 | ? LastString 53 | : T extends readonly [...infer _, infer L] 54 | ? L 55 | : T[T['length']] | undefined 56 | 57 | /** 58 | * Returns the last element of the given list or string. 59 | * 60 | * @param val - `string` or any `array` object 61 | * @returns The last element of the `val` 62 | * 63 | * @remarks 64 | * The maximum number of characters for the type system to work properly is 24. 65 | * 66 | * @example 67 | * ```ts 68 | * // String 69 | * last('') // '' 70 | * last('hello') // 'o' 71 | * ``` 72 | * 73 | * @example 74 | * ```ts 75 | * // Array 76 | * last('hello', 'new', 'world') // 'world' 77 | * last([]) // undefined 78 | * last(['one', 2, 3, 4]) // 4 79 | * ``` 80 | * 81 | * @see Related to {@link head} 82 | * 83 | * @public 84 | */ 85 | const last = (val: T): Last => 86 | ifElse( 87 | isArray(val), 88 | () => takeLast(1, val)[0], 89 | () => takeLast(1, val) 90 | ) as Last 91 | 92 | export { last } 93 | export type { Last } 94 | -------------------------------------------------------------------------------- /common/last_test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { assertEqual } from '../test/asserts.ts' 4 | import { Last, last } from './last.ts' 5 | 6 | Deno.test('last', () => { 7 | const table: [string | unknown[], unknown][] = [ 8 | ['', ''], 9 | ['a', 'a'], 10 | [' ab', 'b'], 11 | ['abcd', 'd'], 12 | ['abcde ', ' '], 13 | ['abcd_', '_'], 14 | [[], undefined], 15 | [[''], ''], 16 | [['hello', 'world'], 'world'], 17 | [['hello', 'new', 'world'], 'world'], 18 | [[['hello', 'new', 'world'], 'test'], 'test'], 19 | [ 20 | [ 21 | ['hello', 'new', 'world'], 22 | ['hello2', 'world'] 23 | ], 24 | ['hello2', 'world'] 25 | ], 26 | [[0], 0], 27 | [[0, 3, 6, 9], 9], 28 | [[{}], {}] 29 | ] 30 | table.forEach(([val, expected]) => { 31 | assertEquals(last(val), expected, `last(${val}) -> ${expected}`) 32 | }) 33 | 34 | assertEqual(last([])) 35 | assertEqual(last([] as const)) 36 | assertEqual(last([] as [])) 37 | assertEqual(last([''])) 38 | assertEqual<''>(last([''] as const)) 39 | assertEqual<''>(last([''] as [''])) 40 | assertEqual(last(['1', 2])) 41 | assertEqual<2>(last(['1', 2] as const)) 42 | assertEqual<[]>(last([100, 200, 'hello', []] as [100, 200, 'hello', []])) 43 | assertEqual(last('')) 44 | assertEqual(last('hello')) 45 | assertEqual(last('hello' as const)) 46 | }) 47 | 48 | Deno.test('Last', () => { 49 | assertEqual>() 50 | assertEqual<'', Last<[''] | readonly ['']>>() 51 | assertEqual>() 52 | assertEqual>() 53 | assertEqual<[], Last<[100, 200, 'hello', []]>>() 54 | assertEqual>() 55 | assertEqual<'', Last<''>>() 56 | assertEqual<'o', Last<'hello'>>() 57 | assertEqual<'x', Last<'abcdefghijklmnopqrstuvwx'>>() 58 | }) 59 | -------------------------------------------------------------------------------- /common/mod.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | export type { Head } from './head.ts' 3 | export { head } from './head.ts' 4 | export type { Init } from './init.ts' 5 | export { init } from './init.ts' 6 | export type { Last } from './last.ts' 7 | export { last } from './last.ts' 8 | export type { Tail } from './tail.ts' 9 | export { tail } from './tail.ts' 10 | -------------------------------------------------------------------------------- /common/tail.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { slice } from '../deps.ts' 3 | 4 | /** 5 | * Infer the tail types. 6 | * @typeParam T - `string` or any `array` 7 | * 8 | * @example 9 | * ```ts 10 | * // String 11 | * Tail // string 12 | * Tail<''> // '' 13 | * Tail<'a'> // '' 14 | * Tail<'hello'> // 'ello' 15 | * ``` 16 | * 17 | * @example 18 | * ```ts 19 | * // Array 20 | * Tail<[] | never[] | readonly [] | readonly never[]> // [] 21 | * Tail<['hello']> // [] 22 | * Tail<['hello', 'world']> // ['world'] 23 | * ``` 24 | * 25 | * @category `Array` `String` 26 | * 27 | * @see Related to {@link Init} 28 | * 29 | * @public 30 | */ 31 | type Tail = T extends string 32 | ? T extends `${string}${infer R}` 33 | ? R 34 | : T extends '' 35 | ? '' 36 | : string 37 | : T extends readonly [unknown, ...infer R] 38 | ? R 39 | : T 40 | /** 41 | * Returns all but the first element of the given list or string. 42 | * 43 | * @param val - string or any array object 44 | * @returns The result of `val.slice(1, Infinity)` 45 | * 46 | * @example 47 | * ```ts 48 | * // String 49 | * tail('hello') // 'ello' 50 | * tail('h') // '' 51 | * tail('') // '' 52 | * ``` 53 | * 54 | * @example 55 | * ```ts 56 | * tail([1, 2, 3]) // [2, 3] 57 | * tail(['hello', 'world']) // ['world'] 58 | * tail(['hello']) // [] 59 | * tail([]) // [] 60 | * ``` 61 | * 62 | * @category `Array` `String` 63 | * 64 | * @see Related to {@link head} 65 | * 66 | * @public 67 | */ 68 | const tail = (val: T): Tail => 69 | slice(1, Infinity, val) as Tail 70 | 71 | export { tail } 72 | export type { Tail } 73 | -------------------------------------------------------------------------------- /common/tail_test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals, assertEqualsType } from '../dev_deps.ts' 3 | import { Tail, tail } from './tail.ts' 4 | 5 | Deno.test('tail', () => { 6 | const tableString: [string, string][] = [ 7 | ['', ''], 8 | ['a', ''], 9 | ['ab', 'b'], 10 | ['abc', 'bc'] 11 | ] 12 | tableString.forEach(([val, expected]) => { 13 | assertEquals(tail(val), expected, `tail(${val}) -> ${expected}`) 14 | }) 15 | 16 | const tableArray: [unknown[], unknown[]][] = [ 17 | [[], []], 18 | [[''], []], 19 | [[undefined], []], 20 | [[null], []], 21 | [[0], []], 22 | [['', ''], ['']], 23 | [[0, 0], [0]], 24 | [[0, ''], ['']], 25 | [['hello', 'world'], ['world']], 26 | [ 27 | ['hello', 'new', 'world'], 28 | ['new', 'world'] 29 | ], 30 | [ 31 | [undefined, null, 'hello', 'world'], 32 | [null, 'hello', 'world'] 33 | ], 34 | [[['hello', 'world']], []] 35 | ] 36 | 37 | tableArray.forEach(([val, expected]) => { 38 | assertEquals(tail(val), expected, `tail(${val}) -> ${expected}`) 39 | }) 40 | 41 | assertEqualsType>() 42 | assertEqualsType<'', Tail<''>>() 43 | assertEqualsType<'', Tail<'a'>>() 44 | assertEqualsType<'b', Tail<'ab'>>() 45 | assertEqualsType<'bcdef', Tail<'abcdef'>>() 46 | assertEqualsType<[], Tail<[]>>() 47 | assertEqualsType<[], Tail<[1]>>() 48 | assertEqualsType<[], Tail>() 49 | assertEqualsType<[2], Tail<[1, 2]>>() 50 | assertEqualsType<[2, 3, 4, 5], Tail<[1, 2, 3, 4, 5]>>() 51 | assertEqualsType<[2, 3, 4, 5], Tail>() 52 | assertEqualsType>() 53 | assertEqualsType>() 54 | }) 55 | -------------------------------------------------------------------------------- /deps.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | export { length } from 'https://deno.land/x/core_fn@v1.0.0-beta.14/mod.ts' 3 | export { slice } from 'https://deno.land/x/core_fn@v1.0.0-beta.14/uncurry/common/slice.ts' 4 | export { curry } from 'https://deno.land/x/curry@v1.0.0/mod.ts' 5 | export { equal } from 'https://deno.land/x/equal@v1.5.0/mod.ts' 6 | export { 7 | isArray, 8 | isFunction, 9 | isLength0, 10 | isNil, 11 | isNumber, 12 | isObject, 13 | isUndefined 14 | } from 'https://deno.land/x/is_valid@v1.0.0-beta.15/mod.ts' 15 | export { 16 | add, 17 | divide, 18 | multiply, 19 | subtract 20 | } from 'https://x.nest.land/arithmetic4@0.1.1/mod.ts' 21 | -------------------------------------------------------------------------------- /dev_deps.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /* eslint-disable @typescript-eslint/no-empty-function */ 3 | /* eslint-disable @typescript-eslint/no-unused-vars */ 4 | 5 | export { 6 | assert, 7 | assertEquals 8 | } from 'https://deno.land/std@0.97.0/testing/asserts.ts' 9 | export const assertEqualsType = (_actual?: U): void => {} 10 | export { length } from 'https://deno.land/x/core_fn@v1.0.0-beta.8/mod.ts' 11 | export { 12 | isNumber, 13 | isString, 14 | isSymbol 15 | } from 'https://deno.land/x/is_valid@v1.0.0-beta.15/mod.ts' 16 | export { spy } from 'https://deno.land/x/mock@v0.9.5/spy.ts' 17 | -------------------------------------------------------------------------------- /docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | const { members } = require('../../temp/fonction.api.json') 2 | const { lowerCase, take } = require('fonction') 3 | const { versions } = require('../../temp/meta.json') 4 | 5 | const links = [ 6 | { text: 'Latest', link: '/api/', activeMatch: '/api/$' }, 7 | ...take(10, versions).map((version) => ({ 8 | text: version, 9 | link: `/api/${version}/`, 10 | activeMatch: `/api/${version}/` 11 | })) 12 | ] 13 | 14 | const title = 'fonction' 15 | const description = 'A modern practical functional library' 16 | const name = 'TomokiMiyauci' 17 | const baseUrl = `https://tomokimiyauci.github.io/${title}` 18 | const baseHead = [ 19 | ['link', { rel: 'shortcut icon', href: `${baseUrl}/favicon.ico` }], 20 | ['meta', { name: 'author', content: name }], 21 | ['meta', { name: 'copyright', content: `2021 ©${name}` }], 22 | ['meta', { property: 'og:title', content: title }], 23 | ['meta', { property: 'og:image', content: `${baseUrl}/logo.png` }], 24 | [ 25 | 'meta', 26 | { 27 | property: 'og:url', 28 | content: baseUrl 29 | } 30 | ], 31 | [ 32 | 'meta', 33 | { 34 | property: 'og:type', 35 | content: 'website' 36 | } 37 | ], 38 | [ 39 | 'meta', 40 | { 41 | property: 'og:site_name', 42 | content: `${title} docs` 43 | } 44 | ], 45 | ['meta', { name: 'twitter:card', content: 'summary' }], 46 | ['meta', { name: 'twitter:site', content: '@tomoki_miyauci' }] 47 | ] 48 | module.exports = { 49 | title, 50 | description, 51 | 52 | base: `/${title}/`, 53 | 54 | locales: { 55 | '/': { 56 | lang: 'en-US', 57 | head: [ 58 | ['meta', { property: 'og:description', content: description }], 59 | ...baseHead 60 | ] 61 | } 62 | }, 63 | 64 | themeConfig: { 65 | algolia: { 66 | apiKey: '2649f37ae80f40be1c843a4d7b775533', 67 | indexName: 'fonction' 68 | }, 69 | locales: { 70 | '/': { 71 | label: 'English', 72 | selectText: 'Languages', 73 | nav: [ 74 | { text: 'Guide', link: '/guide/', activeMatch: '^/guide' }, 75 | { text: 'API', link: '/api/', activeMatch: '^/api' }, 76 | { 77 | text: 'Releases', 78 | items: links 79 | }, 80 | { 81 | text: 'Release Notes', 82 | link: `https://github.com/${name}/${title}/blob/main/CHANGELOG.md` 83 | } 84 | ], 85 | editLinkText: 'Edit this page on GitHub', 86 | lastUpdated: 'Last Updated', 87 | sidebar: { 88 | '/api/': 'auto', 89 | '/': [ 90 | { 91 | text: 'Guide', 92 | children: [ 93 | { 94 | text: 'Getting Started', 95 | link: '/guide/' 96 | } 97 | ] 98 | }, 99 | { 100 | text: 'API', 101 | link: '/api/', 102 | children: [ 103 | { 104 | text: 'functions', 105 | link: '/api/#functions' 106 | }, 107 | { 108 | text: 'types', 109 | link: '/api/#types' 110 | } 111 | ] 112 | } 113 | ] 114 | } 115 | } 116 | }, 117 | 118 | repo: `${name}/${title}`, 119 | logo: '/logo.png', 120 | docsDir: 'docs', 121 | docsBranch: 'main', 122 | 123 | editLinks: true 124 | }, 125 | markdown: { 126 | config: (md) => { 127 | md.use(require('markdown-it-attrs')) 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- 1 | .nav-bar .logo { 2 | height: 42px; 3 | margin-right: 6px; 4 | border-radius: 0.25rem; 5 | } 6 | 7 | .nav-bar-title { 8 | display: flex; 9 | align-items: center; 10 | } 11 | 12 | .image { 13 | border-radius: 0.5rem; 14 | } 15 | 16 | :root { 17 | --c-brand: rgb(11, 105, 228); 18 | --c-brand-light: rgb(11, 105, 228); 19 | } 20 | 21 | .custom-block.tip { 22 | border-color: var(--c-brand-light); 23 | } 24 | 25 | .DocSearch { 26 | --docsearch-primary-color: var(--c-brand) !important; 27 | } 28 | 29 | .tag { 30 | --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); 31 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), 32 | var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 33 | border-width: 1px; 34 | --tw-text-opacity: 1; 35 | color: rgba(255, 255, 255, var(--tw-text-opacity)); 36 | border-radius: 0.25rem; 37 | vertical-align: middle; 38 | padding-top: 0.25rem; 39 | padding-bottom: 0.25rem; 40 | padding-left: 0.5rem; 41 | padding-right: 0.5rem; 42 | } 43 | 44 | .tag.beta { 45 | background-color: #e7c000; 46 | } 47 | 48 | .tag.deprecated { 49 | background-color: #c00; 50 | } 51 | 52 | .tag.math { 53 | background-color: rgba(11, 105, 228, 0.9); 54 | } 55 | 56 | .tag.array { 57 | background-color: rgba(76, 11, 228, 0.8); 58 | } 59 | 60 | .tag.string { 61 | background-color: #e7c100; 62 | } 63 | 64 | .tag.object { 65 | background-color: #e77000; 66 | } 67 | 68 | .tag.alias { 69 | background-color: #00e7a2; 70 | } 71 | 72 | .tag.logic { 73 | background-color: #e7039b; 74 | } 75 | 76 | .tag.version { 77 | z-index: 3; 78 | padding-top: 0.3rem; 79 | padding-bottom: 0.3rem; 80 | padding-left: 0.75rem; 81 | padding-right: 0.75rem; 82 | background-image: linear-gradient(to top left, var(--tw-gradient-stops)); 83 | } 84 | 85 | .tag.version.latest { 86 | --tw-gradient-from: #8b5cf6; 87 | --tw-gradient-stops: var(--tw-gradient-from), 88 | var(--tw-gradient-to, rgba(167, 139, 250, 0)), 89 | var(--tw-gradient-to, rgba(52, 211, 153, 0)); 90 | --tw-gradient-to: rgb(11, 105, 228); 91 | } 92 | 93 | .tag.version.past { 94 | --tw-gradient-from: #8b5cf6; 95 | --tw-gradient-stops: var(--tw-gradient-from), 96 | var(--tw-gradient-to, rgba(167, 139, 250, 0)), 97 | var(--tw-gradient-to, rgba(52, 211, 153, 0)); 98 | --tw-gradient-to: #636268; 99 | } 100 | 101 | .my-1 { 102 | margin-top: 0.1rem; 103 | margin-bottom: 0; 104 | } 105 | 106 | .mr-2 { 107 | margin-right: 0.5rem; 108 | } 109 | 110 | .desc { 111 | --tw-gradient-to: #dbe4ff; 112 | --tw-gradient-from: #ffffff; 113 | --tw-gradient-stops: var(--tw-gradient-from), 114 | var(--tw-gradient-to, rgba(224, 231, 255, 0)); 115 | background-image: linear-gradient(to top right, var(--tw-gradient-stops)); 116 | margin-top: 0.5rem; 117 | margin-bottom: 0; 118 | padding-top: 1rem; 119 | padding-bottom: 1rem; 120 | padding-left: 1rem; 121 | font-size: large; 122 | border-radius: 0.375rem; 123 | --tw-border-opacity: 1; 124 | border-width: 1px; 125 | border-style: solid; 126 | border-color: rgba(11, 105, 228, var(--tw-border-opacity)); 127 | --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 128 | 0 2px 4px -1px rgba(0, 0, 0, 0.06); 129 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), 130 | var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 131 | } 132 | 133 | .parameters-detail { 134 | margin: 1rem 0 1rem 0; 135 | } 136 | 137 | .table > thead > tr > th:nth-child(2) { 138 | width: 100%; 139 | } 140 | 141 | .returns { 142 | background-color: rgba(11, 105, 228, 0.2); 143 | --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); 144 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), 145 | var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 146 | color: rgb(11, 105, 228); 147 | } 148 | 149 | hr { 150 | border-top: none; 151 | border-bottom: 1px solid var(--c-divider); 152 | } 153 | 154 | hr:last-child { 155 | display: none; 156 | } 157 | 158 | .fixed { 159 | position: fixed; 160 | } 161 | 162 | .bottom-14 { 163 | bottom: 14px; 164 | } 165 | 166 | .right-14 { 167 | right: 14px; 168 | } 169 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import Theme from 'vitepress/theme' 2 | import './custom.css' 3 | 4 | export default { 5 | ...Theme 6 | } 7 | -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | head: 3 | - - link 4 | - rel: canonical 5 | href: https://tomokimiyauci.github.io/fonction/guide/ 6 | - - link 7 | - rel: alternate 8 | hreflang: en 9 | href: https://tomokimiyauci.github.io/fonction/guide/ 10 | - - link 11 | - rel: alternate 12 | hreflang: x-default 13 | href: https://tomokimiyauci.github.io/fonction/guide/ 14 | --- 15 | 16 | ## :seedling: Release Notes 17 | 18 | Latest version: ![npm](https://img.shields.io/npm/v/fonction?color=blue) 19 | 20 | Detailed release notes for each version are available on [GitHub](https://github.com/TomokiMiyauci/fonction/blob/main/CHANGELOG.md). 21 | 22 | ## :rocket: Getting Started 23 | 24 | ### CDN 25 | 26 | `fonction` provides UMD and ESM. 27 | For prototyping and learning purposes, the latest version is available as follows: 28 | 29 | #### UMD 30 | 31 | ```html 32 | 33 | 34 | 37 | ``` 38 | 39 | #### ESM 40 | 41 | ```html 42 | 46 | ``` 47 | 48 | ### NPM 49 | 50 | with Yarn 51 | 52 | ```bash 53 | yarn add -D fonction 54 | ``` 55 | 56 | with NPM 57 | 58 | ```bash 59 | npm i -D fonction 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /icon.gif 4 | heroAlt: Logo image 5 | actionText: Get Started 6 | actionLink: /guide/ 7 | features: 8 | - title: '💚 Friendly type definition' 9 | details: 'All functions written by TypeScript. The type system infers the optimal return value for the argument.' 10 | - title: '🌎 Universal module' 11 | details: 'Provide universal functions as ES modules and UMD' 12 | - title: '📦 Optimized, super slim size' 13 | details: 'We pay particular attention to the bundle size to prevent unused code from getting in when bundling.' 14 | - title: '📄 TSDoc-style comments' 15 | details: 'All functions have TSDoc-style comments. This is useful because you can learn more about the function when using the latest editors.' 16 | - title: '🔢 Bigint support' 17 | details: 'Not only number but also bigint is supported as standard.' 18 | - title: '🦕 Deno support' 19 | details: 'Support multi platform of Node and Deno.' 20 | 21 | footer: MIT Licensed | Copyright © 2021-present 22 | --- 23 | -------------------------------------------------------------------------------- /docs/public/googlef5dce3c92d21b4b2.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googlef5dce3c92d21b4b2.html -------------------------------------------------------------------------------- /docs/public/icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomokiMiyauci/fonction/d4ce6bcff85752f47b99c2e87ddb3161fa5acaa7/docs/public/icon.gif -------------------------------------------------------------------------------- /docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomokiMiyauci/fonction/d4ce6bcff85752f47b99c2e87ddb3161fa5acaa7/docs/public/logo.png -------------------------------------------------------------------------------- /docs/views/api.eta: -------------------------------------------------------------------------------- 1 | ### <%= it.name %> 2 | 3 | <% if (it.version) { %> 4 | 5 | <% if ( it.isLatest ) { %> 6 | Added from <% if (it.versionLink) { %>[<%= it.version %>](./<%= it.version %>/#<%= it.name.toLowerCase() %>)<% } else { %>`<%= it.version %>`<% } %> 7 | {.my-1} 8 | <% } else { %> 9 | Added from <% if (it.versionLink ) { %>[<%= it.version %>](../<%= it.version %>/)<% } else { %>`<%= it.version %>`<% } %> 10 | {.my-1} 11 | <% } %> 12 | <% } %> 13 | 14 | <% it.sees.forEach((see) => { %> 15 | :link:  16 | <% see.forEach((link) => { %> 17 | [<%= link %>](#<%= link.toLowerCase() %>)  18 | <% }) %> 19 | <% }) %> 20 | 21 | <% if(!!it.categories.length) { %> 22 |

23 | <% it.categories.forEach((category) => { %> 24 | <%= category %> 25 | <% }) %> 26 |

27 | <% } %> 28 | 29 | <% it.tagName %> 30 | 31 | <% if (it.tagName === '@beta') { %> 32 | beta 33 | <% } %> 34 | 35 | <% if (it.deprecated) { %> 36 | deprecate 37 | <% } %> 38 | 39 | <%= it.description %> 40 | 41 | {.desc} 42 | 43 | <% if (it.tagName === '@beta') { %> 44 | ::: warning 45 | This API is provided as a preview for developers and may change based on feedback that we receive. 46 | Do not use this API in a production environment. 47 | ::: 48 | <% } %> 49 | 50 | <% if (it.deprecated) { %> 51 | ::: danger 52 | This function will remove next major release. 53 | ::: 54 | <% } %> 55 | 56 | 57 | **Signature:** 58 | 59 | ```ts 60 | <%= it.signature %> 61 | 62 | ``` 63 | 64 | <% if(!!it.params.length || !!it.returns.length) { %>
65 | Parameters 66 | 67 | <% if(!!it.params.length) { %> 68 | | Parameter | Description | 69 | | --------- | ----------- | 70 | <% it.params.forEach(([parameterName, description]) => { %> 71 | | <%= parameterName %> | <%= description %> | 72 | <% }) %> 73 | {.table} 74 | <% } %> 75 | 76 | <% if(!!it.returns.length) { %> 77 | =><% it.returns.forEach((_return) => { %> 78 | <%= _return %> 79 | <% }) %> 80 | <% } %> 81 | 82 | 83 |
84 | <% } %> 85 | 86 | <% it.remarks.forEach((remark) => { %> 87 | ::: tip Remark 88 | <%= remark %> 89 | 90 | ::: 91 | <% }) %> 92 | 93 | <% it.examples.forEach(([language, code], index) => { 94 | %> 95 | #### Example <%= it.examples.length === 1 ? '' : index + 1 %> 96 | 97 | 98 | ```<%= language %> 99 | 100 | <%= code %> 101 | ``` 102 | 103 | <%});%> 104 | 105 | <% if(it.isLatest && it.test) { %>
106 | Tests 107 | 108 | ```ts 109 | <%= it.test %> 110 | ``` 111 | 112 |
113 | <% } %> 114 | 115 | <% if (it.isLatest) { %> [View source on GitHub](https://github.com/TomokiMiyauci/fonction/blob/main/<%= it.dir %>/<%= it.name %>.ts) 116 | <% } %> 117 | 118 | --- 119 | -------------------------------------------------------------------------------- /egg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://x.nest.land/eggs@0.3.6/src/schema.json", 3 | "name": "fonction", 4 | "entry": "./mod.ts", 5 | "description": "A modern practical functional library", 6 | "homepage": "https://github.com/TomokiMiyauci/fonction", 7 | "version": "1.5.0", 8 | "files": [ 9 | "./docs/public/icon.gif", 10 | "./mod.ts", 11 | "./deps.ts", 12 | "./src/**/*.ts", 13 | "./README.md", 14 | "./LICENSE", 15 | "./CHANGELOG.md" 16 | ], 17 | "ignore": [".git"], 18 | "checkFormat": false, 19 | "checkTests": false, 20 | "checkInstallation": false, 21 | "check": true 22 | } 23 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | export * from './common/mod.ts' 3 | export { curry } from './deps.ts' 4 | export { add } from './src/add.ts' 5 | export { advance } from './src/advance.ts' 6 | export { and } from './src/and.ts' 7 | export { append } from './src/append.ts' 8 | export { chunk } from './src/chunk.ts' 9 | export { _ } from './src/constants/index.ts' 10 | export { constructorName } from './src/constructorName.ts' 11 | export { dec } from './src/dec.ts' 12 | export { defaultTo } from './src/defaultTo.ts' 13 | export { divide } from './src/divide.ts' 14 | export { equal } from './src/equal.ts' 15 | export { F } from './src/F.ts' 16 | export type { FlattenDeep } from './src/flattenDeep.ts' 17 | export { flattenDeep } from './src/flattenDeep.ts' 18 | export { gt } from './src/gt.ts' 19 | export { gte } from './src/gte.ts' 20 | export { has } from './src/has.ts' 21 | export { identity } from './src/identity.ts' 22 | export { ifElse } from './src/ifElse.ts' 23 | export { ifElseFn } from './src/ifElseFn.ts' 24 | export { inc } from './src/inc.ts' 25 | export { K } from './src/K.ts' 26 | export { lt } from './src/lt.ts' 27 | export { lte } from './src/lte.ts' 28 | export { multiply } from './src/multiply.ts' 29 | export { N } from './src/N.ts' 30 | export { NN } from './src/NN.ts' 31 | export { not } from './src/not.ts' 32 | export { or } from './src/or.ts' 33 | export { pipe } from './src/pipe.ts' 34 | export { prepend } from './src/prepend.ts' 35 | export { product } from './src/product.ts' 36 | export { props } from './src/props.ts' 37 | export { subtract } from './src/subtract.ts' 38 | export { sum } from './src/sum.ts' 39 | export { T } from './src/T.ts' 40 | export { take } from './src/take.ts' 41 | export { takeLast } from './src/takeLast.ts' 42 | export { tap } from './src/tap.ts' 43 | export { tryCatch } from './src/tryCatch.ts' 44 | export type { 45 | AnyFn, 46 | Arity1Fn, 47 | Empty, 48 | FalsyLike, 49 | Ord, 50 | Primitive, 51 | Space, 52 | TypedArray 53 | } from './src/types/index.ts' 54 | export { uniq } from './src/uniq.ts' 55 | export { xor } from './src/xor.ts' 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fonction", 3 | "description": "A modern practical functional library", 4 | "version": "2.1.0", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "types": "dist/index.es.d.ts", 8 | "exports": { 9 | ".": { 10 | "import": "./dist/index.es.js", 11 | "require": "./dist/index.cjs.js" 12 | } 13 | }, 14 | "sideEffects": false, 15 | "license": "MIT", 16 | "scripts": { 17 | "commit": "cz", 18 | "prepare": "husky install", 19 | "prepare:docs": "yarn prepare:full-docs && yarn prepare:latest-docs", 20 | "prepare:latest-docs": "esno scripts/gen-api-model.ts && esno scripts/gen-api.ts", 21 | "prepare:full-docs": "esno scripts/gen-full-docs.ts", 22 | "dev": "vitepress dev docs", 23 | "lint": "eslint . --ext .ts --ignore-pattern dist", 24 | "prepare:build": "esno scripts/pre-build.ts", 25 | "build": "rollup -c rollup.config.ts", 26 | "build:docs": "vitepress build docs", 27 | "serve": "vitepress serve docs", 28 | "test": "deno test test/", 29 | "release": "semantic-release" 30 | }, 31 | "devDependencies": { 32 | "@commitlint/cli": "^12.0.1", 33 | "@microsoft/api-documenter": "^7.13.6", 34 | "@microsoft/api-extractor": "^7.15.1", 35 | "@rollup/plugin-replace": "^2.4.2", 36 | "@semantic-release/changelog": "^5.0.1", 37 | "@semantic-release/git": "^9.0.0", 38 | "@types/fs-extra": "^9.0.11", 39 | "@typescript-eslint/eslint-plugin": "^4.20.0", 40 | "@typescript-eslint/parser": "^4.20.0", 41 | "@wessberg/rollup-plugin-ts": "^1.3.11", 42 | "commitizen": "^4.2.3", 43 | "commitlint-config-gitmoji": "^2.2.3", 44 | "cz-emoji": "^1.3.1", 45 | "eslint": "^7.23.0", 46 | "eslint-plugin-simple-import-sort": "^7.0.0", 47 | "eslint-plugin-tsdoc": "^0.2.11", 48 | "esno": "^0.7.3", 49 | "eta": "^1.12.1", 50 | "fonction": "^1.3.0", 51 | "fs-extra": "^10.0.0", 52 | "husky": "^6.0.0", 53 | "markdown-it-attrs": "^4.0.0", 54 | "prettier": "^2.2.1", 55 | "rollup": "^2.45.1", 56 | "rollup-plugin-dts": "^3.0.1", 57 | "rollup-plugin-terser": "^7.0.2", 58 | "semantic-release": "^17.4.2", 59 | "semantic-release-gitmoji": "^1.3.4", 60 | "typescript": "^4.2.3", 61 | "vitepress": "^0.13.0" 62 | }, 63 | "files": [ 64 | "dist" 65 | ], 66 | "keywords": [ 67 | "functional", 68 | "fp", 69 | "function", 70 | "pure", 71 | "typescript", 72 | "curried" 73 | ], 74 | "author": { 75 | "name": "TomokiMiyauci", 76 | "email": "development.operation6.6.6@gmail.com", 77 | "url": "https://miyauchi.dev/" 78 | }, 79 | "homepage": "https://github.com/TomokiMiyauci/fonction#readme", 80 | "bugs": "https://github.com/TomokiMiyauci/fonction/issues", 81 | "repository": { 82 | "type": "git", 83 | "url": "https://github.com/TomokiMiyauci/fonction.git" 84 | }, 85 | "funding": { 86 | "type": "patreon", 87 | "url": "https://www.patreon.com/tomoki_miyauci" 88 | }, 89 | "browserslist": [ 90 | "> 0.5%", 91 | "last 1 version", 92 | "not IE <= 11", 93 | "not ie_mob <= 11", 94 | "node 14" 95 | ], 96 | "dependencies": { 97 | "@miyauci/is-valid": "1.0.0-beta.15", 98 | "arithmetic4": "^2.0.0", 99 | "core-fn": "1.0.0-beta.14", 100 | "curry-rice": "^1.0.0", 101 | "lauqe": "^1.5.0" 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /rollup.config.ts: -------------------------------------------------------------------------------- 1 | import replace from '@rollup/plugin-replace' 2 | import ts from '@wessberg/rollup-plugin-ts' 3 | import { resolve } from 'path' 4 | import dts from 'rollup-plugin-dts' 5 | import { terser } from 'rollup-plugin-terser' 6 | 7 | import { dependencies, main, module } from './package.json' 8 | 9 | const baseDir = resolve(__dirname) 10 | const outputDir = resolve(baseDir, 'dist') 11 | const inputFilePath = resolve(baseDir, 'mod.ts') 12 | const declareFilePath = resolve(outputDir, 'index.es.d.ts') 13 | const replaceOption = { 14 | '.ts': '', 15 | 'https://x.nest.land/arithmetic4@0.1.1/mod': 'arithmetic4', 16 | 'https://deno.land/x/equal@v1.5.0/mod': 'lauqe', 17 | 'https://deno.land/x/curry@v1.0.0/mod': 'curry-rice', 18 | 'https://deno.land/x/core_fn@v1.0.0-beta.14/mod': 'core-fn', 19 | 'https://deno.land/x/core_fn@v1.0.0-beta.14/uncurry/common/slice': 20 | 'core-fn/uncurry', 21 | 'https://deno.land/x/is_valid@v1.0.0-beta.15/mod': '@miyauci/is-valid', 22 | preventAssignment: true 23 | } 24 | const banner = 25 | '/*! Copyright (c) 2021-present the Fonction authors. All rights reserved. MIT license. */' 26 | const external = [...Object.keys(dependencies), 'core-fn/uncurry'] 27 | 28 | const config = [ 29 | { 30 | input: inputFilePath, 31 | // eslint-disable-next-line no-sparse-arrays 32 | plugins: [ 33 | replace(replaceOption), 34 | ts({ 35 | transpiler: 'babel', 36 | tsconfig: (resolvedConfig) => ({ 37 | ...resolvedConfig, 38 | declaration: false 39 | }) 40 | }), 41 | , 42 | terser() 43 | ], 44 | 45 | external, 46 | 47 | output: { 48 | file: main, 49 | format: 'cjs', 50 | sourcemap: true, 51 | banner 52 | } 53 | }, 54 | { 55 | input: inputFilePath, 56 | plugins: [ 57 | replace(replaceOption), 58 | ts({ 59 | transpiler: 'babel' 60 | }), 61 | terser() 62 | ], 63 | 64 | external, 65 | 66 | output: { 67 | file: module, 68 | format: 'es', 69 | sourcemap: true, 70 | banner 71 | } 72 | }, 73 | { 74 | input: declareFilePath, 75 | output: { file: declareFilePath }, 76 | 77 | plugins: [ 78 | dts({ 79 | respectExternal: true, 80 | compilerOptions: { 81 | declarationMap: true 82 | } 83 | }) 84 | ] 85 | } 86 | ] 87 | 88 | export default config 89 | -------------------------------------------------------------------------------- /scripts/gen-api-list.ts: -------------------------------------------------------------------------------- 1 | import { isArray } from '@miyauci/is-valid' 2 | import { render } from 'eta' 3 | import { has, props } from 'fonction' 4 | 5 | import api from '../api' 6 | 7 | const getApiListTable = (): string => { 8 | const _api = Object.entries(api) 9 | _api.sort((p1, p2) => { 10 | const p1Key = p1[0], 11 | p2Key = p2[0] 12 | if (p1Key < p2Key) { 13 | return -1 14 | } 15 | if (p1Key > p2Key) { 16 | return 1 17 | } 18 | return 0 19 | }) 20 | 21 | const tableList = _api.reduce((acc, [moduleName, arr]) => { 22 | if (isArray(arr)) { 23 | return { 24 | ...acc, 25 | [moduleName]: arr.reduce( 26 | (acc, cur) => { 27 | return { ...acc, [cur]: moduleName } 28 | }, 29 | { fonction: moduleName } 30 | ) 31 | } 32 | } else { 33 | const isNoImplement = has('fonction', arr) 34 | ? props('fonction', arr) 35 | ? props('fonction', arr) 36 | : undefined 37 | : moduleName 38 | return { ...acc, [moduleName]: { ...arr, fonction: isNoImplement } } 39 | } 40 | }, {} as any) 41 | 42 | const header = `| Name | Fonction | Rambda | Ramda | Lodash | 43 | | ------ | -------- | ------ | ------ | ------ | 44 | ` 45 | const template = `| <%= it.moduleName %> | <%= it.fonction === it.moduleName ? '[✅](#' + it.moduleName.toLowerCase() + ')' : it.fonction ? '[' + it.fonction + '](#' + it.fonction.toLowerCase() + ')' : '' %> | <%= it.rambda === it.moduleName ? '[✅](https://selfrefactor.github.io/rambda/#/?id=' + it.moduleName.toLowerCase() + ')' : it.rambda ?? '' %> | <%= it.ramda === it.moduleName ? "✅" : it.ramda ?? '' %> | <%= it.lodash === it.moduleName ? "✅" : it.lodash ?? '' %> |` 46 | 47 | const body = Object.entries(tableList).map(([moduleName, fn]: any) => { 48 | return render(template, { 49 | moduleName, 50 | fonction: fn['fonction'], 51 | rambda: fn['rambda'], 52 | ramda: fn['rambda'], 53 | lodash: fn['lodash'] 54 | }) 55 | }) 56 | 57 | return `
58 | Cross-functional comparison 59 | 60 | ${header}${body.join('\n')} 61 | 62 |
63 | ` 64 | } 65 | 66 | export { getApiListTable } 67 | -------------------------------------------------------------------------------- /scripts/gen-api-model.ts: -------------------------------------------------------------------------------- 1 | import { Extractor, ExtractorConfig } from '@microsoft/api-extractor' 2 | import { readFileSync, writeFileSync } from 'fs-extra' 3 | import { resolve } from 'path' 4 | 5 | const replace = (path: string): void => { 6 | const content = readFileSync(path, { 7 | encoding: 'utf-8' 8 | }) 9 | 10 | const replaced = content 11 | .replace(/isNaN_2/g, 'isNaN') 12 | .replace(/length_2/g, 'length') 13 | writeFileSync(path, replaced) 14 | } 15 | 16 | const rootPath = resolve(__dirname, '..') 17 | const json = resolve(rootPath, 'temp', 'fonction.api.json') 18 | const run = () => { 19 | const apiExtractorJsonPath = resolve(rootPath, 'api-extractor.json') 20 | 21 | const extractorConfig = ExtractorConfig.loadFileAndPrepare( 22 | apiExtractorJsonPath 23 | ) 24 | const extractorResult = Extractor.invoke(extractorConfig, { 25 | localBuild: true, 26 | showVerboseMessages: true 27 | }) 28 | 29 | if (extractorResult.succeeded) { 30 | console.log(`API Extractor completed successfully`) 31 | 32 | replace(json) 33 | 34 | process.exitCode = 0 35 | } else { 36 | console.error( 37 | `API Extractor completed with ${extractorResult.errorCount} errors` + 38 | ` and ${extractorResult.warningCount} warnings` 39 | ) 40 | process.exitCode = 1 41 | } 42 | } 43 | 44 | if (require.main === module) { 45 | run() 46 | } 47 | 48 | export { replace } 49 | -------------------------------------------------------------------------------- /scripts/gen-full-docs.ts: -------------------------------------------------------------------------------- 1 | import { Extractor, ExtractorConfig } from '@microsoft/api-extractor' 2 | import { execSync } from 'child_process' 3 | import { take } from 'fonction' 4 | import { mkdirsSync, outputJSONSync, readJSONSync } from 'fs-extra' 5 | import { resolve } from 'path' 6 | 7 | import { run as _run } from './gen-api.ts' 8 | import { replace } from './gen-api-model.ts' 9 | import { formatModuleStats, getModuleStarts } from './gen-relations.ts' 10 | const getVersionList = (): string[] => { 11 | const log = execSync('npm view fonction versions --json') 12 | return JSON.parse(log.toString()) 13 | } 14 | 15 | const generateModuleList = (): void => { 16 | const versions = getVersionList().reverse() 17 | outputJSONSync(resolve(__dirname, '..', 'temp', 'meta.json'), { 18 | versions 19 | }) 20 | } 21 | 22 | const generateApiJson = (version: string): string => { 23 | const baseDir = resolve(__dirname, '..', 'temp', 'fonction', version) 24 | mkdirsSync(baseDir) 25 | 26 | execSync(`yarn --cwd temp/fonction/${version}/ init -y`) 27 | execSync(`yarn --cwd temp/fonction/${version}/ add fonction@${version}`) 28 | const apiJsonFilePath = resolve(baseDir, 'fonction.api.json') 29 | const extractorConfig = ExtractorConfig.prepare({ 30 | configObject: { 31 | mainEntryPointFilePath: resolve( 32 | baseDir, 33 | 'node_modules', 34 | 'fonction', 35 | 'dist', 36 | 'index.es.d.ts' 37 | ), 38 | compiler: { 39 | tsconfigFilePath: resolve(__dirname, '..', 'tsconfig.json') 40 | }, 41 | 42 | projectFolder: baseDir, 43 | 44 | docModel: { 45 | enabled: true, 46 | apiJsonFilePath 47 | } 48 | }, 49 | configObjectFullPath: undefined, 50 | packageJsonFullPath: resolve(baseDir, 'package.json') 51 | }) 52 | 53 | Extractor.invoke(extractorConfig, { 54 | localBuild: true, 55 | showVerboseMessages: true 56 | }) 57 | 58 | replace(apiJsonFilePath) 59 | return apiJsonFilePath 60 | } 61 | 62 | const run = async () => { 63 | const { versions }: { versions: string[] } = readJSONSync( 64 | resolve(__dirname, '..', 'temp', 'meta.json'), 65 | { 66 | encoding: 'utf-8' 67 | } 68 | ) 69 | 70 | const list = await Promise.all( 71 | versions.map((version) => [version, generateApiJson(version)] as const) 72 | ) 73 | 74 | const moduleVersions = await getModuleStarts(versions) 75 | const formattedModuleVersions = formatModuleStats( 76 | moduleVersions, 77 | take(10, versions) 78 | ) 79 | 80 | take(10, list).forEach(([version, path]) => { 81 | _run({ 82 | version, 83 | apiJsonPath: path, 84 | editLink: false, 85 | isLatest: false, 86 | moduleVersions: formattedModuleVersions 87 | }) 88 | }) 89 | } 90 | 91 | if (require.main === module) { 92 | generateModuleList() 93 | run() 94 | } 95 | 96 | export { getVersionList } 97 | -------------------------------------------------------------------------------- /scripts/gen-relations.ts: -------------------------------------------------------------------------------- 1 | import { ApiModel } from '@microsoft/api-extractor-model' 2 | import { head, N, or, tail } from 'fonction' 3 | import { pathExistsSync } from 'fs-extra' 4 | import { resolve } from 'path' 5 | 6 | const apiModel = new ApiModel() 7 | 8 | const getModuleStarts = async ( 9 | versions: string[] 10 | ): Promise> => { 11 | const fullModuleVersionList = await Promise.all( 12 | versions.map((version) => { 13 | return [ 14 | version, 15 | ...(getModuleList( 16 | resolve( 17 | __dirname, 18 | '..', 19 | 'temp', 20 | 'fonction', 21 | version, 22 | 'fonction.api.json' 23 | ) 24 | ) ?? []) 25 | ] 26 | }) 27 | ) 28 | const publicModuleVersionList = fullModuleVersionList.filter((moduleList) => { 29 | const version = head(moduleList) 30 | return N(version.includes('beta')) 31 | }) 32 | return publicModuleVersionList.reduce((acc, cur) => { 33 | const version = head(cur) 34 | const modules = tail(cur) 35 | 36 | modules.forEach((module) => { 37 | acc[module] = version 38 | }) 39 | 40 | return acc 41 | }, {} as Record) 42 | } 43 | 44 | const formatModuleStats = (stats: Record, versions: string[]) => 45 | Object.entries(stats).reduce( 46 | (acc, [key, version]) => { 47 | return { 48 | ...acc, 49 | [key]: { 50 | version, 51 | linkable: versions.includes(version as string) 52 | } 53 | } 54 | }, 55 | {} as Record< 56 | string, 57 | { 58 | version: string 59 | linkable: boolean 60 | } 61 | > 62 | ) 63 | 64 | const getModuleList = (path: string) => { 65 | if (N(pathExistsSync(path))) return 66 | 67 | const apiPackage = apiModel.loadPackage(path) 68 | const moduleList = apiPackage.members[0].members 69 | .map(({ displayName: name, kind }) => 70 | or(kind === 'Variable', kind === 'TypeAlias') ? name : undefined 71 | ) 72 | .filter((_) => N(N(_))) 73 | return moduleList as string[] 74 | } 75 | 76 | export { formatModuleStats, getModuleStarts } 77 | -------------------------------------------------------------------------------- /src/F.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { AnyFn } from './types/index.ts' 3 | 4 | /** 5 | * A function that always returns `false`. Any passed in parameters are ignored. 6 | * 7 | * @returns false 8 | * 9 | * @example 10 | * ```ts 11 | * F() // false 12 | * F(1, 'hello', 'world') // false 13 | * ``` 14 | * 15 | * @see Related to {@link T} 16 | * 17 | * @public 18 | */ 19 | const F: AnyFn = () => false 20 | 21 | export { F } 22 | -------------------------------------------------------------------------------- /src/K.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /** 3 | * K combinator. Returns a function that always returns the given value. 4 | * 5 | * @param val - The value to wrap in a function 6 | * @returns Function wrapped `val` 7 | * 8 | * @example 9 | * ```ts 10 | * const k = K('k') 11 | * k() // 'k' 12 | * ``` 13 | * 14 | * @public 15 | */ 16 | const K = (val: T): (() => T) => (): T => val 17 | 18 | export { K } 19 | -------------------------------------------------------------------------------- /src/N.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { FalsyLike } from './types/index.ts' 3 | /** 4 | * Returns the `!` of its argument. 5 | * 6 | * @param val - Input any value 7 | * @returns The result of `!val` 8 | * 9 | * @remarks 10 | * The Definition of Falsy 11 | * - `''` 12 | * - `false` 13 | * - `0` 14 | * - `NaN` 15 | * - `undefined` 16 | * - `null` 17 | * 18 | * @example 19 | * ```ts 20 | * N('') // true 21 | * N(false) // true 22 | * N(0) // true 23 | * N(NaN) // true 24 | * N(undefined) // true 25 | * N(null) // true 26 | * 27 | * N({}) // false 28 | * N([]) // false 29 | * ``` 30 | * 31 | * @category `Logic` 32 | * 33 | * @see Related to {@link NN} 34 | * 35 | * @public 36 | */ 37 | const N = (val: T): T extends FalsyLike ? true : boolean => 38 | !val as T extends FalsyLike ? true : boolean 39 | export { N } 40 | -------------------------------------------------------------------------------- /src/NN.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { FalsyLike } from './types/index.ts' 3 | /** 4 | * Abbreviation for Not Not. Returns the `!!` of its argument. 5 | * 6 | * @param val - Input any value 7 | * @returns The result of `!!val` 8 | * 9 | * @remarks 10 | * The Definition of Falsy 11 | * - `''` 12 | * - `false` 13 | * - `0` 14 | * - `NaN` 15 | * - `undefined` 16 | * - `null` 17 | * 18 | * @example 19 | * ```ts 20 | * NN('') // false 21 | * NN(false) // false 22 | * NN(0) // false 23 | * NN(NaN) // false 24 | * NN(undefined) // false 25 | * NN(null) // false 26 | * 27 | * NN({}) // true 28 | * NN([]) // true 29 | * ``` 30 | * 31 | * @category `Logic` 32 | * 33 | * @see Related to {@link N} 34 | * 35 | * @public 36 | */ 37 | const NN = (val: T): T extends FalsyLike ? false : boolean => 38 | !!val as T extends FalsyLike ? false : boolean 39 | export { NN } 40 | -------------------------------------------------------------------------------- /src/T.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { AnyFn } from './types/index.ts' 3 | 4 | /** 5 | * A function that always returns `true`. Any passed in parameters are ignored. 6 | * 7 | * @returns `True` 8 | * 9 | * @example 10 | * ```ts 11 | * T() // true 12 | * T(1, 'hello', 'world') // true 13 | * ``` 14 | * 15 | * @see Related to {@link F} 16 | * 17 | * @public 18 | */ 19 | const T: AnyFn = () => true 20 | 21 | export { T } 22 | -------------------------------------------------------------------------------- /src/_/has.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { hasOwnProperty } from '../constants/index.ts' 3 | 4 | /** 5 | * Returns whether or not an object has an own property with the specified name. 6 | * 7 | * @param props - The name of the property to check for 8 | * @param obj - The check object 9 | * @returns The result of `Object.prototype.hasOwnProperty.call(obj, props)` 10 | * 11 | * @example 12 | * ```ts 13 | * has('hello', { hello: 'world' }) // true 14 | * has(0, { 0 : 1}) // true 15 | * has('', {}) // false 16 | * has('hello', { hi : hello: 'world' }) // false 17 | * ``` 18 | * 19 | * @internal 20 | */ 21 | const has = >( 22 | props: T, 23 | obj: U 24 | ): U extends Record ? true : false => 25 | hasOwnProperty.call(obj, props) as U extends Record ? true : false 26 | 27 | export { has } 28 | -------------------------------------------------------------------------------- /src/_/hasPath.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { head } from '../../common/head.ts' 3 | import { tail } from '../../common/tail.ts' 4 | import { isLength0, isObject, isUndefined } from '../../deps.ts' 5 | import { and } from '../and.ts' 6 | import { ifElse } from '../ifElse.ts' 7 | import { has } from './has.ts' 8 | 9 | /** 10 | * Returns whether or not a path exists in an object. Only the object's own properties are checked. 11 | * 12 | * @param path - The path to use 13 | * @param obj - The object to check the path in 14 | * @returns Whether the path exists 15 | * 16 | * @example 17 | * ```ts 18 | * hasPath(['hello'], { hello: 'world' }) // true 19 | * hasPath([0], { 0: 1 }) // true 20 | * hasPath(['hello', 'world'], { hello: { world: '' } } // true 21 | * 22 | * hasPath(['hi'], { hello: '' } ) // false 23 | * hasPath(['hi', 'Tom'], { hi: { John: 1 } } ) // false 24 | * ``` 25 | * 26 | * @internal 27 | */ 28 | 29 | // TODO: Improve type inference 30 | const hasPath = ( 31 | path: (string | number)[], 32 | obj: Record 33 | ): boolean => { 34 | const key = head(path) 35 | if (isUndefined(key)) return false 36 | const rest = tail(path) 37 | if (isLength0(rest)) { 38 | return has(key, obj) 39 | } 40 | return ifElse( 41 | and(has(key, obj), () => isObject(obj[key])), 42 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 43 | () => hasPath(rest, obj[key] as any), 44 | false 45 | ) 46 | } 47 | 48 | export { hasPath } 49 | -------------------------------------------------------------------------------- /src/_/prop.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { has } from '../has.ts' 3 | import { ifElse } from '../ifElse.ts' 4 | /** 5 | * Returns a function that when supplied an object returns the indicated property of that object, if it exists. 6 | * 7 | * @param val - input property key 8 | * @param obj - The object to query 9 | * @returns The result of safety `obj[val]` 10 | * 11 | * @example 12 | * ```ts 13 | * prop('x', { x: 'hello' }) // 'hello' 14 | * prop(1, { 1: 100 }) // 100 15 | * prop('x', {}) // undefined 16 | * ``` 17 | * 18 | * @internal 19 | */ 20 | const prop = < 21 | T extends string | number, 22 | U extends Record 23 | >( 24 | val: T, 25 | obj: U 26 | ): U extends Record ? U[T] : undefined => 27 | ifElse(has(val, obj), () => obj[val], undefined) as U extends Record< 28 | T, 29 | unknown 30 | > 31 | ? U[T] 32 | : undefined 33 | export { prop } 34 | -------------------------------------------------------------------------------- /src/_/propPath.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { has } from '../has.ts' 3 | import { ifElse } from '../ifElse.ts' 4 | import { N } from '../N.ts' 5 | 6 | /** 7 | * Returns a function that when supplied an object returns the indicated property of that object, if it exists. 8 | * 9 | * @param val - input property key 10 | * @param obj - The object to query 11 | * @returns The result of safety `obj[val]` 12 | * 13 | * @example 14 | * ```ts 15 | * propPath('x', { x: 'hello' }) // 'hello' 16 | * propPath(1, { 1: 100 }) // 100 17 | * propPath('x', {}) // undefined 18 | * ``` 19 | * 20 | * @internal 21 | */ 22 | const propPath = < 23 | T extends (string | number)[], 24 | U extends Record 25 | >( 26 | val: T, 27 | obj: U 28 | ): unknown | undefined => 29 | ifElse(N(has(val, obj)), undefined, () => 30 | val.reduce((acc, cur) => acc[cur] as never, obj as U) 31 | ) 32 | 33 | export { propPath } 34 | 35 | propPath([''], { '': '' }) 36 | -------------------------------------------------------------------------------- /src/add.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { add as _add } from '../deps.ts' 3 | 4 | // re-export 5 | 6 | /** 7 | * Adds first argument and second argument. 8 | * 9 | * @param a - The first input number 10 | * @param b - The second input number 11 | * @returns The result of `a + b` 12 | * 13 | * @example 14 | * ```ts 15 | * // Basic 16 | * add(1, 2) // 3 17 | * ``` 18 | * @example 19 | * ```ts 20 | * // Bigint 21 | * add(1n, 2n) // 3n 22 | * ``` 23 | * 24 | * @example 25 | * ```ts 26 | * // Curry 27 | * const plus2(2) 28 | * plus2(-3) // -1 29 | * ``` 30 | * 31 | * @category `Math` 32 | * 33 | * @see Related to {@link subtract} {@link multiply} {@link divide} 34 | * 35 | * @public 36 | */ 37 | export const add = _add 38 | -------------------------------------------------------------------------------- /src/advance.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isFunction } from '../deps.ts' 3 | import { ifElse } from './ifElse.ts' 4 | import { AnyFn } from './types/index.ts' 5 | /** 6 | * Returns return value if argument is `function`; otherwise returns the value as it is. 7 | * 8 | * @param val - Input any value 9 | * @returns The result of `typeof val === 'function' ? val(): val` 10 | * 11 | * @example 12 | * ```ts 13 | * advance(1) // 1 14 | * advance(() => 1) // 1 15 | * ``` 16 | * 17 | * @category `Logic` 18 | * 19 | * @public 20 | */ 21 | const advance = (val: T | AnyFn): T => 22 | ifElse(isFunction(val), () => (val as AnyFn)(), val) 23 | 24 | export { advance } 25 | -------------------------------------------------------------------------------- /src/and.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { advance } from './advance.ts' 3 | import { ifElse } from './ifElse.ts' 4 | import { NN } from './NN.ts' 5 | import { FalsyLike } from './types/index.ts' 6 | import { AnyFn } from './types/index.ts' 7 | /** 8 | * Returns `true` if both arguments are true; otherwise `false`. 9 | * 10 | * @param a - The first input any value 11 | * @param b - The second input any value 12 | * @returns The result of `!!a && !!bb` (if argument is function, return value) 13 | * 14 | * @remarks 15 | * If you pass a function as an argument, return value will evaluate. 16 | * 17 | * @example 18 | * ```ts 19 | * and(true, true) // true 20 | * and(false, true) // false 21 | * and(true, false) // false 22 | * and(false, false) // false 23 | * and(() => 1, () => 2) // true 24 | * and(() => 1, () => 0) // false 25 | * ``` 26 | * 27 | * @category `Logic` 28 | * 29 | * @see Related to {@link or} {@link xor} 30 | * 31 | * @public 32 | */ 33 | const and = ( 34 | a: T | AnyFn, 35 | b: U | AnyFn 36 | ): T extends FalsyLike ? false : U extends FalsyLike ? false : boolean => 37 | ifElse( 38 | NN(advance(a as unknown)), 39 | () => NN(advance(b as unknown)) as any, 40 | false 41 | ) 42 | 43 | export { and } 44 | -------------------------------------------------------------------------------- /src/append.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /** 3 | * Returns a new list containing the contents of the given list, followed by the given value. 4 | * 5 | * @param val - The value to add to the end of the new list 6 | * @param list - The list of elements to add a new item to 7 | * @returns The result of `[...list, val]` 8 | * 9 | * @example 10 | * ```ts 11 | * append('Tom', ['hello']) // ['hello', 'Tom'] 12 | * append('Tom', []) // ['Tom'] 13 | * append(['Tom'], ['hello', 'world']) // ['hello', 'world', ['Tom']] 14 | * ``` 15 | * 16 | * @see Related to {@link prepend} 17 | * 18 | * @category `Array` 19 | * 20 | * @public 21 | */ 22 | const append = (val: T, list: U[]): (T | U)[] => [...list, val] 23 | export { append } 24 | -------------------------------------------------------------------------------- /src/chunk.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { add } from './add.ts' 3 | import { ifElse } from './ifElse.ts' 4 | import { lte } from './lte.ts' 5 | /** 6 | * Return an array of elements split into groups the length of size. 7 | * 8 | * @param size - The length of each chunk 9 | * @param array - The array to process 10 | * @returns Returns the new array of chunks 11 | * 12 | * @remarks 13 | * If array can't be split evenly, the final chunk will be the remaining elements. 14 | * 15 | * @example 16 | * ```ts 17 | * // Basic 18 | * chunk(1, ['a', 'b', 'c', 'd']) // [['a'], ['b'], ['c'], ['d']] 19 | * chunk(3, ['a', 'b', 'c', 'd']) // [['a', 'b', 'c'], ['d']] 20 | * chunk(5, ['a', 'b', 'c', 'd']) // [['a', 'b', 'c', 'd']] 21 | * ``` 22 | * 23 | * @example 24 | * ```ts 25 | * // Illegal size 26 | * chunk(0, ['a', 'b', 'c']) // ['a', 'b', 'c'] 27 | * chunk(-3, ['a', 'b', 'c']) // ['a', 'b', 'c'] 28 | * chunk(5, []) // [] 29 | * ``` 30 | * 31 | * @category `Array` 32 | * 33 | * @public 34 | */ 35 | const chunk = ( 36 | size: T, 37 | array: U 38 | ): T extends 0 39 | ? U 40 | : `${T}` extends `-${number}` 41 | ? U 42 | : U extends readonly [] 43 | ? U 44 | : U extends readonly (infer R)[] 45 | ? R[][] 46 | : never => 47 | ifElse( 48 | lte(size, 0 as T), 49 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 50 | array as any, 51 | () => 52 | array.reduce( 53 | (acc, _, index) => 54 | ifElse(index % size, acc, [ 55 | ...(acc as never), 56 | array.slice(index, add(index, size)) 57 | ]), 58 | [] 59 | ) 60 | ) 61 | 62 | export { chunk } 63 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | export { _ } from 'https://x.nest.land/arithmetic4@0.1.1/mod.ts' 3 | export const NULL = null 4 | export const JSON_OBJECT = 'Object' 5 | 6 | const { prototype } = Object 7 | const { hasOwnProperty } = prototype 8 | 9 | export { hasOwnProperty } 10 | -------------------------------------------------------------------------------- /src/constructorName.ts: -------------------------------------------------------------------------------- 1 | import { isNil } from '../deps.ts' 2 | import { and } from './and.ts' 3 | import { ifElse } from './ifElse.ts' 4 | import { N } from './N.ts' 5 | 6 | /** 7 | * Safe getter for `constructor.name`. 8 | * @param val - Any value 9 | * @returns If `val` is `null` or `undefined`, empty string; otherwise `constructor.name` 10 | * 11 | * @example 12 | * ```ts 13 | * constructorName(null) // '' 14 | * constructorName(undefined) // '' 15 | * constructorName({}) // 'Object' 16 | * constructorName('') // 'String' 17 | * ``` 18 | * 19 | * @public 20 | */ 21 | const constructorName = (val: unknown): string => 22 | ifElse( 23 | and(N(isNil(val)), () => (val as Record).constructor), 24 | () => (val as Record).constructor.name ?? '', 25 | '' 26 | ) 27 | 28 | export { constructorName } 29 | -------------------------------------------------------------------------------- /src/dec.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isNumber } from '../deps.ts' 3 | import { subtract } from './subtract.ts' 4 | 5 | /** 6 | * Decrements its argument. 7 | * 8 | * @param val - input `number` or `bigint` 9 | * @returns Decremented `val` 10 | * 11 | * @example 12 | * ```ts 13 | * dec(100) // 99 14 | * dec(10n) // 9n 15 | * ``` 16 | * 17 | * @see Related to {@link inc} 18 | * 19 | * @public 20 | */ 21 | const dec: { 22 | (val: number): number 23 | (val: bigint): bigint 24 | } = (val: unknown) => 25 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 26 | (isNumber(val) ? subtract(val, 1) : subtract(val as bigint, 1n)) as any 27 | 28 | export { dec } 29 | -------------------------------------------------------------------------------- /src/defaultTo.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isNil } from '../deps.ts' 3 | import { or } from './or.ts' 4 | 5 | /** 6 | * Returns the second argument if it is not `null`, `undefined` or `NaN`; otherwise the first argument is returned. 7 | * 8 | * @param a - `a` will be returned instead of `default` 9 | * @returns Returns a function that stores the default `a` value. The function accept `b` argument. 10 | * if `b` is `null`, `undefined` or `NaN`, return `a`; otherwise return `b` 11 | * 12 | * @example 13 | * ```ts 14 | * const defaultVal = defaultTo('anonymous') 15 | * defaultVal(undefined) // 'anonymous' 16 | * defaultVal(null) // 'anonymous' 17 | * defaultVal(NaN) // 'anonymous' 18 | * 19 | * defaultVal('Tom') // 'Tom' 20 | * ``` 21 | * 22 | * @public 23 | */ 24 | const defaultTo = 25 | (a: T) => 26 | ( 27 | b: U 28 | ): U extends null | undefined ? T : U extends number ? U : T | U => 29 | (or(isNil(b), () => Number.isNaN(b)) ? a : b) as U extends null | undefined 30 | ? T 31 | : U extends number 32 | ? U 33 | : T | U 34 | 35 | export { defaultTo } 36 | -------------------------------------------------------------------------------- /src/divide.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { divide as _divide } from '../deps.ts' 3 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 4 | import { _ } from './constants/index.ts' 5 | 6 | // re-export 7 | 8 | /** 9 | * Divide its second argument from its first argument. 10 | * 11 | * @param a - The first input number 12 | * @param b - The second input number 13 | * @returns The result of `a / b` 14 | 15 | * @remarks 16 | * Since division is not idempotent, there are two ways to curry. 17 | * 18 | * @example 19 | * ```ts 20 | * // Number 21 | * divide(10, 100) // 0.1 22 | * ``` 23 | * 24 | * @example 25 | * ```ts 26 | * // Bigint 27 | * divide(1n, 2n) // 3n 28 | * ``` 29 | * 30 | * @example 31 | * ```ts 32 | * // First argument curry 33 | * const reciprocal = divide(1) 34 | * reciprocal(4) // 0.25 35 | * ``` 36 | * 37 | * @example 38 | * ```ts 39 | * // Second argument curry 40 | * import { _ } from 'fonction' 41 | * const half = divide(_, 2) 42 | * half(20) // 10 43 | * ``` 44 | * 45 | * @category `Math` 46 | * 47 | * @see Related to {@link add} {@link subtract} {@link multiply} 48 | * 49 | * @public 50 | */ 51 | export const divide = _divide 52 | -------------------------------------------------------------------------------- /src/equal.ts: -------------------------------------------------------------------------------- 1 | import { equal as _equal } from '../deps.ts' 2 | 3 | /** 4 | * Returns `true` if its arguments are equivalent, `false` otherwise. Handles cyclical data structures. 5 | * 6 | * @param a - Input any value 7 | * @param b - Input any value 8 | * @returns Return `true` if the reference memory is the same or the property members and their values are the same 9 | * 10 | * @example 11 | * ```ts 12 | * equals(-0, 0) // true 13 | * equals(NaN, NaN) // true 14 | * equals([[[[]]]], [[[[]]]]) // true 15 | * equals({ a: { b: [1, 2, 3]}}, { a: { b: [1, 2, 3]}}) // true 16 | * ``` 17 | * 18 | * @public 19 | */ 20 | const equal = _equal 21 | 22 | export { equal } 23 | -------------------------------------------------------------------------------- /src/flattenDeep.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /** 3 | * Infer deep flatted array. 4 | * 5 | * @typeParam T - input any array 6 | * @returns Deep flatted array 7 | * 8 | * @example 9 | * ```ts 10 | * FlattenDeep<[]> // [] 11 | * FlattenDeep<[[1, [2, [3, [4]], 5]]> // [1, 2, 3, 4, 5] 12 | * ``` 13 | * 14 | * @category `Array` 15 | * 16 | * @public 17 | */ 18 | type FlattenDeep = T extends readonly [ 19 | infer A, 20 | ...infer Rest 21 | ] 22 | ? A extends readonly unknown[] 23 | ? [...FlattenDeep, ...FlattenDeep] 24 | : [A, ...FlattenDeep] 25 | : [...T] 26 | /** 27 | * Recursively flattens array. 28 | * 29 | * @param val - The `array` to flatten 30 | * @returns The result of `val.flat(Infinity)` 31 | * 32 | * @example 33 | * ```ts 34 | * flattenDeep([]) // [] 35 | * flattenDeep([1, [2, [3, [4]], 5]]) // [1, 2, 3, 4, 5] 36 | * ``` 37 | * 38 | * @public 39 | */ 40 | const flattenDeep = (val: T): FlattenDeep => 41 | val.flat(Infinity) as FlattenDeep 42 | 43 | export { flattenDeep } 44 | export type { FlattenDeep } 45 | -------------------------------------------------------------------------------- /src/gt.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { Ord } from './types/index.ts' 3 | /** 4 | * Returns `true` if the first argument is greater than the second; otherwise `false`. 5 | * 6 | * @param a - The first input value 7 | * @param b - The second input value 8 | * @returns The result of `a > b` 9 | * 10 | * @example 11 | * ```ts 12 | * // Number 13 | * gt(2, 1) // true 14 | * gt(2, 2) // false 15 | * ``` 16 | * 17 | * @example 18 | * ```ts 19 | * // Bigint 20 | * gt(2n, 1n) // true 21 | * gt(2n, 2n) // false 22 | * ``` 23 | * 24 | * @example 25 | * ```ts 26 | * // String 27 | * gt('z', 'a') // true 28 | * gt('a', 'z') // false 29 | * ``` 30 | * 31 | * @example 32 | * ```ts 33 | * // Boolean 34 | * gt(true, false) // true 35 | * gt(false, true) // false 36 | * gt(true, true) // false 37 | * gt(false, false) // false 38 | * ``` 39 | * 40 | * @example 41 | * ```ts 42 | * // Date 43 | * gt(new Date('2000/1/2'), new Date('2000/1/1')) // true 44 | * gt(new Date('1999/12/31'), new Date('2000/1/1')) // false 45 | * gt(new Date('2000/1/1'), new Date('2000/1/1')) // false 46 | * ``` 47 | * 48 | * @see Related to {@link gte} {@link lt} {@link lte} 49 | * 50 | * @public 51 | */ 52 | const gt = (a: T, b: T): boolean => a > b 53 | 54 | export { gt } 55 | -------------------------------------------------------------------------------- /src/gte.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { Ord } from './types/index.ts' 3 | 4 | /** 5 | * Returns `true` if the first argument is greater than or equal to the second; otherwise `false`. 6 | * 7 | * @param a - The first input value 8 | * @param b - The second input value 9 | * @returns The result of `a >= b` 10 | * 11 | * @example 12 | * ```ts 13 | * // Number 14 | * gte(2, 1) // true 15 | * gte(2, 2) // true 16 | * gte(2, 3) // false 17 | * ``` 18 | * 19 | * @example 20 | * ```ts 21 | * // Bigint 22 | * gte(2n, 1n) // true 23 | * gte(2n, 2n) // true 24 | * gte(2n, 3n) // false 25 | * ``` 26 | * 27 | * @example 28 | * ```ts 29 | * // String 30 | * gte('z', 'a') // true 31 | * gte('a', 'a') // true 32 | * gte('a', 'z') // false 33 | * ``` 34 | * 35 | * @example 36 | * ```ts 37 | * // Boolean 38 | * gte(true, false) // true 39 | * gte(true, true) // true 40 | * gte(false, false) // true 41 | * gte(false, true) // false 42 | * ``` 43 | * 44 | * @example 45 | * ```ts 46 | * // Date 47 | * gte(new Date('2000/1/2'), new Date('2000/1/1')) // true 48 | * gte(new Date('2000/1/1'), new Date('2000/1/1')) // true 49 | * gte(new Date('1999/12/31'), new Date('2000/1/1')) // false 50 | * ``` 51 | * 52 | * @see Related to {@link gt} {@link lt} {@link lte} 53 | * 54 | * @public 55 | */ 56 | const gte = (a: T, b: T): boolean => a >= b 57 | 58 | export { gte } 59 | -------------------------------------------------------------------------------- /src/has.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isArray } from '../deps.ts' 3 | import { has as _has } from './_/has.ts' 4 | import { hasPath as _hasPath } from './_/hasPath.ts' 5 | 6 | /** 7 | * Returns whether or not an object has an own property with the specified name. 8 | * 9 | * @param props - The name of the property to check for 10 | * @param obj - The check object 11 | * @returns The result of `Object.prototype.hasOwnProperty` 12 | * 13 | * @example 14 | * ```ts 15 | * // Flat 16 | * has('hello', { hello: 'world' }) // true 17 | * has(0, { 0 : 1}) // true 18 | * has('', {}) // false 19 | * has('hello', { hi : hello: 'world' }) // false 20 | * ``` 21 | * 22 | * @example 23 | * ```ts 24 | * // Nest 25 | * hasPath(['hello'], { hello: 'world' }) // true 26 | * hasPath([0], { 0: 1 }) // true 27 | * hasPath(['hello', 'world'], { hello: { world: '' } } // true 28 | * 29 | * hasPath(['hi'], { hello: '' } ) // false 30 | * hasPath(['hi', 'Tom'], { hi: { John: 1 } } ) // false 31 | * ``` 32 | * 33 | * @category `Object` 34 | * 35 | * @see Related to {@link props} 36 | * 37 | * @public 38 | */ 39 | const has = < 40 | T extends string | number | (string | number)[], 41 | U extends Record 42 | >( 43 | props: T, 44 | obj: U 45 | ): T extends unknown[] 46 | ? boolean 47 | : T extends string | number 48 | ? U extends Record 49 | ? true 50 | : false 51 | : never => 52 | isArray(props) 53 | ? _hasPath(props, obj) 54 | : // eslint-disable-next-line @typescript-eslint/no-explicit-any 55 | (_has(props as string | number, obj) as any) 56 | 57 | export { has } 58 | -------------------------------------------------------------------------------- /src/identical.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /** 3 | * Return the parameter supplied to it. 4 | * 5 | * @param val - The value to return 6 | * @returns The result of `val` 7 | * 8 | * @example 9 | * ```ts 10 | * identity(1) // 1 11 | * identity({}) // {} 12 | * ``` 13 | * 14 | * @public 15 | */ 16 | const identity = (val: T): T => val 17 | 18 | export { identity } 19 | -------------------------------------------------------------------------------- /src/identity.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /** 3 | * Return the parameter supplied to it. 4 | * 5 | * @param val - The value to return 6 | * @returns The result of `val` 7 | * 8 | * @example 9 | * ```ts 10 | * identity(1) // 1 11 | * identity({}) // {} 12 | * ``` 13 | * 14 | * @public 15 | */ 16 | const identity = (val: T): T => val 17 | 18 | export { identity } 19 | -------------------------------------------------------------------------------- /src/ifElse.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isFunction } from '../deps.ts' 3 | import { NN } from './NN.ts' 4 | import { AnyFn } from './types/index.ts' 5 | import { FalsyLike } from './types/index.ts' 6 | /** 7 | * Return the `onTrue` or the `onFalse` value depending upon the result of the condition `val`. 8 | * 9 | * @param val - A predicate value 10 | * @param onTrue - The `val` evaluates to a truthy value 11 | * @param onFalse - The `val` evaluates to a falsy value 12 | * @returns The result of `!!val` ? `onTrue` : `onFalse` (if argument is function, return value) 13 | * 14 | * @remarks 15 | * If you pass a function as an argument, return value will evaluate. 16 | * 17 | * @example 18 | * ```ts 19 | * ifElse(true, 1, 0) // 1 20 | * ifElse(false, 1, 0) // 0 21 | * ifElse(undefined, 1, 0) // 0 22 | * ifElse(() => true, () => 1, () => 0) // 1 23 | * ``` 24 | * 25 | * @category `Logic` 26 | * 27 | * @see Related to {@link ifElseFn} 28 | * 29 | * @public 30 | */ 31 | const ifElse = ( 32 | val: V | AnyFn, 33 | onTrue: T | AnyFn, 34 | onFalse: F | AnyFn 35 | ): V extends FalsyLike ? F : V extends true ? T : T | F => { 36 | const result = isFunction(val) ? NN(val()) : NN(val) 37 | return result 38 | ? isFunction(onTrue) 39 | ? (onTrue() as V extends FalsyLike ? F : V extends true ? T : T | F) 40 | : (onTrue as V extends FalsyLike ? F : V extends true ? T : T | F) 41 | : isFunction(onFalse) 42 | ? (onFalse() as V extends FalsyLike ? F : V extends true ? T : T | F) 43 | : (onFalse as V extends FalsyLike ? F : V extends true ? T : T | F) 44 | } 45 | 46 | export { ifElse } 47 | -------------------------------------------------------------------------------- /src/ifElseFn.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isFunction } from '../deps.ts' 3 | import { ifElse } from './ifElse.ts' 4 | import { FalsyLike } from './types/index.ts' 5 | /** 6 | * Creates a function that will process either the `onTrue` or the `onFalse` function depending upon the result of the condition predicate. 7 | * 8 | * @param condition - A predicate function 9 | * @param onTrue - Any value or A function to invoke when the `condition` evaluates to a truthy value 10 | * @param onFalse - Any value or A function to invoke when the `condition` evaluates to a falsy value 11 | * @returns A new function that will process either the `onTrue` or the `onFalse` function depending upon the result of the `condition` predicate 12 | * 13 | * @example 14 | * ```ts 15 | * ifElseFn((x: number) => x > 10, 'big', 'small')(20) // 'big' 16 | * const fn = ifElseFn((x: number) => x > 10, (x) => x + 1, (x) => x - 1) 17 | * fn(11) // 12 18 | * fn(9) // 8 19 | * ``` 20 | * 21 | * @category `Logic` 22 | * 23 | * @see Related to {@link ifElse} 24 | * 25 | * @public 26 | */ 27 | const ifElseFn = 28 | ( 29 | condition: (val: V) => R, 30 | onTrue: T | ((val: V) => T), 31 | onFalse: F | ((val: V) => F) 32 | ) => 33 | (val: V): R extends true ? T : R extends FalsyLike ? F : T | F => 34 | ifElse( 35 | condition(val), 36 | () => 37 | ifElse( 38 | isFunction(onTrue), 39 | () => (onTrue as any)(val), 40 | () => onTrue 41 | ), 42 | () => 43 | ifElse( 44 | isFunction(onFalse), 45 | () => (onFalse as any)(val), 46 | () => onFalse 47 | ) 48 | ) 49 | 50 | export { ifElseFn } 51 | -------------------------------------------------------------------------------- /src/inc.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isNumber } from '../deps.ts' 3 | import { add } from './add.ts' 4 | 5 | /** 6 | * Increments its argument. 7 | * 8 | * @param val - Input `number` or `bigint` 9 | * @returns Incremented `val` 10 | * 11 | * @example 12 | * ```ts 13 | * inc(100) // 101 14 | * inc(10n) // 11n 15 | * ``` 16 | * 17 | * @see Related to {@link dec} 18 | * 19 | * @public 20 | */ 21 | const inc: { 22 | (val: number): number 23 | (val: bigint): bigint 24 | } = (val: unknown) => 25 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 26 | (isNumber(val) ? add(val, 1) : add(val as bigint, 1n)) as any 27 | 28 | export { inc } 29 | -------------------------------------------------------------------------------- /src/lt.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { Ord } from './types/index.ts' 3 | 4 | /** 5 | * Returns `true` if the first argument is less than the second; otherwise `false`. 6 | * 7 | * @param a - The first input value 8 | * @param b - The second input value 9 | * @returns The result of `a < b` 10 | * 11 | * @example 12 | * ```ts 13 | * // Number 14 | * lt(1, 2) // true 15 | * lt(2, 2) // false 16 | * ``` 17 | * 18 | * @example 19 | * ```ts 20 | * // Bigint 21 | * lt(1n, 2n) // true 22 | * lt(2n, 2n) // false 23 | * ``` 24 | * 25 | * @example 26 | * ```ts 27 | * // String 28 | * lt('a', 'z') // true 29 | * lt('a', 'a') // false 30 | * ``` 31 | * 32 | * @example 33 | * ```ts 34 | * // Boolean 35 | * lt(false, true) // true 36 | * lt(true, true) // false 37 | * lt(false, false) // false 38 | * lt(true, false) // false 39 | * ``` 40 | * 41 | * @example 42 | * ```ts 43 | * // Date 44 | * lt(new Date('1999/12/31'), new Date('2000/1/1')) // true 45 | * lt(new Date('2000/1/1'), new Date('2000/1/1')) // false 46 | * lt(new Date('2000/1/2'), new Date('2000/1/1')) // false 47 | * ``` 48 | * 49 | * @see Related to {@link lte} {@link gt} {@link gte} 50 | * 51 | * @public 52 | */ 53 | const lt = (a: T, b: T): boolean => a < b 54 | 55 | export { lt } 56 | -------------------------------------------------------------------------------- /src/lte.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { Ord } from './types/index.ts' 3 | 4 | /** 5 | * Returns `true` if the first argument is less than or equal to the second; otherwise `false`. 6 | * 7 | * @param a - The first input value 8 | * @param b - The second input value 9 | * @returns The result of `a <= b` 10 | * 11 | * @example 12 | * ```ts 13 | * // Number 14 | * lte(1, 2) // true 15 | * lte(2, 2) // true 16 | * lte(2, 1) // false 17 | * ``` 18 | * 19 | * @example 20 | * ```ts 21 | * // Bigint 22 | * lte(1n, 2n) // true 23 | * lte(2n, 2n) // true 24 | * lte(2n, 1n) // true 25 | * ``` 26 | * 27 | * @example 28 | * ```ts 29 | * // String 30 | * lte('a', 'z') // true 31 | * lte('a', 'a') // true 32 | * lte('z', 'a') // false 33 | * ``` 34 | * 35 | * @example 36 | * ```ts 37 | * // Boolean 38 | * lte(true, true) // true 39 | * lte(false, false) // true 40 | * lte(false, true) // true 41 | * lte(true, false) // false 42 | * ``` 43 | * 44 | * @example 45 | * ```ts 46 | * // Date 47 | * lte(new Date('2000/1/1'), new Date('2000/1/1')) // true 48 | * lte(new Date('1999/12/31'), new Date('2000/1/1')) // true 49 | * lte(new Date('2000/1/2'), new Date('2000/1/1')) // false 50 | * ``` 51 | * 52 | * @see Related to {@link lt} {@link gt} {@link gte} 53 | * 54 | * @public 55 | */ 56 | const lte = (a: T, b: T): boolean => a <= b 57 | 58 | export { lte } 59 | -------------------------------------------------------------------------------- /src/multiply.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { multiply as _multiply } from '../deps.ts' 3 | 4 | // re-export 5 | 6 | /** 7 | * Multiplies first argument and second argument. 8 | * 9 | * @param a - The first input number 10 | * @param b - The second input number 11 | * @returns The result of `a * b` 12 | * 13 | * @example 14 | * ```ts 15 | * // Basic 16 | * multiply(2, 3) // 6 17 | * ``` 18 | * 19 | * @example 20 | * ```ts 21 | * // Bigint 22 | * multiply(2n, 3n) // 6n 23 | * ``` 24 | * 25 | * @example 26 | * ```ts 27 | * // Curry 28 | * const double = multiply(2) 29 | * double(4) // 8 30 | * ``` 31 | * 32 | * @category `Math` 33 | * 34 | * @see Related to {@link add} {@link subtract} {@link divide} 35 | * 36 | * @public 37 | */ 38 | export const multiply = _multiply 39 | -------------------------------------------------------------------------------- /src/not.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { N } from './N.ts' 3 | import { AnyFn } from './types/index.ts' 4 | /** 5 | * Returns the function as is with return value `!`. 6 | * 7 | * @param val - Input any `function` 8 | * @returns The result is function what return value with `!` 9 | * 10 | * @example 11 | * ```ts 12 | * not(() => true)() // false 13 | * const gt10 = (val: number) => val > 10 14 | * not(gt10)(11) // false 15 | * ``` 16 | * 17 | * @public 18 | */ 19 | 20 | const not = 21 | (fn: T) => 22 | (...val: Parameters): boolean => 23 | N(fn(...val)) 24 | 25 | export { not } 26 | -------------------------------------------------------------------------------- /src/or.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { advance } from './advance.ts' 3 | import { NN } from './NN.ts' 4 | import { FalsyLike } from './types/index.ts' 5 | import { AnyFn } from './types/index.ts' 6 | 7 | /** 8 | * Returns true if one or both of its arguments are true; otherwise false. 9 | * 10 | * @param a - The first input any value 11 | * @param b - The second input any value 12 | * @returns The result of `!!a || !!bb` (if argument is function, return value) 13 | * 14 | * @remarks 15 | * If you pass a function as an argument, return value will evaluate. 16 | 17 | * @example 18 | * ```ts 19 | * or(true, true) // true 20 | * or(false, true) // true 21 | * or(true, false) // true 22 | * or(false, false) // false 23 | * 24 | * or(() => 0, () => 1) // true 25 | * or(() => 0, () => 0) // false 26 | * ``` 27 | * 28 | * @category `Logic` 29 | * 30 | * @see Related to {@link and} {@link xor} 31 | * 32 | * @public 33 | */ 34 | const or = ( 35 | a: T | AnyFn, 36 | b: U | AnyFn 37 | ): T extends FalsyLike ? (U extends FalsyLike ? false : boolean) : boolean => 38 | (NN(advance(a)) || NN(advance(b))) as T extends FalsyLike 39 | ? U extends FalsyLike 40 | ? false 41 | : boolean 42 | : boolean 43 | export { or } 44 | -------------------------------------------------------------------------------- /src/pipe.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { AnyFn, Arity1Fn } from './types/index.ts' 3 | 4 | /** 5 | * Performs left-to-right function composition. 6 | * 7 | * @param functions - Multi any functions 8 | * @returns A `function` what argument is `function[0]` argument 9 | * 10 | * @remarks 11 | * The first argument may have any arity; the remaining arguments must be unary. 12 | * 13 | * @example 14 | * ```ts 15 | * const fn = pipe(add , inc) 16 | * fn(1, 1) // 3 17 | * ``` 18 | * 19 | * @public 20 | */ 21 | const pipe: Pipe = 22 | (...args: AnyFn[]) => 23 | (...initialArg: unknown[]) => 24 | args.reduce( 25 | (acc, cur, index) => cur(...(index === 0 ? acc : [acc])) as unknown[], 26 | initialArg 27 | ) 28 | 29 | export { pipe } 30 | 31 | type Pipe = { 32 | (fn1: F1): (...initialArg: Parameters) => ReturnType 33 | 34 | >>(...fn1: [F1, F2]): ( 35 | ...initialArg: Parameters 36 | ) => ReturnType 37 | 38 | < 39 | F1 extends AnyFn, 40 | F2 extends Arity1Fn>, 41 | F3 extends Arity1Fn> 42 | >( 43 | ...fn1: [F1, F2, F3] 44 | ): (...initialArg: Parameters) => ReturnType 45 | 46 | < 47 | F1 extends AnyFn, 48 | F2 extends Arity1Fn>, 49 | F3 extends Arity1Fn>, 50 | F4 extends Arity1Fn> 51 | >( 52 | ...fn1: [F1, F2, F3, F4] 53 | ): (...initialArg: Parameters) => ReturnType 54 | 55 | < 56 | F1 extends AnyFn, 57 | F2 extends Arity1Fn>, 58 | F3 extends Arity1Fn>, 59 | F4 extends Arity1Fn>, 60 | F5 extends Arity1Fn> 61 | >( 62 | ...fn1: [F1, F2, F3, F4, F5] 63 | ): (...initialArg: Parameters) => ReturnType 64 | 65 | < 66 | F1 extends AnyFn, 67 | F2 extends Arity1Fn>, 68 | F3 extends Arity1Fn>, 69 | F4 extends Arity1Fn>, 70 | F5 extends Arity1Fn>, 71 | F6 extends Arity1Fn> 72 | >( 73 | ...fn1: [F1, F2, F3, F4, F5, F6] 74 | ): (...initialArg: Parameters) => ReturnType 75 | 76 | < 77 | F1 extends AnyFn, 78 | F2 extends Arity1Fn>, 79 | F3 extends Arity1Fn>, 80 | F4 extends Arity1Fn>, 81 | F5 extends Arity1Fn>, 82 | F6 extends Arity1Fn>, 83 | F7 extends Arity1Fn> 84 | >( 85 | ...fn1: [F1, F2, F3, F4, F5, F6, F7] 86 | ): (...initialArg: Parameters) => ReturnType 87 | 88 | < 89 | F1 extends AnyFn, 90 | F2 extends Arity1Fn>, 91 | F3 extends Arity1Fn>, 92 | F4 extends Arity1Fn>, 93 | F5 extends Arity1Fn>, 94 | F6 extends Arity1Fn>, 95 | F7 extends Arity1Fn>, 96 | F8 extends Arity1Fn> 97 | >( 98 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8] 99 | ): (...initialArg: Parameters) => ReturnType 100 | 101 | < 102 | F1 extends AnyFn, 103 | F2 extends Arity1Fn>, 104 | F3 extends Arity1Fn>, 105 | F4 extends Arity1Fn>, 106 | F5 extends Arity1Fn>, 107 | F6 extends Arity1Fn>, 108 | F7 extends Arity1Fn>, 109 | F8 extends Arity1Fn>, 110 | F9 extends Arity1Fn> 111 | >( 112 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8, F9] 113 | ): (...initialArg: Parameters) => ReturnType 114 | 115 | < 116 | F1 extends AnyFn, 117 | F2 extends Arity1Fn>, 118 | F3 extends Arity1Fn>, 119 | F4 extends Arity1Fn>, 120 | F5 extends Arity1Fn>, 121 | F6 extends Arity1Fn>, 122 | F7 extends Arity1Fn>, 123 | F8 extends Arity1Fn>, 124 | F9 extends Arity1Fn>, 125 | F10 extends Arity1Fn> 126 | >( 127 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8, F9, F10] 128 | ): (...initialArg: Parameters) => ReturnType 129 | 130 | < 131 | F1 extends AnyFn, 132 | F2 extends Arity1Fn>, 133 | F3 extends Arity1Fn>, 134 | F4 extends Arity1Fn>, 135 | F5 extends Arity1Fn>, 136 | F6 extends Arity1Fn>, 137 | F7 extends Arity1Fn>, 138 | F8 extends Arity1Fn>, 139 | F9 extends Arity1Fn>, 140 | F10 extends Arity1Fn>, 141 | F11 extends Arity1Fn> 142 | >( 143 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11] 144 | ): (...initialArg: Parameters) => ReturnType 145 | 146 | < 147 | F1 extends AnyFn, 148 | F2 extends Arity1Fn>, 149 | F3 extends Arity1Fn>, 150 | F4 extends Arity1Fn>, 151 | F5 extends Arity1Fn>, 152 | F6 extends Arity1Fn>, 153 | F7 extends Arity1Fn>, 154 | F8 extends Arity1Fn>, 155 | F9 extends Arity1Fn>, 156 | F10 extends Arity1Fn>, 157 | F11 extends Arity1Fn>, 158 | F12 extends Arity1Fn> 159 | >( 160 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12] 161 | ): (...initialArg: Parameters) => ReturnType 162 | 163 | < 164 | F1 extends AnyFn, 165 | F2 extends Arity1Fn>, 166 | F3 extends Arity1Fn>, 167 | F4 extends Arity1Fn>, 168 | F5 extends Arity1Fn>, 169 | F6 extends Arity1Fn>, 170 | F7 extends Arity1Fn>, 171 | F8 extends Arity1Fn>, 172 | F9 extends Arity1Fn>, 173 | F10 extends Arity1Fn>, 174 | F11 extends Arity1Fn>, 175 | F12 extends Arity1Fn>, 176 | F13 extends Arity1Fn> 177 | >( 178 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13] 179 | ): (...initialArg: Parameters) => ReturnType 180 | 181 | < 182 | F1 extends AnyFn, 183 | F2 extends Arity1Fn>, 184 | F3 extends Arity1Fn>, 185 | F4 extends Arity1Fn>, 186 | F5 extends Arity1Fn>, 187 | F6 extends Arity1Fn>, 188 | F7 extends Arity1Fn>, 189 | F8 extends Arity1Fn>, 190 | F9 extends Arity1Fn>, 191 | F10 extends Arity1Fn>, 192 | F11 extends Arity1Fn>, 193 | F12 extends Arity1Fn>, 194 | F13 extends Arity1Fn>, 195 | F14 extends Arity1Fn> 196 | >( 197 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14] 198 | ): (...initialArg: Parameters) => ReturnType 199 | 200 | < 201 | F1 extends AnyFn, 202 | F2 extends Arity1Fn>, 203 | F3 extends Arity1Fn>, 204 | F4 extends Arity1Fn>, 205 | F5 extends Arity1Fn>, 206 | F6 extends Arity1Fn>, 207 | F7 extends Arity1Fn>, 208 | F8 extends Arity1Fn>, 209 | F9 extends Arity1Fn>, 210 | F10 extends Arity1Fn>, 211 | F11 extends Arity1Fn>, 212 | F12 extends Arity1Fn>, 213 | F13 extends Arity1Fn>, 214 | F14 extends Arity1Fn>, 215 | F15 extends Arity1Fn> 216 | >( 217 | ...fn1: [F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15] 218 | ): (...initialArg: Parameters) => ReturnType 219 | 220 | < 221 | F1 extends AnyFn, 222 | F2 extends Arity1Fn>, 223 | F3 extends Arity1Fn>, 224 | F4 extends Arity1Fn>, 225 | F5 extends Arity1Fn>, 226 | F6 extends Arity1Fn>, 227 | F7 extends Arity1Fn>, 228 | F8 extends Arity1Fn>, 229 | F9 extends Arity1Fn>, 230 | F10 extends Arity1Fn>, 231 | F11 extends Arity1Fn>, 232 | F12 extends Arity1Fn>, 233 | F13 extends Arity1Fn>, 234 | F14 extends Arity1Fn>, 235 | F15 extends Arity1Fn>, 236 | F16 extends Arity1Fn> 237 | >( 238 | ...fn1: [ 239 | F1, 240 | F2, 241 | F3, 242 | F4, 243 | F5, 244 | F6, 245 | F7, 246 | F8, 247 | F9, 248 | F10, 249 | F11, 250 | F12, 251 | F13, 252 | F14, 253 | F15, 254 | F16 255 | ] 256 | ): (...initialArg: Parameters) => ReturnType 257 | 258 | < 259 | F1 extends AnyFn, 260 | F2 extends Arity1Fn>, 261 | F3 extends Arity1Fn>, 262 | F4 extends Arity1Fn>, 263 | F5 extends Arity1Fn>, 264 | F6 extends Arity1Fn>, 265 | F7 extends Arity1Fn>, 266 | F8 extends Arity1Fn>, 267 | F9 extends Arity1Fn>, 268 | F10 extends Arity1Fn>, 269 | F11 extends Arity1Fn>, 270 | F12 extends Arity1Fn>, 271 | F13 extends Arity1Fn>, 272 | F14 extends Arity1Fn>, 273 | F15 extends Arity1Fn>, 274 | F16 extends Arity1Fn>, 275 | F17 extends Arity1Fn> 276 | >( 277 | ...fn1: [ 278 | F1, 279 | F2, 280 | F3, 281 | F4, 282 | F5, 283 | F6, 284 | F7, 285 | F8, 286 | F9, 287 | F10, 288 | F11, 289 | F12, 290 | F13, 291 | F14, 292 | F15, 293 | F16, 294 | F17 295 | ] 296 | ): (...initialArg: Parameters) => ReturnType 297 | } 298 | -------------------------------------------------------------------------------- /src/prepend.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /** 3 | * Returns a new list with the given value at the front, followed by the contents of the list. 4 | * 5 | * @param val - The value to add to the front of the new list 6 | * @param list - The list of elements to add a new item to 7 | * @returns The result of `[val, ...list]` 8 | * 9 | * @example 10 | * ```ts 11 | * prepend('Tom', ['hello']) // ['Tom', 'hello'] 12 | * prepend('Tom', []) // ['Tom'] 13 | * prepend(['Tom'], ['hello', 'world']) // [['Tom'], 'hello', 'world'] 14 | * ``` 15 | * 16 | * @category `Array` 17 | * 18 | * @see Related to {@link append} 19 | * 20 | * @public 21 | */ 22 | const prepend = (val: T, list: U[]): (T | U)[] => [val, ...list] 23 | export { prepend } 24 | -------------------------------------------------------------------------------- /src/product.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { head } from '../common/head.ts' 3 | import { isNumber, isUndefined } from '../deps.ts' 4 | import { ifElse } from './ifElse.ts' 5 | import { multiply } from './multiply.ts' 6 | /** 7 | * Multiplies together all the elements of a list. 8 | * 9 | * @param val - list An array of numbers 10 | * @returns The product of all the numbers in the list 11 | * 12 | * @example 13 | * ```ts 14 | * product([1, 2, 3, 4, 5]) // 120 15 | * product([1n, 2n, 3n, 4n, 5n]) //120n 16 | * product([]) // 0 17 | * ``` 18 | * 19 | * @category `Math` 20 | * 21 | * @public 22 | */ 23 | const product: { 24 | (val: []): 0 25 | (val: number[]): number 26 | (val: bigint[]): bigint 27 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 28 | } = (val: any) => { 29 | const _head = head(val) as number | bigint | undefined 30 | return ifElse(isUndefined(_head), 0, () => { 31 | const init = ifElse(isNumber(_head), 1, 1n) 32 | return val.reduce(multiply, init) 33 | }) 34 | } 35 | 36 | export { product } 37 | -------------------------------------------------------------------------------- /src/props.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { prop } from './_/prop.ts' 3 | 4 | /** 5 | * Returns a function that when supplied an object returns the indicated property of that object, if it exists. 6 | * 7 | * @param val - Input property key 8 | * @param obj - The object to query 9 | * @returns The result of safety `obj[val]` or `obj[val[0]][val[1]][val[...x]]` 10 | * 11 | * @example 12 | * ```ts 13 | * props('x', { x: 'hello' }) // 'hello' 14 | * props(1, { 1: 100 }) // 100 15 | * props('x', {}) // undefined 16 | * ``` 17 | * 18 | * @category `Object` 19 | * 20 | * @see Related to {@link has} 21 | * 22 | * @public 23 | */ 24 | const props = < 25 | T extends string | number, 26 | U extends Record 27 | >( 28 | val: T, 29 | obj: U 30 | ): U extends Record ? U[T] : undefined => prop(val, obj) 31 | export { props } 32 | -------------------------------------------------------------------------------- /src/subtract.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 3 | import { subtract as _subtract } from '../deps.ts' 4 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 5 | import { _ } from './constants/index.ts' 6 | 7 | // re-export 8 | 9 | /** 10 | * Subtracts its second argument from its first argument. 11 | * 12 | * @param a - The first input number 13 | * @param b - The second input number 14 | * @returns The result of `a - b` 15 | * 16 | * @remarks 17 | * Since subtraction is not idempotent, there are two ways to curry. 18 | * 19 | * @example 20 | * ```ts 21 | * // Number 22 | * subtract(2, 1) // 1 23 | * ``` 24 | * 25 | * @example 26 | * ```ts 27 | * // Bigint 28 | * subtract(3n, 2n) //1n 29 | * ``` 30 | * 31 | * @example 32 | * ```ts 33 | * // First argument curry 34 | * const from5Minus = subtract(5) 35 | * from5Minus(10) // -5 36 | * ``` 37 | * 38 | * @example 39 | * ```ts 40 | * // Second argument curry 41 | * import { _ } from 'fonction' 42 | * const minus5 = (_, 5) 43 | * minus5(20) // 15 44 | * ``` 45 | * 46 | * @category `Math` 47 | * 48 | * @see Related to {@link add} {@link multiply} {@link divide} 49 | * 50 | * @public 51 | */ 52 | export const subtract = _subtract 53 | -------------------------------------------------------------------------------- /src/sum.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { head } from '../common/head.ts' 3 | import { isNumber, isUndefined } from '../deps.ts' 4 | import { add } from './add.ts' 5 | import { ifElse } from './ifElse.ts' 6 | /** 7 | * Adds together all the elements of a list. 8 | * 9 | * @param val - list An array of numbers 10 | * @returns The sum of all the numbers in the list 11 | * 12 | * @example 13 | * ```ts 14 | * sum([1, 2, 3, 4, 5]) // 15 15 | * sum([1n, 2n, 3n, 4n, 5n]) // 15n 16 | * sum([]) // 0 17 | * ``` 18 | * 19 | * @category `Math` 20 | * 21 | * @public 22 | */ 23 | const sum: { 24 | (val: []): 0 25 | (val: number[]): number 26 | (val: bigint[]): bigint 27 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 28 | } = (val: any) => { 29 | const _head = head(val) as number | bigint | undefined 30 | return ifElse(isUndefined(_head), 0, () => { 31 | const init = ifElse(isNumber(_head), 0, 0n) 32 | return val.reduce(add, init) 33 | }) 34 | } 35 | 36 | export { sum } 37 | -------------------------------------------------------------------------------- /src/take.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | 3 | import { ifElse } from './ifElse.ts' 4 | import { lt } from './lt.ts' 5 | 6 | /** 7 | * Return a slice of string or array with `n` elements taken from the beginning. 8 | * 9 | * @param howMany - The number of elements to take 10 | * @param val - `String` or `Array` to query 11 | * @returns The slice of array 12 | * 13 | * @example 14 | * ```ts 15 | * // String 16 | * take(3, 'hello') // 'hel' 17 | * ``` 18 | * 19 | * @example 20 | * ```ts 21 | * // Array 22 | * take(3, [1, 2, 3, 4]) // [1, 2, 3] 23 | * ``` 24 | * 25 | * @category `String` `Array` 26 | * 27 | * @see Related to {@link takeLast} 28 | * 29 | * @public 30 | */ 31 | const take = ( 32 | howMany: number, 33 | val: T 34 | ): T => 35 | ifElse( 36 | lt(howMany, 0), 37 | () => val.slice(howMany) as T, 38 | () => val.slice(0, howMany) as T 39 | ) 40 | 41 | export { take } 42 | -------------------------------------------------------------------------------- /src/takeLast.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | 3 | import { ifElse } from './ifElse.ts' 4 | import { lte } from './lte.ts' 5 | 6 | /** 7 | * Return a slice of string or array with `n` elements taken from the end. 8 | * 9 | * @param howMany - The number of elements to take 10 | * @param val - `String` or `Array` to query 11 | * @returns The slice of array 12 | * 13 | * @example 14 | * ```ts 15 | * // String 16 | * takeLast(3, 'hello') // 'llo' 17 | * ``` 18 | * 19 | * @example 20 | * ```ts 21 | * // Array 22 | * takeLast(3, [1, 2, 3, 4]) // [2, 3, 4] 23 | * ``` 24 | * 25 | * @category `String` `Array` 26 | * 27 | * @see Related to {@link take} 28 | * 29 | * @public 30 | */ 31 | const takeLast = ( 32 | howMany: number, 33 | val: T 34 | ): T => 35 | ifElse( 36 | lte(howMany, 0), 37 | () => val.slice(0, -howMany) as T, 38 | () => val.slice(-howMany) as T 39 | ) 40 | 41 | export { takeLast } 42 | -------------------------------------------------------------------------------- /src/tap.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { Arity1Fn } from './types/index.ts' 3 | 4 | /** 5 | * Runs the given function with the supplied value, then returns the value. 6 | * 7 | * @param fn - The function to call with `val`. The return value of fn will be thrown away. 8 | * @returns The result of `(val) => fn(val)` 9 | * 10 | * @example 11 | * ```ts 12 | * tap(console.log)('hello') // hello 13 | * // log: hello 14 | * ``` 15 | * 16 | * @public 17 | */ 18 | const tap = 19 | (fn: Arity1Fn) => 20 | (val: R): R => { 21 | fn(val) 22 | return val 23 | } 24 | 25 | export { tap } 26 | -------------------------------------------------------------------------------- /src/tryCatch.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { isFunction, isUndefined } from '../deps.ts' 3 | import { advance } from './advance.ts' 4 | import { ifElse } from './ifElse.ts' 5 | import { N } from './N.ts' 6 | import { AnyFn } from './types/index.ts' 7 | 8 | /** 9 | * `tryCatch` takes two functions, a `tryer` and a `catcher`. The returned function evaluates the `tryer`; if it does not throw, it simply returns the result. If the `tryer` does throw, the returned function evaluates the catcher function and returns its result. 10 | * 11 | * @param tryer - The function that may throw. 12 | * @param catcher - The function that will be evaluated if tryer throws. 13 | * @returns - The result of `try { tryer() } catch(e) { catcher(e) }` 14 | * 15 | * @example 16 | * ```ts 17 | * tryCatch(() => { throw Error('error') }) // Error('error') 18 | * tryCatch(() => { throw Error('error') }, 0) // 0 19 | * tryCatch(() => { throw Error('error') }, (e: Error) => e.message ) // 'error' 20 | * ``` 21 | * 22 | * @category `Logic` 23 | * 24 | * @public 25 | */ 26 | const tryCatch = ( 27 | tryer: AnyFn, 28 | catcher?: E | AnyFn 29 | ): R | E => { 30 | try { 31 | return advance(tryer) 32 | } catch (e) { 33 | return ifElse( 34 | isFunction(catcher), 35 | () => (catcher as AnyFn)(e), 36 | () => ifElse(N(isUndefined(catcher)), catcher, e) 37 | ) 38 | } 39 | } 40 | 41 | export { tryCatch } 42 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /* eslint-disable @typescript-eslint/no-explicit-any */ 3 | /** 4 | * Type of any function. 5 | * 6 | * @public 7 | * 8 | * @typeParam T - Argument types 9 | */ 10 | export type AnyFn = (...args: T[]) => U 11 | 12 | /** 13 | * Type of arity 1 function. 14 | * 15 | * @public 16 | * 17 | * @typeParam T - Argument types 18 | */ 19 | export type Arity1Fn = (args: T) => U 20 | 21 | /** 22 | * Alias for Primitive values types. 23 | * 24 | * @category `Alias` 25 | * 26 | * @public 27 | * 28 | */ 29 | export type Primitive = 30 | | string 31 | | number 32 | | bigint 33 | | boolean 34 | | symbol 35 | | undefined 36 | | null 37 | 38 | /** 39 | * Abbreviation for Ordinal. 40 | * 41 | * @category `Alias` 42 | * 43 | * @public 44 | */ 45 | export type Ord = string | number | bigint | boolean | Date 46 | 47 | /** 48 | * Alias for Empty values 49 | * 50 | * @category `Alias` 51 | * 52 | * @public 53 | */ 54 | // eslint-disable-next-line @typescript-eslint/ban-types 55 | export type Empty = '' | [] | {} 56 | 57 | /** 58 | * Alias for Falsy values. 59 | * 60 | * @category `Alias` 61 | * 62 | * @public 63 | * @deprecated 64 | * Rename to `FalsyLike` 65 | */ 66 | export type Falsy = false | '' | 0 | null | undefined 67 | 68 | /** 69 | * Alias for Falsy values. 70 | * 71 | * @remarks 72 | * This is not a strict `Falsy`. TypeScript type system cannot define `NaN`. 73 | * 74 | * @category `Alias` 75 | * 76 | * @public 77 | */ 78 | export type FalsyLike = false | '' | 0 | 0n | null | undefined 79 | 80 | /** 81 | * Alias for Space values. 82 | * 83 | * @category `Alias` 84 | * 85 | * @public 86 | */ 87 | export type Space = ' ' | '\n' | '\t' 88 | 89 | export type InferArray = T extends (infer R)[] ? R : never 90 | 91 | /** 92 | * Convert `string` to `array` types. 93 | * 94 | * @typeParam T - Any string 95 | * @returns String array 96 | * 97 | * @example 98 | * ```ts 99 | * String2Array string[] 100 | * String2Array<''> // [] 101 | * String2Array<'hello'> // ["h", "e", "l", "l", "o"] 102 | * ``` 103 | * 104 | * @internal 105 | */ 106 | export type String2Array = T extends '' 107 | ? [] 108 | : T extends `${infer F}${infer R}` 109 | ? [F, ...String2Array] 110 | : string[] 111 | 112 | /** 113 | * Alias for TypedArray 114 | * 115 | * @beta 116 | */ 117 | export type TypedArray = 118 | | Int8Array 119 | | Uint8Array 120 | | Uint8ClampedArray 121 | | Int16Array 122 | | Uint16Array 123 | | Int32Array 124 | | Uint32Array 125 | | Float32Array 126 | | Float64Array 127 | | BigInt64Array 128 | | BigUint64Array 129 | -------------------------------------------------------------------------------- /src/uniq.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { equal } from './equal.ts' 3 | import { ifElse } from './ifElse.ts' 4 | 5 | /** 6 | * Returns a new `Array` containing only one copy of each element in the original array. `equal` is used to determine equality. 7 | * 8 | * @param val - Input any `array` 9 | * @returns The list of unique items 10 | * 11 | * @example 12 | * ```ts 13 | * uniq([1, 2, 1, 1]) // [1, 2] 14 | * uniq([{}, {}, [], []]) // [{}, []] 15 | * uniq([[1, 2, 3], [1, 2, 3]]) // [[1, 2, 3]] 16 | * ``` 17 | * 18 | * @category `Array` 19 | * 20 | * @see Related to {@link equal} 21 | * 22 | * @public 23 | */ 24 | const uniq = (val: readonly T[]): T[] => 25 | Array.from(new Set(val)).reduce((acc, cur) => { 26 | const result = acc.some((val) => equal(cur, val)) 27 | return ifElse(result, acc, () => [...acc, cur]) 28 | }, [] as T[]) 29 | 30 | export { uniq } 31 | -------------------------------------------------------------------------------- /src/xor.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { advance } from './advance.ts' 3 | import { N } from './N.ts' 4 | import { FalsyLike } from './types/index.ts' 5 | import { AnyFn } from './types/index.ts' 6 | 7 | /** 8 | * Returns true if one of the arguments is truthy and the other is falsy; otherwise false. 9 | * 10 | * @param a - The first input any value 11 | * @param b - The second input any value 12 | * @returns The result of `!a !== !b` (if argument is function, return value) 13 | * 14 | * @example 15 | * ```ts 16 | * xor(true, false) // true 17 | * xor(false, true) // true 18 | * xor(true, true) // false 19 | * xor(false, false) // false 20 | * xor(() => 1, () => 0) // true 21 | * xor(() => 0, () => 0) // false 22 | * ``` 23 | * 24 | * @category `Logic` 25 | * 26 | * @see Related to {@link and} {@link or} 27 | * 28 | * @public 29 | */ 30 | const xor = ( 31 | a: T | AnyFn, 32 | b: U | AnyFn 33 | ): T extends FalsyLike ? (U extends FalsyLike ? false : boolean) : boolean => 34 | (N(advance(a)) !== (N(advance(b)) as unknown)) as T extends FalsyLike 35 | ? U extends FalsyLike 36 | ? false 37 | : boolean 38 | : boolean 39 | export { xor } 40 | -------------------------------------------------------------------------------- /test/F.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { F } from '../src/F.ts' 4 | import { assertReturnType } from './asserts.ts' 5 | 6 | Deno.test('F', () => { 7 | const table: unknown[] = [ 8 | [''], 9 | [1, 2, 3], 10 | [{}, [], undefined, null], 11 | [undefined], 12 | [null] 13 | ] 14 | table.forEach((val) => { 15 | assertEquals(F(val), false, `F(${val}) -> false`) 16 | }) 17 | 18 | assertReturnType(F) 19 | }) 20 | -------------------------------------------------------------------------------- /test/K.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { K } from '../src/K.ts' 4 | 5 | Deno.test('K', () => { 6 | const table: [unknown][] = [ 7 | [''], 8 | [{}], 9 | ['hello'], 10 | [() => 1], 11 | [[]], 12 | [undefined], 13 | [null] 14 | ] 15 | 16 | table.forEach(([val]) => { 17 | assertEquals(K(val)(), val, `K(${val})() -> ${val}`) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /test/N.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { N } from '../src/N.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('N', () => { 7 | const table: [unknown, boolean][] = [ 8 | ['', true], 9 | [undefined, true], 10 | [null, true], 11 | [0, true], 12 | [NaN, true], 13 | [false, true], 14 | [[], false], 15 | [{}, false], 16 | ['hello', false], 17 | [Infinity, false], 18 | [1, false], 19 | [-1, false], 20 | [true, false] 21 | ] 22 | 23 | table.forEach(([val, expected]) => { 24 | assertEquals(N(val), expected, `N(${val}) -> ${expected}`) 25 | }) 26 | 27 | assertEqual(N('' as const)) 28 | assertEqual(N(0 as const)) 29 | assertEqual(N(false as const)) 30 | assertEqual(N(undefined)) 31 | assertEqual(N(null)) 32 | assertEqual(N(String)) 33 | assertEqual(N(Number)) 34 | assertEqual(N(NaN)) 35 | assertEqual(N(BigInt)) 36 | assertEqual(N(Symbol)) 37 | assertEqual(N(Date)) 38 | assertEqual(N(Object)) 39 | assertEqual(N(Array)) 40 | }) 41 | -------------------------------------------------------------------------------- /test/NN.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { NN } from '../src/NN.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('NN', () => { 7 | const table: [unknown, boolean][] = [ 8 | ['', false], 9 | [undefined, false], 10 | [null, false], 11 | [0, false], 12 | [NaN, false], 13 | [false, false], 14 | [[], true], 15 | [{}, true], 16 | ['hello', true], 17 | [Infinity, true], 18 | [1, true], 19 | [-1, true], 20 | [true, true] 21 | ] 22 | 23 | table.forEach(([val, expected]) => { 24 | assertEquals(NN(val), expected, `NN(${val}) -> ${expected}`) 25 | }) 26 | 27 | assertEqual(NN('' as const)) 28 | assertEqual(NN(0 as const)) 29 | assertEqual(NN(false as const)) 30 | assertEqual(NN(undefined)) 31 | assertEqual(NN(null)) 32 | assertEqual(NN(String)) 33 | assertEqual(NN(Number)) 34 | assertEqual(NN(NaN)) 35 | assertEqual(NN(BigInt)) 36 | assertEqual(NN(Symbol)) 37 | assertEqual(NN(Date)) 38 | assertEqual(NN(Object)) 39 | assertEqual(NN(Array)) 40 | }) 41 | -------------------------------------------------------------------------------- /test/T.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { T } from '../src/T.ts' 4 | import { assertReturnType } from './asserts.ts' 5 | 6 | Deno.test('T', () => { 7 | const table: unknown[] = [ 8 | [''], 9 | [1, 2, 3], 10 | [{}, [], undefined, null], 11 | [undefined], 12 | [null] 13 | ] 14 | table.forEach((val) => { 15 | assertEquals(T(val), true, `T(${val}) -> true`) 16 | }) 17 | 18 | assertReturnType(T) 19 | }) 20 | -------------------------------------------------------------------------------- /test/_/has.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../../dev_deps.ts' 3 | import { has } from '../../src/_/has.ts' 4 | 5 | Deno.test('has', () => { 6 | const table: [string | number, Record, boolean][] = [ 7 | ['', {}, false], 8 | ['', { ' ': '' }, false], 9 | ['', { ' ': { '': '' } }, false], 10 | [0, {}, false], 11 | [0, { 1: '' }, false], 12 | [0, { 1: { 0: '' } }, false], 13 | ['', { '': '' }, true], 14 | ['Hello', { hello: '' }, false], 15 | ['Hello', { Hello: '' }, true], 16 | ['hello', { hello: '' }, true], 17 | [0, { 0: 1 }, true] 18 | ] 19 | table.forEach(([a, b, expected]) => { 20 | assertEquals(has(a, b), expected, `has(${a}, ${b}) -> ${expected}`) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /test/_/hasPath.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../../dev_deps.ts' 3 | import { hasPath } from '../../src/_/hasPath.ts' 4 | 5 | Deno.test('hasPath', () => { 6 | const table: [(string | number)[], Record, boolean][] = 7 | [ 8 | [[], {}, false], 9 | [[], { '': '' }, false], 10 | [[0], {}, false], 11 | [[0], { '': '' }, false], 12 | [[0], { 0: '' }, true], 13 | [[0, 0], { 0: { 0: 1 } }, true], 14 | [[0, 'a'], { 0: { 0: 'b' } }, false], 15 | [[0, 'a'], { 0: { a: 'b' } }, true], 16 | [[''], {}, false], 17 | [[''], { ' ': '' }, false], 18 | [['a', 'b'], { a: '' }, false], 19 | [['a', 'b'], { a: { c: '' } }, false], 20 | [ 21 | ['a', 'b'], 22 | { 23 | a: { 24 | a: '' 25 | } 26 | }, 27 | false 28 | ], 29 | [['a'], { a: '' }, true], 30 | [['a'], { a: {} }, true], 31 | [['a', 'b'], { a: { b: '' } }, true], 32 | [['a', 'b'], { a: { b: {} } }, true], 33 | [['a', 'b', 'c'], { a: { b: { c: '' } } }, true], 34 | [[0, 'a', 'B'], { 0: { a: { B: 'c' } } }, true] 35 | ] 36 | 37 | table.forEach(([a, b, expected]) => { 38 | assertEquals(hasPath(a, b), expected, `hasPath(${a}, ${b}) -> ${expected}`) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /test/_/prop.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../../dev_deps.ts' 3 | import { prop } from '../../src/_/prop.ts' 4 | 5 | Deno.test('prop', () => { 6 | const table: [string | number, Record, unknown][] = [ 7 | ['', {}, undefined], 8 | ['', { ' ': '' }, undefined], 9 | ['', { ' ': { '': '' } }, undefined], 10 | [0, {}, undefined], 11 | [0, { 1: '' }, undefined], 12 | [0, { 1: { 0: '' } }, undefined], 13 | ['', { '': '' }, ''], 14 | ['Hello', { hello: '' }, undefined], 15 | ['Hello', { Hello: '' }, ''], 16 | ['hello', { hello: '' }, ''], 17 | [0, { 0: 1 }, 1] 18 | ] 19 | table.forEach(([a, b, expected]) => { 20 | assertEquals(prop(a, b), expected, `prop(${a}, ${b}) -> ${expected}`) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /test/_/propPath.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../../dev_deps.ts' 3 | import { propPath } from '../../src/_/propPath.ts' 4 | 5 | Deno.test('propPath', () => { 6 | const table: [(string | number)[], Record, unknown][] = 7 | [ 8 | [[''], {}, undefined], 9 | [[0], {}, undefined], 10 | [[0, 1], {}, undefined], 11 | [[0, 1, 'a', 'b'], { 0: 1 }, undefined], 12 | [[0, 'a', 'b'], { 0: [] }, undefined], 13 | [[''], { '': 'a' }, 'a'], 14 | [['a', 'b', 'c', 'd'], { a: { b: { c: { d: 'e' } } } }, 'e'], 15 | [ 16 | ['a', 'b', 'c', 'd', 0, 0, 1], 17 | { a: { b: { c: { d: { 0: { 0: { 1: {} } } } } } } }, 18 | {} 19 | ], 20 | [['a', 'b'], { a: { c: 'd' } }, undefined], 21 | [['a', 'b', 'c'], { a: { c: 'd' } }, undefined] 22 | ] 23 | table.forEach(([a, b, expected]) => { 24 | assertEquals( 25 | propPath(a, b), 26 | expected, 27 | `propPath(${a}, ${b}) -> ${expected}` 28 | ) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /test/advance.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { advance } from '../src/advance.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('advance', () => { 7 | const table: [unknown, unknown][] = [ 8 | [1, 1], 9 | [0, 0], 10 | [() => 1, 1], 11 | [() => 0, 0] 12 | ] 13 | 14 | table.forEach(([val, expected]) => { 15 | assertEquals(advance(val), expected, `add(${val}) -> ${expected}`) 16 | }) 17 | 18 | assertEqual(advance(false)) 19 | assertEqual<1>(advance(1)) 20 | assertEqual(advance(() => true)) 21 | assertEqual(advance(() => false)) 22 | }) 23 | -------------------------------------------------------------------------------- /test/and.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { and } from '../src/and.ts' 4 | import { Falsy } from './../src/types/index.ts' 5 | import { assertEqual } from './asserts.ts' 6 | 7 | Deno.test('and', () => { 8 | const table: [unknown, unknown, boolean][] = [ 9 | [true, true, true], 10 | [false, true, false], 11 | [true, false, false], 12 | [false, false, false], 13 | [() => true, true, true], 14 | [() => true, false, false], 15 | [() => true, () => false, false], 16 | [() => 1, () => 2, true], 17 | [() => 0, () => 1, false], 18 | [true, () => 1, true], 19 | [true, () => 0, false] 20 | ] 21 | 22 | table.forEach(([a, b, expected]) => { 23 | assertEquals(and(a, b), expected, `add(${a}, ${b}) -> ${expected}`) 24 | }) 25 | 26 | assertEqual(and(false as Falsy, false as Falsy)) 27 | assertEqual(and(false as Falsy, Boolean)) 28 | assertEqual(and(Boolean, false as Falsy)) 29 | assertEqual(and(Boolean, Boolean)) 30 | assertEqual( 31 | and( 32 | () => false as const, 33 | () => false 34 | ) 35 | ) 36 | assertEqual( 37 | and( 38 | () => false, 39 | () => false as const 40 | ) 41 | ) 42 | assertEqual(and(() => false as const, 1)) 43 | assertEqual(and(() => false as const, 1 as const)) 44 | }) 45 | -------------------------------------------------------------------------------- /test/append.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { append } from '../src/append.ts' 4 | 5 | Deno.test('append', () => { 6 | const table: [unknown, unknown[], unknown[]][] = [ 7 | [null, [], [null]], 8 | [undefined, [], [undefined]], 9 | ['', [], ['']], 10 | [{}, [], [{}]], 11 | [0, [], [0]], 12 | ['a', ['b'], ['b', 'a']], 13 | ['a', ['b', 'c', 'd'], ['b', 'c', 'd', 'a']], 14 | [[], [], [[]]], 15 | [[1], [], [[1]]], 16 | [[1], [2], [2, [1]]], 17 | [[1], [2, 3, 4], [2, 3, 4, [1]]] 18 | ] 19 | 20 | table.forEach(([val, list, expected]) => { 21 | assertEquals( 22 | append(val, list), 23 | expected, 24 | `append(${val}, ${list}) -> ${expected}` 25 | ) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /test/asserts.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /* eslint-disable @typescript-eslint/no-empty-function */ 3 | /* eslint-disable @typescript-eslint/no-unused-vars */ 4 | 5 | export const assertEqual = (_actual?: U): void => {} 6 | export const assertReturnType = (_fn: (...args: any[]) => T): void => {} 7 | -------------------------------------------------------------------------------- /test/chunk.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { chunk } from '../src/chunk.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('chunk', () => { 7 | const arr = ['a', 'b', 'c', 'd'] 8 | const arr2 = [{}, [], 0, null, undefined] 9 | const table: [number, unknown[], unknown[][] | unknown[]][] = [ 10 | [1, [], []], 11 | [0, [], []], 12 | [2, [], []], 13 | [1, [''], [['']]], 14 | [2, [''], [['']]], 15 | [3, [''], [['']]], 16 | [4, [''], [['']]], 17 | [0, [''], ['']], 18 | [-0, [''], ['']], 19 | [-1, [''], ['']], 20 | [-2, [''], ['']], 21 | [-3, [''], ['']], 22 | [-4, [''], ['']], 23 | [1, arr, [['a'], ['b'], ['c'], ['d']]], 24 | [ 25 | 2, 26 | arr, 27 | [ 28 | ['a', 'b'], 29 | ['c', 'd'] 30 | ] 31 | ], 32 | [3, arr, [['a', 'b', 'c'], ['d']]], 33 | [4, arr, [['a', 'b', 'c', 'd']]], 34 | [5, arr, [['a', 'b', 'c', 'd']]], 35 | [6, arr, [['a', 'b', 'c', 'd']]], 36 | [1, arr2, [[{}], [[]], [0], [null], [undefined]]], 37 | [2, arr2, [[{}, []], [0, null], [undefined]]], 38 | [ 39 | 3, 40 | arr2, 41 | [ 42 | [{}, [], 0], 43 | [null, undefined] 44 | ] 45 | ], 46 | [4, arr2, [[{}, [], 0, null], [undefined]]], 47 | [5, arr2, [[{}, [], 0, null, undefined]]], 48 | [6, arr2, [[{}, [], 0, null, undefined]]] 49 | ] 50 | 51 | table.forEach(([a, b, expected]) => { 52 | assertEquals(chunk(a, b), expected, `chunk(${a}, ${b}) -> ${expected}`) 53 | }) 54 | 55 | assertEqual(chunk(0, [])) 56 | assertEqual<[]>(chunk(0, [] as [])) 57 | assertEqual(chunk(0, [] as const)) 58 | assertEqual<[]>(chunk(1, [] as [])) 59 | assertEqual(chunk(-1, [''])) 60 | assertEqual(chunk(-0, [''])) 61 | assertEqual(chunk(0, [''])) 62 | assertEqual(chunk(1, [''])) 63 | assertEqual(chunk(2, [''])) 64 | assertEqual(chunk(3, [''])) 65 | assertEqual(chunk(4, [''])) 66 | assertEqual<''[][]>(chunk(1, [''] as const)) 67 | assertEqual( 68 | chunk(-4, ['a', 'b', 'c', 'd'] as const) 69 | ) 70 | assertEqual( 71 | chunk(0, ['a', 'b', 'c', 'd'] as const) 72 | ) 73 | // TODO: Implement more rigorous type inference 74 | // assertEqual<[['a'], ['b'], ['c'], ['d']]>( 75 | // chunk(1, ['a', 'b', 'c', 'd'] as ['a', 'b', 'c', 'd']) 76 | // ) 77 | // assertEqual<[['a', 'b'], ['c', 'd']]>( 78 | // chunk(2, ['a', 'b', 'c', 'd'] as ['a', 'b', 'c', 'd']) 79 | // ) 80 | // assertEqual<[['a', 'b', 'c'], ['d']]>( 81 | // chunk(3, ['a', 'b', 'c', 'd'] as ['a', 'b', 'c', 'd']) 82 | // ) 83 | // assertEqual<[['a', 'b', 'c', 'd']]>( 84 | // chunk(4, ['a', 'b', 'c', 'd'] as ['a', 'b', 'c', 'd']) 85 | // ) 86 | }) 87 | -------------------------------------------------------------------------------- /test/constants/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /* eslint-disable @typescript-eslint/no-empty-function */ 3 | /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ 4 | export const ZERO = 0 5 | export const ONE = 1 6 | export const BIG1 = 1n 7 | export const SYMBOL = Symbol('test') 8 | export const EMPTY_STRING = '' 9 | export const EMPTY_OBJECT = {} 10 | export const EMPTY_ARRAY = [] 11 | export const MAP = new Map() 12 | export const SET = new Set() 13 | export const WEAK_MAP = new WeakMap() 14 | export const WEAK_SET = new WeakSet() 15 | export const VOID_FN = () => {} 16 | export const VOID_PROMISE = new Promise(() => {}) 17 | export const DATE = new Date('2000/1/1') 18 | -------------------------------------------------------------------------------- /test/constructorName.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals, isSymbol } from '../dev_deps.ts' 3 | import { constructorName } from '../src/constructorName.ts' 4 | 5 | Deno.test('constructorName', () => { 6 | function fn() { 7 | true 8 | } 9 | class Class {} 10 | const table: [unknown, string][] = [ 11 | [Object, 'Function'], 12 | [new Object(), 'Object'], 13 | [Object(), 'Object'], 14 | [{}, 'Object'], 15 | [{ hoge: 'huga' }, 'Object'], 16 | [new Number(), 'Number'], 17 | [Number(), 'Number'], 18 | [Number, 'Function'], 19 | [1, 'Number'], 20 | ['', 'String'], 21 | [String(), 'String'], 22 | [String, 'Function'], 23 | [new String(), 'String'], 24 | [new Boolean(), 'Boolean'], 25 | [true, 'Boolean'], 26 | [Boolean, 'Function'], 27 | [new Boolean(), 'Boolean'], 28 | [Boolean(), 'Boolean'], 29 | [undefined, ''], 30 | [null, ''], 31 | [Symbol(), 'Symbol'], 32 | [Symbol, 'Function'], 33 | [1n, 'BigInt'], 34 | [BigInt, 'Function'], 35 | [Array, 'Function'], 36 | [Array([]), 'Array'], 37 | [new Array([]), 'Array'], 38 | [[], 'Array'], 39 | [Date, 'Function'], 40 | [new Date(0), 'Date'], 41 | [Date(), 'String'], 42 | [/a/, 'RegExp'], 43 | [RegExp, 'Function'], 44 | [new RegExp(''), 'RegExp'], 45 | [Error, 'Function'], 46 | [Error(''), 'Error'], 47 | [new Error(), 'Error'], 48 | [TypeError, 'Function'], 49 | [TypeError(), 'TypeError'], 50 | [new TypeError(), 'TypeError'], 51 | [Set, 'Function'], 52 | [new Set(), 'Set'], 53 | [Map, 'Function'], 54 | [new Map(), 'Map'], 55 | [() => true, 'Function'], 56 | [fn, 'Function'], 57 | [Class, 'Function'], 58 | [new Class(), 'Class'] 59 | ] 60 | table.forEach(([val, expected]) => { 61 | assertEquals( 62 | constructorName(val), 63 | expected, 64 | `constructorName(${isSymbol(val) ? 'symbol' : val}) -> ${expected}` 65 | ) 66 | }) 67 | }) 68 | -------------------------------------------------------------------------------- /test/dec.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { dec } from '../src/dec.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('dec', () => { 7 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 8 | const table: [number | bigint | any, number | bigint][] = [ 9 | [0, -1], 10 | [-10, -11], 11 | [10, 9], 12 | [0n, -1n], 13 | [-10n, -11n], 14 | [10n, 9n] 15 | ] 16 | table.forEach(([val, expected]) => { 17 | assertEquals(dec(val), expected, `dec(${val}) -> ${expected}`) 18 | }) 19 | 20 | assertEqual(dec(1 as const)) 21 | assertEqual(dec(1)) 22 | assertEqual(dec(1n as const)) 23 | assertEqual(dec(1n)) 24 | }) 25 | -------------------------------------------------------------------------------- /test/defaultTo.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { defaultTo } from '../src/defaultTo.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('defaultTo', () => { 7 | const defaultValue = 'hello' 8 | const table: [unknown, unknown, unknown][] = [ 9 | [defaultValue, '', ''], 10 | [defaultValue, 'world', 'world'], 11 | [defaultValue, undefined, defaultValue], 12 | [defaultValue, null, defaultValue], 13 | [defaultValue, NaN, defaultValue], 14 | [defaultValue, NaN, defaultValue], 15 | [defaultValue, 0, 0], 16 | [defaultValue, {}, {}], 17 | [defaultValue, [], []] 18 | ] 19 | table.forEach(([a, b, expected]) => { 20 | assertEquals( 21 | defaultTo(a)(b), 22 | expected, 23 | `defaultTo(${a}, ${b}) -> ${expected}` 24 | ) 25 | }) 26 | 27 | assertEqual(defaultTo('')(undefined as undefined)) 28 | assertEqual(defaultTo('')(null as null)) 29 | assertEqual<''>(defaultTo('' as const)(undefined)) 30 | assertEqual<''>(defaultTo('' as const)(null)) 31 | assertEqual(defaultTo('')(100)) 32 | assertEqual(defaultTo('')(NaN)) 33 | assertEqual<'' | number>(defaultTo('' as const)(NaN)) 34 | }) 35 | -------------------------------------------------------------------------------- /test/flattenDeep.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { FlattenDeep as Flat, flattenDeep } from '../src/flattenDeep.ts' 4 | import { assertEqual } from './asserts.ts' 5 | Deno.test('flattenDeep', () => { 6 | const table: [unknown[], unknown[]][] = [ 7 | [[], []], 8 | [[null], [null]], 9 | [ 10 | [null, undefined, 1, 'hello'], 11 | [null, undefined, 1, 'hello'] 12 | ], 13 | [[[]], []], 14 | [[[1]], [1]], 15 | [[[1, 2, 3]], [1, 2, 3]], 16 | [[[1, 2, 3, undefined, null]], [1, 2, 3, undefined, null]], 17 | [ 18 | [[1, 2, 3, undefined, null], 4, 5, 6], 19 | [1, 2, 3, undefined, null, 4, 5, 6] 20 | ], 21 | [ 22 | [ 23 | [1, 2, 3, undefined, null], 24 | [4, 5, 6] 25 | ], 26 | [1, 2, 3, undefined, null, 4, 5, 6] 27 | ], 28 | [ 29 | [[1, 2, 3, undefined, ['hello', 4], null]], 30 | [1, 2, 3, undefined, 'hello', 4, null] 31 | ], 32 | [ 33 | [ 34 | '', 35 | [1, 2, 3, undefined, ['hello', 4], null], 36 | [5, 6, ['world']], 37 | [[7, 8], 9] 38 | ], 39 | ['', 1, 2, 3, undefined, 'hello', 4, null, 5, 6, 'world', 7, 8, 9] 40 | ] 41 | ] 42 | table.forEach(([val, expected]) => { 43 | assertEquals( 44 | flattenDeep(val), 45 | expected, 46 | `flattenDeep(${val}) -> ${expected}` 47 | ) 48 | }) 49 | }) 50 | 51 | Deno.test('types', () => { 52 | assertEqual<[], Flat<[]>>() 53 | assertEqual>() 54 | // TODO: Success this case 55 | // assertEqual>() 56 | assertEqual<[''], Flat<['']>>() 57 | assertEqual<[number], Flat<[number]>>() 58 | assertEqual<[number, string], Flat<[number, string]>>() 59 | assertEqual>() 60 | assertEqual<(number | string)[], Flat<(number | string)[]>>() 61 | assertEqual>() 62 | assertEqual>() 63 | assertEqual>() 64 | assertEqual< 65 | readonly ['', '', 'hello'], 66 | Flat 67 | >() 68 | }) 69 | -------------------------------------------------------------------------------- /test/gt.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { gt } from '../src/gt.ts' 4 | import { Ord } from '../src/types/index.ts' 5 | 6 | Deno.test('gt', () => { 7 | const table: [Ord, Ord, boolean][] = [ 8 | [0, 0, false], 9 | [0, 1, false], 10 | [1, 0, true], 11 | [0n, 0n, false], 12 | [0n, 1n, false], 13 | [1n, 0n, true], 14 | ['a', 'a', false], 15 | ['a', 'z', false], 16 | ['z', 'a', true], 17 | ['za', 'a', true], 18 | [true, true, false], 19 | [false, true, false], 20 | [false, false, false], 21 | [true, false, true], 22 | [new Date('2000/1/1 00:00:00'), new Date('2000/1/1 00:00:00'), false], 23 | [new Date('1999/12/31'), new Date('2000/1/1'), false], 24 | [new Date('2000/1/2'), new Date('2000/1/1'), true] 25 | ] 26 | table.forEach(([a, b, expected]) => { 27 | assertEquals(gt(a, b), expected, `gt(${a}, ${b}) -> ${expected}`) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /test/gte.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { gte } from '../src/gte.ts' 4 | import { Ord } from '../src/types/index.ts' 5 | 6 | Deno.test('gte', () => { 7 | const table: [Ord, Ord, boolean][] = [ 8 | [0, 1, false], 9 | [0, 0, true], 10 | [1, 0, true], 11 | [0n, 1n, false], 12 | [0n, 0n, true], 13 | [1n, 0n, true], 14 | ['a', 'z', false], 15 | ['a', 'a', true], 16 | ['z', 'a', true], 17 | ['za', 'a', true], 18 | [false, true, false], 19 | [false, false, true], 20 | [true, true, true], 21 | [true, false, true], 22 | [new Date('1999/12/31'), new Date('2000/1/1'), false], 23 | [new Date('2000/1/1 00:00:00'), new Date('2000/1/1 00:00:00'), true], 24 | [new Date('2000/1/2'), new Date('2000/1/1'), true] 25 | ] 26 | 27 | table.forEach(([a, b, expected]) => { 28 | assertEquals(gte(a, b), expected, `gte(${a}, ${b}) -> ${expected}`) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /test/has.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { has } from '../src/has.ts' 4 | 5 | Deno.test('has', () => { 6 | const tablePrimitive: [ 7 | string | number, 8 | Record, 9 | boolean 10 | ][] = [ 11 | ['', {}, false], 12 | ['', { ' ': '' }, false], 13 | ['', { ' ': { '': '' } }, false], 14 | [0, {}, false], 15 | [0, { 1: '' }, false], 16 | [0, { 1: { 0: '' } }, false], 17 | ['', { '': '' }, true], 18 | ['Hello', { hello: '' }, false], 19 | ['Hello', { Hello: '' }, true], 20 | ['hello', { hello: '' }, true], 21 | [0, { 0: 1 }, true] 22 | ] 23 | 24 | tablePrimitive.forEach(([a, b, expected]) => { 25 | assertEquals(has(a, b), expected, `has(${a}, ${b}) -> ${expected}`) 26 | }) 27 | 28 | const tableArray: [ 29 | (string | number)[], 30 | Record, 31 | boolean 32 | ][] = [ 33 | [[], {}, false], 34 | [[], { '': '' }, false], 35 | [[0], {}, false], 36 | [[0], { '': '' }, false], 37 | [[0], { 0: '' }, true], 38 | [[0, 0], { 0: { 0: 1 } }, true], 39 | [[0, 'a'], { 0: { 0: 'b' } }, false], 40 | [[0, 'a'], { 0: { a: 'b' } }, true], 41 | [[''], {}, false], 42 | [[''], { ' ': '' }, false], 43 | [['a', 'b'], { a: '' }, false], 44 | [['a', 'b'], { a: { c: '' } }, false], 45 | [ 46 | ['a', 'b'], 47 | { 48 | a: { 49 | a: '' 50 | } 51 | }, 52 | false 53 | ], 54 | [['a'], { a: '' }, true], 55 | [['a'], { a: {} }, true], 56 | [['a', 'b'], { a: { b: '' } }, true], 57 | [['a', 'b'], { a: { b: {} } }, true], 58 | [['a', 'b', 'c'], { a: { b: { c: '' } } }, true], 59 | [[0, 'a', 'B'], { 0: { a: { B: 'c' } } }, true] 60 | ] 61 | tableArray.forEach(([a, b, expected]) => { 62 | assertEquals(has(a, b), expected, `has(${a}, ${b}) -> ${expected}`) 63 | }) 64 | }) 65 | -------------------------------------------------------------------------------- /test/identity.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { identity } from '../src/identity.ts' 4 | 5 | Deno.test('identity', () => { 6 | const table: [unknown, unknown][] = [ 7 | ['', ''], 8 | [0, 0], 9 | [1n, 1n], 10 | [() => 1, () => 1], 11 | [{}, {}], 12 | [[], []] 13 | ] 14 | table.forEach(([val]) => { 15 | assertEquals(identity(val), val, `identity(${val}) -> ${val}`) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /test/ifElse.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | 3 | import { assertEquals, length, spy } from '../dev_deps.ts' 4 | import { ifElse } from '../src/ifElse.ts' 5 | import { T } from '../src/T.ts' 6 | import { assertEqual } from './asserts.ts' 7 | Deno.test('ifElse', () => { 8 | const table: [unknown, unknown, unknown, unknown][] = [ 9 | [true, 1, 0, 1], 10 | [{}, 1, 0, 1], 11 | [[], 1, 0, 1], 12 | ['hello', 1, 0, 1], 13 | [false, 1, 0, 0], 14 | ['', 1, 0, 0], 15 | [NaN, 1, 0, 0], 16 | [undefined, 1, 0, 0], 17 | [null, 1, 0, 0], 18 | [0, 1, 0, 0], 19 | [() => true, 1, 0, 1], 20 | [() => false, 1, 0, 0], 21 | [() => 1, 1, 0, 1], 22 | [() => 0, 1, 0, 0] 23 | ] 24 | 25 | table.forEach(([val, onTrue, onFalse, expected]) => { 26 | assertEquals( 27 | ifElse(val, onTrue, onFalse), 28 | expected, 29 | `ifElse(${val}, ${onTrue}, ${onFalse}) -> ${expected}` 30 | ) 31 | }) 32 | 33 | assertEqual(ifElse(true, 1, 0)) 34 | assertEqual(ifElse(true as const, 1, 0)) 35 | assertEqual<1>(ifElse(true as const, 1 as const, 0)) 36 | assertEqual<0>(ifElse(false as const, 1 as const, 0 as const)) 37 | assertEqual<1 | ''>(ifElse(false, 1 as const, '' as const)) 38 | assertEqual<1 | ''>(ifElse({}, 1 as const, '' as const)) 39 | assertEqual<1>(ifElse(() => true as const, 1 as const, '' as const)) 40 | assertEqual<''>(ifElse(() => false as const, 1 as const, '' as const)) 41 | assertEqual<1 | ''>(ifElse(() => 1, 1 as const, '' as const)) 42 | }) 43 | 44 | Deno.test('ifElse:iife', () => { 45 | const table: [unknown, boolean, boolean, number][] = [ 46 | [true, true, true, 2], 47 | [true, false, true, 1], 48 | [true, true, false, 1], 49 | [false, true, true, 2], 50 | [false, false, true, 1], 51 | [false, true, false, 1] 52 | ] 53 | 54 | table.forEach(([val, onTrue, onFalse, expected]) => { 55 | const fn = spy() 56 | ifElse(val, onTrue ? fn() : T, onFalse ? fn() : T) 57 | assertEquals( 58 | length(fn.calls), 59 | expected, 60 | `ifElse(${val}, fn(), fn()) -> fn.calls.length:${expected}` 61 | ) 62 | }) 63 | }) 64 | 65 | Deno.test('ifElse:fn', () => { 66 | const table: [unknown, unknown][] = [ 67 | [true, true], 68 | [false, undefined] 69 | ] 70 | 71 | table.forEach(([val, expected]) => { 72 | const onTrue = spy(() => true) 73 | ifElse(val, onTrue, T) 74 | 75 | assertEquals( 76 | onTrue.calls[0]?.returned, 77 | expected, 78 | `ifElse(${val}, fn, fn) -> fn.calls[0].returned:${expected}` 79 | ) 80 | }) 81 | }) 82 | -------------------------------------------------------------------------------- /test/ifElseFn.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { ifElseFn } from '../src/ifElseFn.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('ifElseFn', () => { 7 | const table: [ 8 | (val: any) => boolean, 9 | ((val: unknown) => boolean) | unknown, 10 | ((val: unknown) => boolean) | unknown, 11 | unknown, 12 | unknown 13 | ][] = [ 14 | [() => true, 1, 0, 1, 1], 15 | [() => false, 1, 0, 1, 0], 16 | [(x: unknown) => !!x, 1, 0, 1, 1], 17 | [(x: unknown) => !!x, 1, 0, 0, 0], 18 | [(x: unknown) => !!x, () => 2, 0, 1, 2], 19 | [(x: unknown) => !!x, () => 2, () => 3, 0, 3], 20 | [(x: unknown) => !!x, (x: number) => x + 1, () => 3, 1, 2], 21 | [(x: unknown) => !!x, (x: number) => x + 1, (x: number) => x - 1, 0, -1] 22 | ] 23 | 24 | table.forEach(([condition, onTrue, onFalse, val, expected]) => { 25 | assertEquals( 26 | ifElseFn(condition, onTrue, onFalse)(val), 27 | expected, 28 | `ifElseFn(${condition}, ${onTrue}, ${onFalse})(${val}) -> ${expected}` 29 | ) 30 | }) 31 | 32 | assertEqual(ifElseFn(() => true as const, 1, 0)(1)) 33 | assertEqual<1>(ifElseFn(() => true as const, 1 as const, 0 as const)(1)) 34 | assertEqual<0>(ifElseFn(() => false as const, 1 as const, 0 as const)(1)) 35 | assertEqual<0>(ifElseFn(() => '' as const, 1 as const, 0 as const)(1)) 36 | assertEqual<0>(ifElseFn(() => undefined, 1 as const, 0 as const)(1)) 37 | assertEqual<0>(ifElseFn(() => null, 1 as const, 0 as const)(1)) 38 | assertEqual<0>(ifElseFn(() => 0 as const, 1 as const, 0 as const)(1)) 39 | assertEqual<1 | 0>(ifElseFn(() => true as boolean, 1 as const, 0 as const)(1)) 40 | assertEqual<1 | 0>(ifElseFn((x: string) => !!x, 1 as const, 0 as const)('')) 41 | assertEqual( 42 | ifElseFn( 43 | (x: number) => !!x, 44 | (x: number) => x + 1, 45 | 0 as const 46 | )(0) 47 | ) 48 | assertEqual( 49 | ifElseFn( 50 | (x: number) => !!x, 51 | (x: number) => x + 1, 52 | (x: number) => x - 1 53 | )(0) 54 | ) 55 | }) 56 | -------------------------------------------------------------------------------- /test/inc.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { inc } from '../src/inc.ts' 4 | import { assertEqual } from './asserts.ts' 5 | Deno.test('inc', () => { 6 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 7 | const table: [number | bigint | any, number | bigint][] = [ 8 | [0, 1], 9 | [-10, -9], 10 | [10, 11], 11 | [0n, 1n], 12 | [-10n, -9n], 13 | [10n, 11n] 14 | ] 15 | table.forEach(([val, expected]) => { 16 | assertEquals(inc(val), expected, `inc(${val}) -> ${expected}`) 17 | }) 18 | 19 | assertEqual(inc(1 as const)) 20 | assertEqual(inc(1)) 21 | assertEqual(inc(1n as const)) 22 | assertEqual(inc(1n)) 23 | }) 24 | -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | export * from './constants/index.ts' 3 | -------------------------------------------------------------------------------- /test/lt.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { lt } from '../src/lt.ts' 4 | import { Ord } from '../src/types/index.ts' 5 | 6 | Deno.test('lt', () => { 7 | const table: [Ord, Ord, boolean][] = [ 8 | [0, 0, false], 9 | [1, 0, false], 10 | [0, 1, true], 11 | [0n, 0n, false], 12 | [1n, 0n, false], 13 | [0n, 1n, true], 14 | ['a', 'a', false], 15 | ['z', 'a', false], 16 | ['za', 'a', false], 17 | ['a', 'z', true], 18 | [true, true, false], 19 | [false, false, false], 20 | [true, false, false], 21 | [false, true, true], 22 | [new Date('2000/1/1 00:00:00'), new Date('2000/1/1 00:00:00'), false], 23 | [new Date('2000/1/2'), new Date('2000/1/1'), false], 24 | [new Date('1999/12/31'), new Date('2000/1/1'), true] 25 | ] 26 | table.forEach(([a, b, expected]) => { 27 | assertEquals(lt(a, b), expected, `lt(${a}, ${b}) -> ${expected}`) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /test/lte.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { lte } from '../src/lte.ts' 4 | import { Ord } from '../src/types/index.ts' 5 | 6 | Deno.test('lte', () => { 7 | const table: [Ord, Ord, boolean][] = [ 8 | [1, 0, false], 9 | [0, 0, true], 10 | [0, 1, true], 11 | [1n, 0n, false], 12 | [0n, 0n, true], 13 | [0n, 1n, true], 14 | ['z', 'a', false], 15 | ['za', 'a', false], 16 | ['a', 'a', true], 17 | ['a', 'z', true], 18 | [true, false, false], 19 | [true, true, true], 20 | [false, false, true], 21 | [false, true, true], 22 | [new Date('2000/1/2'), new Date('2000/1/1'), false], 23 | [new Date('2000/1/1 00:00:00'), new Date('2000/1/1 00:00:00'), true], 24 | [new Date('1999/12/31'), new Date('2000/1/1'), true] 25 | ] 26 | table.forEach(([a, b, expected]) => { 27 | assertEquals(lte(a, b), expected, `lte(${a}, ${b}) -> ${expected}`) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /test/not.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals, isString } from '../dev_deps.ts' 3 | import { not } from '../src/not.ts' 4 | import { AnyFn } from '../src/types/index.ts' 5 | import { assertEqual } from './asserts.ts' 6 | 7 | Deno.test('not', () => { 8 | const table: [AnyFn, unknown[], boolean][] = [ 9 | [() => true, [false], false], 10 | [() => false, [false], true], 11 | [(a: string) => a, [''], true], 12 | [(a: string) => a, [''], true], 13 | [(a: number, b: number) => a + b, [-1, 1], true], 14 | [(a: number, b: number) => a + b, [1, 1], false], 15 | [(a: number, b: number) => a + b, [1, 1, 1], false], 16 | [isString, [1], true], 17 | [isString, [''], false] 18 | ] 19 | 20 | table.forEach(([val, args, expected]) => { 21 | assertEquals( 22 | not(val)(...args), 23 | expected, 24 | `not(${val})(${args}) -> ${expected}` 25 | ) 26 | }) 27 | 28 | assertEqual<() => boolean>(not(() => true)) 29 | assertEqual<(arg: unknown) => boolean>(not(isString)) 30 | assertEqual<(a: string, b: string) => boolean>( 31 | not((a: string, b: string) => a + b) 32 | ) 33 | assertEqual<(...val: unknown[]) => boolean>(not(Array)) 34 | }) 35 | -------------------------------------------------------------------------------- /test/or.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals, length, spy } from '../dev_deps.ts' 3 | import { or } from '../src/or.ts' 4 | import { FalsyLike } from './../src/types/index.ts' 5 | import { assertEqual } from './asserts.ts' 6 | 7 | Deno.test('or', () => { 8 | const table: [unknown, unknown, boolean][] = [ 9 | [false, true, true], 10 | [true, false, true], 11 | [true, true, true], 12 | [false, false, false], 13 | [() => 1, () => 1, true], 14 | [() => 1, () => 0, true], 15 | [() => 0, () => 1, true], 16 | [() => 0, () => 0, false], 17 | [false, () => 0, false], 18 | [false, () => 1, true] 19 | ] 20 | table.forEach(([a, b, expected]) => { 21 | assertEquals(or(a, b), expected, `or(${a}, ${b}) -> ${expected}`) 22 | }) 23 | 24 | const fn = spy(() => true) 25 | const fn2 = spy(() => false) 26 | 27 | or(fn, fn2) 28 | assertEquals(length(fn2.calls), 0) 29 | 30 | assertEqual(or(false as FalsyLike, false as FalsyLike)) 31 | assertEqual(or(Boolean, Boolean)) 32 | assertEqual( 33 | or( 34 | () => false as const, 35 | () => true as const 36 | ) 37 | ) 38 | assertEqual( 39 | or( 40 | () => false as const, 41 | () => false as const 42 | ) 43 | ) 44 | 45 | // Because Truthy can not define. 46 | assertEqual(or(true as const, true as const)) 47 | assertEqual(or(true as const, Boolean)) 48 | assertEqual(or(Boolean, true as const)) 49 | }) 50 | -------------------------------------------------------------------------------- /test/pipe.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | /* eslint-disable @typescript-eslint/no-empty-function */ 3 | import { assertEquals, isNumber } from '../dev_deps.ts' 4 | import { N } from '../src/N.ts' 5 | import { pipe } from '../src/pipe.ts' 6 | import { AnyFn } from '../src/types/index.ts' 7 | import { assertEqual } from './asserts.ts' 8 | 9 | Deno.test('pipe', () => { 10 | const table: [AnyFn[], unknown, unknown][] = [ 11 | [[() => {}, () => {}], '', undefined], 12 | [[() => {}, () => true], '', true], 13 | [[() => {}, () => true], 1, true], 14 | [[() => 1, (n: number) => n + 1], 1, 2], 15 | [[isNumber, N], '', true], 16 | [[N, N], 1, true], 17 | [[isNumber, N], 1, false], 18 | [[() => true, () => false, () => true, () => false], 1, false] 19 | ] 20 | 21 | table.forEach(([[fn1, fn2], argument, expected]) => { 22 | assertEquals( 23 | pipe(fn1, fn2)(argument), 24 | expected, 25 | `pipe(${fn1}, ${fn2})(${argument}) -> ${expected}` 26 | ) 27 | }) 28 | 29 | assertEqual(pipe(isNumber, N)(1)) 30 | 31 | const pipetest = pipe( 32 | (_: number, __: string, ___: number) => { 33 | return 1 as const 34 | }, 35 | (a) => a, 36 | () => [] as [], 37 | (a) => a, 38 | (a) => a, 39 | (a) => a, 40 | (_) => '' as const, 41 | (a) => a, 42 | (a) => a, 43 | (a) => a, 44 | (a) => a, 45 | (a) => a, 46 | (_) => 1 as const, 47 | (a) => a, 48 | (a) => a, 49 | (_) => '' as const, 50 | (a) => a 51 | ) 52 | assertEqual<''>(pipetest(1, '', 1)) 53 | }) 54 | -------------------------------------------------------------------------------- /test/prepend.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { prepend } from '../src/prepend.ts' 4 | 5 | Deno.test('prepend', () => { 6 | const table: [unknown, unknown[], unknown[]][] = [ 7 | [null, [], [null]], 8 | [undefined, [], [undefined]], 9 | ['', [], ['']], 10 | [{}, [], [{}]], 11 | [0, [], [0]], 12 | ['a', ['b'], ['a', 'b']], 13 | ['a', ['b', 'c', 'd'], ['a', 'b', 'c', 'd']], 14 | [[], [], [[]]], 15 | [[1], [], [[1]]], 16 | [[1], [2], [[1], 2]], 17 | [[1], [2, 3, 4], [[1], 2, 3, 4]] 18 | ] 19 | table.forEach(([val, list, expected]) => { 20 | assertEquals( 21 | prepend(val, list), 22 | expected, 23 | `prepend(${val}, ${list}) -> ${expected}` 24 | ) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /test/product.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { product } from '../src/product.ts' 4 | 5 | Deno.test('product', () => { 6 | const tableNumber: [number[], number][] = [ 7 | [[], 0], 8 | [[0, 0], 0], 9 | [[1], 1], 10 | [[1, 2, 3, 4, 5], 120], 11 | [[1, -2, 3, -4, 5], 120] 12 | ] 13 | 14 | tableNumber.forEach(([val, expected]) => { 15 | assertEquals(product(val), expected, `product(${val}) -> ${expected}`) 16 | }) 17 | 18 | const tableBigint: [bigint[], bigint][] = [ 19 | [[0n], 0n], 20 | [[1n], 1n], 21 | [[1n, 2n, 3n, 4n, 5n], 120n], 22 | [[1n, -2n, 3n, -4n, 5n], 120n] 23 | ] 24 | 25 | tableBigint.forEach(([val, expected]) => { 26 | assertEquals(product(val), expected, `product(${val}) -> ${expected}`) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /test/props.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { props } from '../src/props.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('props', () => { 7 | const table: [string | number, Record, unknown][] = [ 8 | ['', {}, undefined], 9 | ['', { ' ': '' }, undefined], 10 | ['', { ' ': { '': '' } }, undefined], 11 | [0, {}, undefined], 12 | [0, { 1: '' }, undefined], 13 | [0, { 1: { 0: '' } }, undefined], 14 | ['', { '': '' }, ''], 15 | ['Hello', { hello: '' }, undefined], 16 | ['Hello', { Hello: '' }, ''], 17 | ['hello', { hello: '' }, ''], 18 | [0, { 0: 1 }, 1] 19 | ] 20 | table.forEach(([a, b, expected]) => { 21 | assertEquals(props(a, b), expected, `props(${a}, ${b}) -> ${expected}`) 22 | }) 23 | 24 | assertEqual(props('', {})) 25 | assertEqual(props('a', {})) 26 | assertEqual(props('a', { a: 'b' })) 27 | assertEqual(props(0, { a: 'b' })) 28 | assertEqual<1>(props(0, { 0: 1 as const })) 29 | assertEqual(props(0, { 0: 1 })) 30 | assertEqual<'b'>(props('a', { a: 'b' as const })) 31 | }) 32 | -------------------------------------------------------------------------------- /test/sum.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { sum } from '../src/sum.ts' 4 | 5 | Deno.test('sum', () => { 6 | const tableNumber: [number[], number][] = [ 7 | [[], 0], 8 | [[0, 0], 0], 9 | [[1], 1], 10 | [[1, 2, 3, 4, 5], 15], 11 | [[1, -2, 3, -4, 5], 3] 12 | ] 13 | tableNumber.forEach(([val, expected]) => { 14 | assertEquals(sum(val), expected, `sum(${val}) -> ${expected}`) 15 | }) 16 | 17 | const tableBigint: [bigint[], bigint][] = [ 18 | [[0n, 0n], 0n], 19 | [[1n], 1n], 20 | [[1n, 2n, 3n, 4n, 5n], 15n], 21 | [[1n, -2n, 3n, -4n, 5n], 3n] 22 | ] 23 | 24 | tableBigint.forEach(([val, expected]) => { 25 | assertEquals(sum(val), expected, `sum(${val}) -> ${expected}`) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /test/tag.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { tap } from '../src/tap.ts' 4 | import { Arity1Fn } from '../src/types/index.ts' 5 | import { assertEqual } from './asserts.ts' 6 | 7 | Deno.test('tap', () => { 8 | const table: [Arity1Fn, unknown][] = [ 9 | [console.log, 'hello'], 10 | [() => console.log(1), ''], 11 | [(a: string) => console.log(a), ''], 12 | [(a: unknown[]) => console.log(a), ['hello', 'world']] 13 | ] 14 | 15 | table.forEach(([val, expected]) => { 16 | assertEquals(tap(val)(expected), expected, `tap(${val}) -> ${expected}`) 17 | }) 18 | 19 | assertEqual<''>(tap(console.log)('')) 20 | assertEqual<''>(tap((_: string) => true)('')) 21 | assertEqual<''>(tap(() => true)('')) 22 | assertEqual(tap((val: unknown[]) => val)(['hello'])) 23 | assertEqual(tap((val: unknown[]) => val)(['hello'])) 24 | assertEqual( 25 | tap((val: readonly unknown[]) => val)(['hello'] as const) 26 | ) 27 | }) 28 | -------------------------------------------------------------------------------- /test/take.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { take } from '../src/take.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('take', () => { 7 | const table: [number, unknown[] | string, unknown[] | string][] = [ 8 | [0, [], []], 9 | [Infinity, [], []], 10 | [Infinity, [], []], 11 | [Infinity, [1], [1]], 12 | [Infinity, [1, 2, 3, 4], [1, 2, 3, 4]], 13 | [3, [1, 2, 3, 4], [1, 2, 3]], 14 | [2, [1, 2, 3, 4], [1, 2]], 15 | [100, [1, 2, 3, 4], [1, 2, 3, 4]], 16 | [0, [1, 2, 3, 4], []], 17 | [-0, [1, 2, 3, 4], []], 18 | [-1, [1, 2, 3, 4], [4]], 19 | [-2, [1, 2, 3, 4], [3, 4]], 20 | [-3, [1, 2, 3, 4], [2, 3, 4]], 21 | [-4, [1, 2, 3, 4], [1, 2, 3, 4]], 22 | [-Infinity, [1, 2, 3, 4], [1, 2, 3, 4]], 23 | [0, 'hello', ''], 24 | [-0, 'hello', ''], 25 | [1, 'hello', 'h'], 26 | [3, 'hello', 'hel'], 27 | [Infinity, 'hello', 'hello'], 28 | [100, 'hello', 'hello'], 29 | [-1, 'hello', 'o'], 30 | [-4, 'hello', 'ello'], 31 | [-5, 'hello', 'hello'], 32 | [-Infinity, 'hello', 'hello'] 33 | ] 34 | table.forEach(([howMany, val, expected]) => { 35 | assertEquals( 36 | take(howMany, val), 37 | expected, 38 | `take(${howMany}, ${val}) -> ${expected}` 39 | ) 40 | }) 41 | 42 | assertEqual(take(0, [])) 43 | assertEqual<[]>(take(0, [] as [])) 44 | assertEqual(take(0, [] as const)) 45 | assertEqual<''>(take(0, '')) 46 | assertEqual<''>(take(0, '' as const)) 47 | }) 48 | -------------------------------------------------------------------------------- /test/takeLast.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { takeLast } from '../src/takeLast.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('takeLast', () => { 7 | const table: [number, unknown[] | string, unknown[] | string][] = [ 8 | [0, [], []], 9 | [Infinity, [], []], 10 | [Infinity, [], []], 11 | [Infinity, [1], [1]], 12 | [Infinity, [1, 2, 3, 4], [1, 2, 3, 4]], 13 | [3, [1, 2, 3, 4], [2, 3, 4]], 14 | [2, [1, 2, 3, 4], [3, 4]], 15 | [100, [1, 2, 3, 4], [1, 2, 3, 4]], 16 | [0, [1, 2, 3, 4], []], 17 | [-0, [1, 2, 3, 4], []], 18 | [-1, [1, 2, 3, 4], [1]], 19 | [-2, [1, 2, 3, 4], [1, 2]], 20 | [-3, [1, 2, 3, 4], [1, 2, 3]], 21 | [-4, [1, 2, 3, 4], [1, 2, 3, 4]], 22 | [-Infinity, [1, 2, 3, 4], [1, 2, 3, 4]], 23 | [0, 'hello', ''], 24 | [-0, 'hello', ''], 25 | [1, 'hello', 'o'], 26 | [3, 'hello', 'llo'], 27 | [Infinity, 'hello', 'hello'], 28 | [100, 'hello', 'hello'], 29 | [-1, 'hello', 'h'], 30 | [-4, 'hello', 'hell'], 31 | [-5, 'hello', 'hello'], 32 | [-Infinity, 'hello', 'hello'] 33 | ] 34 | table.forEach(([howMany, val, expected]) => { 35 | assertEquals( 36 | takeLast(howMany, val), 37 | expected, 38 | `takeLast(${howMany}, ${val}) -> ${expected}` 39 | ) 40 | }) 41 | 42 | assertEqual(takeLast(0, [])) 43 | assertEqual<[]>(takeLast(0, [] as [])) 44 | assertEqual(takeLast(0, [] as const)) 45 | assertEqual<''>(takeLast(0, '')) 46 | assertEqual<''>(takeLast(0, '' as const)) 47 | }) 48 | -------------------------------------------------------------------------------- /test/tryCatch.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { tryCatch } from '../src/tryCatch.ts' 4 | import { AnyFn } from '../src/types/index.ts' 5 | import { assertEqual } from './asserts.ts' 6 | 7 | Deno.test('tryCatch', () => { 8 | const table: [AnyFn, unknown][] = [ 9 | [() => true, true], 10 | [() => false, false], 11 | [ 12 | () => { 13 | throw Error('hello') 14 | }, 15 | Error('hello') 16 | ] 17 | ] 18 | table.forEach(([val, expected]) => { 19 | assertEquals(tryCatch(val), expected, `tryCatch(${val}) -> ${expected}`) 20 | }) 21 | 22 | const table2: [AnyFn, unknown | AnyFn, unknown][] = [ 23 | [() => true, () => false, true], 24 | [() => true, false, true], 25 | [ 26 | () => { 27 | throw Error('hello') 28 | }, 29 | false, 30 | false 31 | ], 32 | [ 33 | () => { 34 | throw Error('hello') 35 | }, 36 | (e: Error) => e.message, 37 | 'hello' 38 | ], 39 | [ 40 | () => { 41 | throw Error('hello') 42 | }, 43 | () => 1, 44 | 1 45 | ] 46 | ] 47 | table2.forEach(([tryer, catcher, expected]) => { 48 | assertEquals( 49 | tryCatch(tryer, catcher), 50 | expected, 51 | `tryCatch(${tryer}, ${catcher}) -> ${expected}` 52 | ) 53 | }) 54 | 55 | assertEqual(tryCatch(() => true)) 56 | assertEqual(tryCatch(() => true)) 57 | assertEqual<1 | Error>(tryCatch<1, Error>(() => 1)) 58 | assertEqual( 59 | tryCatch(() => { 60 | throw Error('hello') 61 | }) 62 | ) 63 | assertEqual( 64 | tryCatch(() => { 65 | throw Error('hello') 66 | }) 67 | ) 68 | assertEqual<0 | 1>(tryCatch(() => 1, 0)) 69 | assertEqual<0 | 1>( 70 | tryCatch( 71 | () => 1, 72 | () => 0 73 | ) 74 | ) 75 | assertEqual<1 | Error>( 76 | tryCatch( 77 | () => 1, 78 | (e: Error) => e 79 | ) 80 | ) 81 | assertEqual<1 | string>( 82 | tryCatch( 83 | () => 1, 84 | (e: Error) => e.message 85 | ) 86 | ) 87 | }) 88 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["jest"], 5 | "baseUrl": "../", 6 | "paths": { 7 | "@/*": ["src/*"], 8 | "@test": ["test"], 9 | "@test/*": ["test/*"] 10 | } 11 | }, 12 | 13 | "include": ["../test/**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /test/uniq.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { uniq } from '../src/uniq.ts' 4 | import { assertEqual } from './asserts.ts' 5 | 6 | Deno.test('uniq', () => { 7 | const table: [unknown[], unknown[]][] = [ 8 | [[], []], 9 | [ 10 | ['', '', '', '', '', 2, '', 1], 11 | ['', 2, 1] 12 | ], 13 | [ 14 | [null, undefined, 1n, null, undefined, 2n], 15 | [null, undefined, 1n, 2n] 16 | ], 17 | [ 18 | [1, 2, 3], 19 | [1, 2, 3] 20 | ], 21 | [ 22 | [1, 1, 2, 2, 3, 3], 23 | [1, 2, 3] 24 | ], 25 | [[{}, {}, {}], [{}]], 26 | [ 27 | [[], {}, [], {}], 28 | [[], {}] 29 | ], 30 | [ 31 | [[], {}, [], {}], 32 | [[], {}] 33 | ], 34 | [ 35 | [[1, 2, 3], { hoge: 'huga' }, [], { hage: 'hoge' }], 36 | [[1, 2, 3], { hoge: 'huga' }, [], { hage: 'hoge' }] 37 | ], 38 | [ 39 | [ 40 | [1, [], [1, [2, [3]]]], 41 | { hoge: 'huga', 1: 0 }, 42 | [1, [], [1, [2, [3]]]], 43 | { hoge: 'huga', 1: 0, 2: 3 } 44 | ], 45 | [ 46 | [1, [], [1, [2, [3]]]], 47 | { hoge: 'huga', 1: 0 }, 48 | { hoge: 'huga', 1: 0, 2: 3 } 49 | ] 50 | ] 51 | ] 52 | table.forEach(([val, expected]) => { 53 | assertEquals(uniq(val), expected, `uniq(${val}) -> ${expected}`) 54 | }) 55 | 56 | assertEqual(uniq([])) 57 | assertEqual(uniq([''])) 58 | assertEqual<''[]>(uniq([''] as const)) 59 | assertEqual<('' | '1' | '2')[]>(uniq(['', '1', '2'] as const)) 60 | assertEqual<('' | '1' | '2')[]>(uniq(['', '1', '2', '1', '2'] as const)) 61 | }) 62 | -------------------------------------------------------------------------------- /test/xor.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. 2 | import { assertEquals } from '../dev_deps.ts' 3 | import { xor } from '../src/xor.ts' 4 | import { Falsy } from './../src/types/index.ts' 5 | import { assertEqual } from './asserts.ts' 6 | 7 | Deno.test('xor', () => { 8 | const table: [unknown, unknown, boolean][] = [ 9 | [false, true, true], 10 | [true, false, true], 11 | [true, true, false], 12 | [false, false, false], 13 | [() => false, () => true, true], 14 | [() => true, () => false, true], 15 | [() => true, () => true, false], 16 | [() => false, () => false, false], 17 | [() => false, () => false, false], 18 | [() => 1, () => 0, true], 19 | [() => 0, () => 0, false], 20 | [true, () => false, true] 21 | ] 22 | table.forEach(([a, b, expected]) => { 23 | assertEquals(xor(a, b), expected, `xor(${a}, ${b}) -> ${expected}`) 24 | }) 25 | 26 | assertEqual(xor(false as Falsy, false as Falsy)) 27 | assertEqual(xor(Boolean, Boolean)) 28 | assertEqual( 29 | xor( 30 | () => 0 as const, 31 | () => 0 as const 32 | ) 33 | ) 34 | assertEqual( 35 | xor( 36 | () => 0 as const, 37 | () => 1 38 | ) 39 | ) 40 | 41 | // Because Truthy can not define. 42 | assertEqual(xor(true as const, true as const)) 43 | assertEqual(xor(true as const, Boolean)) 44 | assertEqual(xor(Boolean, true as const)) 45 | }) 46 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "esModuleInterop": true, 7 | 8 | "strict": true, 9 | "noUnusedLocals": true, 10 | "noUnusedParameters": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "allowJs": false, 14 | "skipLibCheck": true, 15 | 16 | "sourceMap": true, 17 | "declaration": true, 18 | "declarationMap": true, 19 | "outDir": "dist", 20 | "resolveJsonModule": true, 21 | "allowSyntheticDefaultImports": true, 22 | "forceConsistentCasingInFileNames": true, 23 | "isolatedModules": true, 24 | "baseUrl": ".", 25 | "paths": { 26 | "@/*": ["src/*"] 27 | } 28 | }, 29 | "include": ["src/**/*.ts"] 30 | } 31 | -------------------------------------------------------------------------------- /tsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", 3 | "tagDefinitions": [ 4 | { 5 | "tagName": "@category", 6 | "syntaxKind": "block" 7 | } 8 | ] 9 | } 10 | --------------------------------------------------------------------------------