├── docs ├── static │ ├── .nojekyll │ └── img │ │ ├── favicon.ico │ │ ├── hero-logo.png │ │ ├── background.png │ │ ├── ts-belt-frame.png │ │ └── ts-belt-logo.png ├── api │ ├── generated │ │ └── _src.mdx │ ├── function.mdx │ ├── guards.mdx │ ├── object.mdx │ ├── boolean.mdx │ ├── number.mdx │ ├── string.mdx │ ├── array.mdx │ ├── result.mdx │ └── option.mdx ├── babel.config.js ├── src │ ├── pages │ │ ├── components │ │ │ ├── Row.module.css │ │ │ ├── Title.module.css │ │ │ ├── Column.module.css │ │ │ ├── Title.js │ │ │ ├── Feature.js │ │ │ ├── Columns.module.css │ │ │ ├── Features.module.css │ │ │ ├── Feature.module.css │ │ │ ├── Page.js │ │ │ ├── Column.js │ │ │ ├── Card.js │ │ │ ├── Button.js │ │ │ ├── Row.js │ │ │ ├── Features.js │ │ │ ├── Columns.js │ │ │ ├── Button.module.css │ │ │ ├── Card.module.css │ │ │ └── Hero.js │ │ └── styles.module.css │ └── theme │ │ └── ReactLiveScope │ │ └── index.js ├── docs │ └── getting-started │ │ └── installation.md ├── .gitignore ├── sidebars.api.js ├── sidebars.js ├── sidebars.benchmarks.js ├── package.json └── benchmarks │ └── introduction.md ├── benchmarks ├── .gitignore ├── index.js ├── index.markdown.js ├── scripts │ ├── generate.sh │ └── run.sh ├── package.json ├── native.js └── simple │ └── intersperse.js ├── tools ├── comment-ppx │ ├── comment-ppx.opam │ ├── dune-project │ ├── .gitignore │ ├── esy.lock │ │ ├── opam │ │ │ ├── seq.base │ │ │ │ ├── files │ │ │ │ │ ├── seq.install │ │ │ │ │ └── META.seq │ │ │ │ └── opam │ │ │ ├── base-unix.base │ │ │ │ └── opam │ │ │ ├── base-threads.base │ │ │ │ └── opam │ │ │ ├── result.1.5 │ │ │ │ └── opam │ │ │ ├── ppx_derivers.1.2.1 │ │ │ │ └── opam │ │ │ ├── fix.20211125 │ │ │ │ └── opam │ │ │ ├── ppx_yojson_conv_lib.v0.14.0 │ │ │ │ └── opam │ │ │ ├── menhir.20211012 │ │ │ │ └── opam │ │ │ ├── sexplib0.v0.14.0 │ │ │ │ └── opam │ │ │ ├── menhirLib.20211012 │ │ │ │ └── opam │ │ │ ├── menhirSdk.20211012 │ │ │ │ └── opam │ │ │ ├── dot-merlin-reader.4.1 │ │ │ │ └── opam │ │ │ ├── junit.2.0.2 │ │ │ │ └── opam │ │ │ ├── ocamlbuild.0.14.0 │ │ │ │ └── opam │ │ │ ├── merlin-extend.0.6 │ │ │ │ └── opam │ │ │ ├── uchar.0.0.2 │ │ │ │ └── opam │ │ │ ├── cppo.1.6.8 │ │ │ │ └── opam │ │ │ ├── stdlib-shims.0.3.0 │ │ │ │ └── opam │ │ │ └── ocaml-compiler-libs.v0.12.4 │ │ │ │ └── opam │ │ ├── .gitignore │ │ ├── .gitattributes │ │ └── overrides │ │ │ ├── opam__s__ocamlbuild_opam__c__0.14.0_opam_override │ │ │ └── package.json │ │ │ └── opam__s__ocamlfind_opam__c__1.9.1_opam_override │ │ │ └── package.json │ ├── ppx.exe │ ├── src │ │ ├── dune │ │ └── Comment_ppx.re │ ├── scripts │ │ └── install.sh │ └── package.json ├── javascript-codemods │ ├── pre │ │ ├── index.ts │ │ ├── spread-rest-args.ts │ │ └── rename-identifiers.ts │ └── post │ │ └── index.ts ├── typescript-codemods │ ├── rename-generics.ts │ ├── make-option.ts │ ├── make-readonly-array.ts │ └── make-readonly-tuples.ts └── rescript-externals │ └── Externals.res ├── src ├── Array │ └── index.js ├── Bool │ ├── index.js │ └── Bool.res ├── Dict │ └── index.js ├── Function │ └── index.js ├── Guards │ ├── index.js │ └── Guards.res ├── Number │ └── index.js ├── String │ └── index.js ├── AsyncOption │ └── index.js ├── AsyncResult │ └── index.js ├── global.d.ts ├── Option │ └── index.js ├── pipe.js ├── Result │ └── index.js ├── flow.js ├── AsyncData │ └── index.js ├── types.ts ├── index.js ├── index.ts └── AsyncDataResult │ └── index.js ├── .github └── FUNDING.yml ├── assets └── ts-belt-frame.png ├── tsconfig.build.json ├── .prettierrc ├── .gitignore ├── jest.config.js ├── __tests__ ├── Function │ ├── coerce.test.ts │ ├── tap.test.ts │ ├── toMutable.test.ts │ ├── memoizeWithKey.test.ts │ ├── once.test.ts │ ├── before.test.ts │ ├── defaultTo.test.ts │ └── after.test.ts ├── String │ ├── trim.test.ts │ ├── trimEnd.test.ts │ ├── trimStart.test.ts │ ├── head.test.ts │ ├── last.test.ts │ ├── length.test.ts │ ├── concat.test.ts │ ├── getUnsafe.test.ts │ ├── prepend.test.ts │ ├── remove.test.ts │ ├── endsWith.test.ts │ ├── startsWith.test.ts │ ├── includes.test.ts │ ├── isEmpty.test.ts │ ├── removeAll.test.ts │ ├── get.test.ts │ ├── isNotEmpty.test.ts │ ├── indexOf.test.ts │ └── lastIndexOf.test.ts ├── Array │ ├── makeEmpty.test.ts │ ├── intersperse.test.ts │ ├── head.test.ts │ ├── map.test.ts │ ├── sort.test.ts │ ├── makeWithIndex.test.ts │ ├── get.test.ts │ ├── take.test.ts │ ├── getBy.test.ts │ ├── splitAt.test.ts │ ├── tail.test.ts │ ├── union.test.ts │ ├── all.test.ts │ ├── flatMap.test.ts │ ├── intersection.test.ts │ ├── any.test.ts │ ├── splitEvery.test.ts │ ├── length.test.ts │ ├── takeWhile.test.ts │ ├── unzip.test.ts │ ├── difference.test.ts │ ├── removeFirst.test.ts │ ├── reverse.test.ts │ ├── isEmpty.test.ts │ ├── filterMap.test.ts │ ├── isNotEmpty.test.ts │ ├── zipWithIndex.test.ts │ ├── dropWhile.test.ts │ ├── removeFirstBy.test.ts │ ├── flip.test.ts │ └── make.test.ts ├── Result │ ├── getExn.test.ts │ ├── isOk.test.ts │ ├── isError.test.ts │ ├── tapError.test.ts │ ├── tap.test.ts │ ├── getWithDefault.test.ts │ ├── fromPromise.test.ts │ ├── fromFalsy.test.ts │ ├── flip.test.ts │ ├── mapWithDefault.test.ts │ ├── fromNullable.test.ts │ └── fromPredicate.test.ts ├── Number │ ├── pred.test.ts │ ├── add.test.ts │ ├── divide.test.ts │ ├── multiply.test.ts │ ├── succ.test.ts │ ├── modulo.test.ts │ ├── subtract.test.ts │ ├── divideWithModulo.test.ts │ ├── lt.test.ts │ ├── gt.test.ts │ ├── clamp.test.ts │ ├── lte.test.ts │ └── gte.test.ts ├── Guards │ ├── isNullable.test.ts │ ├── isNull.test.ts │ ├── isUndefined.test.ts │ ├── isNotNullable.test.ts │ ├── isDate.test.ts │ ├── isNumber.test.ts │ ├── isString.test.ts │ ├── isBoolean.test.ts │ ├── isError.test.ts │ ├── isObject.test.ts │ ├── isArray.test.ts │ ├── isFunction.test.ts │ ├── isPromise.test.ts │ └── isNot.test.ts ├── Option │ ├── tap.test.ts │ ├── fromPromise.test.ts │ ├── isNone.test.ts │ ├── isSome.test.ts │ ├── zip.test.ts │ ├── getExn.test.ts │ ├── contains.test.ts │ ├── fromFalsy.test.ts │ ├── toNullable.test.ts │ ├── map.test.ts │ ├── toUndefined.test.ts │ ├── fromExecution.test.ts │ ├── fromNullable.test.ts │ └── fromPredicate.test.ts ├── Bool │ ├── inverse.test.ts │ ├── or.test.ts │ ├── and.test.ts │ ├── nor.test.ts │ ├── xor.test.ts │ ├── nand.test.ts │ ├── xnor.test.ts │ └── implies.test.ts ├── AsyncData │ └── isInit.test.ts └── Dict │ ├── merge.test.ts │ ├── values.test.ts │ ├── keys.test.ts │ ├── isEmpty.test.ts │ └── getUnsafe.test.ts ├── bsconfig.json ├── tsconfig.json ├── scripts ├── test.ts └── generate.ts └── LICENSE /docs/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/api/generated/_src.mdx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /benchmarks/.gitignore: -------------------------------------------------------------------------------- 1 | .results/ 2 | -------------------------------------------------------------------------------- /tools/comment-ppx/comment-ppx.opam: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Array/index.js: -------------------------------------------------------------------------------- 1 | export * from './Array.bs.js' 2 | -------------------------------------------------------------------------------- /src/Bool/index.js: -------------------------------------------------------------------------------- 1 | export * from './Bool.bs.js' 2 | -------------------------------------------------------------------------------- /src/Dict/index.js: -------------------------------------------------------------------------------- 1 | export * from './Dict.bs.js' 2 | -------------------------------------------------------------------------------- /tools/comment-ppx/dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.6) 2 | -------------------------------------------------------------------------------- /src/Function/index.js: -------------------------------------------------------------------------------- 1 | export * from './Function.bs.js' 2 | -------------------------------------------------------------------------------- /src/Guards/index.js: -------------------------------------------------------------------------------- 1 | export * from './Guards.bs.js' 2 | -------------------------------------------------------------------------------- /src/Number/index.js: -------------------------------------------------------------------------------- 1 | export * from './Number.bs.js' 2 | -------------------------------------------------------------------------------- /src/String/index.js: -------------------------------------------------------------------------------- 1 | export * from './String.bs.js' 2 | -------------------------------------------------------------------------------- /tools/comment-ppx/.gitignore: -------------------------------------------------------------------------------- 1 | _esy 2 | _build 3 | *.install 4 | -------------------------------------------------------------------------------- /src/AsyncOption/index.js: -------------------------------------------------------------------------------- 1 | export * from './AsyncOption.bs.js' 2 | -------------------------------------------------------------------------------- /src/AsyncResult/index.js: -------------------------------------------------------------------------------- 1 | export * from './AsyncResult.bs.js' 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ["https://www.buymeacoffee.com/utSC0k7"] 2 | -------------------------------------------------------------------------------- /assets/ts-belt-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobily/ts-belt/HEAD/assets/ts-belt-frame.png -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/seq.base/files/seq.install: -------------------------------------------------------------------------------- 1 | lib:[ 2 | "META.seq" {"META"} 3 | ] 4 | -------------------------------------------------------------------------------- /tools/comment-ppx/ppx.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobily/ts-belt/HEAD/tools/comment-ppx/ppx.exe -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobily/ts-belt/HEAD/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/static/img/hero-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobily/ts-belt/HEAD/docs/static/img/hero-logo.png -------------------------------------------------------------------------------- /docs/static/img/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobily/ts-belt/HEAD/docs/static/img/background.png -------------------------------------------------------------------------------- /docs/static/img/ts-belt-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobily/ts-belt/HEAD/docs/static/img/ts-belt-frame.png -------------------------------------------------------------------------------- /docs/static/img/ts-belt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobily/ts-belt/HEAD/docs/static/img/ts-belt-logo.png -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | 3 | declare global { 4 | namespace Belt { 5 | type UseMutableArrays = 0 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Reset any possible .gitignore, we want all esy.lock to be un-ignored. 3 | !* 4 | -------------------------------------------------------------------------------- /src/Option/index.js: -------------------------------------------------------------------------------- 1 | export * from './Option.bs.js' 2 | 3 | export const Some = value => value 4 | export const None = undefined 5 | -------------------------------------------------------------------------------- /docs/src/pages/components/Row.module.css: -------------------------------------------------------------------------------- 1 | .row { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | width: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": [ 4 | "./__tests__/**/*", 5 | "./playground" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | # Set eol to LF so files aren't converted to CRLF-eol on Windows. 3 | * text eol=lf linguist-generated 4 | -------------------------------------------------------------------------------- /docs/src/pages/components/Title.module.css: -------------------------------------------------------------------------------- 1 | .title { 2 | font-size: 1.8rem; 3 | color: var(--ifm-color-gray-900); 4 | text-align: center; 5 | margin-bottom: 0; 6 | } 7 | -------------------------------------------------------------------------------- /tools/comment-ppx/src/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name comment_ppx) 3 | (wrapped false) 4 | (public_name comment-ppx.lib) 5 | (kind ppx_rewriter) 6 | (libraries ppxlib) 7 | ) 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "typescript", 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "all", 6 | "arrowParens": "avoid", 7 | "printWidth": 80 8 | } 9 | -------------------------------------------------------------------------------- /tools/comment-ppx/scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -x 5 | esy install 6 | esy build 7 | find ./_build/default -name '*.exe' -exec cp "{}" ./ \; 8 | exit 0 9 | -------------------------------------------------------------------------------- /src/pipe.js: -------------------------------------------------------------------------------- 1 | export function pipe() { 2 | let x = arguments[0] 3 | 4 | for (let i = 1, l = arguments.length; i < l; i++) { 5 | x = arguments[i](x) 6 | } 7 | 8 | return x 9 | } 10 | -------------------------------------------------------------------------------- /docs/src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | /** 3 | * CSS files with the .module.css suffix will be treated as CSS modules 4 | * and scoped locally. 5 | */ 6 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/seq.base/files/META.seq: -------------------------------------------------------------------------------- 1 | name="seq" 2 | version="[distributed with OCaml 4.07 or above]" 3 | description="dummy backward-compatibility package for iterators" 4 | requires="" 5 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/base-unix.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Unix library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /docs/api/function.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: function 3 | title: Function 4 | --- 5 | 6 | import Function, { toc as functiontoc } from "./generated/_function.mdx" 7 | 8 | 9 | 10 | export const toc = functiontoc 11 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/base-threads.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Threads library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /docs/src/theme/ReactLiveScope/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import * as Belt from '../../../..' 3 | 4 | const ReactLiveScope = { 5 | React, 6 | ...Belt, 7 | ...React, 8 | } 9 | 10 | export default ReactLiveScope 11 | -------------------------------------------------------------------------------- /docs/api/guards.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: guards 3 | title: Guards 4 | --- 5 | 6 | import Guards, { toc as guardstoc } from "./generated/_guards.mdx" 7 | 8 | Various TypeScript guards. 9 | 10 | 11 | 12 | export const toc = guardstoc 13 | -------------------------------------------------------------------------------- /docs/api/object.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: object 3 | title: Object (Dict) 4 | --- 5 | 6 | import Dict, { toc as dicttoc } from "./generated/_dict.mdx" 7 | 8 | Utility functions for `Object`. 9 | 10 | 11 | 12 | export const toc = dicttoc 13 | -------------------------------------------------------------------------------- /docs/api/boolean.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: boolean 3 | title: Boolean 4 | --- 5 | 6 | import Boolean, { toc as booltoc } from "./generated/_bool.mdx" 7 | 8 | Utility functions for `Boolean`. 9 | 10 | 11 | 12 | export const toc = booltoc 13 | -------------------------------------------------------------------------------- /docs/api/number.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: number 3 | title: Number 4 | --- 5 | 6 | import Number, { toc as numbertoc } from "./generated/_number.mdx" 7 | 8 | Utility functions for `Number`. 9 | 10 | 11 | 12 | export const toc = numbertoc 13 | -------------------------------------------------------------------------------- /docs/src/pages/components/Column.module.css: -------------------------------------------------------------------------------- 1 | .column { 2 | display: flex; 3 | flex-direction: column; 4 | flex-basis: 100%; 5 | flex: 1; 6 | } 7 | 8 | @media screen and (max-width: 768px) { 9 | .column { 10 | margin-bottom: 1rem; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Result/index.js: -------------------------------------------------------------------------------- 1 | export * from './Result.bs.js' 2 | 3 | export const Ok = value => { 4 | return { 5 | TAG: 0, 6 | _0: value, 7 | } 8 | } 9 | 10 | export const Error = value => { 11 | return { 12 | TAG: 1, 13 | _0: value, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/src/pages/components/Title.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Title.module.css' 4 | 5 | const Title = props => { 6 | const { children } = props 7 | return

{children}

8 | } 9 | 10 | export default Title 11 | -------------------------------------------------------------------------------- /src/flow.js: -------------------------------------------------------------------------------- 1 | export function flow() { 2 | let fns = arguments 3 | 4 | return function () { 5 | let x = fns[0].apply(null, arguments) 6 | 7 | for (let i = 1, l = fns.length; i < l; i++) { 8 | x = fns[i](x) 9 | } 10 | 11 | return x 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .env 3 | 4 | .idea/ 5 | .settings 6 | .vscode/ 7 | node_modules/ 8 | coverage/ 9 | 10 | *.log 11 | *.tsbuildinfo 12 | 13 | dist/ 14 | lib/ 15 | playground/ 16 | 17 | .merlin 18 | .bsb.lock 19 | 20 | *.bs.js 21 | *.gen.tsx 22 | 23 | ./src/**/index.ts 24 | -------------------------------------------------------------------------------- /docs/docs/getting-started/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: installation 3 | title: Installation 4 | --- 5 | 6 | Use either `npm` or `yarn` to install the package: 7 | 8 | ```shell 9 | yarn add @mobily/ts-belt 10 | ``` 11 | 12 | ```shell 13 | npm install @mobily/ts-belt --save 14 | ``` 15 | -------------------------------------------------------------------------------- /benchmarks/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const Benchr = require('benchr') 4 | 5 | const files = process.argv.slice(2) 6 | 7 | const runner = new Benchr( 8 | { 9 | reporter: 'console', 10 | }, 11 | files, 12 | ) 13 | 14 | runner.run() 15 | -------------------------------------------------------------------------------- /docs/src/pages/components/Feature.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Feature.module.css' 4 | 5 | const Feature = props => { 6 | const { children } = props 7 | 8 | return {children} 9 | } 10 | 11 | export default Feature 12 | -------------------------------------------------------------------------------- /docs/src/pages/components/Columns.module.css: -------------------------------------------------------------------------------- 1 | .columns { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | flex: 1; 6 | } 7 | 8 | @media screen and (max-width: 768px) { 9 | .columns { 10 | flex-direction: column; 11 | margin-bottom: 0 !important; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /benchmarks/index.markdown.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const Benchr = require('benchr') 4 | 5 | const files = process.argv.slice(2) 6 | 7 | const runner = new Benchr( 8 | { 9 | reporter: './reporter.markdown.js', 10 | }, 11 | files, 12 | ) 13 | 14 | runner.run() 15 | -------------------------------------------------------------------------------- /docs/src/pages/components/Features.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | text-align: center; 3 | max-width: 74vw; 4 | } 5 | 6 | @media screen and (max-width: 768px) { 7 | .features { 8 | max-width: 100vh; 9 | padding: 0 1rem; 10 | } 11 | } 12 | 13 | .dot { 14 | margin: 0 16px; 15 | color: #000; 16 | } 17 | -------------------------------------------------------------------------------- /docs/src/pages/components/Feature.module.css: -------------------------------------------------------------------------------- 1 | .feature { 2 | font-size: 1.3rem; 3 | line-height: 2rem; 4 | color: var(--ifm-color-gray-700); 5 | } 6 | 7 | @media screen and (max-width: 992px) { 8 | .feature { 9 | font-size: 1.2rem; 10 | } 11 | } 12 | 13 | .feature > strong { 14 | color: #000; 15 | } 16 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | verbose: true, 3 | // bail: true, 4 | transform: { 5 | '^.+\\.ts': 'ts-jest', 6 | }, 7 | testRegex: './__tests__/.+\\.test\\.ts$', 8 | moduleFileExtensions: ['ts', 'js'], 9 | collectCoverage: true, 10 | rootDir: __dirname, 11 | maxWorkers: 2, 12 | testTimeout: 30000, 13 | } 14 | -------------------------------------------------------------------------------- /src/AsyncData/index.js: -------------------------------------------------------------------------------- 1 | export * from './AsyncData.bs.js' 2 | 3 | export const Init = 0 4 | export const Loading = 1 5 | 6 | export const Reloading = value => { 7 | return { 8 | TAG: 0, 9 | _0: value, 10 | } 11 | } 12 | 13 | export const Complete = value => { 14 | return { 15 | TAG: 1, 16 | _0: value, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/src/pages/components/Page.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Layout from '@theme/Layout' 3 | 4 | import styles from './Page.module.css' 5 | 6 | const Page = props => { 7 | const { children } = props 8 | 9 | return ( 10 | 11 |
{children}
12 |
13 | ) 14 | } 15 | 16 | export default Page 17 | -------------------------------------------------------------------------------- /__tests__/Function/coerce.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { F } from '../..' 4 | 5 | const x = ['x', 'y'] as ReadonlyArray 6 | const y = ['x', 'y'] as const 7 | 8 | describe('coerce', () => { 9 | it('provides correct types', () => { 10 | expectType(F.coerce(x)) 11 | expectType<['x', 'z']>(F.coerce<['x', 'z']>(y)) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export declare type Array = Belt.UseMutableArrays extends 1 4 | ? T[] 5 | : readonly T[] 6 | export declare type Mutable = { -readonly [P in keyof T]-?: T[P] } 7 | export declare type ExtractValue = Exclude 8 | export declare type UnpackArray = T extends Array 9 | ? UnpackArray 10 | : T 11 | -------------------------------------------------------------------------------- /docs/sidebars.api.js: -------------------------------------------------------------------------------- 1 | const makeSidebar = names => 2 | names.map(name => { 3 | return { 4 | type: 'doc', 5 | id: name, 6 | className: `sidebar-api sidebar-api-${name}`, 7 | } 8 | }) 9 | 10 | module.exports = { 11 | sidebar: makeSidebar([ 12 | 'pipe-flow', 13 | 'array', 14 | 'boolean', 15 | 'function', 16 | 'guards', 17 | 'number', 18 | 'object', 19 | 'option', 20 | 'result', 21 | 'string', 22 | ]), 23 | } 24 | -------------------------------------------------------------------------------- /__tests__/String/trim.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S } from '../..' 4 | 5 | describe('trim', () => { 6 | it('provides correct types', () => { 7 | expectType(S.trim('text')) 8 | }) 9 | 10 | it('returns a new string with leading and trailing whitespace removed from string', () => { 11 | expect(S.trim(' text')).toEqual('text') 12 | }) 13 | 14 | it('*', () => { 15 | expect(S.trim(' text')).toEqual('text') 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /docs/api/string.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: string 3 | title: String 4 | --- 5 | 6 | import String, { toc as stringtoc } from "./generated/_string.mdx" 7 | 8 | Utility functions for `String`. 9 | 10 | ```jsx live 11 | function() { 12 | const value = pipe( 13 | ['hello', 'world', '+ts', '+belt'], 14 | A.filter(S.startsWith('+')), 15 | A.join('-'), 16 | S.removeAll('+'), 17 | ) 18 | 19 | return value 20 | } 21 | ``` 22 | 23 | 24 | 25 | export const toc = stringtoc 26 | -------------------------------------------------------------------------------- /__tests__/Array/makeEmpty.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A } from '../..' 4 | 5 | describe('makeEmpty', () => { 6 | it('provides correct types', () => { 7 | expectType>(A.makeEmpty()) 8 | }) 9 | 10 | it('creates an empty array', () => { 11 | const result = A.makeEmpty() 12 | expect(result).toEqual([]) 13 | }) 14 | 15 | it('*', () => { 16 | expect(A.makeEmpty()).toEqual([]) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /__tests__/String/trimEnd.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S } from '../..' 4 | 5 | describe('trimEnd', () => { 6 | it('provides correct types', () => { 7 | expectType(S.trim('text')) 8 | }) 9 | 10 | it('returns a new string with trailing whitespace removed from string', () => { 11 | expect(S.trimEnd(' text ')).toEqual(' text') 12 | }) 13 | 14 | it('*', () => { 15 | expect(S.trimEnd(' text ')).toEqual(' text') 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /__tests__/String/trimStart.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S } from '../..' 4 | 5 | describe('trimStart', () => { 6 | it('provides correct types', () => { 7 | expectType(S.trim('text')) 8 | }) 9 | 10 | it('returns a new string with leading whitespace removed from string', () => { 11 | expect(S.trimStart(' text ')).toEqual('text ') 12 | }) 13 | 14 | it('*', () => { 15 | expect(S.trimStart(' text ')).toEqual('text ') 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /docs/src/pages/components/Column.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { useColumns } from './Columns' 4 | 5 | import styles from './Column.module.css' 6 | 7 | const Column = props => { 8 | const { children } = props 9 | const { space } = useColumns() 10 | 11 | return ( 12 |
18 | {children} 19 |
20 | ) 21 | } 22 | 23 | export default Column 24 | -------------------------------------------------------------------------------- /__tests__/Array/intersperse.test.ts: -------------------------------------------------------------------------------- 1 | import { A, pipe } from '../..' 2 | 3 | const xs = [1, 2, 3, 4, 5] 4 | 5 | // TODO: expectTypes 6 | describe('intersperse', () => { 7 | it('happy', () => { 8 | const result = A.intersperse(xs, 0) 9 | expect(result).toEqual([1, 0, 2, 0, 3, 0, 4, 0, 5]) 10 | }) 11 | }) 12 | 13 | describe('intersperse (pipe)', () => { 14 | it('happy', () => { 15 | const result = pipe(xs, A.intersperse(0)) 16 | expect(result).toEqual([1, 0, 2, 0, 3, 0, 4, 0, 5]) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /__tests__/Function/tap.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, F, N, A } from '../..' 2 | 3 | describe('tap', () => { 4 | it('applies a side-effect', () => { 5 | const spy = jest.fn() 6 | 7 | A.forEach([1, 2, 3], F.tap(spy)) 8 | 9 | expect(spy).toBeCalledTimes(3) 10 | }) 11 | 12 | it('*', () => { 13 | expect( 14 | pipe( 15 | A.makeWithIndex(3, N.succ), 16 | F.tap(xs => console.log(xs)), 17 | A.map(value => value * 2), 18 | ), 19 | ).toEqual([2, 4, 6]) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /benchmarks/scripts/generate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | mkdir -p ./.results 4 | 5 | results_file="./.results/results.md" 6 | 7 | rm -f $results_file 8 | 9 | glob_files=".*" 10 | 11 | complex=($(grep -HRl "$glob_files" ./complex)) 12 | 13 | for i in "${complex[@]}" 14 | do 15 | node "./index.markdown.js" "$i" 2>&1 | tee -a $results_file 16 | done 17 | 18 | simple=($(grep -HRl "$glob_files" ./simple)) 19 | 20 | for i in "${simple[@]}" 21 | do 22 | node "./index.markdown.js" "$i" 2>&1 | tee -a $results_file 23 | done 24 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/seq.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: " " 3 | authors: " " 4 | homepage: " " 5 | depends: [ 6 | "ocaml" {>= "4.07.0"} 7 | ] 8 | dev-repo: "git+https://github.com/ocaml/ocaml.git" 9 | bug-reports: "https://caml.inria.fr/mantis/main_page.php" 10 | synopsis: 11 | "Compatibility package for OCaml's standard iterator type starting from 4.07." 12 | extra-files: [ 13 | ["seq.install" "md5=026b31e1df290373198373d5aaa26e42"] 14 | ["META.seq" "md5=b33c8a1a6c7ed797816ce27df4855107"] 15 | ] 16 | -------------------------------------------------------------------------------- /__tests__/Array/head.test.ts: -------------------------------------------------------------------------------- 1 | import { A, O } from '../..' 2 | 3 | describe('head', () => { 4 | it('returns None', () => { 5 | expect(A.head([])).toEqual(O.None) 6 | }) 7 | 8 | it('returns Some', () => { 9 | expect(A.head([1, 2, 3])).toEqual(O.Some(1)) 10 | expect(A.head([0, 2, 3])).toEqual(O.Some(0)) 11 | expect(A.head([false, true, true])).toEqual(O.Some(false)) 12 | expect(A.head([{ prop: 1 }, { prop: 2 }])).toEqual(O.Some({ prop: 1 })) 13 | expect(A.head([[1], [2]])).toEqual(O.Some([1])) 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /docs/src/pages/components/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Link from '@docusaurus/Link' 4 | import useBaseUrl from '@docusaurus/useBaseUrl' 5 | 6 | import styles from './Card.module.css' 7 | 8 | const Card = props => { 9 | const { children, title, to } = props 10 | const link = useBaseUrl(to) 11 | 12 | return ( 13 | 14 |
{title}
15 |
{children}
16 | 17 | ) 18 | } 19 | 20 | export default Card 21 | -------------------------------------------------------------------------------- /__tests__/Array/map.test.ts: -------------------------------------------------------------------------------- 1 | import { A, pipe } from '../..' 2 | 3 | const xs = [1, 2, 3, 4, 5] 4 | 5 | // TODO: expectType 6 | describe('map', () => { 7 | it('returns correct value', () => { 8 | const result = A.map(xs, value => value * 2) 9 | expect(result).toEqual([2, 4, 6, 8, 10]) 10 | }) 11 | }) 12 | 13 | describe('map (pipe)', () => { 14 | it('returns correct value', () => { 15 | const result = pipe( 16 | xs, 17 | A.map(value => value * 2), 18 | ) 19 | 20 | expect(result).toEqual([2, 4, 6, 8, 10]) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /__tests__/Function/toMutable.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { F } from '../..' 4 | 5 | const arr = ['x', 'y'] as ReadonlyArray 6 | const tuple = ['x', 'y'] as const 7 | const obj = { 8 | prop: '1', 9 | } as { 10 | readonly prop: string 11 | } 12 | 13 | describe('toMutable', () => { 14 | it('provides correct types', () => { 15 | expectType(F.toMutable(arr)) 16 | expectType<['x', 'y']>(F.toMutable(tuple)) 17 | expectType<{ 18 | prop: string 19 | }>(F.toMutable(obj)) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { pipe } from './pipe.js' 2 | export { flow } from './flow.js' 3 | 4 | export * as F from './Function' 5 | export * as A from './Array' 6 | export * as R from './Result' 7 | export * as G from './Guards' 8 | export * as O from './Option' 9 | export * as S from './String' 10 | export * as D from './Dict' 11 | export * as B from './Bool' 12 | export * as N from './Number' 13 | 14 | export * as AD from './AsyncData' 15 | export * as ADR from './AsyncDataResult' 16 | export * as AO from './AsyncOption' 17 | export * as AR from './AsyncResult' 18 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { pipe } from './pipe' 2 | export { flow } from './flow' 3 | 4 | export * as F from './Function' 5 | export * as A from './Array' 6 | export * as R from './Result' 7 | export * as G from './Guards' 8 | export * as O from './Option' 9 | 10 | export * as S from './String' 11 | export * as D from './Dict' 12 | export * as B from './Bool' 13 | export * as N from './Number' 14 | 15 | export * as AD from './AsyncData' 16 | export * as ADR from './AsyncDataResult' 17 | export * as AO from './AsyncOption' 18 | export * as AR from './AsyncResult' 19 | -------------------------------------------------------------------------------- /docs/api/array.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: array 3 | title: Array 4 | --- 5 | 6 | import Array, { toc as arraytoc } from "./generated/_array.mdx" 7 | 8 | Utility functions for `Array`. 9 | 10 | ```jsx live 11 | function() { 12 | const xs = A.makeWithIndex(5, index => index) // → [0, 1, 2, 3, 4] 13 | const value = pipe( 14 | xs, 15 | A.tailOrEmpty, // → [1, 2, 3, 4] 16 | A.take(2), // → [1, 2] 17 | A.map(value => value * 2), // → [2, 4] 18 | ) 19 | 20 | return JSON.stringify(value) 21 | } 22 | ``` 23 | 24 | 25 | 26 | export const toc = arraytoc 27 | -------------------------------------------------------------------------------- /tools/javascript-codemods/pre/index.ts: -------------------------------------------------------------------------------- 1 | import { API, FileInfo } from 'jscodeshift' 2 | 3 | import dataFirst from './make-data-first' 4 | import spreadRest from './spread-rest-args' 5 | import uncurry from './uncurry-functions' 6 | import rename from './rename-identifiers' 7 | 8 | const transform = (file: FileInfo, api: API) => { 9 | const j = api.jscodeshift 10 | const source = [spreadRest, dataFirst, uncurry, rename].reduce((acc, fn) => { 11 | return fn(acc, j) 12 | }, file.source) 13 | 14 | return j(source).toSource() 15 | } 16 | 17 | export default transform 18 | -------------------------------------------------------------------------------- /benchmarks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-belt-benchmarks", 3 | "private": true, 4 | "version": "0.1.0", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "scripts": { 8 | "test": "NODE_ENV=test node ./ensure-identical-output.js", 9 | "start": "bash ./scripts/run.sh", 10 | "generate": "bash ./scripts/generate.sh" 11 | }, 12 | "devDependencies": { 13 | "benchr": "^4.3.0" 14 | }, 15 | "dependencies": { 16 | "list": "^2.0.19", 17 | "lodash": "^4.17.21", 18 | "rambda": "^6.9.0", 19 | "ramda": "^0.27.1", 20 | "remeda": "^0.0.32" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /__tests__/Array/sort.test.ts: -------------------------------------------------------------------------------- 1 | import { A, pipe } from '../..' 2 | 3 | const xs = [9, 2, 6, 4, 8, 5, 1, 7, 3] 4 | 5 | // TODO: expectType 6 | describe('sort', () => { 7 | it('returns correctly sorted array', () => { 8 | const result = A.sort(xs, (a, b) => a - b) 9 | expect(result).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]) 10 | }) 11 | }) 12 | 13 | describe('sort (pipe)', () => { 14 | it('returns correctly sorted array', () => { 15 | const result = pipe( 16 | xs, 17 | A.sort((a, b) => a - b), 18 | ) 19 | expect(result).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /tools/typescript-codemods/rename-generics.ts: -------------------------------------------------------------------------------- 1 | import { API } from 'jscodeshift' 2 | 3 | const transform = (source: string, j: API['jscodeshift']): string => { 4 | const generics = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] 5 | 6 | // rename T1, T2, T3… to A, B, C… 7 | return j(source) 8 | .find(j.Identifier) 9 | .filter(p => { 10 | return /^T[0-9]$/.test(p.value.name) 11 | }) 12 | .replaceWith(p => { 13 | const [, index] = p.value.name.split('') 14 | return j.identifier(generics[parseInt(index, 10) - 1]) 15 | }) 16 | .toSource() 17 | } 18 | 19 | export default transform 20 | -------------------------------------------------------------------------------- /docs/sidebars.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sidebar: [ 3 | { 4 | type: 'doc', 5 | id: 'introduction', 6 | }, 7 | { 8 | type: 'category', 9 | label: 'Getting started', 10 | collapsed: false, 11 | items: [ 12 | 'getting-started/installation', 13 | 'getting-started/config', 14 | 'getting-started/usage', 15 | ], 16 | }, 17 | { 18 | type: 'doc', 19 | id: 'changelog', 20 | }, 21 | { 22 | type: 'link', 23 | label: 'Go to API', 24 | href: '/api/array', 25 | className: 'sidebar-api-button', 26 | }, 27 | ], 28 | } 29 | -------------------------------------------------------------------------------- /tools/rescript-externals/Externals.res: -------------------------------------------------------------------------------- 1 | external coerce: 'a => 'b = "%identity" 2 | external raw_comment: string => 'a = "#raw_stmt" 3 | 4 | external unsafeToJsExn: 'a => Js.Exn.t = "%identity" 5 | 6 | @val 7 | external assign: (Js.Dict.t<'a>, Js.Dict.t<'a>) => Js.Dict.t<'a> = "Object.assign" 8 | 9 | @val 10 | external assign2: (Js.Dict.t<'a>, Js.Dict.t<'a>, Js.Dict.t<'a>) => Js.Dict.t<'a> = "Object.assign" 11 | 12 | @val 13 | external entries: Js.Dict.t<'a> => array<(Js.Dict.key, 'a)> = "Object.entries" 14 | 15 | @send 16 | external trimEnd: string => string = "trimEnd" 17 | 18 | @send 19 | external trimStart: string => string = "trimStart" 20 | -------------------------------------------------------------------------------- /docs/src/pages/components/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import clsx from 'clsx' 3 | 4 | import Link from '@docusaurus/Link' 5 | import useBaseUrl from '@docusaurus/useBaseUrl' 6 | 7 | import styles from './Button.module.css' 8 | 9 | const Button = props => { 10 | const { children, to, variant } = props 11 | 12 | return ( 13 | 21 | {children} 22 | 23 | ) 24 | } 25 | 26 | export default Button 27 | -------------------------------------------------------------------------------- /docs/src/pages/components/Row.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Row.module.css' 4 | 5 | const Row = props => { 6 | const { 7 | children, 8 | alignX = 'flex-start', 9 | marginBottom = 0, 10 | padding = 0, 11 | paddingX, 12 | paddingY, 13 | } = props 14 | return ( 15 |
23 | {children} 24 |
25 | ) 26 | } 27 | 28 | export default Row 29 | -------------------------------------------------------------------------------- /__tests__/String/head.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S, O } from '../..' 4 | 5 | describe('head', () => { 6 | it('provides correct types', () => { 7 | expectType>(S.head('text')) 8 | }) 9 | 10 | it('returns None if the given string is empty', () => { 11 | expect(S.head('')).toEqual(O.None) 12 | }) 13 | 14 | it('Returns Some(value) where value is the first character of the string', () => { 15 | expect(S.head('random-text')).toEqual(O.Some('r')) 16 | }) 17 | 18 | it('*', () => { 19 | const { Some } = O 20 | expect(S.head('random-text')).toEqual(Some('r')) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /__tests__/String/last.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S, O } from '../..' 4 | 5 | describe('last', () => { 6 | it('provides correct types', () => { 7 | expectType>(S.last('text')) 8 | }) 9 | 10 | it('returns None if the given string is empty', () => { 11 | expect(S.last('')).toEqual(O.None) 12 | }) 13 | 14 | it('returns Some(value) where value is the last character of the string', () => { 15 | expect(S.last('random-text')).toEqual(O.Some('t')) 16 | }) 17 | 18 | it('*', () => { 19 | const { Some } = O 20 | expect(S.last('random-text')).toEqual(Some('t')) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /__tests__/Result/getExn.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, R } from '../..' 2 | 3 | describe('getExn', () => { 4 | it('should throw an error', () => { 5 | expect(() => { 6 | pipe(R.fromNullable(null, 'this is bad'), R.getExn) 7 | }).toThrow(Object) 8 | }) 9 | 10 | it('returns a value', () => { 11 | expect(pipe(R.fromNullable('value', 'this is bad'), R.getExn)).toEqual( 12 | 'value', 13 | ) 14 | }) 15 | 16 | it('*', () => { 17 | expect( 18 | pipe( 19 | R.fromNullable('hello', 'oops!'), 20 | R.map(value => `${value} world!`), 21 | R.getExn, 22 | ), 23 | ).toEqual('hello world!') 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /docs/src/pages/components/Features.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Features.module.css' 4 | 5 | const Features = props => { 6 | const { children } = props 7 | const length = React.Children.count(children) 8 | 9 | return ( 10 |
11 | {React.Children.map(children, (child, index) => { 12 | return ( 13 | 14 | {child} 15 | {index === length - 1 ? null : ( 16 | · 17 | )} 18 | 19 | ) 20 | })} 21 |
22 | ) 23 | } 24 | 25 | export default Features 26 | -------------------------------------------------------------------------------- /__tests__/Array/makeWithIndex.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A } from '../..' 4 | 5 | describe('makeWithIndex', () => { 6 | it('provides correct types', () => { 7 | expectType>(A.makeWithIndex(4, index => `${index}`)) 8 | expectType>(A.makeWithIndex(4, index => index * 2)) 9 | }) 10 | 11 | it('returns a new array of size `n`', () => { 12 | const result = A.makeWithIndex(5, index => index * 2) 13 | expect(result).toEqual([0, 2, 4, 6, 8]) 14 | }) 15 | 16 | it('*', () => { 17 | expect(A.makeWithIndex(5, index => index * 2)).toEqual([0, 2, 4, 6, 8]) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /__tests__/Array/get.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | import { A, O } from '../..' 3 | 4 | describe('get', () => { 5 | it('provides correct types', () => { 6 | expectType>(A.get([1, 2, 3, 4, 5], 0)) 7 | }) 8 | 9 | it('returns None', () => { 10 | expect(A.get([], 0)).toEqual(O.None) 11 | expect(A.get([1, 2, 3], 3)).toEqual(O.None) 12 | }) 13 | 14 | it('returns Some', () => { 15 | expect(A.get([1, 2, 3], 0)).toEqual(O.Some(1)) 16 | expect(A.get([0, 2, 3], 0)).toEqual(O.Some(0)) 17 | expect(A.get([true, true, false], 2)).toEqual(O.Some(false)) 18 | expect(A.get([[1], [2]], 1)).toEqual(O.Some([2])) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /benchmarks/native.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pipe: (...fns) => (arg) => fns.reduce((arg, fn) => fn(arg), arg), 3 | find: (closure) => (array) => array.find(closure), 4 | map: (closure) => (array) => array.map(closure), 5 | filter: (closure) => (array) => array.filter(closure), 6 | flat: (array) => array.flat(), 7 | deepFlat: (array) => array.flat(Infinity), 8 | forEach: (closure) => (array) => array.forEach(closure), 9 | fromEntries: (entries) => Object.fromEntries(entries), 10 | entries: (object) => Object.entries(object), 11 | reduce: (closure, init) => (array) => array.reduce(closure, init), 12 | safeSort: (closure) => (array) => [...array].sort(closure), 13 | } 14 | -------------------------------------------------------------------------------- /__tests__/Array/take.test.ts: -------------------------------------------------------------------------------- 1 | import { A } from '../..' 2 | 3 | describe('take', () => { 4 | it('returns an empty array', () => { 5 | expect(A.take([1, 2, 3], -1)).toEqual([]) 6 | expect(A.take([], 0)).toEqual([]) 7 | expect(A.take([1, 2, 3], 0)).toEqual([]) 8 | }) 9 | 10 | it('returns a new array including the first `n` items', () => { 11 | expect(A.take([1], 1)).toEqual([1]) 12 | expect(A.take([1, 2, 3], 1)).toEqual([1]) 13 | expect(A.take([[1], [2]], 1)).toEqual([[1]]) 14 | expect(A.take([true, true, false], 2)).toEqual([true, true]) 15 | expect(A.take([1, 2, 3], 3)).toEqual([1, 2, 3]) 16 | expect(A.take([1, 2, 3], 4)).toEqual([1, 2, 3]) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /docs/src/pages/components/Columns.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import styles from './Columns.module.css' 4 | 5 | const Context = React.createContext({ 6 | space: 0, 7 | }) 8 | 9 | export const useColumns = () => React.useContext(Context) 10 | 11 | const Columns = props => { 12 | const { children, space, marginBottom = 0 } = props 13 | return ( 14 | 15 |
22 | {children} 23 |
24 |
25 | ) 26 | } 27 | 28 | export default Columns 29 | -------------------------------------------------------------------------------- /benchmarks/scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | mkdir -p ./.results 4 | 5 | date_now=$(date "+%F-%H-%M") 6 | results_file="./.results/results-$date_now.txt" 7 | 8 | rm -f $results_file 9 | 10 | glob_files=".*" 11 | 12 | complex=($(grep -HRl "$glob_files" ./complex)) 13 | 14 | for i in "${complex[@]}" 15 | do 16 | node "./index.js" "$i" 2>&1 | tee -a $results_file 17 | sed -i '' "s/\\[23m//g" $results_file 18 | sed -i '' "s/\\[3m//g" $results_file 19 | done 20 | 21 | simple=($(grep -HRl "$glob_files" ./simple)) 22 | 23 | for i in "${simple[@]}" 24 | do 25 | node "./index.js" "$i" 2>&1 | tee -a $results_file 26 | sed -i '' "s/\\[23m//g" $results_file 27 | sed -i '' "s/\\[3m//g" $results_file 28 | done 29 | -------------------------------------------------------------------------------- /__tests__/Result/isOk.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, R } from '../..' 2 | 3 | describe('isOk', () => { 4 | it('returns true', () => { 5 | expect(R.isOk(R.Ok('this is fine'))).toBeTruthy() 6 | expect(pipe(R.fromNullable('value', 'this is bad'), R.isOk)).toBeTruthy() 7 | }) 8 | 9 | it('returns false', () => { 10 | expect(R.isOk(R.Error('this is bad'))).toBeFalsy() 11 | expect(pipe(R.fromNullable(null, 'this is bad'), R.isOk)).toBeFalsy() 12 | }) 13 | 14 | it('*', () => { 15 | expect(R.isOk(R.Ok('good'))).toEqual(true) 16 | expect(pipe(R.fromNullable(4, 'error'), R.isOk)).toEqual(true) 17 | expect(R.isOk(R.Error('bad'))).toEqual(false) 18 | expect(pipe(R.fromNullable(null, 'error'), R.isOk)).toEqual(false) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /__tests__/Number/pred.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, pipe } from '../..' 4 | 5 | describe('pred', () => { 6 | it('provides correct types', () => { 7 | expectType(N.pred(2)) 8 | }) 9 | 10 | it('subtracts 1 from the given number', () => { 11 | expect(N.pred(4)).toEqual(3) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.pred(6)).toEqual(5) 16 | }) 17 | }) 18 | 19 | describe('pred (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType(pipe(3, N.pred)) 22 | }) 23 | 24 | it('subtracts 1 from the given number', () => { 25 | expect(pipe(2, N.pred)).toEqual(1) 26 | }) 27 | 28 | it('*', () => { 29 | expect(pipe(5, N.pred)).toEqual(4) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /__tests__/Guards/isNullable.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { G, pipe } from '../..' 4 | 5 | describe('isNullable', () => { 6 | it('provides correct types', () => { 7 | const x = '' as unknown as null | string 8 | 9 | if (G.isNullable(x)) { 10 | expectType(x) 11 | } 12 | }) 13 | 14 | it('determines whether the provided value is nullable', () => { 15 | expect(G.isNullable(undefined)).toEqual(true) 16 | expect(G.isNullable(null)).toEqual(true) 17 | }) 18 | 19 | it('*', () => { 20 | expect(G.isNullable(null)).toEqual(true) 21 | }) 22 | }) 23 | 24 | describe('isNullable (pipe)', () => { 25 | it('*', () => { 26 | expect(pipe(undefined, G.isNullable)).toEqual(true) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /__tests__/Result/isError.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, R } from '../..' 2 | 3 | describe('isError', () => { 4 | it('returns true', () => { 5 | expect(R.isError(R.Error('bad'))).toBeTruthy() 6 | expect(pipe(R.fromNullable(null, 'this is bad'), R.isError)).toBeTruthy() 7 | }) 8 | 9 | it('returns false', () => { 10 | expect(R.isError(R.Ok('good'))).toBeFalsy() 11 | expect(pipe(R.fromNullable('value', 'this is bad'), R.isError)).toBeFalsy() 12 | }) 13 | 14 | it('*', () => { 15 | expect(R.isError(R.Error('bad'))).toEqual(true) 16 | expect(pipe(R.fromNullable(null, 'error'), R.isError)).toEqual(true) 17 | expect(R.isError(R.Ok('good'))).toEqual(false) 18 | expect(pipe(R.fromNullable(4, 'error'), R.isError)).toEqual(false) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /__tests__/Number/add.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, pipe } from '../..' 4 | 5 | describe('add', () => { 6 | it('provides correct types', () => { 7 | expectType(N.add(1, 2)) 8 | }) 9 | 10 | it('returns the sum of two numbers', () => { 11 | expect(N.add(10, 20)).toEqual(30) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.add(10, 20)).toEqual(30) 16 | }) 17 | }) 18 | 19 | describe('add (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType(pipe(1, N.add(2))) 22 | }) 23 | 24 | it('returns the sum of two numbers', () => { 25 | expect(pipe(10, N.add(20))).toEqual(30) 26 | }) 27 | 28 | it('*', () => { 29 | expect(pipe(5, N.add(10))).toEqual(15) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /__tests__/Number/divide.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, pipe } from '../..' 4 | 5 | describe('divide', () => { 6 | it('provides correct types', () => { 7 | expectType(N.divide(1, 2)) 8 | }) 9 | 10 | it('divides two numbers', () => { 11 | expect(N.divide(20, 10)).toEqual(2) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.divide(20, 5)).toEqual(4) 16 | }) 17 | }) 18 | 19 | describe('divide (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType(pipe(1, N.divide(2))) 22 | }) 23 | 24 | it('divides two numbers', () => { 25 | expect(pipe(20, N.divide(2))).toEqual(10) 26 | }) 27 | 28 | it('*', () => { 29 | expect(pipe(40, N.divide(4))).toEqual(10) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/overrides/opam__s__ocamlbuild_opam__c__0.14.0_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < ocamlbuild-0.14.0.patch' : 'true'}" 7 | ], 8 | [ 9 | "make", 10 | "-f", 11 | "configure.make", 12 | "all", 13 | "OCAMLBUILD_PREFIX=#{self.install}", 14 | "OCAMLBUILD_BINDIR=#{self.bin}", 15 | "OCAMLBUILD_LIBDIR=#{self.lib}", 16 | "OCAMLBUILD_MANDIR=#{self.man}", 17 | "OCAMLBUILD_NATIVE=true", 18 | "OCAMLBUILD_NATIVE_TOOLS=true" 19 | ], 20 | [ 21 | "make", 22 | "check-if-preinstalled", 23 | "all", 24 | "#{os == 'windows' ? 'install' : 'opam-install'}" 25 | ] 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /src/AsyncDataResult/index.js: -------------------------------------------------------------------------------- 1 | export * from './AsyncDataResult.bs.js' 2 | 3 | export const Init = 0 4 | export const Loading = 1 5 | 6 | export const ReloadingOk = value => { 7 | return { 8 | TAG: 0, 9 | _0: { 10 | TAG: 0, 11 | _0: value, 12 | }, 13 | } 14 | } 15 | 16 | export const ReloadingError = value => { 17 | return { 18 | TAG: 0, 19 | _0: { 20 | TAG: 1, 21 | _0: value, 22 | }, 23 | } 24 | } 25 | 26 | export const CompleteOk = value => { 27 | return { 28 | TAG: 1, 29 | _0: { 30 | TAG: 0, 31 | _0: value, 32 | }, 33 | } 34 | } 35 | 36 | export const CompleteError = value => { 37 | return { 38 | TAG: 1, 39 | _0: { 40 | TAG: 1, 41 | _0: value, 42 | }, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /__tests__/Number/multiply.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, pipe } from '../..' 4 | 5 | describe('multiply', () => { 6 | it('provides correct types', () => { 7 | expectType(N.multiply(2, 2)) 8 | }) 9 | 10 | it('multiplies two numbers', () => { 11 | expect(N.multiply(2, 4)).toEqual(8) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.multiply(3, 6)).toEqual(18) 16 | }) 17 | }) 18 | 19 | describe('multiply (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType(pipe(3, N.multiply(6))) 22 | }) 23 | 24 | it('multiplies two numbers', () => { 25 | expect(pipe(2, N.multiply(2))).toEqual(4) 26 | }) 27 | 28 | it('*', () => { 29 | expect(pipe(8, N.multiply(4))).toEqual(32) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /docs/src/pages/components/Button.module.css: -------------------------------------------------------------------------------- 1 | .button { 2 | height: 56px; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | padding: 0 40px; 7 | font-size: 1rem; 8 | text-transform: uppercase; 9 | letter-spacing: 3px; 10 | } 11 | 12 | .buttonOutline { 13 | border: 4px solid var(--ifm-color-gray-900); 14 | color: var(--ifm-color-gray-900); 15 | border-radius: 4px; 16 | } 17 | 18 | .buttonOutline:hover { 19 | border-color: var(--ifm-color-primary); 20 | color: var(--ifm-color-primary); 21 | } 22 | 23 | .buttonFull { 24 | border: none; 25 | background-color: var(--ifm-color-gray-900); 26 | color: var(--ifm-color-white); 27 | border-radius: 4px; 28 | } 29 | 30 | .buttonFull:hover { 31 | background-color: var(--ifm-color-primary); 32 | } 33 | -------------------------------------------------------------------------------- /__tests__/Array/getBy.test.ts: -------------------------------------------------------------------------------- 1 | import { A, O } from '../..' 2 | 3 | describe('getBy', () => { 4 | it('returns None', () => { 5 | expect(A.getBy([1, 2, 3], n => n === 0)).toEqual(O.None) 6 | expect(A.getBy([false, false, false], state => state)).toEqual(O.None) 7 | expect( 8 | A.getBy([{ prop: null }, { prop: false }, { prop: undefined }], obj => Boolean(obj.prop)), 9 | ).toEqual(O.None) 10 | }) 11 | 12 | it('returns Some', () => { 13 | expect(A.getBy(['a', 'ab', 'bc'], str => str.length === 2)).toEqual(O.Some('ab')) 14 | expect(A.getBy([1, 2, 3], value => value === 2)).toEqual(O.Some(2)) 15 | expect( 16 | A.getBy([{ prop: 'ab' }, { prop: 'abc' }, { prop: 'bcd' }], obj => obj.prop.length > 2), 17 | ).toEqual(O.Some({ prop: 'abc' })) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /__tests__/Array/splitAt.test.ts: -------------------------------------------------------------------------------- 1 | import { A, O } from '../..' 2 | 3 | describe('splitAt', () => { 4 | it('returns None', () => { 5 | expect(A.splitAt([], 1)).toEqual(O.None) 6 | expect(A.splitAt([1, 2, 3], -1)).toEqual(O.None) 7 | expect(A.splitAt([1, 2, 3], 4)).toEqual(O.None) 8 | }) 9 | 10 | it('returns Some', () => { 11 | expect(A.splitAt([], 0)).toEqual(O.Some([[], []])) 12 | expect(A.splitAt([1], 1)).toEqual(O.Some([[1], []])) 13 | expect(A.splitAt([1, 2], 1)).toEqual(O.Some([[1], [2]])) 14 | expect(A.splitAt([true, true, false], 2)).toEqual( 15 | O.Some([[true, true], [false]]), 16 | ) 17 | expect(A.splitAt([[1], [2], [3], [4]], 2)).toEqual( 18 | O.Some([ 19 | [[1], [2]], 20 | [[3], [4]], 21 | ]), 22 | ) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /__tests__/Array/tail.test.ts: -------------------------------------------------------------------------------- 1 | import { A, O, pipe } from '../..' 2 | 3 | describe('tail', () => { 4 | it('returns None', () => { 5 | expect(A.tail([])).toEqual(O.None) 6 | }) 7 | 8 | it('returns Some', () => { 9 | expect(A.tail([1, 2, 3])).toEqual(O.Some([2, 3])) 10 | expect(A.tail([true, true, false])).toEqual(O.Some([true, false])) 11 | expect(A.tail([{ prop: 1 }, { prop: 2 }])).toEqual(O.Some([{ prop: 2 }])) 12 | expect(A.tail([[1], [2], [3]])).toEqual(O.Some([[2], [3]])) 13 | }) 14 | 15 | it('*', () => { 16 | const { Some, None } = O 17 | 18 | expect(A.tail([1, 2, 3])).toEqual(Some([2, 3])) 19 | expect(A.tail([1])).toEqual(Some([])) 20 | expect(A.tail([])).toEqual(None) 21 | expect(pipe([1, 2, 3, 4], A.tail)).toEqual(Some([2, 3, 4])) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /__tests__/Array/union.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | describe('difference', () => { 6 | it('provides correct types', () => { 7 | expectType>(A.union(['', 'hello', 'world'], [''])) 8 | }) 9 | 10 | it('*', () => { 11 | expect(A.union([1, 2, 3, 4], [3, 4, 5, 6])).toEqual([1, 2, 3, 4, 5, 6]) 12 | }) 13 | }) 14 | 15 | describe('union (pipe)', () => { 16 | it('provides correct types', () => { 17 | expectType>( 18 | pipe([5, 2, 3, 5, 6], A.union([5, 2, 3, 1, 5, 4])), 19 | ) 20 | }) 21 | 22 | it('*', () => { 23 | expect(pipe([5, 2, 3, 5, 6], A.union([5, 2, 3, 1, 5, 4]))).toEqual( 24 | // prettier-ignore 25 | [5, 2, 3, 6, 1, 4], 26 | ) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /__tests__/Guards/isNull.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { G, pipe } from '../..' 4 | 5 | describe('isNull', () => { 6 | it('provides correct types', () => { 7 | const x = null 8 | 9 | if (G.isNull(x)) { 10 | expectType(x) 11 | } 12 | 13 | const y: unknown = null 14 | 15 | if (G.isNull(y)) { 16 | expectType(y) 17 | } 18 | }) 19 | 20 | it('determines whether the provided value is null', () => { 21 | expect(G.isNull(undefined)).toEqual(false) 22 | expect(G.isNull(null)).toEqual(true) 23 | }) 24 | 25 | it('*', () => { 26 | expect(G.isNull(null)).toEqual(true) 27 | }) 28 | }) 29 | 30 | describe('isNull (pipe)', () => { 31 | it('*', () => { 32 | expect(pipe(null, G.isNull)).toEqual(true) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mobily/ts-belt", 3 | "version": "3.0.0", 4 | "namespace": false, 5 | "bsc-flags": ["-bs-super-errors", "-bs-no-version-header"], 6 | "gentypeconfig": { 7 | "language": "typescript", 8 | "importPath": "relative", 9 | "debug": { 10 | "all": false 11 | }, 12 | "exportInterfaces": false 13 | }, 14 | "suffix": ".bs.js", 15 | "package-specs": { 16 | "module": "es6", 17 | "in-source": true 18 | }, 19 | "sources": [ 20 | { 21 | "dir": "src", 22 | "subdirs": true 23 | }, 24 | { 25 | "dir": "tools/rescript-externals" 26 | } 27 | ], 28 | "bs-dependencies": ["@ryyppy/rescript-promise"], 29 | "bs-dev-dependencies": [], 30 | "ppx-flags": [ 31 | ["./tools/comment-ppx/ppx.exe -as-ppx"] 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /__tests__/Number/succ.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, A, pipe } from '../..' 4 | 5 | describe('succ', () => { 6 | it('provides correct types', () => { 7 | expectType(N.succ(2)) 8 | }) 9 | 10 | it('adds 1 to the given number', () => { 11 | expect(N.succ(4)).toEqual(5) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.succ(0)).toEqual(1) 16 | expect(A.makeWithIndex(4, N.succ)).toEqual([1, 2, 3, 4]) 17 | }) 18 | }) 19 | 20 | describe('succ (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe(3, N.succ)) 23 | }) 24 | 25 | it('adds 1 to the given number', () => { 26 | expect(pipe(2, N.succ)).toEqual(3) 27 | }) 28 | 29 | it('*', () => { 30 | expect(pipe(5, N.succ)).toEqual(6) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /__tests__/Array/all.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | describe('all', () => { 6 | it('provides correct types', () => { 7 | expectType(A.all(['hello', 'world'], value => value.length > 0)) 8 | }) 9 | 10 | it('*', () => { 11 | expect(A.all(['hello', 'world'], value => value.length > 0)).toEqual(true) 12 | }) 13 | }) 14 | 15 | describe('all (pipe)', () => { 16 | it('provides correct types', () => { 17 | expectType( 18 | pipe( 19 | [1, 2, 3, 4, 5], 20 | A.all(value => value > 0), 21 | ), 22 | ) 23 | }) 24 | 25 | it('*', () => { 26 | expect( 27 | pipe( 28 | [1, 2, 3, 4, 5], 29 | A.all(value => value > 3), 30 | ), 31 | ).toEqual(false) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /__tests__/Number/modulo.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, pipe } from '../..' 4 | 5 | describe('modulo', () => { 6 | it('provides correct types', () => { 7 | expectType(N.modulo(30, 6)) 8 | }) 9 | 10 | it('returns the remainder of a number division', () => { 11 | expect(N.modulo(20, 4)).toEqual(0) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.modulo(20, 6)).toEqual(2) 16 | }) 17 | }) 18 | 19 | describe('modulo (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType(pipe(30, N.modulo(6))) 22 | }) 23 | 24 | it('returns the remainder of a number division', () => { 25 | expect(pipe(20, N.modulo(2))).toEqual(0) 26 | }) 27 | 28 | it('*', () => { 29 | expect(pipe(30, N.modulo(4))).toEqual(2) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /docs/sidebars.benchmarks.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sidebar: [ 3 | { 4 | type: 'doc', 5 | id: 'introduction', 6 | }, 7 | { 8 | type: 'category', 9 | label: 'v3.12.0', 10 | collapsed: false, 11 | items: ['v3.12.0/macbook-pro-2021'], 12 | }, 13 | { 14 | type: 'category', 15 | label: 'v3.7.0', 16 | collapsed: false, 17 | items: ['v3.7.0/macbook-pro-2017', 'v3.7.0/macbook-air-2020'], 18 | }, 19 | { 20 | type: 'category', 21 | label: 'v3.0.0', 22 | collapsed: false, 23 | items: [ 24 | 'v3.0.0/macbook-pro-2017', 25 | 'v3.0.0/macbook-pro-2019', 26 | 'v3.0.0/macbook-air-2020', 27 | 'v3.0.0/macbook-pro-2021', 28 | 'v3.0.0/windows-10-i7-10700k', 29 | ], 30 | }, 31 | ], 32 | } 33 | -------------------------------------------------------------------------------- /__tests__/Option/tap.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, O, A } from '../..' 2 | 3 | describe('tap', () => { 4 | it('applies a side-effect', () => { 5 | const spy = jest.fn() 6 | const value = pipe( 7 | O.fromNullable(['hello', 'world']), 8 | O.flatMap(A.head), 9 | O.tap(str => { 10 | spy() 11 | expect(str).toEqual('hello') 12 | }), 13 | O.getWithDefault(''), 14 | ) 15 | 16 | expect(spy).toBeCalledTimes(1) 17 | expect(value).toEqual('hello') 18 | }) 19 | 20 | it('*', () => { 21 | expect( 22 | pipe( 23 | O.fromNullable(['hello', 'world']), 24 | O.flatMap(A.get(1)), 25 | O.tap(str => { 26 | console.log(str) // ⬅️ 'world' 27 | }), 28 | O.getWithDefault(''), 29 | ), 30 | ).toEqual('world') 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /__tests__/Number/subtract.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, pipe } from '../..' 4 | 5 | describe('subtract', () => { 6 | it('provides correct types', () => { 7 | expectType(N.subtract(2, 1)) 8 | }) 9 | 10 | it('returns the difference of two numbers', () => { 11 | expect(N.subtract(20, 10)).toEqual(10) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.subtract(20, 10)).toEqual(10) 16 | }) 17 | }) 18 | 19 | describe('subtract (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType(pipe(2, N.subtract(1))) 22 | }) 23 | 24 | it('returns the difference of two numbers', () => { 25 | expect(pipe(20, N.subtract(10))).toEqual(10) 26 | }) 27 | 28 | it('*', () => { 29 | expect(pipe(15, N.subtract(10))).toEqual(5) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /tools/javascript-codemods/pre/spread-rest-args.ts: -------------------------------------------------------------------------------- 1 | import { API } from 'jscodeshift' 2 | 3 | const transform = (source: string, j: API['jscodeshift']): string => { 4 | const root = j(source) 5 | 6 | root 7 | .find(j.Identifier, { 8 | name: 'restArgs', 9 | }) 10 | .filter(p => { 11 | return p.parent.value.type === 'FunctionExpression' 12 | }) 13 | .replaceWith(p => { 14 | return j.restElement(p.value) 15 | }) 16 | .toSource() 17 | 18 | root 19 | .find(j.Identifier, { 20 | name: 'restArgs', 21 | }) 22 | .filter(p => { 23 | return p.parent.value.type === 'CallExpression' 24 | }) 25 | .replaceWith(p => { 26 | return j.spreadElement(p.value) 27 | }) 28 | .toSource() 29 | 30 | return root.toSource() 31 | } 32 | 33 | export default transform 34 | -------------------------------------------------------------------------------- /__tests__/Array/flatMap.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | const xs = [1, 2, 3] 6 | 7 | describe('flatMap', () => { 8 | it('provides correct types', () => { 9 | expectType>( 10 | A.flatMap(['hello', 'world'], value => { 11 | return [value.length] 12 | }), 13 | ) 14 | }) 15 | 16 | it('returns correct value', () => { 17 | const result = A.flatMap(xs, value => [value * 2, value * 10]) 18 | expect(result).toEqual([2, 10, 4, 20, 6, 30]) 19 | }) 20 | }) 21 | 22 | describe('flatMap (pipe)', () => { 23 | it('returns correct value', () => { 24 | const result = pipe( 25 | xs, 26 | A.flatMap(value => [value, value + 10]), 27 | ) 28 | 29 | expect(result).toEqual([1, 11, 2, 12, 3, 13]) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /__tests__/Array/intersection.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | describe('intersection', () => { 6 | it('provides correct types', () => { 7 | expectType>( 8 | A.intersection(['', 'hello', 'world'], ['']), 9 | ) 10 | }) 11 | 12 | it('*', () => { 13 | expect(A.intersection([1, 2, 3, 4], [3, 4, 5, 6])).toEqual([3, 4]) 14 | }) 15 | }) 16 | 17 | describe('intersection (pipe)', () => { 18 | it('provides correct types', () => { 19 | expectType>( 20 | pipe([1, 2, 3, 4, 5], A.intersection([3, 4, 5, 6])), 21 | ) 22 | }) 23 | 24 | it('*', () => { 25 | expect(pipe([5, 2, 3, 5, 6], A.intersection([5, 2, 3, 1, 5, 4]))).toEqual( 26 | // prettier-ignore 27 | [5, 2, 3], 28 | ) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /__tests__/Result/tapError.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, R } from '../..' 2 | 3 | describe('tapError', () => { 4 | it('applies a side-effect', () => { 5 | const spy = jest.fn() 6 | const value = pipe( 7 | R.fromNullable(null, 'value cannot be nullable'), 8 | R.tapError(err => { 9 | spy() 10 | expect(err).toEqual('value cannot be nullable') 11 | }), 12 | R.getWithDefault(false), 13 | ) 14 | 15 | expect(spy).toBeCalledTimes(1) 16 | expect(value).toEqual(false) 17 | }) 18 | 19 | it('*', () => { 20 | expect( 21 | pipe( 22 | R.fromNullable(null, 'value cannot be nullable'), 23 | R.tapError(err => { 24 | console.log(err) // ⬅️ 'value cannot be nullable' 25 | }), 26 | R.getWithDefault(false), 27 | ), 28 | ).toEqual(false) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /__tests__/Array/any.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | describe('any', () => { 6 | it('provides correct types', () => { 7 | expectType( 8 | A.any(['', 'hello', 'world'], value => value.length > 0), 9 | ) 10 | }) 11 | 12 | it('*', () => { 13 | expect(A.any(['', 'hello', 'world'], value => value.length > 0)).toEqual( 14 | true, 15 | ) 16 | }) 17 | }) 18 | 19 | describe('any (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType( 22 | pipe( 23 | [1, 2, 3, 4, 5], 24 | A.any(value => value > 3), 25 | ), 26 | ) 27 | }) 28 | 29 | it('*', () => { 30 | expect( 31 | pipe( 32 | [1, 2, 3, 4, 5], 33 | A.any(value => value > 5), 34 | ), 35 | ).toEqual(false) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /__tests__/Result/tap.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, R, S } from '../..' 2 | 3 | describe('tap', () => { 4 | it('applies a side-effect', () => { 5 | const spy = jest.fn() 6 | const value = pipe( 7 | R.fromNullable('hello', 'value cannot be nullable'), 8 | R.map(S.isEmpty), 9 | R.tap(isEmpty => { 10 | spy() 11 | expect(isEmpty).toEqual(false) 12 | }), 13 | R.getWithDefault(false), 14 | ) 15 | 16 | expect(spy).toBeCalledTimes(1) 17 | expect(value).toEqual(false) 18 | }) 19 | 20 | it('*', () => { 21 | expect( 22 | pipe( 23 | R.fromNullable('hello', 'value cannot be nullable'), 24 | R.map(S.isEmpty), 25 | R.tap(isEmpty => { 26 | console.log(isEmpty) // ⬅️ false 27 | }), 28 | R.getWithDefault(false), 29 | ), 30 | ).toEqual(false) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /__tests__/Option/fromPromise.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | import { O } from '../..' 3 | 4 | describe('fromPromise', () => { 5 | it('provides correct types', () => { 6 | expectType>>(O.fromPromise(Promise.resolve(42))) 7 | }) 8 | 9 | it('returns None', async () => { 10 | expect(await O.fromPromise(Promise.reject('hello world'))).toEqual(O.None) 11 | }) 12 | 13 | it('returns Some', async () => { 14 | expect(await O.fromPromise(Promise.resolve('hello world'))).toEqual( 15 | O.Some('hello world'), 16 | ) 17 | }) 18 | 19 | it('*', async () => { 20 | const { Some, None } = O 21 | 22 | expect(await O.fromPromise(Promise.resolve('hello world'))).toEqual( 23 | Some('hello world'), 24 | ) 25 | 26 | expect(await O.fromPromise(Promise.reject('oops'))).toEqual(None) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /tools/javascript-codemods/pre/rename-identifiers.ts: -------------------------------------------------------------------------------- 1 | import { API, Identifier } from 'jscodeshift' 2 | 3 | const transform = (source: string, j: API['jscodeshift']): string => { 4 | const root = j(source) 5 | const literals: [string, string][] = [ 6 | ['when_', 'when'], 7 | ['not_', 'not'], 8 | ['or_', 'or'], 9 | ['and_', 'and'], 10 | ] 11 | const equalName = 12 | (p: Identifier) => 13 | ([search]: [string, string]) => { 14 | return p.name === search 15 | } 16 | 17 | root 18 | .find(j.Identifier) 19 | .filter(p => { 20 | return literals.some(equalName(p.value)) 21 | }) 22 | .replaceWith(p => { 23 | // @ts-expect-error 24 | const [, value] = literals.find(equalName(p.value)) 25 | return j.identifier(value) 26 | }) 27 | 28 | return root.toSource() 29 | } 30 | 31 | export default transform 32 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/result.1.5/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Jane Street developers" 3 | authors: ["Jane Street Group, LLC"] 4 | homepage: "https://github.com/janestreet/result" 5 | dev-repo: "git+https://github.com/janestreet/result.git" 6 | bug-reports: "https://github.com/janestreet/result/issues" 7 | license: "BSD-3-Clause" 8 | build: [["dune" "build" "-p" name "-j" jobs]] 9 | depends: [ 10 | "ocaml" 11 | "dune" {>= "1.0"} 12 | ] 13 | synopsis: "Compatibility Result module" 14 | description: """ 15 | Projects that want to use the new result type defined in OCaml >= 4.03 16 | while staying compatible with older version of OCaml should use the 17 | Result module defined in this library.""" 18 | url { 19 | src: 20 | "https://github.com/janestreet/result/releases/download/1.5/result-1.5.tbz" 21 | checksum: "md5=1b82dec78849680b49ae9a8a365b831b" 22 | } 23 | -------------------------------------------------------------------------------- /__tests__/Guards/isUndefined.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { G, pipe } from '../..' 4 | 5 | describe('isUndefined', () => { 6 | it('provides correct types', () => { 7 | const x = undefined 8 | 9 | if (G.isUndefined(x)) { 10 | expectType(x) 11 | } 12 | 13 | const y: unknown = undefined 14 | 15 | if (G.isUndefined(y)) { 16 | expectType(y) 17 | } 18 | }) 19 | 20 | it('determines whether the provided value is undefined', () => { 21 | expect(G.isUndefined(undefined)).toEqual(true) 22 | expect(G.isUndefined(null)).toEqual(false) 23 | }) 24 | 25 | it('*', () => { 26 | expect(G.isUndefined(undefined)).toEqual(true) 27 | }) 28 | }) 29 | 30 | describe('isUndefined (pipe)', () => { 31 | it('*', () => { 32 | expect(pipe(undefined, G.isUndefined)).toEqual(true) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/ppx_derivers.1.2.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "jeremie@dimino.org" 3 | authors: ["Jérémie Dimino"] 4 | license: "BSD-3-Clause" 5 | homepage: "https://github.com/ocaml-ppx/ppx_derivers" 6 | bug-reports: "https://github.com/ocaml-ppx/ppx_derivers/issues" 7 | dev-repo: "git+https://github.com/ocaml-ppx/ppx_derivers.git" 8 | build: [ 9 | ["dune" "build" "-p" name "-j" jobs] 10 | ] 11 | depends: [ 12 | "ocaml" 13 | "dune" 14 | ] 15 | synopsis: "Shared [@@deriving] plugin registry" 16 | description: """ 17 | Ppx_derivers is a tiny package whose sole purpose is to allow 18 | ppx_deriving and ppx_type_conv to inter-operate gracefully when linked 19 | as part of the same ocaml-migrate-parsetree driver.""" 20 | url { 21 | src: "https://github.com/ocaml-ppx/ppx_derivers/archive/1.2.1.tar.gz" 22 | checksum: "md5=5dc2bf130c1db3c731fe0fffc5648b41" 23 | } 24 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/fix.20211125/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | ] 6 | homepage: "https://gitlab.inria.fr/fpottier/fix" 7 | dev-repo: "git+https://gitlab.inria.fr/fpottier/fix.git" 8 | bug-reports: "francois.pottier@inria.fr" 9 | license: "LGPL-2.0-only" 10 | build: [ 11 | ["dune" "build" "-p" name "-j" jobs] 12 | ] 13 | depends: [ 14 | "ocaml" { >= "4.03" } 15 | "dune" { >= "1.3" } 16 | ] 17 | synopsis: "Facilities for memoization and fixed points" 18 | url { 19 | src: 20 | "https://gitlab.inria.fr/fpottier/fix/-/archive/20211125/archive.tar.gz" 21 | checksum: [ 22 | "md5=d3d316080a2fc9a4f56c15040e141364" 23 | "sha512=850cf0d3c6db806ac1d0b9bf39ad82529aecd56af07b2b421f48af15afdeab493f7b73e5d9e7d492e56717a8aeeb61466d87ac8a51fac30e3f77028b5ecd57c4" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tools/comment-ppx/src/Comment_ppx.re: -------------------------------------------------------------------------------- 1 | open Ppxlib; 2 | 3 | module Helper = Ast_helper; 4 | module Builder = Ast_builder.Default; 5 | 6 | let string_payload = 7 | Ast_pattern.( 8 | pstr( 9 | pstr_eval( 10 | pexp_constant(pconst_string(__', __, __)), 11 | nil 12 | ) ^:: nil, 13 | ), 14 | ); 15 | 16 | let expander = (~loc, ~path as _, payload, _label, _) => { 17 | let str = "/** " ++ payload.txt ++ " */" 18 | let ident = Helper.Exp.ident(~loc, {txt: Lident("raw_comment"), loc}); 19 | 20 | Helper.Exp.apply( 21 | ~loc, 22 | ~attrs=[], 23 | ident, 24 | [(Nolabel, Ast_builder.Default.estring(~loc, str))], 25 | ); 26 | } 27 | 28 | 29 | let extension = 30 | Ppxlib.Extension.declare("comment", Ppxlib.Extension.Context.Expression, string_payload, expander); 31 | 32 | let () = Driver.register_transformation(~extensions=[extension], "comment-ppx"); 33 | -------------------------------------------------------------------------------- /__tests__/Array/splitEvery.test.ts: -------------------------------------------------------------------------------- 1 | import { A, pipe } from '../..' 2 | 3 | const xs = [1, 2, 3, 4, 5, 6, 7] 4 | 5 | // TODO: expectType 6 | describe('splitEvery', () => { 7 | it('returns an array of arrays, where each of the inner arrays has length equal to `n`', () => { 8 | const result = A.splitEvery(xs, 3) 9 | expect(result).toEqual([[1, 2, 3], [4, 5, 6], [7]]) 10 | }) 11 | 12 | it('returns the original array inside a new array if n is out of range', () => { 13 | expect(A.splitEvery(xs, 0)).toEqual([[1, 2, 3, 4, 5, 6, 7]]) 14 | expect(A.splitEvery(xs, 8)).toEqual([[1, 2, 3, 4, 5, 6, 7]]) 15 | }) 16 | }) 17 | 18 | describe('splitEvery (pipe)', () => { 19 | it('returns an array of arrays, where each of the inner arrays has length equal to `n`', () => { 20 | const result = pipe(xs, A.splitEvery(3)) 21 | expect(result).toEqual([[1, 2, 3], [4, 5, 6], [7]]) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /__tests__/Bool/inverse.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('inverse', () => { 6 | it('provides correct types', () => { 7 | expectType(B.inverse(true)) 8 | }) 9 | 10 | it('negates the given boolean', () => { 11 | expect(B.inverse(true)).toEqual(false) 12 | expect(B.inverse(false)).toEqual(true) 13 | }) 14 | 15 | it('*', () => { 16 | expect(B.inverse(false)).toEqual(true) 17 | }) 18 | }) 19 | 20 | describe('inverse (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe(true, B.inverse)) 23 | }) 24 | 25 | it('negates the given boolean', () => { 26 | expect(pipe(true, B.inverse)).toEqual(false) 27 | expect(pipe(false, B.inverse)).toEqual(true) 28 | }) 29 | 30 | it('*', () => { 31 | expect(pipe(true, B.inverse)).toEqual(false) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /__tests__/Result/getWithDefault.test.ts: -------------------------------------------------------------------------------- 1 | import { pipe, R } from '../..' 2 | 3 | describe('getWithDefault', () => { 4 | it('returns a default value', () => { 5 | expect( 6 | pipe(R.fromNullable(null, 'error'), R.getWithDefault('default value')), 7 | ).toEqual('default value') 8 | }) 9 | 10 | it('should skip a default value', () => { 11 | expect(pipe(R.fromNullable(1, 'error'), R.getWithDefault(2))).toEqual(1) 12 | }) 13 | 14 | it('*', () => { 15 | expect( 16 | pipe( 17 | R.fromNullable('hello', 'oops!'), 18 | R.map(value => `${value} world!`), 19 | R.getWithDefault('error'), 20 | ), 21 | ).toBe('hello world!') 22 | 23 | expect( 24 | pipe( 25 | R.fromNullable(null, 'oops!'), 26 | R.map(value => `${value} world!`), 27 | R.getWithDefault('error'), 28 | ), 29 | ).toBe('error') 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /docs/api/result.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: result 3 | title: Result 4 | --- 5 | 6 | `Result` type is really useful to describe the result of a certain operation without relying on exceptions. 7 | 8 | import Result, { toc as resulttoc } from "./generated/_result.mdx" 9 | 10 | ```ts 11 | type Result = Ok | Error 12 | ``` 13 | 14 | ```jsx live 15 | function() { 16 | const obj = { 17 | // ⬇️ update the value below to either greater than 0 or `null/undefined` in order to see changes 18 | value: 0, 19 | } 20 | const value = pipe( 21 | R.fromNullable(obj.value, 'value cannot be nullable!'), 22 | R.flatMap(value => { 23 | return value === 0 ? R.Error('never divide by zero!') : R.Ok(100 / value) 24 | }), 25 | R.match(value => `100 / ${obj.value} = ${value}`, err => err), 26 | ) 27 | 28 | return value 29 | } 30 | ``` 31 | 32 | 33 | 34 | export const toc = resulttoc 35 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-belt-docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "dev": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "serve": "docusaurus serve", 12 | "clear": "docusaurus clear" 13 | }, 14 | "dependencies": { 15 | "@docusaurus/core": "^2.0.0-beta.10", 16 | "@docusaurus/preset-classic": "^2.0.0-beta.10", 17 | "@docusaurus/theme-live-codeblock": "^2.0.0-beta.10", 18 | "@easyops-cn/docusaurus-search-local": "^0.20.0", 19 | "@mdx-js/react": "^1.6.21", 20 | "@svgr/webpack": "^5.5.0", 21 | "clsx": "^1.1.1", 22 | "file-loader": "^6.2.0", 23 | "prism-react-renderer": "^1.2.1", 24 | "react": "^17.0.1", 25 | "react-dom": "^17.0.1", 26 | "url-loader": "^4.1.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /docs/src/pages/components/Card.module.css: -------------------------------------------------------------------------------- 1 | .card { 2 | border: 1px solid var(--ifm-color-gray-200); 3 | border-radius: 4px; 4 | display: block; 5 | cursor: pointer; 6 | transition: all .5s; 7 | min-height: 175px; 8 | color: #111; 9 | } 10 | 11 | @media screen and (max-width: 768px) { 12 | .card { 13 | min-height: 0; 14 | } 15 | } 16 | 17 | .card:hover { 18 | text-decoration: none; 19 | box-shadow: 0 6px 16px -8px #00000014, 0 9px 28px #0000000d, 0 12px 48px 16px #00000008; 20 | border-color: transparent; 21 | background-color: rgba(255, 255, 255, 0.33); 22 | } 23 | 24 | .title { 25 | padding: 12px; 26 | border-bottom: 1px solid var(--ifm-color-gray-200); 27 | font-size: 1rem; 28 | font-weight: 500; 29 | color: var(--ifm-color-gray-700); 30 | transition: color .5s; 31 | } 32 | 33 | .card:hover > .title { 34 | color: #000; 35 | } 36 | 37 | .body { 38 | padding: 12px; 39 | } 40 | -------------------------------------------------------------------------------- /__tests__/Option/isNone.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | import { pipe, O } from '../..' 3 | 4 | describe('isNone', () => { 5 | it('provides correct types', () => { 6 | expectType(O.isNone(O.None)) 7 | expectType(O.isNone(O.Some('hello'))) 8 | }) 9 | 10 | it('returns true', () => { 11 | expect(O.isNone(O.None)).toBeTruthy() 12 | expect(pipe(O.fromNullable(null), O.isNone)).toBeTruthy() 13 | }) 14 | 15 | it('returns false', () => { 16 | expect(O.isNone(O.Some('value'))).toBeFalsy() 17 | expect(pipe(O.fromNullable('value'), O.isNone)).toBeFalsy() 18 | }) 19 | 20 | it('*', () => { 21 | expect(O.isNone(O.None)).toEqual(true) 22 | expect(pipe(O.fromNullable(null), O.isNone)).toEqual(true) 23 | expect(O.isNone(O.Some('hello world!'))).toEqual(false) 24 | expect(pipe(O.fromNullable('hello world!'), O.isNone)).toEqual(false) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /__tests__/Option/isSome.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | import { pipe, O } from '../..' 3 | 4 | describe('isSome', () => { 5 | it('provides correct types', () => { 6 | expectType(O.isSome(O.None)) 7 | expectType(O.isSome(O.Some('hello'))) 8 | }) 9 | 10 | it('returns true', () => { 11 | expect(O.isSome(O.Some('string'))).toBeTruthy() 12 | expect(pipe(O.fromNullable('value'), O.isSome)).toBeTruthy() 13 | }) 14 | 15 | it('returns false', () => { 16 | expect(O.isSome(O.None)).toBeFalsy() 17 | expect(pipe(O.fromNullable(null), O.isSome)).toBeFalsy() 18 | }) 19 | 20 | it('*', () => { 21 | expect(O.isSome(O.Some('hello world!'))).toEqual(true) 22 | expect(pipe(O.fromNullable('hello world!'), O.isSome)).toEqual(true) 23 | expect(O.isSome(O.None)).toEqual(false) 24 | expect(pipe(O.fromNullable(null), O.isSome)).toEqual(false) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /__tests__/String/length.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S, pipe } from '../..' 4 | 5 | describe('length', () => { 6 | it('provides correct types', () => { 7 | expectType(S.length('ts-belt')) 8 | }) 9 | 10 | it('returns the correct size of the given string', () => { 11 | expect(S.length('hello')).toEqual(5) 12 | expect(S.length('')).toEqual(0) 13 | }) 14 | 15 | it('*', () => { 16 | expect(S.length('hello')).toEqual(5) 17 | }) 18 | }) 19 | 20 | describe('length (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe('hello', S.length)) 23 | }) 24 | 25 | it('returns the correct size of the given string', () => { 26 | expect(pipe('hello', S.length)).toEqual(5) 27 | expect(pipe('', S.length)).toEqual(0) 28 | }) 29 | 30 | it('*', () => { 31 | expect(pipe('ts-belt', S.length)).toEqual(7) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /__tests__/AsyncData/isInit.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | import { pipe, AD } from '../..' 3 | 4 | describe('isInit', () => { 5 | it('provides correct types', () => { 6 | expectType(AD.isInit(AD.Init)) 7 | expectType(AD.isInit(AD.Complete('hello world'))) 8 | }) 9 | 10 | it('returns true', () => { 11 | expect(AD.isInit(AD.Init)).toBeTruthy() 12 | expect(pipe(AD.Init, AD.isInit)).toBeTruthy() 13 | }) 14 | 15 | it('returns false', () => { 16 | expect(AD.isInit(AD.Loading)).toBeFalsy() 17 | expect(pipe(AD.Complete(0), AD.isInit)).toBeFalsy() 18 | }) 19 | 20 | // it('*', () => { 21 | // expect(AD.isInit(AD.Init)).toEqual(true) 22 | // expect(pipe(AD.Init, AD.isInit)).toEqual(true) 23 | // expect(AD.isInit(AD.Reloading('hello world'))).toEqual(false) 24 | // expect(pipe(AD.Complete('hello world'), AD.isInit)).toEqual(false) 25 | // }) 26 | }) 27 | -------------------------------------------------------------------------------- /__tests__/Array/length.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | describe('length', () => { 6 | it('provides correct types', () => { 7 | expectType(A.length([1, 2, 3, 4, 5])) 8 | }) 9 | 10 | it('returns the correct size of the given array', () => { 11 | expect(A.length([1, 2, 3, 4, 5])).toEqual(5) 12 | expect(A.length([])).toEqual(0) 13 | }) 14 | 15 | it('*', () => { 16 | expect(A.length(['hello', 'world'])).toEqual(2) 17 | }) 18 | }) 19 | 20 | describe('length (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe([1, 2, 3], A.length)) 23 | }) 24 | 25 | it('returns the correct size of the given array', () => { 26 | expect(pipe([1, 2, 3], A.length)).toEqual(3) 27 | expect(pipe([], A.length)).toEqual(0) 28 | }) 29 | 30 | it('*', () => { 31 | expect(pipe([0, 2, 4], A.length)).toEqual(3) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /__tests__/Result/fromPromise.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | import { R } from '../..' 3 | 4 | describe('fromPromise', () => { 5 | it('provides correct types', () => { 6 | expectType>>( 7 | R.fromPromise(Promise.resolve(42)), 8 | ) 9 | }) 10 | 11 | it('returns Error', async () => { 12 | expect(await R.fromPromise(Promise.reject('hello world'))).toEqual( 13 | R.Error('hello world'), 14 | ) 15 | }) 16 | 17 | it('returns Some', async () => { 18 | expect(await R.fromPromise(Promise.resolve('hello world'))).toEqual( 19 | R.Ok('hello world'), 20 | ) 21 | }) 22 | 23 | it('*', async () => { 24 | const { Ok, Error } = R 25 | 26 | expect(await R.fromPromise(Promise.resolve('hello world'))).toEqual( 27 | Ok('hello world'), 28 | ) 29 | 30 | expect(await R.fromPromise(Promise.reject('oops'))).toEqual(Error('oops')) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/ppx_yojson_conv_lib.v0.14.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Jane Street developers" 3 | authors: ["Jane Street Group, LLC"] 4 | homepage: "https://github.com/janestreet/ppx_yojson_conv_lib" 5 | bug-reports: "https://github.com/janestreet/ppx_yojson_conv_lib/issues" 6 | dev-repo: "git+https://github.com/janestreet/ppx_yojson_conv_lib.git" 7 | doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/ppx_yojson_conv_lib/index.html" 8 | license: "MIT" 9 | build: [ 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | depends: [ 13 | "ocaml" {>= "4.02.3"} 14 | "dune" {>= "2.0.0"} 15 | "yojson" {>= "1.7.0"} 16 | ] 17 | synopsis: "Runtime lib for ppx_yojson_conv" 18 | description: " 19 | Part of the Jane Street's PPX rewriters collection. 20 | " 21 | url { 22 | src: "https://ocaml.janestreet.com/ocaml-core/v0.14/files/ppx_yojson_conv_lib-v0.14.0.tar.gz" 23 | checksum: "md5=e23c5593a7211ad4fb09e26e9a74698a" 24 | } 25 | -------------------------------------------------------------------------------- /tools/comment-ppx/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "comment-ppx", 3 | "version": "0.1.0", 4 | "esy": { 5 | "buildsInSource": "_build", 6 | "build": "dune build -p comment-ppx", 7 | "buildDev": [ 8 | [ 9 | "dune", 10 | "build", 11 | "--promote-install-files", 12 | "--root", 13 | "." 14 | ] 15 | ], 16 | "release": { 17 | "bin": [ 18 | "bin" 19 | ] 20 | } 21 | }, 22 | "devDependencies": { 23 | "ocaml": "~4.10.0", 24 | "@esy-ocaml/reason": "^3.6.2", 25 | "@opam/dune": ">=2.8.4", 26 | "@opam/ppxlib": "0.22.0", 27 | "@reason-native/rely": "^3.2.1", 28 | "@opam/ocaml-lsp-server": "1.4.1" 29 | }, 30 | "scripts": { 31 | "build": "esy dune build -p comment-ppx", 32 | "dev": "esy build dune build -p comment-ppx", 33 | "format": "esy dune build @fmt --auto-promote", 34 | "utop": "esy dune utop lib -- -implicit-bindings" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tools/typescript-codemods/make-option.ts: -------------------------------------------------------------------------------- 1 | import { API } from 'jscodeshift' 2 | 3 | const transform = (source: string, j: API['jscodeshift']): string => { 4 | // T | null | undefined to Option 5 | return j(source) 6 | .find(j.TSUnionType) 7 | .filter(p => { 8 | return ( 9 | p.value.types.some(value => value.type === 'TSNullKeyword') && 10 | p.value.types.some(value => value.type === 'TSUndefinedKeyword') 11 | ) 12 | }) 13 | .replaceWith(p => { 14 | const typeReference = p.value.types.find( 15 | value => 16 | value.type !== 'TSUndefinedKeyword' && value.type !== 'TSNullKeyword', 17 | ) 18 | 19 | if (typeReference) { 20 | return j.tsTypeReference( 21 | j.identifier('Option'), 22 | j.tsTypeParameterInstantiation([typeReference]), 23 | ) 24 | } 25 | 26 | return p.value 27 | }) 28 | .toSource() 29 | } 30 | 31 | export default transform 32 | -------------------------------------------------------------------------------- /__tests__/Number/divideWithModulo.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { N, pipe } from '../..' 4 | 5 | describe('divideWithModulo', () => { 6 | it('provides correct types', () => { 7 | expectType(N.divideWithModulo(4, 2)) 8 | }) 9 | 10 | it('returns the quotient and remainder of a number division', () => { 11 | expect(N.divideWithModulo(20, 10)).toEqual([2, 0]) 12 | }) 13 | 14 | it('*', () => { 15 | expect(N.divideWithModulo(20, 5)).toEqual([4, 0]) 16 | }) 17 | }) 18 | 19 | describe('divideWithModulo (pipe)', () => { 20 | it('provides correct types', () => { 21 | expectType(pipe(4, N.divideWithModulo(2))) 22 | }) 23 | 24 | it('returns the quotient and remainder of a number division', () => { 25 | expect(pipe(20, N.divideWithModulo(2))).toEqual([10, 0]) 26 | }) 27 | 28 | it('*', () => { 29 | expect(pipe(30, N.divideWithModulo(4))).toEqual([7.5, 2]) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /__tests__/Array/takeWhile.test.ts: -------------------------------------------------------------------------------- 1 | import { A, pipe } from '../..' 2 | 3 | const xs = [1, 2, 3, 4, 5, 6, 7] 4 | 5 | // TODO: expectType 6 | describe('takeWhile', () => { 7 | it('returns a new array, filled with elements from the provided array until an element does not pass the provided predicate', () => { 8 | expect(A.takeWhile(xs, x => x < 4)).toEqual([1, 2, 3]) 9 | expect(A.takeWhile([3, 5, 3], x => x < 4)).toEqual([3]) 10 | }) 11 | 12 | it('returns correct array elements if either true or false', () => { 13 | expect(A.takeWhile(xs, _x => true)).toEqual([1, 2, 3, 4, 5, 6, 7]) 14 | expect(A.takeWhile(xs, _x => false)).toEqual([]) 15 | }) 16 | }) 17 | 18 | describe('takeWhile (pipe)', () => { 19 | it('returns a new array, filled with elements from the provided array until an element does not pass the provided predicate', () => { 20 | const result = pipe( 21 | xs, 22 | A.takeWhile(x => x < 4), 23 | ) 24 | expect(result).toEqual([1, 2, 3]) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /__tests__/Bool/or.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('or', () => { 6 | it('provides correct types', () => { 7 | expectType(B.or(true, true)) 8 | }) 9 | 10 | it('combines two booleans using OR', () => { 11 | expect(B.or(true, true)).toEqual(true) 12 | expect(B.or(false, false)).toEqual(false) 13 | expect(B.or(true, false)).toEqual(true) 14 | }) 15 | 16 | it('*', () => { 17 | expect(B.or(true, false)).toEqual(true) 18 | }) 19 | }) 20 | 21 | describe('or (pipe)', () => { 22 | it('provides correct types', () => { 23 | expectType(pipe(true, B.or(true))) 24 | }) 25 | 26 | it('combines two booleans using OR', () => { 27 | expect(pipe(true, B.or(true))).toEqual(true) 28 | expect(pipe(false, B.or(false))).toEqual(false) 29 | expect(pipe(true, B.or(false))).toEqual(true) 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe(false, B.or(false))).toEqual(false) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /__tests__/Guards/isNotNullable.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { G, pipe } from '../..' 4 | 5 | describe('isNotNullable', () => { 6 | it('provides correct types', () => { 7 | const x = '' as unknown as null | string 8 | 9 | if (G.isNotNullable(x)) { 10 | expectType(x) 11 | } 12 | }) 13 | 14 | it('determines whether the provided value is not nullable', () => { 15 | expect(G.isNotNullable(undefined)).toEqual(false) 16 | expect(G.isNotNullable(null)).toEqual(false) 17 | expect(G.isNotNullable('ts-belt')).toEqual(true) 18 | expect(G.isNotNullable([])).toEqual(true) 19 | }) 20 | 21 | it('*', () => { 22 | expect(G.isNotNullable('ts-belt')).toEqual(true) 23 | expect(G.isNotNullable(null)).toEqual(false) 24 | }) 25 | }) 26 | 27 | describe('isNotNullable (pipe)', () => { 28 | it('*', () => { 29 | expect(pipe(0, G.isNotNullable)).toEqual(true) 30 | expect(pipe(undefined, G.isNotNullable)).toEqual(false) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /__tests__/Bool/and.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('and', () => { 6 | it('provides correct types', () => { 7 | expectType(B.and(true, true)) 8 | }) 9 | 10 | it('combines two boolean using AND', () => { 11 | expect(B.and(true, true)).toEqual(true) 12 | expect(B.and(false, false)).toEqual(false) 13 | expect(B.and(true, false)).toEqual(false) 14 | }) 15 | 16 | it('*', () => { 17 | expect(B.and(true, true)).toEqual(true) 18 | }) 19 | }) 20 | 21 | describe('and (pipe)', () => { 22 | it('provides correct types', () => { 23 | expectType(pipe(true, B.and(true))) 24 | }) 25 | 26 | it('combines two boolean using AND', () => { 27 | expect(pipe(true, B.and(true))).toEqual(true) 28 | expect(pipe(false, B.and(false))).toEqual(false) 29 | expect(pipe(true, B.and(false))).toEqual(false) 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe(true, B.and(false))).toEqual(false) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /__tests__/Bool/nor.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('nor', () => { 6 | it('provides correct types', () => { 7 | expectType(B.nor(true, true)) 8 | }) 9 | 10 | it('combines two booleans using NOR', () => { 11 | expect(B.nor(true, true)).toEqual(false) 12 | expect(B.nor(false, false)).toEqual(true) 13 | expect(B.nor(true, false)).toEqual(false) 14 | }) 15 | 16 | it('*', () => { 17 | expect(B.nor(true, false)).toEqual(false) 18 | }) 19 | }) 20 | 21 | describe('nor (pipe)', () => { 22 | it('provides correct types', () => { 23 | expectType(pipe(true, B.nor(true))) 24 | }) 25 | 26 | it('combines two booleans using NOR', () => { 27 | expect(pipe(true, B.nor(true))).toEqual(false) 28 | expect(pipe(false, B.nor(false))).toEqual(true) 29 | expect(pipe(true, B.nor(false))).toEqual(false) 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe(false, B.nor(false))).toEqual(true) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /__tests__/Bool/xor.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('xor', () => { 6 | it('provides correct types', () => { 7 | expectType(B.xor(true, true)) 8 | }) 9 | 10 | it('combines two booleans using XOR', () => { 11 | expect(B.xor(true, true)).toEqual(false) 12 | expect(B.xor(false, false)).toEqual(false) 13 | expect(B.xor(true, false)).toEqual(true) 14 | }) 15 | 16 | it('*', () => { 17 | expect(B.xor(true, false)).toEqual(true) 18 | }) 19 | }) 20 | 21 | describe('xor (pipe)', () => { 22 | it('provides correct types', () => { 23 | expectType(pipe(true, B.xor(true))) 24 | }) 25 | 26 | it('combines two booleans using XOR', () => { 27 | expect(pipe(true, B.xor(true))).toEqual(false) 28 | expect(pipe(false, B.xor(false))).toEqual(false) 29 | expect(pipe(true, B.xor(false))).toEqual(true) 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe(false, B.xor(false))).toEqual(false) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /benchmarks/simple/intersperse.js: -------------------------------------------------------------------------------- 1 | const { makeBenchmark, addTsBelt, addRambda, addRamda } = require('../utils') 2 | 3 | const input = [1, 2, 3, 4, 5, 6, 7, 8, 9] 4 | 5 | module.exports = makeBenchmark( 6 | 'intersperse', 7 | addTsBelt(tsBelt => { 8 | const { A, pipe } = tsBelt 9 | 10 | return [ 11 | () => { 12 | return A.intersperse(input, 0) 13 | }, 14 | () => { 15 | return pipe(input, A.intersperse(0)) 16 | }, 17 | ] 18 | }), 19 | addRamda(ramda => { 20 | const { pipe, intersperse } = ramda 21 | 22 | return [ 23 | () => { 24 | return intersperse(0, input) 25 | }, 26 | () => { 27 | return pipe(intersperse(0))(input) 28 | }, 29 | ] 30 | }), 31 | addRambda(rambda => { 32 | const { pipe, intersperse } = rambda 33 | 34 | return [ 35 | () => { 36 | return intersperse(0, input) 37 | }, 38 | () => { 39 | return pipe(intersperse(0))(input) 40 | }, 41 | ] 42 | }), 43 | ) 44 | -------------------------------------------------------------------------------- /__tests__/Bool/nand.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('nand', () => { 6 | it('provides correct types', () => { 7 | expectType(B.nand(true, true)) 8 | }) 9 | 10 | it('combines two booleans using NAND', () => { 11 | expect(B.nand(true, true)).toEqual(false) 12 | expect(B.nand(false, false)).toEqual(true) 13 | expect(B.nand(true, false)).toEqual(true) 14 | }) 15 | 16 | it('*', () => { 17 | expect(B.nand(true, false)).toEqual(true) 18 | }) 19 | }) 20 | 21 | describe('nand (pipe)', () => { 22 | it('provides correct types', () => { 23 | expectType(pipe(true, B.nand(true))) 24 | }) 25 | 26 | it('combines two booleans using NAND', () => { 27 | expect(pipe(true, B.nand(true))).toEqual(false) 28 | expect(pipe(false, B.nand(false))).toEqual(true) 29 | expect(pipe(true, B.nand(false))).toEqual(true) 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe(false, B.nand(false))).toEqual(true) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /__tests__/Bool/xnor.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('xnor', () => { 6 | it('provides correct types', () => { 7 | expectType(B.xnor(true, true)) 8 | }) 9 | 10 | it('combines two booleans using XNOR', () => { 11 | expect(B.xnor(true, true)).toEqual(true) 12 | expect(B.xnor(false, false)).toEqual(true) 13 | expect(B.xnor(true, false)).toEqual(false) 14 | }) 15 | 16 | it('*', () => { 17 | expect(B.xnor(true, false)).toEqual(false) 18 | }) 19 | }) 20 | 21 | describe('xnor (pipe)', () => { 22 | it('provides correct types', () => { 23 | expectType(pipe(true, B.xnor(true))) 24 | }) 25 | 26 | it('combines two booleans using XNOR', () => { 27 | expect(pipe(true, B.xnor(true))).toEqual(true) 28 | expect(pipe(false, B.xnor(false))).toEqual(true) 29 | expect(pipe(true, B.xnor(false))).toEqual(false) 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe(false, B.xnor(false))).toEqual(true) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /__tests__/Array/unzip.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | const xs = [ 6 | A.toTuple([1, 2]), 7 | A.toTuple([3, 4]), 8 | A.toTuple([5, 6]), 9 | A.toTuple([7, 8]), 10 | ] 11 | 12 | describe('unzip', () => { 13 | it('provides correct types', () => { 14 | expectType, ReadonlyArray]>( 15 | A.unzip(xs), 16 | ) 17 | }) 18 | 19 | it('returns a pair of arrays', () => { 20 | const result = A.unzip(xs) 21 | expect(result).toEqual([ 22 | [1, 3, 5, 7], 23 | [2, 4, 6, 8], 24 | ]) 25 | }) 26 | }) 27 | 28 | describe('unzip (pipe)', () => { 29 | it('provides correct types', () => { 30 | expectType, ReadonlyArray]>( 31 | pipe(xs, A.unzip), 32 | ) 33 | }) 34 | 35 | it('returns a pair of arrays', () => { 36 | const result = pipe(xs, A.unzip) 37 | expect(result).toEqual([ 38 | [1, 3, 5, 7], 39 | [2, 4, 6, 8], 40 | ]) 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "forceConsistentCasingInFileNames": true, 4 | "emitDeclarationOnly": true, 5 | "rootDir": "./src", 6 | "baseUrl": ".", 7 | "lib": ["esnext"], 8 | "declaration": true, 9 | "module": "commonjs", 10 | "moduleResolution": "node", 11 | "target": "esnext", 12 | "strict": true, 13 | "sourceMap": false, 14 | "pretty": true, 15 | "skipLibCheck": true, 16 | "noImplicitAny": true, 17 | "allowUnreachableCode": false, 18 | "allowUnusedLabels": false, 19 | "exactOptionalPropertyTypes": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noImplicitOverride": true, 22 | "noImplicitReturns": true, 23 | "noPropertyAccessFromIndexSignature": true, 24 | "noUncheckedIndexedAccess": true, 25 | "noUnusedLocals": true, 26 | "noUnusedParameters": true 27 | }, 28 | "include": [ 29 | "./__tests__/**/*", 30 | "./playground/*.ts", 31 | "./src/**/index.ts" 32 | ], 33 | "exclude": [ 34 | "./src/**/*.gen.tsx" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/menhir.20211012/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "https://gitlab.inria.fr/fpottier/menhir/-/issues" 10 | license: "LGPL-2.0-only with OCaml-LGPL-linking-exception" 11 | build: [ 12 | ["dune" "build" "-p" name "-j" jobs] 13 | ] 14 | depends: [ 15 | "ocaml" {>= "4.02.3"} 16 | "dune" {>= "2.2.0"} 17 | "menhirLib" {= version} 18 | "menhirSdk" {= version} 19 | ] 20 | synopsis: "An LR(1) parser generator" 21 | url { 22 | src: 23 | "https://gitlab.inria.fr/fpottier/menhir/-/archive/20211012/archive.tar.gz" 24 | checksum: [ 25 | "md5=f631f4c03859254a7d725f054633ee44" 26 | "sha512=13376d3c07158c36dd9b4617294a7e4d53ba90062ab09fae48c36b76f08133e2ffc4be13a1bc88980617c5d1046631844815c9ee7fd7c821699bacaf245b1ed8" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/sexplib0.v0.14.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Jane Street developers" 3 | authors: ["Jane Street Group, LLC"] 4 | homepage: "https://github.com/janestreet/sexplib0" 5 | bug-reports: "https://github.com/janestreet/sexplib0/issues" 6 | dev-repo: "git+https://github.com/janestreet/sexplib0.git" 7 | doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/sexplib0/index.html" 8 | license: "MIT" 9 | build: [ 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | depends: [ 13 | "ocaml" {>= "4.04.2"} 14 | "dune" {>= "2.0.0"} 15 | ] 16 | synopsis: "Library containing the definition of S-expressions and some base converters" 17 | description: " 18 | Part of Jane Street's Core library 19 | The Core suite of libraries is an industrial strength alternative to 20 | OCaml's standard library that was developed by Jane Street, the 21 | largest industrial user of OCaml. 22 | " 23 | url { 24 | src: "https://ocaml.janestreet.com/ocaml-core/v0.14/files/sexplib0-v0.14.0.tar.gz" 25 | checksum: "md5=37aff0af8f8f6f759249475684aebdc4" 26 | } 27 | -------------------------------------------------------------------------------- /__tests__/Array/difference.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | type Obj = { 6 | readonly a?: number 7 | readonly b?: number 8 | readonly c?: number 9 | } 10 | 11 | describe('difference', () => { 12 | it('provides correct types', () => { 13 | expectType>( 14 | A.difference(['', 'hello', 'world'], ['']), 15 | ) 16 | }) 17 | 18 | it('returns a correct result', () => { 19 | expect( 20 | A.difference([{ a: 1 }, { b: 2 }], [{ a: 1 }, { c: 3 }]), 21 | ).toEqual([{ b: 2 }]) 22 | }) 23 | 24 | it('*', () => { 25 | expect(A.difference([1, 2, 3, 4], [3, 4, 5, 6])).toEqual([1, 2]) 26 | }) 27 | }) 28 | 29 | describe('difference (pipe)', () => { 30 | it('provides correct types', () => { 31 | expectType>( 32 | pipe([5, 2, 3, 5, 6], A.difference([5, 2, 3, 1, 5, 4])), 33 | ) 34 | }) 35 | 36 | it('*', () => { 37 | expect(pipe([5, 2, 3, 5, 6], A.difference([5, 2, 3, 1, 5, 4]))).toEqual([6]) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /__tests__/Array/removeFirst.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { A, pipe } from '../..' 4 | 5 | const xs = [1, 2, 1, 3] 6 | 7 | describe('removeFirst', () => { 8 | it('provides correct types', () => { 9 | expectType>(A.removeFirst(xs, 1)) 10 | }) 11 | 12 | it('removes the first occurence of the given value', () => { 13 | expect(A.removeFirst(xs, 1)).toEqual([2, 1, 3]) 14 | }) 15 | 16 | it('*', () => { 17 | expect(A.removeFirst(['hello', 'hello', 'world'], 'hello')).toEqual( 18 | // prettier-ignore 19 | ['hello', 'world'], 20 | ) 21 | }) 22 | }) 23 | 24 | describe('removeFirst (pipe)', () => { 25 | it('provides correct types', () => { 26 | expectType>(pipe(xs, A.removeFirst(1))) 27 | }) 28 | 29 | it('removes the first occurence of the given value', () => { 30 | expect(pipe(xs, A.removeFirst(1))).toEqual([2, 1, 3]) 31 | }) 32 | 33 | it('*', () => { 34 | expect(pipe([4, 5, 2, 1, 3], A.removeFirst(1))).toEqual([4, 5, 2, 3]) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /__tests__/String/concat.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S, A, pipe } from '../..' 4 | 5 | describe('concat', () => { 6 | it('provides correct types', () => { 7 | expectType(S.concat('hello', 'world')) 8 | expectType(A.reduce(['hello', 'world'], '', S.concat)) 9 | }) 10 | 11 | it('returns a new string with append added after str', () => { 12 | expect(S.concat('hello', 'world')).toEqual('helloworld') 13 | }) 14 | 15 | it('*', () => { 16 | expect(S.concat('hello', 'world')).toEqual('helloworld') 17 | }) 18 | }) 19 | 20 | describe('concat (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe('hello', S.concat('world'))) 23 | expectType(pipe(['hello', 'world'], A.reduce('', S.concat))) 24 | }) 25 | 26 | it('returns a new string with append added after str', () => { 27 | expect(pipe('hello', S.concat('world'))).toEqual('helloworld') 28 | }) 29 | 30 | it('*', () => { 31 | expect(pipe('ts', S.concat('belt'))).toEqual('tsbelt') 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /scripts/test.ts: -------------------------------------------------------------------------------- 1 | import { task, desc, option, setGlobalOptions } from 'foy' 2 | import * as globby from 'globby' 3 | 4 | setGlobalOptions({ 5 | strict: true, 6 | logCommand: false, 7 | loading: false, 8 | }) 9 | 10 | type Options = { 11 | readonly namespace: string 12 | readonly file: string 13 | readonly coverage: boolean 14 | } 15 | 16 | desc('Run tests') 17 | option('-n, --namespace ', 'namespace') 18 | option('-f, --file ', 'file') 19 | option('-c, --coverage', 'coverage') 20 | task('run', async ctx => { 21 | const coverage = ctx.options.coverage ? '--coverage' : '' 22 | 23 | const cmd = ['yarn', 'jest', coverage] 24 | 25 | if (ctx.options.namespace || ctx.options.file) { 26 | const namespace = ctx.options.namespace || '**' 27 | const file = ctx.options.file ? `${ctx.options.file}.test.ts` : '*.test.ts' 28 | 29 | const files = await globby(`__tests__/${namespace}/${file}`) 30 | 31 | cmd.push(...files) 32 | 33 | await ctx.exec(cmd.join(' ')) 34 | return 35 | } 36 | 37 | await ctx.exec(cmd.join(' ')) 38 | }) 39 | -------------------------------------------------------------------------------- /__tests__/String/getUnsafe.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S, A, pipe } from '../..' 4 | 5 | describe('getUnsafe', () => { 6 | it('provides correct types', () => { 7 | expectType(S.getUnsafe('hello', 0)) 8 | expectType>(A.map(['hello', 'world'], S.getUnsafe(1))) 9 | }) 10 | 11 | it('returns the nth element of the given string', () => { 12 | expect(S.getUnsafe('hello', 1)).toEqual('e') 13 | }) 14 | 15 | it('*', () => { 16 | expect(S.getUnsafe('hello', 1)).toEqual('e') 17 | }) 18 | }) 19 | 20 | describe('getUnsafe (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe('hello', S.getUnsafe(1))) 23 | expectType>( 24 | pipe(['hello', 'world'], A.map(S.getUnsafe(1))), 25 | ) 26 | }) 27 | 28 | it('returns the nth element of the given string', () => { 29 | expect(pipe('ts-belt', S.getUnsafe(1))).toEqual('s') 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe('world', S.getUnsafe(1))).toEqual('o') 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /__tests__/String/prepend.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S, A, pipe } from '../..' 4 | 5 | describe('prepend', () => { 6 | it('provides correct types', () => { 7 | expectType(S.prepend('hello', 'world')) 8 | expectType(A.reduce(['hello', 'world'], '', S.prepend)) 9 | }) 10 | 11 | it('returns a new string with append added after str', () => { 12 | expect(S.prepend('hello', 'world')).toEqual('worldhello') 13 | }) 14 | 15 | it('*', () => { 16 | expect(S.prepend('hello', 'world')).toEqual('worldhello') 17 | }) 18 | }) 19 | 20 | describe('prepend (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe('hello', S.prepend('world'))) 23 | expectType(pipe(['hello', 'world'], A.reduce('', S.prepend))) 24 | }) 25 | 26 | it('returns a new string with append added after str', () => { 27 | expect(pipe('hello', S.prepend('world'))).toEqual('worldhello') 28 | }) 29 | 30 | it('*', () => { 31 | expect(pipe('ts', S.prepend('belt'))).toEqual('beltts') 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /__tests__/Bool/implies.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { B, pipe } from '../..' 4 | 5 | describe('implies', () => { 6 | it('provides correct types', () => { 7 | expectType(B.implies(true, true)) 8 | }) 9 | 10 | it('combines two booleans using an implication', () => { 11 | expect(B.implies(true, true)).toEqual(true) 12 | expect(B.implies(false, false)).toEqual(true) 13 | expect(B.implies(true, false)).toEqual(false) 14 | }) 15 | 16 | it('*', () => { 17 | expect(B.implies(false, true)).toEqual(true) 18 | }) 19 | }) 20 | 21 | describe('implies (pipe)', () => { 22 | it('provides correct types', () => { 23 | expectType(pipe(true, B.implies(true))) 24 | }) 25 | 26 | it('combines two booleans using an implication', () => { 27 | expect(pipe(true, B.implies(true))).toEqual(true) 28 | expect(pipe(false, B.implies(false))).toEqual(true) 29 | expect(pipe(true, B.implies(false))).toEqual(false) 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe(true, B.implies(false))).toEqual(false) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /__tests__/String/remove.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { S, A, pipe } from '../..' 4 | 5 | describe('remove', () => { 6 | it('provides correct types', () => { 7 | expectType(S.remove('hello', 'h')) 8 | expectType>(A.map(['hello', 'world'], S.remove('o'))) 9 | }) 10 | 11 | it('returns true if the given string starts with substr', () => { 12 | expect(S.remove('hello', 'o')).toEqual('hell') 13 | }) 14 | 15 | it('*', () => { 16 | expect(S.remove('hello', 'l')).toEqual('helo') 17 | }) 18 | }) 19 | 20 | describe('remove (pipe)', () => { 21 | it('provides correct types', () => { 22 | expectType(pipe('hello', S.remove('h'))) 23 | expectType>( 24 | pipe(['hello', 'world'], A.map(S.remove('h'))), 25 | ) 26 | }) 27 | 28 | it('returns true if the given string ends with substr', () => { 29 | expect(pipe('ts-belt', S.remove('ts'))).toEqual('-belt') 30 | }) 31 | 32 | it('*', () => { 33 | expect(pipe('ts-belt', S.remove('ts-'))).toEqual('belt') 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/menhirLib.20211012/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "https://gitlab.inria.fr/fpottier/menhir/-/issues" 10 | license: "LGPL-2.0-only with OCaml-LGPL-linking-exception" 11 | build: [ 12 | ["dune" "build" "-p" name "-j" jobs] 13 | ] 14 | depends: [ 15 | "ocaml" { >= "4.02.3" } 16 | "dune" { >= "2.0.0" } 17 | ] 18 | conflicts: [ 19 | "menhir" { != version } 20 | ] 21 | synopsis: "Runtime support library for parsers generated by Menhir" 22 | url { 23 | src: 24 | "https://gitlab.inria.fr/fpottier/menhir/-/archive/20211012/archive.tar.gz" 25 | checksum: [ 26 | "md5=f631f4c03859254a7d725f054633ee44" 27 | "sha512=13376d3c07158c36dd9b4617294a7e4d53ba90062ab09fae48c36b76f08133e2ffc4be13a1bc88980617c5d1046631844815c9ee7fd7c821699bacaf245b1ed8" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /tools/comment-ppx/esy.lock/opam/menhirSdk.20211012/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "https://gitlab.inria.fr/fpottier/menhir/-/issues" 10 | license: "LGPL-2.0-only with OCaml-LGPL-linking-exception" 11 | build: [ 12 | ["dune" "build" "-p" name "-j" jobs] 13 | ] 14 | depends: [ 15 | "ocaml" { >= "4.02.3" } 16 | "dune" { >= "2.0.0" } 17 | ] 18 | conflicts: [ 19 | "menhir" { != version } 20 | ] 21 | synopsis: "Compile-time library for auxiliary tools related to Menhir" 22 | url { 23 | src: 24 | "https://gitlab.inria.fr/fpottier/menhir/-/archive/20211012/archive.tar.gz" 25 | checksum: [ 26 | "md5=f631f4c03859254a7d725f054633ee44" 27 | "sha512=13376d3c07158c36dd9b4617294a7e4d53ba90062ab09fae48c36b76f08133e2ffc4be13a1bc88980617c5d1046631844815c9ee7fd7c821699bacaf245b1ed8" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /__tests__/Function/memoizeWithKey.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect' 2 | 3 | import { F, N, A, S } from '../..' 4 | 5 | const fn = (n: number) => { 6 | return `called ${n} times` 7 | } 8 | 9 | describe('memoizeWithKey', () => { 10 | it('provides correct types', () => { 11 | expectType<(n: number) => string>(F.memoizeWithKey(S.make, fn)) 12 | expectType<(n: number) => number>(F.memoizeWithKey(S.make, N.add(2))) 13 | }) 14 | 15 | it('*', () => { 16 | let calls = 0 17 | const makeArray = F.memoizeWithKey(S.make, (value: number) => { 18 | calls = calls + 1 19 | return A.makeWithIndex(value, index => index * 2) 20 | }) 21 | 22 | expect( 23 | /* 24 | let calls = 0 25 | const makeArray = F.memoizeWithKey(S.make, (value: number) => { 26 | calls = calls + 1 27 | return A.makeWithIndex(value, index => index * 2) 28 | }) 29 | */ 30 | makeArray(4), 31 | ).toEqual([0, 2, 4, 6]) 32 | expect(makeArray(4)).toEqual([0, 2, 4, 6]) 33 | expect(makeArray(4)).toEqual([0, 2, 4, 6]) 34 | expect(calls).toEqual(1) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /docs/api/option.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: option 3 | title: Option 4 | --- 5 | 6 | import Option, { toc as optiontoc } from "./generated/_option.mdx" 7 | 8 | Belt (ReScript) represents the existence and nonexistence of a value by wrapping it with the `Option` type. TS Belt does the same and provides utility-functions for convenient work with the `Option` type. 9 | 10 | ```ts 11 | type Option = T | undefined | null 12 | ``` 13 | 14 | :::warning 15 | 16 | Adding `noUncheckedIndexedAccess` to your `tsconfig.json` is mandatory for the `Option` type! 17 | 18 | ::: 19 | 20 | ```jsx live 21 | function() { 22 | // ⬇️ remove all elements in the array below in order to see the default value 23 | const xs = ['hello', 'world', 'ts', 'belt'] 24 | const value = pipe( 25 | O.fromNullable(xs), // → Some(['hello', 'world', 'ts', 'belt']) 26 | O.flatMap(A.dropExactly(2)), // → Some(['ts', 'belt']) 27 | O.map(A.join('-')), // → Some('ts-belt') 28 | O.getWithDefault('default value'), // returns `default value` if `None` 29 | ) 30 | 31 | return value 32 | } 33 | ``` 34 | 35 |