├── .circleci └── config.yml ├── .config ├── .eslintrc.json ├── .github ├── CONTRIBUTING.md └── FUNDING.yml ├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── dist └── bundle.js ├── index.js ├── package.json ├── scripts ├── .eslintrc.json ├── bundle ├── generate-readme ├── lint └── prepublish └── test ├── .eslintrc.json ├── I.js ├── Just.js ├── K.js ├── Left.js ├── NODE_ENV.js ├── Nothing.js ├── Pair.js ├── Right.js ├── T.js ├── add.js ├── all.js ├── alt.js ├── and.js ├── any.js ├── ap.js ├── apFirst.js ├── apSecond.js ├── append.js ├── array.js ├── bimap.js ├── boolean.js ├── chain.js ├── chainRec.js ├── clamp.js ├── complement.js ├── compose.js ├── concat.js ├── contramap.js ├── create.js ├── div.js ├── drop.js ├── dropLast.js ├── dropWhile.js ├── duplicate.js ├── either.js ├── elem.js ├── elem_.js ├── empty.js ├── encase.js ├── env.js ├── equals.js ├── even.js ├── extend.js ├── extract.js ├── filter.js ├── find.js ├── findMap.js ├── flip.js ├── foldMap.js ├── fromEither.js ├── fromLeft.js ├── fromMaybe.js ├── fromMaybe_.js ├── fromPairs.js ├── fromRight.js ├── fst.js ├── get.js ├── gets.js ├── groupBy.js ├── gt.js ├── gte.js ├── head.js ├── id.js ├── ifElse.js ├── init.js ├── insert.js ├── intercalate.js ├── internal ├── List.cjs ├── List.mjs ├── Sum.cjs ├── Sum.mjs ├── area.js ├── factorial.js ├── rem.js ├── sanctuary.js └── strMap.js ├── invert.js ├── is.js ├── isJust.js ├── isLeft.js ├── isNothing.js ├── isRight.js ├── join.js ├── joinWith.js ├── justs.js ├── keys.js ├── last.js ├── lefts.js ├── lift2.js ├── lift3.js ├── lines.js ├── lt.js ├── lte.js ├── map.js ├── mapLeft.js ├── mapMaybe.js ├── match.js ├── matchAll.js ├── max.js ├── maybe.js ├── maybeToNullable.js ├── maybe_.js ├── min.js ├── mult.js ├── negate.js ├── none.js ├── not.js ├── odd.js ├── of.js ├── on.js ├── or.js ├── package.json ├── pairs.js ├── pair~.js ├── parseDate.js ├── parseFloat.js ├── parseInt.js ├── parseJson.js ├── pipe.js ├── pipeK.js ├── pow.js ├── prepend.js ├── product.js ├── promap.js ├── prop.js ├── props.js ├── range.js ├── reduce.js ├── reduce_.js ├── regex.js ├── regexEscape.js ├── reject.js ├── remove.js ├── replace.js ├── reverse.js ├── rights.js ├── sequence.js ├── show.js ├── singleton.js ├── size.js ├── snd.js ├── sort.js ├── sortBy.js ├── splitOn.js ├── splitOnRegex.js ├── stripPrefix.js ├── stripSuffix.js ├── sub.js ├── sum.js ├── swap.js ├── tagBy.js ├── tail.js ├── take.js ├── takeLast.js ├── takeWhile.js ├── test.js ├── toLower.js ├── toUpper.js ├── traverse.js ├── trim.js ├── type.js ├── unchecked.js ├── unfold.js ├── unless.js ├── unlines.js ├── unwords.js ├── value.js ├── values.js ├── when.js ├── words.js ├── zero.js ├── zip.js └── zipWith.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | node: circleci/node@6.3.0 5 | 6 | workflows: 7 | test: 8 | jobs: 9 | - node/test: 10 | setup: 11 | # derive cache key from package.json 12 | - run: cp package.json package-lock.json 13 | override-ci-command: rm package-lock.json && npm install && git checkout -- package.json 14 | matrix: 15 | parameters: 16 | version: 17 | - 18.0.0 18 | - 20.0.0 19 | - 22.0.0 20 | -------------------------------------------------------------------------------- /.config: -------------------------------------------------------------------------------- 1 | repo-owner = sanctuary-js 2 | repo-name = sanctuary 3 | contributing-file = .github/CONTRIBUTING.md 4 | module-type = commonjs 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["./node_modules/sanctuary-style/eslint.json"], 4 | "overrides": [ 5 | { 6 | "files": ["index.js"], 7 | "globals": {"__doctest": "readonly", "define": "readonly", "module": "readonly", "process": "readonly", "require": "readonly", "self": "readonly"}, 8 | "rules": { 9 | "max-len": ["error", {"code": 79, "ignoreUrls": true, "ignoreTemplateLiterals": true, "ignorePattern": "^ *//(# | .* :: |[.] > |[.] // |[.] \\[.*\\]: |[.] .* Function x )"}], 10 | "no-param-reassign": ["off"] 11 | } 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Note: __README.md__ is generated from comments in __index.js__. Do not modify 4 | __README.md__ directly. 5 | 6 | 1. Update local main branch: 7 | 8 | $ git checkout main 9 | $ git pull upstream main 10 | 11 | 2. Create feature branch: 12 | 13 | $ git checkout -b feature-x 14 | 15 | 3. Make one or more atomic commits, and ensure that each commit has a 16 | descriptive commit message. Commit messages should be line wrapped 17 | at 72 characters. 18 | 19 | 4. Run `npm test`, and address any errors. Preferably, fix commits in place 20 | using `git rebase` or `git commit --amend` to make the changes easier to 21 | review. 22 | 23 | 5. Push: 24 | 25 | $ git push origin feature-x 26 | 27 | 6. Open a pull request. 28 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [davidchambers, Avaq] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Sanctuary 4 | Copyright (c) 2016 Plaid Technologies, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or 11 | sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanctuary", 3 | "version": "3.1.0", 4 | "description": "Refuge from unsafe JavaScript", 5 | "license": "MIT", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/sanctuary-js/sanctuary.git" 9 | }, 10 | "scripts": { 11 | "doctest": "sanctuary-doctest", 12 | "lint": "sanctuary-lint", 13 | "release": "sanctuary-release", 14 | "test": "npm run lint && sanctuary-test && npm run doctest" 15 | }, 16 | "dependencies": { 17 | "sanctuary-def": "0.22.0", 18 | "sanctuary-either": "2.1.0", 19 | "sanctuary-maybe": "2.1.0", 20 | "sanctuary-pair": "2.1.0", 21 | "sanctuary-show": "2.0.0", 22 | "sanctuary-type-classes": "12.1.0", 23 | "sanctuary-type-identifiers": "3.0.0" 24 | }, 25 | "devDependencies": { 26 | "fantasy-land": "5.0.0", 27 | "jsverify": "0.8.x", 28 | "sanctuary-descending": "2.1.0", 29 | "sanctuary-identity": "2.1.0", 30 | "sanctuary-scripts": "7.0.x" 31 | }, 32 | "files": [ 33 | "/LICENSE", 34 | "/README.md", 35 | "/index.js", 36 | "/package.json" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /scripts/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["../.eslintrc.json"], 4 | "env": {"node": true} 5 | } 6 | -------------------------------------------------------------------------------- /scripts/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | const fs = require ('node:fs'); 6 | const path = require ('node:path'); 7 | 8 | const sanctuary = require ('../package.json'); 9 | 10 | 11 | if (!(Object.prototype.hasOwnProperty.call (process.env, 'VERSION'))) { 12 | process.stderr.write ('VERSION not specified\n'); 13 | process.exit (1); 14 | } 15 | const VERSION = process.env.VERSION; 16 | 17 | // expandDependencies :: StrMap String -> StrMap (Array String) 18 | const expandDependencies = children => { 19 | const descendants = Object.create (null); 20 | const todo = Object.keys (children); 21 | while (todo.length > 0) { 22 | const name = todo.shift (); 23 | descendants[name] = Object.keys ( 24 | (require (`../node_modules/${name}/package.json`)).dependencies 25 | ); 26 | Array.prototype.push.apply (todo, descendants[name]); 27 | } 28 | return descendants; 29 | }; 30 | 31 | // orderDependencies :: StrMap (Array String) -> Array String 32 | const orderDependencies = deps => { 33 | const done = []; 34 | const todo = (Object.keys (deps)).sort (); 35 | while (todo.length > 0) { 36 | const name = todo.shift (); 37 | (deps[name].every (name => done.includes (name)) ? done : todo) 38 | .push (name); 39 | } 40 | return done; 41 | }; 42 | 43 | // dependencies :: Array String 44 | const dependencies = 45 | orderDependencies (expandDependencies (sanctuary.dependencies)); 46 | 47 | process.stdout.write ( 48 | `// sanctuary@${VERSION} with bundled dependencies: 49 | // 50 | ${dependencies 51 | .map (name => `// - ${name}@${(require (name + '/package.json')).version}`) 52 | .join ('\n')} 53 | 54 | ${dependencies 55 | .map (name => fs.readFileSync (path.join ('node_modules', name, 'index.js'), 56 | 'utf8')) 57 | .join ('\n')} 58 | ${fs.readFileSync ('index.js', 'utf8')}` 59 | ); 60 | -------------------------------------------------------------------------------- /scripts/generate-readme: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euf -o pipefail 3 | 4 | cp index.js index.js.orig 5 | trap 'mv index.js.orig index.js' EXIT 6 | 7 | awk ' 8 | { 9 | if ($1 == "//." && $2 ~ /^#{1,6}$/) { 10 | text = "❑ " 11 | slug = "section:" 12 | for (n = 3 ; ; n += 1) { 13 | text = text $n 14 | gsub(/\W/, "", $n) 15 | slug = slug tolower($n) 16 | if (n == NF) { 17 | break 18 | } 19 | text = text " " 20 | slug = slug "-" 21 | } 22 | print "//. " $2 " " text "" 23 | } else { 24 | print 25 | } 26 | } 27 | ' index.js.orig >index.js 28 | 29 | node_modules/.bin/sanctuary-generate-readme 30 | -------------------------------------------------------------------------------- /scripts/lint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euf -o pipefail 3 | 4 | node_modules/.bin/sanctuary-lint "$@" 5 | 6 | node_modules/.bin/eslint \ 7 | --report-unused-disable-directives \ 8 | -- scripts/bundle 9 | -------------------------------------------------------------------------------- /scripts/prepublish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euf -o pipefail 3 | 4 | node_modules/.bin/sanctuary-prepublish "$@" 5 | 6 | rm -rf node_modules 7 | npm install 8 | mkdir -p -- dist 9 | scripts/bundle >dist/bundle.js 10 | git add -- dist/bundle.js 11 | -------------------------------------------------------------------------------- /test/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["../.eslintrc.json"], 4 | "parserOptions": {"ecmaVersion": 2020, "sourceType": "module"}, 5 | "env": {"node": true}, 6 | "rules": { 7 | "max-len": ["off"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/I.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('I', () => { 9 | 10 | eq (String (S.I), 'I :: a -> a'); 11 | 12 | eq (S.I ([1, 2, 3]), [1, 2, 3]); 13 | eq (S.I (['foo', 42]), ['foo', 42]); 14 | 15 | const x = Symbol ('x'); 16 | eq (S.I (x) === x, true); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/Just.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('Just', () => { 9 | 10 | eq (String (S.Just), 'Just :: a -> Maybe a'); 11 | 12 | eq (S.Just (42), S.Just (42)); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/K.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('K', () => { 9 | 10 | eq (String (S.K), 'K :: a -> b -> a'); 11 | 12 | eq (S.K (21) ([]), 21); 13 | eq (S.K (42) (null), 42); 14 | eq (S.K (84) (undefined), 84); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /test/Left.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('Left', () => { 9 | 10 | eq (String (S.Left), 'Left :: a -> Either a b'); 11 | 12 | eq (S.Left (42), S.Left (42)); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/NODE_ENV.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq, throws} from 'node:assert'; 2 | import fs from 'node:fs'; 3 | import module from 'node:module'; 4 | import path from 'node:path'; 5 | import url from 'node:url'; 6 | import vm from 'node:vm'; 7 | 8 | import test from 'oletus'; 9 | 10 | 11 | const __filename = url.fileURLToPath (import.meta.url); 12 | const __dirname = path.dirname (__filename); 13 | 14 | const source = fs.readFileSync (path.join (__dirname, '..', 'index.js'), 'utf8'); 15 | 16 | const {version: $$version} = ( 17 | JSON.parse ( 18 | fs.readFileSync ( 19 | path.join (__dirname, '..', 'node_modules', 'sanctuary-def', 'package.json') 20 | ) 21 | ) 22 | ); 23 | 24 | const expected = new TypeError ([ 25 | 'Invalid value', 26 | '', 27 | 'add :: FiniteNumber -> FiniteNumber -> FiniteNumber', 28 | ' ^^^^^^^^^^^^', 29 | ' 1', 30 | '', 31 | '1) "foo" :: String', 32 | '', 33 | 'The value at position 1 is not a member of ‘FiniteNumber’.', 34 | '', 35 | 'See https://github.com/sanctuary-js/sanctuary-def/tree/v' + $$version + '#FiniteNumber for information about the FiniteNumber type.', 36 | '', 37 | ].join ('\n')); 38 | 39 | test ('typeof process === "undefined"', () => { 40 | const context = { 41 | module: {exports: {}}, 42 | require: module.createRequire (import.meta.url), 43 | }; 44 | vm.runInNewContext (source, context); 45 | 46 | throws (() => { context.module.exports.add ('foo'); }, expected); 47 | }); 48 | 49 | test ('typeof process !== "undefined" && process == null', () => { 50 | const context = { 51 | module: {exports: {}}, 52 | process: null, 53 | require: module.createRequire (import.meta.url), 54 | }; 55 | vm.runInNewContext (source, context); 56 | 57 | throws (() => { context.module.exports.add ('foo'); }, expected); 58 | }); 59 | 60 | test ('typeof process !== "undefined" && process != null && process.env == null', () => { 61 | const context = { 62 | module: {exports: {}}, 63 | process: {}, 64 | require: module.createRequire (import.meta.url), 65 | }; 66 | vm.runInNewContext (source, context); 67 | 68 | throws (() => { context.module.exports.add ('foo'); }, expected); 69 | }); 70 | 71 | test ('typeof process !== "undefined" && process != null && process.env != null && process.env.NODE_ENV == null', () => { 72 | const context = { 73 | module: {exports: {}}, 74 | process: {env: {}}, 75 | require: module.createRequire (import.meta.url), 76 | }; 77 | vm.runInNewContext (source, context); 78 | 79 | throws (() => { context.module.exports.add ('foo'); }, expected); 80 | }); 81 | 82 | test ('typeof process !== "undefined" && process != null && process.env != null && process.env.NODE_ENV !== "production"', () => { 83 | const context = { 84 | module: {exports: {}}, 85 | process: {env: {NODE_ENV: 'XXX'}}, 86 | require: module.createRequire (import.meta.url), 87 | }; 88 | vm.runInNewContext (source, context); 89 | 90 | throws (() => { context.module.exports.add ('foo'); }, expected); 91 | }); 92 | 93 | test ('typeof process !== "undefined" && process != null && process.env != null && process.env.NODE_ENV === "production"', () => { 94 | const context = { 95 | module: {exports: {}}, 96 | process: {env: {NODE_ENV: 'production'}}, 97 | require: module.createRequire (import.meta.url), 98 | }; 99 | vm.runInNewContext (source, context); 100 | 101 | eq (context.module.exports.add ('foo') ('bar'), 'foobar'); 102 | }); 103 | -------------------------------------------------------------------------------- /test/Nothing.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('Nothing', () => { 9 | 10 | eq (S.show (S.Nothing), 'Nothing'); 11 | 12 | eq (S.Nothing, S.Nothing); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/Pair.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('Pair', () => { 9 | 10 | eq (String (S.Pair), 'Pair :: a -> b -> Pair a b'); 11 | 12 | eq (S.Pair ('foo') (42), S.Pair ('foo') (42)); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/Right.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('Right', () => { 9 | 10 | eq (String (S.Right), 'Right :: b -> Either a b'); 11 | 12 | eq (S.Right (42), S.Right (42)); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/T.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('T', () => { 9 | 10 | eq (String (S.T), 'T :: a -> (a -> b) -> b'); 11 | 12 | eq (S.T ('!') (S.concat ('foo')), 'foo!'); 13 | eq (S.T ('!') (S.concat ('bar')), 'bar!'); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/add.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('add', () => { 9 | 10 | eq (String (S.add), 'add :: FiniteNumber -> FiniteNumber -> FiniteNumber'); 11 | 12 | eq (S.add (1) (1), 2); 13 | eq (S.add (-1) (-1), -2); 14 | eq (S.add (1.5) (1), 2.5); 15 | eq (S.add (-1.5) (-1), -2.5); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/all.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('all', () => { 11 | 12 | eq (String (S.all), 'all :: Foldable f => (a -> Boolean) -> f a -> Boolean'); 13 | 14 | eq (S.all (S.gt (0)) ([]), true); 15 | eq (S.all (S.gt (0)) ([0]), false); 16 | eq (S.all (S.gt (0)) ([1]), true); 17 | eq (S.all (S.gt (0)) ([0, 0]), false); 18 | eq (S.all (S.gt (0)) ([0, 1]), false); 19 | eq (S.all (S.gt (0)) ([1, 0]), false); 20 | eq (S.all (S.gt (0)) ([1, 1]), true); 21 | 22 | eq (S.all (S.gt (0)) (Nil), true); 23 | eq (S.all (S.gt (0)) (Cons (0) (Nil)), false); 24 | eq (S.all (S.gt (0)) (Cons (1) (Nil)), true); 25 | eq (S.all (S.gt (0)) (Cons (0) (Cons (0) (Nil))), false); 26 | eq (S.all (S.gt (0)) (Cons (0) (Cons (1) (Nil))), false); 27 | eq (S.all (S.gt (0)) (Cons (1) (Cons (0) (Nil))), false); 28 | eq (S.all (S.gt (0)) (Cons (1) (Cons (1) (Nil))), true); 29 | 30 | eq (S.all (S.gt (0)) (S.Nothing), true); 31 | eq (S.all (S.gt (0)) (S.Just (0)), false); 32 | eq (S.all (S.gt (0)) (S.Just (1)), true); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /test/alt.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('alt', () => { 9 | 10 | eq (String (S.alt), 'alt :: Alt f => f a -> f a -> f a'); 11 | 12 | eq (S.alt ([]) ([]), []); 13 | eq (S.alt ([1, 2, 3]) ([]), [1, 2, 3]); 14 | eq (S.alt ([]) ([1, 2, 3]), [1, 2, 3]); 15 | eq (S.alt ([4, 5, 6]) ([1, 2, 3]), [1, 2, 3, 4, 5, 6]); 16 | eq (S.alt ({}) ({}), {}); 17 | eq (S.alt ({a: 1, b: 2, c: 3}) ({}), {a: 1, b: 2, c: 3}); 18 | eq (S.alt ({}) ({a: 1, b: 2, c: 3}), {a: 1, b: 2, c: 3}); 19 | eq (S.alt ({d: 4, e: 5, f: 6}) ({a: 1, b: 2, c: 3}), {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}); 20 | eq (S.alt ({c: 4, d: 5, e: 6}) ({a: 1, b: 2, c: 3}), {a: 1, b: 2, c: 4, d: 5, e: 6}); 21 | eq (S.alt (S.Nothing) (S.Nothing), S.Nothing); 22 | eq (S.alt (S.Just (1)) (S.Nothing), S.Just (1)); 23 | eq (S.alt (S.Nothing) (S.Just (2)), S.Just (2)); 24 | eq (S.alt (S.Just (4)) (S.Just (3)), S.Just (3)); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /test/and.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('and', () => { 9 | 10 | eq (String (S.and), 'and :: Boolean -> Boolean -> Boolean'); 11 | 12 | eq (S.and (false) (false), false); 13 | eq (S.and (false) (true), false); 14 | eq (S.and (true) (false), false); 15 | eq (S.and (true) (true), true); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/any.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('any', () => { 11 | 12 | eq (String (S.any), 'any :: Foldable f => (a -> Boolean) -> f a -> Boolean'); 13 | 14 | eq (S.any (S.gt (0)) ([]), false); 15 | eq (S.any (S.gt (0)) ([0]), false); 16 | eq (S.any (S.gt (0)) ([1]), true); 17 | eq (S.any (S.gt (0)) ([0, 0]), false); 18 | eq (S.any (S.gt (0)) ([0, 1]), true); 19 | eq (S.any (S.gt (0)) ([1, 0]), true); 20 | eq (S.any (S.gt (0)) ([1, 1]), true); 21 | 22 | eq (S.any (S.gt (0)) (Nil), false); 23 | eq (S.any (S.gt (0)) (Cons (0) (Nil)), false); 24 | eq (S.any (S.gt (0)) (Cons (1) (Nil)), true); 25 | eq (S.any (S.gt (0)) (Cons (0) (Cons (0) (Nil))), false); 26 | eq (S.any (S.gt (0)) (Cons (0) (Cons (1) (Nil))), true); 27 | eq (S.any (S.gt (0)) (Cons (1) (Cons (0) (Nil))), true); 28 | eq (S.any (S.gt (0)) (Cons (1) (Cons (1) (Nil))), true); 29 | 30 | eq (S.any (S.gt (0)) (S.Nothing), false); 31 | eq (S.any (S.gt (0)) (S.Just (0)), false); 32 | eq (S.any (S.gt (0)) (S.Just (1)), true); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /test/ap.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('ap', () => { 9 | 10 | eq (String (S.ap), 'ap :: Apply f => f (a -> b) -> f a -> f b'); 11 | 12 | eq (S.ap ([]) ([]), []); 13 | eq (S.ap ([]) ([1, 2, 3]), []); 14 | eq (S.ap ([S.add (1)]) ([]), []); 15 | eq (S.ap ([S.add (1)]) ([1, 2, 3]), [2, 3, 4]); 16 | eq (S.ap ([S.sub (1), Math.sqrt]) ([1, 4, 9]), [0, 3, 8, 1, 2, 3]); 17 | eq (S.ap ({}) ({}), {}); 18 | eq (S.ap ({}) ({x: 1, y: 2, z: 3}), {}); 19 | eq (S.ap ({x: S.add (1)}) ({}), {}); 20 | eq (S.ap ({x: S.add (1)}) ({x: 1}), {x: 2}); 21 | eq (S.ap ({x: S.add (1), y: S.sub (1), z: Math.sqrt}) ({w: 0, x: 1, y: 2}), {x: 2, y: 1}); 22 | eq (S.ap (S.Nothing) (S.Nothing), S.Nothing); 23 | eq (S.ap (S.Nothing) (S.Just (9)), S.Nothing); 24 | eq (S.ap (S.Just (Math.sqrt)) (S.Nothing), S.Nothing); 25 | eq (S.ap (S.Just (Math.sqrt)) (S.Just (9)), S.Just (3)); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/apFirst.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('apFirst', () => { 9 | 10 | eq (String (S.apFirst), 'apFirst :: Apply f => f a -> f b -> f a'); 11 | 12 | eq (S.apFirst ([1, 2]) ([3, 4]), [1, 1, 2, 2]); 13 | eq (S.apFirst (S.Just (1)) (S.Just (2)), S.Just (1)); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/apSecond.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('apSecond', () => { 9 | 10 | eq (String (S.apSecond), 'apSecond :: Apply f => f a -> f b -> f b'); 11 | 12 | eq (S.apSecond ([1, 2]) ([3, 4]), [3, 4, 3, 4]); 13 | eq (S.apSecond (S.Just (1)) (S.Just (2)), S.Just (2)); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/append.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('append', () => { 9 | 10 | eq (String (S.append), 'append :: (Applicative f, Semigroup f) => a -> f a -> f a'); 11 | 12 | eq (S.append (3) ([]), [3]); 13 | eq (S.append (3) ([1, 2]), [1, 2, 3]); 14 | eq (S.append ([5, 6]) ([[1, 2], [3, 4]]), [[1, 2], [3, 4], [5, 6]]); 15 | 16 | eq (S.append ([2]) (S.Nothing), S.Just ([2])); 17 | eq (S.append ([2]) (S.Just ([1])), S.Just ([1, 2])); 18 | 19 | eq (S.append ([2]) (S.Left ('error')), S.Right ([2])); 20 | eq (S.append ([2]) (S.Right ([1])), S.Right ([1, 2])); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /test/array.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('array', () => { 9 | 10 | eq (String (S.array), 'array :: b -> (a -> Array a -> b) -> Array a -> b'); 11 | 12 | const size = S.array (0) (head => tail => 1 + size (tail)); 13 | eq (size ([]), 0); 14 | eq (size (['foo']), 1); 15 | eq (size (['foo', 'bar']), 2); 16 | eq (size (['foo', 'bar', 'baz']), 3); 17 | 18 | const reverse = S.array ([]) (head => tail => S.append (head) (reverse (tail))); 19 | eq (reverse ([]), []); 20 | eq (reverse (['foo']), ['foo']); 21 | eq (reverse (['foo', 'bar']), ['bar', 'foo']); 22 | eq (reverse (['foo', 'bar', 'baz']), ['baz', 'bar', 'foo']); 23 | 24 | const tail = S.array (S.Nothing) (S.K (S.Just)); 25 | eq (tail ([]), S.Nothing); 26 | eq (tail (['foo']), S.Just ([])); 27 | eq (tail (['foo', 'bar']), S.Just (['bar'])); 28 | eq (tail (['foo', 'bar', 'baz']), S.Just (['bar', 'baz'])); 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /test/bimap.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('bimap', () => { 9 | 10 | eq (String (S.bimap), 'bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d'); 11 | 12 | eq (S.bimap (S.toUpper) (S.add (1)) (S.Left ('xxx')), S.Left ('XXX')); 13 | eq (S.bimap (S.toUpper) (S.add (1)) (S.Right (1000)), S.Right (1001)); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/boolean.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('boolean', () => { 9 | 10 | eq (String (S.boolean), 'boolean :: a -> a -> Boolean -> a'); 11 | 12 | eq (S.boolean ('no') ('yes') (false), 'no'); 13 | eq (S.boolean ('no') ('yes') (true), 'yes'); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/chain.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('chain', () => { 9 | 10 | eq (String (S.chain), 'chain :: Chain m => (a -> m b) -> m a -> m b'); 11 | 12 | eq (S.chain (S.I) ([[1, 2], [3, 4], [5, 6]]), [1, 2, 3, 4, 5, 6]); 13 | eq (S.chain (S.parseFloat) (S.Nothing), S.Nothing); 14 | eq (S.chain (S.parseFloat) (S.Just ('X')), S.Nothing); 15 | eq (S.chain (S.parseFloat) (S.Just ('0')), S.Just (0)); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/chainRec.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('chainRec', () => { 9 | 10 | eq (String (S.chainRec), 'chainRec :: ChainRec m => TypeRep (m b) -> (a -> m (Either a b)) -> a -> m b'); 11 | 12 | eq (S.chainRec (Array) 13 | (s => s.length === 2 ? S.map (S.Right) ([s + '!', s + '?']) 14 | : S.map (S.Left) ([s + 'o', s + 'n'])) 15 | (''), 16 | ['oo!', 'oo?', 'on!', 'on?', 'no!', 'no?', 'nn!', 'nn?']); 17 | 18 | // The following test case is concerned with stack usage rather than with 19 | // the correctness of the result. This test case is a slightly modified 20 | // version of one from sanctuary-type-classes. The "stop" value is lower 21 | // to prevent the execution time from exceeding the test runner's timeout. 22 | eq (S.chainRec (Function) 23 | (n => n === 3000 ? S.map (S.Right) (env => n + env.inc) 24 | : S.map (S.Left) (env => n + env.step)) 25 | (0) 26 | ({step: 2, inc: 100}), 27 | 3100); 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /test/clamp.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('clamp', () => { 9 | 10 | eq (String (S.clamp), 'clamp :: Ord a => a -> a -> a -> a'); 11 | 12 | eq (S.clamp (0) (100) (-1), 0); 13 | eq (S.clamp (0) (100) (0), 0); 14 | eq (S.clamp (0) (100) (50), 50); 15 | eq (S.clamp (0) (100) (100), 100); 16 | eq (S.clamp (0) (100) (101), 100); 17 | 18 | eq (S.clamp ('A') ('Z') ('0'), 'A'); 19 | eq (S.clamp ('A') ('Z') ('A'), 'A'); 20 | eq (S.clamp ('A') ('Z') ('X'), 'X'); 21 | eq (S.clamp ('A') ('Z') ('Z'), 'Z'); 22 | eq (S.clamp ('A') ('Z') ('~'), 'Z'); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/complement.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('complement', () => { 9 | 10 | eq (String (S.complement), 'complement :: (a -> Boolean) -> a -> Boolean'); 11 | 12 | eq (S.complement (S.odd) (1), false); 13 | eq (S.complement (S.odd) (2), true); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/compose.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('compose', () => { 9 | 10 | eq (String (S.compose), 'compose :: Semigroupoid s => s b c -> s a b -> s a c'); 11 | 12 | eq (S.compose (S.mult (2)) (S.add (1)) (20), 42); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/concat.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('concat', () => { 9 | 10 | eq (String (S.concat), 'concat :: Semigroup a => a -> a -> a'); 11 | 12 | eq (S.concat ([]) ([]), []); 13 | eq (S.concat ([1, 2, 3]) ([]), [1, 2, 3]); 14 | eq (S.concat ([]) ([4, 5, 6]), [4, 5, 6]); 15 | eq (S.concat ([1, 2, 3]) ([4, 5, 6]), [1, 2, 3, 4, 5, 6]); 16 | 17 | eq (S.concat ('') (''), ''); 18 | eq (S.concat ('foo') (''), 'foo'); 19 | eq (S.concat ('') ('bar'), 'bar'); 20 | eq (S.concat ('foo') ('bar'), 'foobar'); 21 | 22 | eq (S.concat (S.Nothing) (S.Nothing), S.Nothing); 23 | eq (S.concat (S.Just ('foo')) (S.Nothing), S.Just ('foo')); 24 | eq (S.concat (S.Nothing) (S.Just ('bar')), S.Just ('bar')); 25 | eq (S.concat (S.Just ('foo')) (S.Just ('bar')), S.Just ('foobar')); 26 | 27 | eq (S.concat (S.Left ('abc')) (S.Left ('def')), S.Left ('abcdef')); 28 | eq (S.concat (S.Right ([1, 2, 3])) (S.Left ('def')), S.Right ([1, 2, 3])); 29 | eq (S.concat (S.Left ('abc')) (S.Right ([4, 5, 6])), S.Right ([4, 5, 6])); 30 | eq (S.concat (S.Right ([1, 2, 3])) (S.Right ([4, 5, 6])), S.Right ([1, 2, 3, 4, 5, 6])); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /test/contramap.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('contramap', () => { 9 | 10 | eq (String (S.contramap), 'contramap :: Contravariant f => (b -> a) -> f a -> f b'); 11 | 12 | eq (S.contramap (S.prop ('length')) (Math.sqrt) ('Sanctuary'), 3); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/create.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq, throws} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import $ from 'sanctuary-def'; 5 | 6 | import S from '../index.js'; 7 | 8 | 9 | // FooTrue42 :: Type 10 | const FooTrue42 = $.EnumType ('my-package/FooTrue42') ('') (['foo', true, 42]); 11 | 12 | // customEnv :: Array Type 13 | const customEnv = S.env.concat ([FooTrue42]); 14 | 15 | const checkedDefaultEnv = S.create ({checkTypes: true, env: S.env}); 16 | const checkedCustomEnv = S.create ({checkTypes: true, env: customEnv}); 17 | const uncheckedDefaultEnv = S.create ({checkTypes: false, env: S.env}); 18 | const uncheckedCustomEnv = S.create ({checkTypes: false, env: customEnv}); 19 | 20 | 21 | test ('create', () => { 22 | 23 | eq (String (S.create), 'create :: { checkTypes :: Boolean, env :: Array Any } -> Object'); 24 | 25 | const expected = S.sort (Object.keys (S)); 26 | eq (S.sort (Object.keys (checkedDefaultEnv)), expected); 27 | eq (S.sort (Object.keys (checkedCustomEnv)), expected); 28 | eq (S.sort (Object.keys (uncheckedDefaultEnv)), expected); 29 | eq (S.sort (Object.keys (uncheckedCustomEnv)), expected); 30 | 31 | eq (checkedDefaultEnv.env, S.env); 32 | eq (checkedCustomEnv.env, customEnv); 33 | eq (uncheckedDefaultEnv.env, S.env); 34 | eq (uncheckedCustomEnv.env, customEnv); 35 | 36 | eq (checkedDefaultEnv.unchecked.env, S.env); 37 | eq (checkedCustomEnv.unchecked.env, customEnv); 38 | eq (uncheckedDefaultEnv.unchecked.env, S.env); 39 | eq (uncheckedCustomEnv.unchecked.env, customEnv); 40 | 41 | eq (uncheckedDefaultEnv.add (1) (42), S.add (1) (42)); 42 | eq (uncheckedDefaultEnv.add (1) ('XXX'), '1XXX'); 43 | 44 | throws (() => { S.I (['foo', 'foo', 42]); }, 45 | new TypeError ('Type-variable constraint violation\n' + 46 | '\n' + 47 | 'I :: a -> a\n' + 48 | ' ^\n' + 49 | ' 1\n' + 50 | '\n' + 51 | '1) ["foo", "foo", 42] :: Array ???\n' + 52 | '\n' + 53 | 'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n')); 54 | 55 | eq (checkedCustomEnv.I (['foo', 'foo', 42]), ['foo', 'foo', 42]); 56 | 57 | }); 58 | -------------------------------------------------------------------------------- /test/div.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('div', () => { 9 | 10 | eq (String (S.div), 'div :: NonZeroFiniteNumber -> FiniteNumber -> FiniteNumber'); 11 | 12 | eq (S.map (S.div (2)) ([0, 1, 2, 3]), [0, 0.5, 1, 1.5]); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/drop.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('drop', () => { 11 | 12 | eq (String (S.drop), 'drop :: (Applicative f, Foldable f, Monoid f) => Integer -> f a -> Maybe (f a)'); 13 | 14 | eq (S.drop (0) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3, 4, 5])); 15 | eq (S.drop (1) ([1, 2, 3, 4, 5]), S.Just ([2, 3, 4, 5])); 16 | eq (S.drop (2) ([1, 2, 3, 4, 5]), S.Just ([3, 4, 5])); 17 | eq (S.drop (3) ([1, 2, 3, 4, 5]), S.Just ([4, 5])); 18 | eq (S.drop (4) ([1, 2, 3, 4, 5]), S.Just ([5])); 19 | eq (S.drop (5) ([1, 2, 3, 4, 5]), S.Just ([])); 20 | eq (S.drop (6) ([1, 2, 3, 4, 5]), S.Nothing); 21 | 22 | eq (S.drop (-1) ([1, 2, 3, 4, 5]), S.Nothing); 23 | 24 | eq (S.drop (0) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Cons (2) (Cons (3) (Nil))))); 25 | eq (S.drop (1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (2) (Cons (3) (Nil)))); 26 | eq (S.drop (2) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (3) (Nil))); 27 | eq (S.drop (3) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Nil)); 28 | eq (S.drop (4) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 29 | 30 | eq (S.drop (-1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /test/dropLast.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('dropLast', () => { 11 | 12 | eq (String (S.dropLast), 'dropLast :: (Applicative f, Foldable f, Monoid f) => Integer -> f a -> Maybe (f a)'); 13 | 14 | eq (S.dropLast (0) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3, 4, 5])); 15 | eq (S.dropLast (1) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3, 4])); 16 | eq (S.dropLast (2) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3])); 17 | eq (S.dropLast (3) ([1, 2, 3, 4, 5]), S.Just ([1, 2])); 18 | eq (S.dropLast (4) ([1, 2, 3, 4, 5]), S.Just ([1])); 19 | eq (S.dropLast (5) ([1, 2, 3, 4, 5]), S.Just ([])); 20 | eq (S.dropLast (6) ([1, 2, 3, 4, 5]), S.Nothing); 21 | 22 | eq (S.dropLast (-1) ([1, 2, 3, 4, 5]), S.Nothing); 23 | 24 | eq (S.dropLast (0) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Cons (2) (Cons (3) (Nil))))); 25 | eq (S.dropLast (1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Cons (2) (Nil)))); 26 | eq (S.dropLast (2) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Nil))); 27 | eq (S.dropLast (3) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Nil)); 28 | eq (S.dropLast (4) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 29 | 30 | eq (S.dropLast (-1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /test/dropWhile.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('dropWhile', () => { 9 | 10 | eq (String (S.dropWhile), 'dropWhile :: (a -> Boolean) -> Array a -> Array a'); 11 | 12 | eq (S.dropWhile (S.odd) ([3, 3, 3, 7, 6, 3, 5, 4]), [6, 3, 5, 4]); 13 | eq (S.dropWhile (S.even) ([3, 3, 3, 7, 6, 3, 5, 4]), [3, 3, 3, 7, 6, 3, 5, 4]); 14 | eq (S.dropWhile (S.odd) ([]), []); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /test/duplicate.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('duplicate', () => { 9 | 10 | eq (String (S.duplicate), 'duplicate :: Extend w => w a -> w (w a)'); 11 | 12 | eq (S.duplicate ([]), []); 13 | eq (S.duplicate ([1]), [[1]]); 14 | eq (S.duplicate ([1, 2]), [[1, 2], [2]]); 15 | eq (S.duplicate ([1, 2, 3]), [[1, 2, 3], [2, 3], [3]]); 16 | eq (S.duplicate (S.reverse) ([1, 2]) ([3, 4]), [4, 3, 2, 1]); 17 | eq (S.duplicate (S.Just (1)), S.Just (S.Just (1))); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/either.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('either', () => { 9 | 10 | eq (String (S.either), 'either :: (a -> c) -> (b -> c) -> Either a b -> c'); 11 | 12 | eq (S.either (S.prop ('length')) (Math.sqrt) (S.Left ('abc')), 3); 13 | eq (S.either (S.prop ('length')) (Math.sqrt) (S.Right (256)), 16); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/elem.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('elem', () => { 9 | 10 | eq (String (S.elem), 'elem :: (Setoid a, Foldable f) => a -> f a -> Boolean'); 11 | 12 | eq (S.elem ('c') (['a', 'b', 'c']), true); 13 | eq (S.elem ('x') (['a', 'b', 'c']), false); 14 | eq (S.elem (3) ({x: 1, y: 2, z: 3}), true); 15 | eq (S.elem (8) ({x: 1, y: 2, z: 3}), false); 16 | eq (S.elem (0) (S.Just (0)), true); 17 | eq (S.elem (0) (S.Just (1)), false); 18 | eq (S.elem (0) (S.Nothing), false); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/elem_.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('elem_', () => { 9 | 10 | eq (String (S.elem_), 'elem_ :: (Setoid a, Foldable f) => f a -> a -> Boolean'); 11 | 12 | eq (S.elem_ (['a', 'b', 'c']) ('c'), true); 13 | eq (S.elem_ (['a', 'b', 'c']) ('x'), false); 14 | eq (S.elem_ ({x: 1, y: 2, z: 3}) (3), true); 15 | eq (S.elem_ ({x: 1, y: 2, z: 3}) (8), false); 16 | eq (S.elem_ (S.Just (0)) (0), true); 17 | eq (S.elem_ (S.Just (1)) (0), false); 18 | eq (S.elem_ (S.Nothing) (0), false); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/empty.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('empty', () => { 9 | 10 | eq (String (S.empty), 'empty :: Monoid a => TypeRep a -> a'); 11 | 12 | eq (S.empty (String), ''); 13 | eq (S.empty (Array), []); 14 | eq (S.empty (Object), {}); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /test/encase.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import area from './internal/area.js'; 8 | import factorial from './internal/factorial.js'; 9 | import rem from './internal/rem.js'; 10 | 11 | 12 | test ('encase', () => { 13 | 14 | eq (String (S.encase), 'encase :: (Throwing e a b) -> a -> Either e b'); 15 | 16 | // safeFactorial :: Number -> Maybe Number 17 | const safeFactorial = S.encase (factorial); 18 | 19 | eq (safeFactorial (5), S.Right (120)); 20 | eq (safeFactorial (-1), S.Left ('Cannot determine factorial of negative number')); 21 | 22 | // safeRem :: Number -> Number -> Maybe Number 23 | const safeRem = S.compose (S.encase) (rem); 24 | 25 | eq (safeRem (42) (5), S.Right (2)); 26 | eq (safeRem (42) (0), S.Left (new Error ('Cannot divide by zero'))); 27 | 28 | // safeArea :: Number -> Number -> Number -> Maybe Number 29 | const safeArea = S.compose (S.compose (S.encase)) (area); 30 | 31 | eq (safeArea (3) (4) (5), S.Right (6)); 32 | eq (safeArea (2) (2) (5), S.Left (new Error ('Impossible triangle'))); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /test/env.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import $ from 'sanctuary-def'; 5 | 6 | import S from '../index.js'; 7 | 8 | 9 | test ('env', () => { 10 | 11 | eq (S.is ($.Array ($.Type)) (S.env), true); 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /test/equals.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('equals', () => { 9 | 10 | eq (String (S.equals), 'equals :: Setoid a => a -> a -> Boolean'); 11 | 12 | eq (S.equals (S.Nothing) (S.Nothing), true); 13 | eq (S.equals (S.Just (NaN)) (S.Just (NaN)), true); 14 | eq (S.equals (S.Just (0)) (S.Just (-0)), true); 15 | eq (S.equals (S.Nothing) (S.Just (0)), false); 16 | eq (S.equals (S.Just (0)) (S.Just (1)), false); 17 | 18 | eq (S.equals (S.Left (NaN)) (S.Left (NaN)), true); 19 | eq (S.equals (S.Left (0)) (S.Left (-0)), true); 20 | eq (S.equals (S.Right (NaN)) (S.Right (NaN)), true); 21 | eq (S.equals (S.Right (0)) (S.Right (-0)), true); 22 | eq (S.equals (S.Left (10)) (S.Left (20)), false); 23 | eq (S.equals (S.Left (10)) (S.Right (0)), false); 24 | eq (S.equals (S.Right (0)) (S.Right (1)), false); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /test/even.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('even', () => { 9 | 10 | eq (String (S.even), 'even :: Integer -> Boolean'); 11 | 12 | eq (S.even (0), true); 13 | eq (S.even (2), true); 14 | eq (S.even (-2), true); 15 | 16 | eq (S.even (1), false); 17 | eq (S.even (-1), false); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/extend.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import Identity from 'sanctuary-identity'; 5 | 6 | import S from './internal/sanctuary.js'; 7 | 8 | 9 | test ('extend', () => { 10 | 11 | eq (String (S.extend), 'extend :: Extend w => (w a -> b) -> w a -> w b'); 12 | 13 | eq (S.extend (S.joinWith ('')) ([]), []); 14 | eq (S.extend (S.joinWith ('')) (['x']), ['x']); 15 | eq (S.extend (S.joinWith ('')) (['x', 'y']), ['xy', 'y']); 16 | eq (S.extend (S.joinWith ('')) (['x', 'y', 'z']), ['xyz', 'yz', 'z']); 17 | eq (S.extend (S.reduce (S.add) (1)) (Identity (42)), Identity (43)); 18 | eq (S.extend (S.T ([3, 4])) (S.reverse) ([1, 2]), [4, 3, 2, 1]); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/extract.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import Identity from 'sanctuary-identity'; 5 | 6 | import S from './internal/sanctuary.js'; 7 | 8 | 9 | test ('extract', () => { 10 | 11 | eq (String (S.extract), 'extract :: Comonad w => w a -> a'); 12 | 13 | eq (S.extract (Identity (42)), 42); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/filter.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('filter', () => { 11 | 12 | eq (String (S.filter), 'filter :: Filterable f => (a -> Boolean) -> f a -> f a'); 13 | 14 | eq (S.filter (S.odd) ([]), []); 15 | eq (S.filter (S.odd) ([0, 2, 4, 6, 8]), []); 16 | eq (S.filter (S.odd) ([1, 3, 5, 7, 9]), [1, 3, 5, 7, 9]); 17 | eq (S.filter (S.odd) ([1, 2, 3, 4, 5]), [1, 3, 5]); 18 | 19 | eq (S.filter (S.odd) ({}), {}); 20 | eq (S.filter (S.odd) ({x: 1}), {x: 1}); 21 | eq (S.filter (S.odd) ({x: 1, y: 2}), {x: 1}); 22 | eq (S.filter (S.odd) ({x: 1, y: 2, z: 3}), {x: 1, z: 3}); 23 | 24 | eq (S.filter (S.odd) (S.Nothing), S.Nothing); 25 | eq (S.filter (S.odd) (S.Just (0)), S.Nothing); 26 | eq (S.filter (S.odd) (S.Just (1)), S.Just (1)); 27 | 28 | eq (S.filter (S.odd) (Nil), Nil); 29 | eq (S.filter (S.odd) (Cons (1) (Nil)), Cons (1) (Nil)); 30 | eq (S.filter (S.odd) (Cons (1) (Cons (2) (Nil))), Cons (1) (Nil)); 31 | eq (S.filter (S.odd) (Cons (1) (Cons (2) (Cons (3) (Nil)))), Cons (1) (Cons (3) (Nil))); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /test/find.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('find', () => { 9 | 10 | eq (String (S.find), 'find :: Foldable f => (a -> Boolean) -> f a -> Maybe a'); 11 | 12 | eq (S.find (S.even) ([]), S.Nothing); 13 | eq (S.find (S.even) ([1, 3, 5, 7, 9]), S.Nothing); 14 | eq (S.find (S.even) ([1, 2, 3, 4, 5]), S.Just (2)); 15 | eq (S.find (S.even) ({}), S.Nothing); 16 | eq (S.find (S.even) ({a: 1, b: 3, c: 5, d: 7, e: 9}), S.Nothing); 17 | eq (S.find (S.even) ({a: 1, b: 2, c: 3, d: 4, e: 5}), S.Just (2)); 18 | eq (S.find (S.even) ({e: 5, d: 4, c: 3, b: 2, a: 1}), S.Just (2)); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/findMap.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('findMap', () => { 9 | 10 | eq (String (S.findMap), 'findMap :: Foldable f => (a -> Maybe b) -> f a -> Maybe b'); 11 | 12 | eq (S.findMap (S.parseInt (16)) ([]), S.Nothing); 13 | eq (S.findMap (S.parseInt (16)) (['H', 'G']), S.Nothing); 14 | eq (S.findMap (S.parseInt (16)) (['H', 'G', 'F', 'E']), S.Just (15)); 15 | eq (S.findMap (S.parseInt (16)) ({}), S.Nothing); 16 | eq (S.findMap (S.parseInt (16)) ({a: 'H', b: 'G'}), S.Nothing); 17 | eq (S.findMap (S.parseInt (16)) ({a: 'H', b: 'G', c: 'F', d: 'E'}), S.Just (15)); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/flip.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('flip', () => { 11 | 12 | eq (String (S.flip), 'flip :: Functor f => f (a -> b) -> a -> f b'); 13 | 14 | eq (S.flip (S.concat) ('foo') ('bar'), 'barfoo'); 15 | eq (S.map (S.flip (S.concat) ('!')) (['BAM', 'POW', 'KA-POW']), ['BAM!', 'POW!', 'KA-POW!']); 16 | eq (S.flip ([Math.floor, Math.ceil]) (1.5), [1, 2]); 17 | eq (S.flip ({floor: Math.floor, ceil: Math.ceil}) (1.5), {floor: 1, ceil: 2}); 18 | eq (S.flip (Cons (Math.floor) (Cons (Math.ceil) (Nil))) (1.5), Cons (1) (Cons (2) (Nil))); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/foldMap.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('foldMap', () => { 9 | 10 | eq (String (S.foldMap), 'foldMap :: (Monoid b, Foldable f) => TypeRep b -> (a -> b) -> f a -> b'); 11 | 12 | const repeat = n => (new Array (n + 1)).join (String (n)); 13 | eq (S.foldMap (String) (repeat) ([]), ''); 14 | eq (S.foldMap (String) (repeat) ([1]), '1'); 15 | eq (S.foldMap (String) (repeat) ([1, 2]), '122'); 16 | eq (S.foldMap (String) (repeat) ([1, 2, 3]), '122333'); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/fromEither.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('fromEither', () => { 9 | 10 | eq (String (S.fromEither), 'fromEither :: Either a a -> a'); 11 | 12 | eq (S.fromEither (S.Left (42)), 42); 13 | eq (S.fromEither (S.Right (42)), 42); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/fromLeft.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('fromLeft', () => { 9 | 10 | eq (String (S.fromLeft), 'fromLeft :: a -> Either a b -> a'); 11 | 12 | eq (S.fromLeft ('abc') (S.Left ('xyz')), 'xyz'); 13 | eq (S.fromLeft ('abc') (S.Right (123)), 'abc'); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/fromMaybe.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('fromMaybe', () => { 9 | 10 | eq (String (S.fromMaybe), 'fromMaybe :: a -> Maybe a -> a'); 11 | 12 | eq (S.fromMaybe (0) (S.Nothing), 0); 13 | eq (S.fromMaybe (0) (S.Just (42)), 42); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/fromMaybe_.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('fromMaybe_', () => { 9 | 10 | eq (String (S.fromMaybe_), 'fromMaybe_ :: (() -> a) -> Maybe a -> a'); 11 | 12 | eq (S.fromMaybe_ (() => 0) (S.Nothing), 0); 13 | eq (S.fromMaybe_ (() => 0) (S.Just (42)), 42); 14 | 15 | let count = 0; 16 | eq (S.fromMaybe_ (() => count += 1) (S.Just (42)), 42); 17 | eq (count, 0); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/fromPairs.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('fromPairs', () => { 9 | 10 | eq (String (S.fromPairs), 'fromPairs :: Foldable f => f (Pair String a) -> StrMap a'); 11 | 12 | eq (S.fromPairs ([]), 13 | {}); 14 | eq (S.fromPairs ([S.Pair ('a') (1), S.Pair ('b') (2), S.Pair ('c') (3)]), 15 | {a: 1, b: 2, c: 3}); 16 | eq (S.fromPairs ({x: S.Pair ('a') (1), y: S.Pair ('b') (2), z: S.Pair ('c') (3)}), 17 | {a: 1, b: 2, c: 3}); 18 | eq (S.fromPairs ([S.Pair ('x') (1), S.Pair ('x') (2)]), 19 | {x: 2}); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /test/fromRight.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('fromRight', () => { 9 | 10 | eq (String (S.fromRight), 'fromRight :: b -> Either a b -> b'); 11 | 12 | eq (S.fromRight (123) (S.Right (789)), 789); 13 | eq (S.fromRight (123) (S.Left ('abc')), 123); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/fst.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('fst', () => { 9 | 10 | eq (String (S.fst), 'fst :: Pair a b -> a'); 11 | 12 | eq (S.fst (S.Pair ('foo') (42)), 'foo'); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/get.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | import vm from 'node:vm'; 3 | 4 | import test from 'oletus'; 5 | import $ from 'sanctuary-def'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('get', () => { 11 | 12 | eq (String (S.get), 'get :: (Any -> Boolean) -> String -> a -> Maybe b'); 13 | 14 | eq (S.get (S.is ($.Number)) ('x') ({x: 0, y: 42}), S.Just (0)); 15 | eq (S.get (S.is ($.Number)) ('y') ({x: 0, y: 42}), S.Just (42)); 16 | eq (S.get (S.is ($.Number)) ('z') ({x: 0, y: 42}), S.Nothing); 17 | eq (S.get (S.is ($.String)) ('z') ({x: 0, y: 42}), S.Nothing); 18 | eq (S.get (S.is ($.String)) ('x') ({x: 0, y: 42}), S.Nothing); 19 | 20 | // 21 | const pattern = vm.runInNewContext ('/.*/'); 22 | eq (S.get (S.is ($.RegExp)) ('x') ({x: pattern}), S.Just (pattern)); 23 | 24 | eq (S.get (S.K (true)) ('valueOf') (null), S.Nothing); 25 | eq (S.get (S.K (true)) ('valueOf') (undefined), S.Nothing); 26 | 27 | eq (S.get (S.is ($.Array ($.Number))) ('x') ({x: [1, 2]}), S.Just ([1, 2])); 28 | eq (S.get (S.is ($.Array ($.Number))) ('x') ({x: [1, 2, null]}), S.Nothing); 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /test/gets.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | import vm from 'node:vm'; 3 | 4 | import test from 'oletus'; 5 | import $ from 'sanctuary-def'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('gets', () => { 11 | 12 | eq (String (S.gets), 'gets :: (Any -> Boolean) -> Array String -> a -> Maybe b'); 13 | 14 | eq (S.gets (S.is ($.Number)) (['x']) ({x: {z: 0}, y: 42}), S.Nothing); 15 | eq (S.gets (S.is ($.Number)) (['y']) ({x: {z: 0}, y: 42}), S.Just (42)); 16 | eq (S.gets (S.is ($.Number)) (['z']) ({x: {z: 0}, y: 42}), S.Nothing); 17 | eq (S.gets (S.is ($.Number)) (['x', 'z']) ({x: {z: 0}, y: 42}), S.Just (0)); 18 | eq (S.gets (S.is ($.Number)) (['a', 'b', 'c']) ({x: {z: 0}, y: 42}), S.Nothing); 19 | eq (S.gets (S.is ($.Number)) ([]) ({x: {z: 0}, y: 42}), S.Nothing); 20 | eq (S.gets (S.is ($.Object)) ([]) ({x: {z: 0}, y: 42}), S.Just ({x: {z: 0}, y: 42})); 21 | 22 | // 23 | const pattern = vm.runInNewContext ('/.*/'); 24 | eq (S.gets (S.is ($.RegExp)) (['x']) ({x: pattern}), S.Just (pattern)); 25 | 26 | eq (S.gets (S.K (true)) (['valueOf']) (null), S.Nothing); 27 | eq (S.gets (S.K (true)) (['valueOf']) (undefined), S.Nothing); 28 | 29 | eq (S.gets (S.is ($.Array ($.Number))) (['x']) ({x: [1, 2]}), S.Just ([1, 2])); 30 | eq (S.gets (S.is ($.Array ($.Number))) (['x']) ({x: [1, 2, null]}), S.Nothing); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /test/groupBy.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | import Z from 'sanctuary-type-classes'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('groupBy', () => { 11 | 12 | eq (String (S.groupBy), 'groupBy :: (a -> a -> Boolean) -> Array a -> Array (Array a)'); 13 | 14 | eq (S.groupBy (x => y => x * y % 3 === 0) ([]), []); 15 | eq (S.groupBy (x => y => x * y % 3 === 0) ([1, 2, 3, 4, 5, 6, 7, 8, 9]), [[1], [2, 3], [4], [5, 6], [7], [8, 9]]); 16 | eq (S.groupBy (S.equals) ([1, 1, 2, 1, 1]), [[1, 1], [2], [1, 1]]); 17 | eq (S.groupBy (x => y => x + y === 0) ([2, -3, 3, 3, 3, 4, -4, 4]), [[2], [-3, 3, 3, 3], [4, -4], [4]]); 18 | 19 | jsc.assert (jsc.forall ('nat -> nat -> bool', 'array nat', (f, xs) => { 20 | const lhs = S.join (S.groupBy (f) (xs)); 21 | const rhs = xs; 22 | return Z.equals (lhs, rhs); 23 | }), {tests: 1000}); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /test/gt.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('gt', () => { 9 | 10 | eq (String (S.gt), 'gt :: Ord a => a -> a -> Boolean'); 11 | 12 | eq (S.filter (S.gt (3)) ([1, 2, 3, 4, 5]), [4, 5]); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/gte.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('gte', () => { 9 | 10 | eq (String (S.gte), 'gte :: Ord a => a -> a -> Boolean'); 11 | 12 | eq (S.filter (S.gte (3)) ([1, 2, 3, 4, 5]), [3, 4, 5]); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/head.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('head', () => { 11 | 12 | eq (String (S.head), 'head :: Foldable f => f a -> Maybe a'); 13 | 14 | eq (S.head ([]), S.Nothing); 15 | eq (S.head (['foo']), S.Just ('foo')); 16 | eq (S.head (['foo', 'bar']), S.Just ('foo')); 17 | eq (S.head (['foo', 'bar', 'baz']), S.Just ('foo')); 18 | 19 | eq (S.head (Nil), S.Nothing); 20 | eq (S.head (Cons ('foo') (Nil)), S.Just ('foo')); 21 | eq (S.head (Cons ('foo') (Cons ('bar') (Nil))), S.Just ('foo')); 22 | eq (S.head (Cons ('foo') (Cons ('bar') (Cons ('baz') (Nil)))), S.Just ('foo')); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/id.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('id', () => { 9 | 10 | eq (String (S.id), 'id :: Category c => TypeRep c -> c'); 11 | 12 | eq (S.id (Function) (42), 42); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/ifElse.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('ifElse', () => { 9 | 10 | eq (String (S.ifElse), 'ifElse :: (a -> Boolean) -> (a -> b) -> (a -> b) -> a -> b'); 11 | 12 | eq (S.ifElse (S.odd) (S.sub (1)) (S.add (1)) (9), 8); 13 | eq (S.ifElse (S.odd) (S.sub (1)) (S.add (1)) (0), 1); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/init.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('init', () => { 11 | 12 | eq (String (S.init), 'init :: (Applicative f, Foldable f, Monoid f) => f a -> Maybe (f a)'); 13 | 14 | eq (S.init ([]), S.Nothing); 15 | eq (S.init (['foo']), S.Just ([])); 16 | eq (S.init (['foo', 'bar']), S.Just (['foo'])); 17 | eq (S.init (['foo', 'bar', 'baz']), S.Just (['foo', 'bar'])); 18 | 19 | eq (S.init (Nil), S.Nothing); 20 | eq (S.init (Cons ('foo') (Nil)), S.Just (Nil)); 21 | eq (S.init (Cons ('foo') (Cons ('bar') (Nil))), S.Just (Cons ('foo') (Nil))); 22 | eq (S.init (Cons ('foo') (Cons ('bar') (Cons ('baz') (Nil)))), S.Just (Cons ('foo') (Cons ('bar') (Nil)))); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/insert.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | import Z from 'sanctuary-type-classes'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('insert', () => { 11 | 12 | eq (String (S.insert), 'insert :: String -> a -> StrMap a -> StrMap a'); 13 | 14 | eq (S.insert ('a') (1) ({}), {a: 1}); 15 | eq (S.insert ('b') (2) ({a: 1}), {a: 1, b: 2}); 16 | eq (S.insert ('c') (3) ({a: 1, b: 2, c: 4}), {a: 1, b: 2, c: 3}); 17 | 18 | jsc.assert (jsc.forall (jsc.string, jsc.number, jsc.dict (jsc.number), (key, val, map) => { 19 | const insert = S.insert (key) (val); 20 | const lhs = insert (insert (map)); 21 | const rhs = insert (map); 22 | return Z.equals (lhs, rhs); 23 | }), {tests: 1000}); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /test/intercalate.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('intercalate', () => { 11 | 12 | eq (String (S.intercalate), 'intercalate :: (Monoid a, Foldable f) => a -> f a -> a'); 13 | 14 | eq (S.intercalate (', ') ([]), ''); 15 | eq (S.intercalate (', ') (['foo']), 'foo'); 16 | eq (S.intercalate (', ') (['foo', 'bar']), 'foo, bar'); 17 | eq (S.intercalate (', ') (['foo', 'bar', 'baz']), 'foo, bar, baz'); 18 | eq (S.intercalate ([0, 0, 0]) ([]), []); 19 | eq (S.intercalate ([0, 0, 0]) ([[1]]), [1]); 20 | eq (S.intercalate ([0, 0, 0]) ([[1], [2]]), [1, 0, 0, 0, 2]); 21 | eq (S.intercalate ([0, 0, 0]) ([[1], [2], [3]]), [1, 0, 0, 0, 2, 0, 0, 0, 3]); 22 | eq (S.intercalate ('.') (Nil), ''); 23 | eq (S.intercalate ('.') (Cons ('x') (Nil)), 'x'); 24 | eq (S.intercalate ('.') (Cons ('x') (Cons ('y') (Nil))), 'x.y'); 25 | eq (S.intercalate ('.') (Cons ('x') (Cons ('y') (Cons ('z') (Nil)))), 'x.y.z'); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/internal/List.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const {deepStrictEqual: eq} = require ('node:assert'); 4 | 5 | const FL = require ('fantasy-land'); 6 | const $ = require ('sanctuary-def'); 7 | const show = require ('sanctuary-show'); 8 | const Z = require ('sanctuary-type-classes'); 9 | const type = require ('sanctuary-type-identifiers'); 10 | 11 | 12 | const List = {prototype: _List.prototype}; 13 | 14 | List.prototype.constructor = List; 15 | 16 | function _List(tag, head, tail) { 17 | this.isCons = tag === 'Cons'; 18 | this.isNil = tag === 'Nil'; 19 | if (this.isCons) { 20 | this.head = head; 21 | this.tail = tail; 22 | } 23 | } 24 | 25 | // listTypeIdent :: String 26 | const listTypeIdent = List.prototype['@@type'] = 'sanctuary/List'; 27 | 28 | // Type :: Type -> Type 29 | List.Type = $.UnaryType 30 | (listTypeIdent) 31 | ('') 32 | ([]) 33 | (x => type (x) === listTypeIdent) 34 | (list => list); 35 | 36 | // Nil :: List a 37 | const Nil = List.Nil = new _List ('Nil'); 38 | 39 | // Cons :: a -> List a -> List a 40 | const Cons = List.Cons = function Cons(head) { 41 | eq (arguments.length, Cons.length); 42 | return function Cons$1(tail) { 43 | eq (arguments.length, Cons$1.length); 44 | return new _List ('Cons', head, tail); 45 | }; 46 | }; 47 | 48 | List[FL.empty] = () => Nil; 49 | 50 | List[FL.of] = x => Cons (x) (Nil); 51 | 52 | List[FL.zero] = List[FL.empty]; 53 | 54 | List.prototype[FL.equals] = function(other) { 55 | return this.isNil ? 56 | other.isNil : 57 | other.isCons && 58 | Z.equals (other.head, this.head) && 59 | Z.equals (other.tail, this.tail); 60 | }; 61 | 62 | List.prototype[FL.concat] = function(other) { 63 | return this.isNil ? 64 | other : 65 | Cons (this.head) (Z.concat (this.tail, other)); 66 | }; 67 | 68 | List.prototype[FL.filter] = function(pred) { 69 | return this.isNil ? 70 | Nil : 71 | pred (this.head) ? 72 | Cons (this.head) (Z.filter (pred, this.tail)) : 73 | Z.filter (pred, this.tail); 74 | }; 75 | 76 | List.prototype[FL.map] = function(f) { 77 | return this.isNil ? 78 | Nil : 79 | Cons (f (this.head)) (Z.map (f, this.tail)); 80 | }; 81 | 82 | List.prototype[FL.ap] = function(other) { 83 | return this.isNil || other.isNil ? 84 | Nil : 85 | Z.concat (Z.map (other.head, this), Z.ap (other.tail, this)); 86 | }; 87 | 88 | List.prototype[FL.chain] = function(f) { 89 | return this.isNil ? 90 | Nil : 91 | Z.concat (f (this.head), Z.chain (f, this.tail)); 92 | }; 93 | 94 | List.prototype[FL.alt] = List.prototype[FL.concat]; 95 | 96 | List.prototype[FL.reduce] = function(f, x) { 97 | return this.isNil ? 98 | x : 99 | Z.reduce (f, f (x, this.head), this.tail); 100 | }; 101 | 102 | List.prototype[FL.traverse] = function(typeRep, f) { 103 | return this.isNil ? 104 | Z.of (typeRep, Nil) : 105 | Z.ap (Z.map (Cons, f (this.head)), Z.traverse (typeRep, f, this.tail)); 106 | }; 107 | 108 | List.prototype.inspect = 109 | List.prototype['@@show'] = function() { 110 | return this.isNil ? 111 | 'Nil' : 112 | 'Cons (' + show (this.head) + ') (' + show (this.tail) + ')'; 113 | }; 114 | 115 | module.exports = List; 116 | -------------------------------------------------------------------------------- /test/internal/List.mjs: -------------------------------------------------------------------------------- 1 | import List from './List.cjs'; 2 | 3 | export {List, Nil, Cons}; 4 | 5 | const {Nil, Cons} = List; 6 | -------------------------------------------------------------------------------- /test/internal/Sum.cjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const FL = require ('fantasy-land'); 4 | const $ = require ('sanctuary-def'); 5 | const show = require ('sanctuary-show'); 6 | const Z = require ('sanctuary-type-classes'); 7 | const type = require ('sanctuary-type-identifiers'); 8 | 9 | 10 | // Sum :: Number -> Sum 11 | function Sum(value) { 12 | if (!(this instanceof Sum)) return new Sum (value); 13 | this.value = value; 14 | } 15 | 16 | // sumTypeIdent :: String 17 | const sumTypeIdent = Sum.prototype['@@type'] = 'sanctuary/Sum'; 18 | 19 | // Type :: Type 20 | Sum.Type = $.NullaryType 21 | (sumTypeIdent) 22 | ('') 23 | ([]) 24 | (x => type (x) === sumTypeIdent); 25 | 26 | Sum[FL.empty] = () => Sum (0); 27 | 28 | Sum.prototype[FL.equals] = function(other) { 29 | return Z.equals (this.value, other.value); 30 | }; 31 | 32 | Sum.prototype[FL.concat] = function(other) { 33 | return Sum (this.value + other.value); 34 | }; 35 | 36 | Sum.prototype[FL.invert] = function() { 37 | return Sum (-this.value); 38 | }; 39 | 40 | Sum.prototype.inspect = 41 | Sum.prototype['@@show'] = function() { 42 | return 'Sum (' + show (this.value) + ')'; 43 | }; 44 | 45 | module.exports = Sum; 46 | -------------------------------------------------------------------------------- /test/internal/Sum.mjs: -------------------------------------------------------------------------------- 1 | import Sum from './Sum.cjs'; 2 | 3 | export {Sum}; 4 | -------------------------------------------------------------------------------- /test/internal/area.js: -------------------------------------------------------------------------------- 1 | export default a => b => c => { 2 | if (Math.max (a, b, c) < (a + b + c) / 2) { 3 | const s = (a + b + c) / 2; 4 | return Math.sqrt (s * (s - a) * (s - b) * (s - c)); 5 | } else { 6 | throw new Error ('Impossible triangle'); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /test/internal/factorial.js: -------------------------------------------------------------------------------- 1 | export default function factorial(n) { 2 | if (n < 0) { 3 | // eslint-disable-next-line no-throw-literal 4 | throw 'Cannot determine factorial of negative number'; 5 | } else if (n === 0) { 6 | return 1; 7 | } else { 8 | return n * factorial (n - 1); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/internal/rem.js: -------------------------------------------------------------------------------- 1 | export default x => y => { 2 | if (y === 0) { 3 | throw new Error ('Cannot divide by zero'); 4 | } else { 5 | return x % y; 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /test/internal/sanctuary.js: -------------------------------------------------------------------------------- 1 | import $ from 'sanctuary-def'; 2 | 3 | import S from '../../index.js'; 4 | 5 | import {List} from './List.mjs'; 6 | import {Sum} from './Sum.mjs'; 7 | 8 | 9 | // env :: Array Type 10 | const env = S.env.concat ([ 11 | List.Type ($.Unknown), 12 | Sum.Type, 13 | ]); 14 | 15 | export default S.create ({checkTypes: true, env}); 16 | -------------------------------------------------------------------------------- /test/internal/strMap.js: -------------------------------------------------------------------------------- 1 | const proto = Object.create (null); 2 | 3 | Object.defineProperty ( 4 | proto, 5 | 'non-enumerable inherited property', 6 | {enumerable: false, value: 'non-enumerable inherited property'} 7 | ); 8 | Object.defineProperty ( 9 | proto, 10 | 'enumerable inherited property', 11 | {enumerable: true, value: 'enumerable inherited property'} 12 | ); 13 | 14 | const strMap = Object.create (proto); 15 | 16 | Object.defineProperty ( 17 | strMap, 18 | 'non-enumerable own property', 19 | {enumerable: false, value: 'non-enumerable own property'} 20 | ); 21 | Object.defineProperty ( 22 | strMap, 23 | 'enumerable own property', 24 | {enumerable: true, value: 'enumerable own property'} 25 | ); 26 | 27 | export default strMap; 28 | -------------------------------------------------------------------------------- /test/invert.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Sum} from './internal/Sum.mjs'; 8 | 9 | 10 | test ('invert', () => { 11 | 12 | eq (String (S.invert), 'invert :: Group g => g -> g'); 13 | 14 | eq (S.invert (Sum (5)), Sum (-5)); 15 | eq (S.invert (Sum (-5)), Sum (5)); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/is.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import $ from 'sanctuary-def'; 5 | 6 | import S from '../index.js'; 7 | 8 | import {Sum} from './internal/Sum.mjs'; 9 | 10 | 11 | test ('is', () => { 12 | 13 | eq (String (S.is), 'is :: Type -> Any -> Boolean'); 14 | 15 | eq (S.is ($.Boolean) (true), true); 16 | eq (S.is ($.Boolean) (false), true); 17 | eq (S.is ($.Boolean) (new Boolean (true)), false); 18 | eq (S.is ($.Boolean) (new Boolean (false)), false); 19 | 20 | eq (S.is ($.Array ($.Integer)) (null), false); 21 | eq (S.is ($.Array ($.Integer)) (undefined), false); 22 | eq (S.is ($.Array ($.Integer)) (['1', '2', '3']), false); 23 | eq (S.is ($.Array ($.Integer)) ([1, 2, 3.14]), false); 24 | eq (S.is ($.Array ($.Integer)) ([1, 2, 3]), true); 25 | eq (S.is ($.Array ($.Integer)) ([]), true); 26 | 27 | eq (S.is ($.Maybe ($.Integer)) (S.Nothing), true); 28 | eq (S.is ($.Maybe ($.Integer)) (S.Just (0)), true); 29 | eq (S.is ($.Maybe ($.Integer)) (S.Left (0)), false); 30 | eq (S.is ($.Maybe ($.Integer)) (S.Right (0)), false); 31 | 32 | eq (S.is ($.Either ($.String) ($.Integer)) (S.Nothing), false); 33 | eq (S.is ($.Either ($.String) ($.Integer)) (S.Just (0)), false); 34 | eq (S.is ($.Either ($.String) ($.Integer)) (S.Left (0)), false); 35 | eq (S.is ($.Either ($.String) ($.Integer)) (S.Right ('')), false); 36 | eq (S.is ($.Either ($.String) ($.Integer)) (S.Left ('')), true); 37 | eq (S.is ($.Either ($.String) ($.Integer)) (S.Right (0)), true); 38 | 39 | const a = $.TypeVariable ('a'); 40 | 41 | eq (S.is ($.Array (a)) ([]), true); 42 | eq (S.is ($.Array (a)) ([1, 2, 3]), true); 43 | eq (S.is ($.Array (a)) (['foo', 'bar', 'baz']), true); 44 | eq (S.is ($.Array (a)) (['foo', true, 42]), false); 45 | eq (S.is ($.Array (a)) ([Sum (1), Sum (2), Sum (3)]), false); 46 | 47 | eq ((S.create ({checkTypes: true, env: []})).is ($.Array (a)) ([]), false); 48 | eq ((S.create ({checkTypes: true, env: [$.String]})).is ($.Array (a)) ([]), true); 49 | eq ((S.create ({checkTypes: true, env: [$.String]})).is ($.Array (a)) ([1, 2, 3]), false); 50 | eq ((S.create ({checkTypes: true, env: [$.Number]})).is ($.Array (a)) ([1, 2, 3]), true); 51 | eq ((S.create ({checkTypes: true, env: [Sum.Type]})).is ($.Array (a)) ([Sum (1), Sum (2), Sum (3)]), true); 52 | 53 | }); 54 | -------------------------------------------------------------------------------- /test/isJust.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('isJust', () => { 9 | 10 | eq (String (S.isJust), 'isJust :: Maybe a -> Boolean'); 11 | 12 | eq (S.isJust (S.Nothing), false); 13 | eq (S.isJust (S.Just (42)), true); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/isLeft.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('isLeft', () => { 9 | 10 | eq (String (S.isLeft), 'isLeft :: Either a b -> Boolean'); 11 | 12 | eq (S.isLeft (S.Left (42)), true); 13 | eq (S.isLeft (S.Right (42)), false); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/isNothing.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('isNothing', () => { 9 | 10 | eq (String (S.isNothing), 'isNothing :: Maybe a -> Boolean'); 11 | 12 | eq (S.isNothing (S.Nothing), true); 13 | eq (S.isNothing (S.Just (42)), false); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/isRight.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('isRight', () => { 9 | 10 | eq (String (S.isRight), 'isRight :: Either a b -> Boolean'); 11 | 12 | eq (S.isRight (S.Left (42)), false); 13 | eq (S.isRight (S.Right (42)), true); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/join.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('join', () => { 9 | 10 | eq (String (S.join), 'join :: Chain m => m (m a) -> m a'); 11 | 12 | eq (S.join ([]), []); 13 | eq (S.join ([[]]), []); 14 | eq (S.join ([[[]]]), [[]]); 15 | eq (S.join ([[1], [2], [3]]), [1, 2, 3]); 16 | eq (S.join ([[[1, 2, 3]]]), [[1, 2, 3]]); 17 | eq (S.join (S.Nothing), S.Nothing); 18 | eq (S.join (S.Just (S.Nothing)), S.Nothing); 19 | eq (S.join (S.Just (S.Just (1))), S.Just (1)); 20 | eq (S.join (S.Just (S.Just (S.Just (1)))), S.Just (S.Just (1))); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /test/joinWith.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('joinWith', () => { 9 | 10 | eq (String (S.joinWith), 'joinWith :: String -> Array String -> String'); 11 | 12 | eq (S.joinWith ('') (['a', 'b', 'c']), 'abc'); 13 | eq (S.joinWith (':') ([]), ''); 14 | eq (S.joinWith (':') (['']), ''); 15 | eq (S.joinWith (':') (['', '']), ':'); 16 | eq (S.joinWith (':') (['', 'foo', '']), ':foo:'); 17 | eq (S.joinWith (':') (['foo', 'bar', 'baz']), 'foo:bar:baz'); 18 | eq (S.joinWith ('::') (['foo', 'bar', 'baz']), 'foo::bar::baz'); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/justs.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('justs', () => { 11 | 12 | eq (String (S.justs), 'justs :: (Filterable f, Functor f) => f (Maybe a) -> f a'); 13 | 14 | eq (S.justs ([]), []); 15 | eq (S.justs ([S.Nothing, S.Nothing]), []); 16 | eq (S.justs ([S.Nothing, S.Just ('b')]), ['b']); 17 | eq (S.justs ([S.Just ('a'), S.Nothing]), ['a']); 18 | eq (S.justs ([S.Just ('a'), S.Just ('b')]), ['a', 'b']); 19 | 20 | eq (S.justs ({}), {}); 21 | eq (S.justs ({x: S.Nothing, y: S.Nothing}), {}); 22 | eq (S.justs ({x: S.Nothing, y: S.Just (2)}), {y: 2}); 23 | eq (S.justs ({x: S.Just (1), y: S.Nothing}), {x: 1}); 24 | eq (S.justs ({x: S.Just (1), y: S.Just (2)}), {x: 1, y: 2}); 25 | 26 | eq (S.justs (S.Nothing), S.Nothing); 27 | eq (S.justs (S.Just (S.Nothing)), S.Nothing); 28 | eq (S.justs (S.Just (S.Just (1))), S.Just (1)); 29 | 30 | eq (S.justs (Nil), Nil); 31 | eq (S.justs (Cons (S.Nothing) (Cons (S.Nothing) (Nil))), Nil); 32 | eq (S.justs (Cons (S.Nothing) (Cons (S.Just (2)) (Nil))), Cons (2) (Nil)); 33 | eq (S.justs (Cons (S.Just (1)) (Cons (S.Nothing) (Nil))), Cons (1) (Nil)); 34 | eq (S.justs (Cons (S.Just (1)) (Cons (S.Just (2)) (Nil))), Cons (1) (Cons (2) (Nil))); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/keys.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import strMap from './internal/strMap.js'; 8 | 9 | 10 | test ('keys', () => { 11 | 12 | eq (String (S.keys), 'keys :: StrMap a -> Array String'); 13 | 14 | eq (S.sort (S.keys ({})), []); 15 | eq (S.sort (S.keys ({a: 1, b: 2, c: 3})), ['a', 'b', 'c']); 16 | 17 | eq (S.keys (strMap), ['enumerable own property']); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/last.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('last', () => { 11 | 12 | eq (String (S.last), 'last :: Foldable f => f a -> Maybe a'); 13 | 14 | eq (S.last ([]), S.Nothing); 15 | eq (S.last (['foo']), S.Just ('foo')); 16 | eq (S.last (['foo', 'bar']), S.Just ('bar')); 17 | eq (S.last (['foo', 'bar', 'baz']), S.Just ('baz')); 18 | 19 | eq (S.last (Nil), S.Nothing); 20 | eq (S.last (Cons ('foo') (Nil)), S.Just ('foo')); 21 | eq (S.last (Cons ('foo') (Cons ('bar') (Nil))), S.Just ('bar')); 22 | eq (S.last (Cons ('foo') (Cons ('bar') (Cons ('baz') (Nil)))), S.Just ('baz')); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/lefts.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('lefts', () => { 11 | 12 | eq (String (S.lefts), 'lefts :: (Filterable f, Functor f) => f (Either a b) -> f a'); 13 | 14 | eq (S.lefts ([]), []); 15 | eq (S.lefts ([S.Right (2), S.Right (1)]), []); 16 | eq (S.lefts ([S.Right (2), S.Left ('b')]), ['b']); 17 | eq (S.lefts ([S.Left ('a'), S.Right (1)]), ['a']); 18 | eq (S.lefts ([S.Left ('a'), S.Left ('b')]), ['a', 'b']); 19 | 20 | eq (S.lefts ({}), {}); 21 | eq (S.lefts ({x: S.Right (2), y: S.Right (1)}), {}); 22 | eq (S.lefts ({x: S.Right (2), y: S.Left ('b')}), {y: 'b'}); 23 | eq (S.lefts ({x: S.Left ('a'), y: S.Right (1)}), {x: 'a'}); 24 | eq (S.lefts ({x: S.Left ('a'), y: S.Left ('b')}), {x: 'a', y: 'b'}); 25 | 26 | eq (S.lefts (S.Nothing), S.Nothing); 27 | eq (S.lefts (S.Just (S.Right (1))), S.Nothing); 28 | eq (S.lefts (S.Just (S.Left ('a'))), S.Just ('a')); 29 | 30 | eq (S.lefts (Nil), Nil); 31 | eq (S.lefts (Cons (S.Right (2)) (Cons (S.Right (1)) (Nil))), Nil); 32 | eq (S.lefts (Cons (S.Right (2)) (Cons (S.Left ('b')) (Nil))), Cons ('b') (Nil)); 33 | eq (S.lefts (Cons (S.Left ('a')) (Cons (S.Right (1)) (Nil))), Cons ('a') (Nil)); 34 | eq (S.lefts (Cons (S.Left ('a')) (Cons (S.Left ('b')) (Nil))), Cons ('a') (Cons ('b') (Nil))); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/lift2.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('lift2', () => { 9 | 10 | eq (String (S.lift2), 'lift2 :: Apply f => (a -> b -> c) -> f a -> f b -> f c'); 11 | 12 | eq (S.lift2 (S.add) (S.Just (3)) (S.Just (3)), S.Just (6)); 13 | eq (S.lift2 (S.add) (S.Nothing) (S.Just (3)), S.Nothing); 14 | 15 | eq (S.lift2 (S.add) (S.Right (3)) (S.Left (4)), S.Left (4)); 16 | eq (S.lift2 (S.add) (S.Right (3)) (S.Right (4)), S.Right (7)); 17 | 18 | eq (S.lift2 (S.add) ([1, 2]) ([10, 20]), [11, 21, 12, 22]); 19 | eq (S.lift2 (S.add) ([]) ([1, 2]), []); 20 | 21 | eq (S.lift2 (S.and) (S.even) (S.gt (0)) (42), true); 22 | eq (S.lift2 (S.and) (S.even) (S.gt (0)) (43), false); 23 | eq (S.lift2 (S.and) (S.even) (S.gt (0)) (-42), false); 24 | eq (S.lift2 (S.and) (S.even) (S.gt (0)) (-43), false); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /test/lift3.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import area from './internal/area.js'; 8 | 9 | 10 | test ('lift3', () => { 11 | 12 | eq (String (S.lift3), 'lift3 :: Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d'); 13 | 14 | eq (S.lift3 (S.reduce) (S.Just (S.add)) (S.Just (0)) (S.Just ([1, 2, 3])), S.Just (6)); 15 | eq (S.lift3 (S.reduce) (S.Just (S.add)) (S.Just (0)) (S.Nothing), S.Nothing); 16 | 17 | eq (S.lift3 (S.reduce) (S.Right (S.add)) (S.Right (0)) (S.Right ([1, 2, 3])), S.Right (6)); 18 | eq (S.lift3 (S.reduce) (S.Right (S.add)) (S.Right (0)) (S.Left ('WHOOPS')), S.Left ('WHOOPS')); 19 | 20 | eq (S.lift3 (S.reduce) ([S.add]) ([0]) ([[1, 2, 3]]), [6]); 21 | eq (S.lift3 (S.reduce) ([S.add]) ([0]) ([]), []); 22 | 23 | eq (S.lift3 (area) (S.sub (1)) (S.I) (S.add (1)) (4), 6); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /test/lines.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('lines', () => { 9 | 10 | eq (String (S.lines), 'lines :: String -> Array String'); 11 | 12 | eq (S.lines (''), []); 13 | eq (S.lines ('\n'), ['']); 14 | eq (S.lines ('\n\n'), ['', '']); 15 | eq (S.lines ('foo\nbar\nbaz'), ['foo', 'bar', 'baz']); 16 | eq (S.lines ('foo\nbar\nbaz\n'), ['foo', 'bar', 'baz']); 17 | eq (S.lines ('\tfoo\r\n\tbar\r\n\tbaz\r\n'), ['\tfoo', '\tbar', '\tbaz']); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/lt.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('lt', () => { 9 | 10 | eq (String (S.lt), 'lt :: Ord a => a -> a -> Boolean'); 11 | 12 | eq (S.filter (S.lt (3)) ([1, 2, 3, 4, 5]), [1, 2]); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/lte.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('lte', () => { 9 | 10 | eq (String (S.lte), 'lte :: Ord a => a -> a -> Boolean'); 11 | 12 | eq (S.filter (S.lte (3)) ([1, 2, 3, 4, 5]), [1, 2, 3]); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/map.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('map', () => { 9 | 10 | eq (String (S.map), 'map :: Functor f => (a -> b) -> f a -> f b'); 11 | 12 | eq (S.map (S.not) (S.odd) (2), true); 13 | eq (S.map (S.not) (S.odd) (3), false); 14 | 15 | eq (S.map (S.mult (4)) (S.Just (2)), S.Just (8)); 16 | eq (S.map (S.mult (4)) (S.Nothing), S.Nothing); 17 | 18 | eq (S.map (S.mult (4)) (S.Left (3)), S.Left (3)); 19 | eq (S.map (S.mult (4)) (S.Right (2)), S.Right (8)); 20 | 21 | eq (S.map (S.mult (2)) ([1, 2, 3]), [2, 4, 6]); 22 | eq (S.map (S.mult (2)) ([]), []); 23 | 24 | eq (S.map (S.mult (2)) ({a: 1, b: 2, c: 3}), {a: 2, b: 4, c: 6}); 25 | eq (S.map (S.mult (2)) ({}), {}); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/mapLeft.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('mapLeft', () => { 9 | 10 | eq (String (S.mapLeft), 'mapLeft :: Bifunctor p => (a -> b) -> p a c -> p b c'); 11 | 12 | eq (S.mapLeft (S.toUpper) (S.Left ('xxx')), S.Left ('XXX')); 13 | eq (S.mapLeft (S.toUpper) (S.Right (1000)), S.Right (1000)); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/mapMaybe.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('mapMaybe', () => { 11 | 12 | eq (String (S.mapMaybe), 'mapMaybe :: (Filterable f, Functor f) => (a -> Maybe b) -> f a -> f b'); 13 | 14 | eq (S.mapMaybe (S.head) ([]), []); 15 | eq (S.mapMaybe (S.head) ([[], [], []]), []); 16 | eq (S.mapMaybe (S.head) ([[1, 2], [3, 4], [5, 6]]), [1, 3, 5]); 17 | eq (S.mapMaybe (S.head) ([[1], [], [3], [], [5], []]), [1, 3, 5]); 18 | 19 | eq (S.mapMaybe (S.head) ({}), {}); 20 | eq (S.mapMaybe (S.head) ({a: [], b: [], c: []}), {}); 21 | eq (S.mapMaybe (S.head) ({a: [1, 2], b: [3, 4], c: [5, 6]}), {a: 1, b: 3, c: 5}); 22 | eq (S.mapMaybe (S.head) ({a: [1], b: [], c: [3], d: [], e: [5], f: []}), {a: 1, c: 3, e: 5}); 23 | 24 | eq (S.mapMaybe (S.head) (S.Nothing), S.Nothing); 25 | eq (S.mapMaybe (S.head) (S.Just ([])), S.Nothing); 26 | eq (S.mapMaybe (S.head) (S.Just ([1, 2])), S.Just (1)); 27 | 28 | eq (S.mapMaybe (S.head) (Nil), 29 | Nil); 30 | eq (S.mapMaybe (S.head) (Cons ([]) (Cons ([]) (Cons ([]) (Nil)))), 31 | Nil); 32 | eq (S.mapMaybe (S.head) (Cons ([1, 2]) (Cons ([3, 4]) (Cons ([5, 6]) (Nil)))), 33 | Cons (1) (Cons (3) (Cons (5) (Nil)))); 34 | eq (S.mapMaybe (S.head) (Cons ([1]) (Cons ([]) (Cons ([3]) (Cons ([]) (Cons ([5]) (Cons ([]) (Nil))))))), 35 | Cons (1) (Cons (3) (Cons (5) (Nil)))); 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /test/match.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | import Z from 'sanctuary-type-classes'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('match', () => { 11 | 12 | eq (String (S.match), 'match :: NonGlobalRegExp -> String -> Maybe (Array (Maybe String))'); 13 | 14 | const scheme = '([a-z][a-z0-9+.-]*)'; 15 | const authentication = '(.*?):(.*?)@'; 16 | const hostname = '(.*?)'; 17 | const port = ':([0-9]*)'; 18 | const pattern = S.regex ('') (scheme + '://(?:' + authentication + ')?' + hostname + '(?:' + port + ')?(?!\\S)'); 19 | 20 | eq (S.match (pattern) ('URL: N/A'), 21 | S.Nothing); 22 | 23 | eq (S.match (pattern) ('URL: http://example.com'), 24 | S.Just ([S.Just ('http'), S.Nothing, S.Nothing, S.Just ('example.com'), S.Nothing])); 25 | 26 | eq (S.match (pattern) ('URL: http://user:pass@example.com:80'), 27 | S.Just ([S.Just ('http'), S.Just ('user'), S.Just ('pass'), S.Just ('example.com'), S.Just ('80')])); 28 | 29 | jsc.assert (jsc.forall (jsc.string, s => { 30 | const p = '([A-Za-z]+)'; 31 | const lhs = S.head (S.matchAll (S.regex ('g') (p)) (s)); 32 | const rhs = S.match (S.regex ('') (p)) (s); 33 | return Z.equals (lhs, rhs); 34 | }), {tests: 1000}); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/matchAll.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('matchAll', () => { 9 | 10 | eq (String (S.matchAll), 'matchAll :: GlobalRegExp -> String -> Array (Array (Maybe String))'); 11 | 12 | const pattern = S.regex ('g') ('<(h[1-6])(?: id="([^"]*)")?>([^<]*)'); 13 | 14 | eq (S.matchAll (pattern) (''), []); 15 | 16 | eq (S.matchAll (pattern) ('

Foo

\n

Bar

\n

Baz

\n'), 17 | [[S.Just ('h1'), S.Nothing, S.Just ('Foo')], 18 | [S.Just ('h2'), S.Just ('bar'), S.Just ('Bar')], 19 | [S.Just ('h2'), S.Just ('baz'), S.Just ('Baz')]]); 20 | 21 | eq (pattern.lastIndex, 0); 22 | 23 | { 24 | // `lastIndex` property is respected and preserved 25 | const pattern = /([0-9])/g; 26 | eq (pattern.lastIndex, 0); 27 | pattern.exec ('123'); 28 | eq (pattern.lastIndex, 1); 29 | eq (S.matchAll (pattern) ('123'), [[S.Just ('2')], [S.Just ('3')]]); 30 | eq (pattern.lastIndex, 1); 31 | } 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /test/max.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('max', () => { 9 | 10 | eq (String (S.max), 'max :: Ord a => a -> a -> a'); 11 | 12 | eq (S.max (10) (2), 10); 13 | eq (S.max (2) (10), 10); 14 | eq (S.max (0.1) (0.01), 0.1); 15 | eq (S.max (0.01) (0.1), 0.1); 16 | eq (S.max (Infinity) (-Infinity), Infinity); 17 | eq (S.max (-Infinity) (Infinity), Infinity); 18 | 19 | eq (S.max (new Date (10)) (new Date (2)), new Date (10)); 20 | eq (S.max (new Date (2)) (new Date (10)), new Date (10)); 21 | 22 | eq (S.max ('abc') ('xyz'), 'xyz'); 23 | eq (S.max ('xyz') ('abc'), 'xyz'); 24 | eq (S.max ('10') ('2'), '2'); 25 | eq (S.max ('2') ('10'), '2'); 26 | eq (S.max ('A') ('a'), 'a'); 27 | eq (S.max ('a') ('A'), 'a'); 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /test/maybe.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('maybe', () => { 9 | 10 | eq (String (S.maybe), 'maybe :: b -> (a -> b) -> Maybe a -> b'); 11 | 12 | eq (S.maybe (0) (Math.sqrt) (S.Nothing), 0); 13 | eq (S.maybe (0) (Math.sqrt) (S.Just (9)), 3); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/maybeToNullable.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('maybeToNullable', () => { 9 | 10 | eq (String (S.maybeToNullable), 'maybeToNullable :: Maybe a -> Nullable a'); 11 | 12 | eq (S.maybeToNullable (S.Nothing), null); 13 | eq (S.maybeToNullable (S.Just (42)), 42); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/maybe_.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import factorial from './internal/factorial.js'; 8 | 9 | 10 | test ('maybe_', () => { 11 | 12 | eq (String (S.maybe_), 'maybe_ :: (() -> b) -> (a -> b) -> Maybe a -> b'); 13 | 14 | eq (S.maybe_ (() => factorial (10)) (Math.sqrt) (S.Nothing), 3628800); 15 | eq (S.maybe_ (() => factorial (10)) (Math.sqrt) (S.Just (9)), 3); 16 | 17 | let count = 0; 18 | eq (S.maybe_ (() => count += 1) (Math.sqrt) (S.Just (9)), 3); 19 | eq (count, 0); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /test/min.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('min', () => { 9 | 10 | eq (String (S.min), 'min :: Ord a => a -> a -> a'); 11 | 12 | eq (S.min (10) (2), 2); 13 | eq (S.min (2) (10), 2); 14 | eq (S.min (0.1) (0.01), 0.01); 15 | eq (S.min (0.01) (0.1), 0.01); 16 | eq (S.min (Infinity) (-Infinity), -Infinity); 17 | eq (S.min (-Infinity) (Infinity), -Infinity); 18 | 19 | eq (S.min (new Date (10)) (new Date (2)), new Date (2)); 20 | eq (S.min (new Date (2)) (new Date (10)), new Date (2)); 21 | 22 | eq (S.min ('abc') ('xyz'), 'abc'); 23 | eq (S.min ('xyz') ('abc'), 'abc'); 24 | eq (S.min ('10') ('2'), '10'); 25 | eq (S.min ('2') ('10'), '10'); 26 | eq (S.min ('A') ('a'), 'A'); 27 | eq (S.min ('a') ('A'), 'A'); 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /test/mult.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('mult', () => { 9 | 10 | eq (String (S.mult), 'mult :: FiniteNumber -> FiniteNumber -> FiniteNumber'); 11 | 12 | eq (S.mult (4) (2), 8); 13 | eq (S.mult (4) (-2), -8); 14 | eq (S.mult (-4) (-2), 8); 15 | eq (S.mult (1.5) (3), 4.5); 16 | eq (S.mult (-1.5) (3), -4.5); 17 | eq (S.mult (-1.5) (-3), 4.5); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/negate.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('negate', () => { 9 | 10 | eq (String (S.negate), 'negate :: ValidNumber -> ValidNumber'); 11 | 12 | eq (S.negate (0.5), -0.5); 13 | eq (S.negate (-0.5), 0.5); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/none.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | import Z from 'sanctuary-type-classes'; 6 | 7 | import S from './internal/sanctuary.js'; 8 | 9 | import {Nil, Cons} from './internal/List.mjs'; 10 | 11 | 12 | test ('none', () => { 13 | 14 | eq (String (S.none), 'none :: Foldable f => (a -> Boolean) -> f a -> Boolean'); 15 | 16 | eq (S.none (S.gt (0)) ([]), true); 17 | eq (S.none (S.gt (0)) ([0]), true); 18 | eq (S.none (S.gt (0)) ([1]), false); 19 | eq (S.none (S.gt (0)) ([0, 0]), true); 20 | eq (S.none (S.gt (0)) ([0, 1]), false); 21 | eq (S.none (S.gt (0)) ([1, 0]), false); 22 | eq (S.none (S.gt (0)) ([1, 1]), false); 23 | 24 | eq (S.none (S.gt (0)) (Nil), true); 25 | eq (S.none (S.gt (0)) (Cons (0) (Nil)), true); 26 | eq (S.none (S.gt (0)) (Cons (1) (Nil)), false); 27 | eq (S.none (S.gt (0)) (Cons (0) (Cons (0) (Nil))), true); 28 | eq (S.none (S.gt (0)) (Cons (0) (Cons (1) (Nil))), false); 29 | eq (S.none (S.gt (0)) (Cons (1) (Cons (0) (Nil))), false); 30 | eq (S.none (S.gt (0)) (Cons (1) (Cons (1) (Nil))), false); 31 | 32 | eq (S.none (S.gt (0)) (S.Nothing), true); 33 | eq (S.none (S.gt (0)) (S.Just (0)), true); 34 | eq (S.none (S.gt (0)) (S.Just (1)), false); 35 | 36 | jsc.assert (jsc.forall (jsc.array (jsc.integer), xs => { 37 | const p = S.odd; 38 | const lhs = S.none (p) (xs); 39 | const rhs = S.not (S.any (p) (xs)); 40 | return Z.equals (lhs, rhs); 41 | }), {tests: 1000}); 42 | 43 | jsc.assert (jsc.forall (jsc.array (jsc.integer), xs => { 44 | const p = S.odd; 45 | const lhs = S.none (p) (xs); 46 | const rhs = S.all (S.complement (p)) (xs); 47 | return Z.equals (lhs, rhs); 48 | }), {tests: 1000}); 49 | 50 | }); 51 | -------------------------------------------------------------------------------- /test/not.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('not', () => { 9 | 10 | eq (String (S.not), 'not :: Boolean -> Boolean'); 11 | 12 | eq (S.not (false), true); 13 | eq (S.not (true), false); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/odd.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('odd', () => { 9 | 10 | eq (String (S.odd), 'odd :: Integer -> Boolean'); 11 | 12 | eq (S.odd (1), true); 13 | eq (S.odd (-1), true); 14 | 15 | eq (S.odd (0), false); 16 | eq (S.odd (2), false); 17 | eq (S.odd (-2), false); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/of.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import Identity from 'sanctuary-identity'; 5 | 6 | import S from './internal/sanctuary.js'; 7 | 8 | 9 | test ('of', () => { 10 | 11 | eq (String (S.of), 'of :: Applicative f => TypeRep (f a) -> a -> f a'); 12 | 13 | eq (S.of (Array) (42), [42]); 14 | eq (S.of (Function) (42) (null), 42); 15 | eq (S.of (S.Maybe) (42), S.Just (42)); 16 | eq (S.of (S.Either) (42), S.Right (42)); 17 | eq (S.of (Identity) (42), Identity (42)); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/on.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import rem from './internal/rem.js'; 8 | 9 | 10 | test ('on', () => { 11 | 12 | eq (String (S.on), 'on :: (b -> b -> c) -> (a -> b) -> a -> a -> c'); 13 | 14 | eq (S.on (rem) (S.prop ('x')) ({x: 5, y: 5}) ({x: 3, y: 3}), 2); 15 | eq (S.on (S.concat) (S.reverse) ([1, 2, 3]) ([4, 5, 6]), [3, 2, 1, 6, 5, 4]); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/or.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('or', () => { 9 | 10 | eq (String (S.or), 'or :: Boolean -> Boolean -> Boolean'); 11 | 12 | eq (S.or (false) (false), false); 13 | eq (S.or (false) (true), true); 14 | eq (S.or (true) (false), true); 15 | eq (S.or (true) (true), true); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /test/pairs.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import strMap from './internal/strMap.js'; 8 | 9 | 10 | test ('pairs', () => { 11 | 12 | eq (String (S.pairs), 'pairs :: StrMap a -> Array (Pair String a)'); 13 | 14 | eq (S.sort (S.pairs ({})), []); 15 | eq (S.sort (S.pairs ({a: 1, b: 2, c: 3})), [S.Pair ('a') (1), S.Pair ('b') (2), S.Pair ('c') (3)]); 16 | 17 | eq (S.pairs (strMap), [S.Pair ('enumerable own property') ('enumerable own property')]); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/pair~.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('pair', () => { 9 | 10 | eq (String (S.pair), 'pair :: (a -> b -> c) -> Pair a b -> c'); 11 | 12 | eq (S.pair (S.concat) (S.Pair ('foo') ('bar')), 'foobar'); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/parseDate.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('parseDate', () => { 9 | 10 | eq (String (S.parseDate), 'parseDate :: String -> Maybe ValidDate'); 11 | 12 | eq (S.parseDate ('2001-02-03T04:05:06Z'), S.Just (new Date ('2001-02-03T04:05:06Z'))); 13 | eq (S.parseDate ('today'), S.Nothing); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/parseFloat.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('parseFloat', () => { 9 | 10 | eq (String (S.parseFloat), 'parseFloat :: String -> Maybe Number'); 11 | 12 | eq (S.parseFloat ('12.34'), S.Just (12.34)); 13 | eq (S.parseFloat ('Infinity'), S.Just (Infinity)); 14 | eq (S.parseFloat ('-Infinity'), S.Just (-Infinity)); 15 | eq (S.parseFloat ('NaN'), S.Just (NaN)); 16 | eq (S.parseFloat ('-NaN'), S.Just (NaN)); // Haskell accepts "-NaN" 17 | eq (S.parseFloat ('0'), S.Just (0)); 18 | eq (S.parseFloat ('-0'), S.Just (-0)); 19 | eq (S.parseFloat ('42'), S.Just (42)); 20 | eq (S.parseFloat ('42.'), S.Just (42)); 21 | eq (S.parseFloat ('0.5'), S.Just (0.5)); 22 | eq (S.parseFloat ('.25'), S.Just (0.25)); 23 | eq (S.parseFloat ('+42'), S.Just (42)); 24 | eq (S.parseFloat ('+42.'), S.Just (42)); 25 | eq (S.parseFloat ('+0.5'), S.Just (0.5)); 26 | eq (S.parseFloat ('+.25'), S.Just (0.25)); 27 | eq (S.parseFloat ('-42'), S.Just (-42)); 28 | eq (S.parseFloat ('-42.'), S.Just (-42)); 29 | eq (S.parseFloat ('-0.5'), S.Just (-0.5)); 30 | eq (S.parseFloat ('-.25'), S.Just (-0.25)); 31 | eq (S.parseFloat ('0.5 '), S.Just (0.5)); 32 | eq (S.parseFloat (' 0.5'), S.Just (0.5)); 33 | eq (S.parseFloat ('0.5x'), S.Nothing); // parseFloat ('0.5x') == 0.5 34 | eq (S.parseFloat ('x0.5'), S.Nothing); 35 | eq (S.parseFloat ('-1e3'), S.Just (-1000)); 36 | eq (S.parseFloat ('-1e03'), S.Just (-1000)); 37 | eq (S.parseFloat ('-1e+3'), S.Just (-1000)); 38 | eq (S.parseFloat ('-1e+03'), S.Just (-1000)); 39 | eq (S.parseFloat ('-1e-3'), S.Just (-0.001)); 40 | eq (S.parseFloat ('-1e-03'), S.Just (-0.001)); 41 | eq (S.parseFloat ('xxx'), S.Nothing); 42 | 43 | }); 44 | -------------------------------------------------------------------------------- /test/parseInt.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq, throws} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('parseInt', () => { 9 | 10 | eq (String (S.parseInt), 'parseInt :: Radix -> String -> Maybe Integer'); 11 | 12 | eq (S.parseInt (10) ('42'), S.Just (42)); 13 | eq (S.parseInt (16) ('2A'), S.Just (42)); 14 | eq (S.parseInt (10) ('NaN'), S.Nothing); 15 | eq (S.parseInt (10) ('xxx'), S.Nothing); 16 | 17 | // Accepts radix in [2 .. 36] 18 | eq (S.parseInt (2) ('1'), S.Just (1)); 19 | eq (S.parseInt (2) ('2'), S.Nothing); 20 | eq (S.parseInt (3) ('2'), S.Just (2)); 21 | eq (S.parseInt (3) ('3'), S.Nothing); 22 | eq (S.parseInt (4) ('3'), S.Just (3)); 23 | eq (S.parseInt (4) ('4'), S.Nothing); 24 | eq (S.parseInt (5) ('4'), S.Just (4)); 25 | eq (S.parseInt (5) ('5'), S.Nothing); 26 | eq (S.parseInt (6) ('5'), S.Just (5)); 27 | eq (S.parseInt (6) ('6'), S.Nothing); 28 | eq (S.parseInt (7) ('6'), S.Just (6)); 29 | eq (S.parseInt (7) ('7'), S.Nothing); 30 | eq (S.parseInt (8) ('7'), S.Just (7)); 31 | eq (S.parseInt (8) ('8'), S.Nothing); 32 | eq (S.parseInt (9) ('8'), S.Just (8)); 33 | eq (S.parseInt (9) ('9'), S.Nothing); 34 | eq (S.parseInt (10) ('9'), S.Just (9)); 35 | eq (S.parseInt (10) ('A'), S.Nothing); 36 | eq (S.parseInt (11) ('A'), S.Just (10)); 37 | eq (S.parseInt (11) ('B'), S.Nothing); 38 | eq (S.parseInt (12) ('B'), S.Just (11)); 39 | eq (S.parseInt (12) ('C'), S.Nothing); 40 | eq (S.parseInt (13) ('C'), S.Just (12)); 41 | eq (S.parseInt (13) ('D'), S.Nothing); 42 | eq (S.parseInt (14) ('D'), S.Just (13)); 43 | eq (S.parseInt (14) ('E'), S.Nothing); 44 | eq (S.parseInt (15) ('E'), S.Just (14)); 45 | eq (S.parseInt (15) ('F'), S.Nothing); 46 | eq (S.parseInt (16) ('F'), S.Just (15)); 47 | eq (S.parseInt (16) ('G'), S.Nothing); 48 | eq (S.parseInt (17) ('G'), S.Just (16)); 49 | eq (S.parseInt (17) ('H'), S.Nothing); 50 | eq (S.parseInt (18) ('H'), S.Just (17)); 51 | eq (S.parseInt (18) ('I'), S.Nothing); 52 | eq (S.parseInt (19) ('I'), S.Just (18)); 53 | eq (S.parseInt (19) ('J'), S.Nothing); 54 | eq (S.parseInt (20) ('J'), S.Just (19)); 55 | eq (S.parseInt (20) ('K'), S.Nothing); 56 | eq (S.parseInt (21) ('K'), S.Just (20)); 57 | eq (S.parseInt (21) ('L'), S.Nothing); 58 | eq (S.parseInt (22) ('L'), S.Just (21)); 59 | eq (S.parseInt (22) ('M'), S.Nothing); 60 | eq (S.parseInt (23) ('M'), S.Just (22)); 61 | eq (S.parseInt (23) ('N'), S.Nothing); 62 | eq (S.parseInt (24) ('N'), S.Just (23)); 63 | eq (S.parseInt (24) ('O'), S.Nothing); 64 | eq (S.parseInt (25) ('O'), S.Just (24)); 65 | eq (S.parseInt (25) ('P'), S.Nothing); 66 | eq (S.parseInt (26) ('P'), S.Just (25)); 67 | eq (S.parseInt (26) ('Q'), S.Nothing); 68 | eq (S.parseInt (27) ('Q'), S.Just (26)); 69 | eq (S.parseInt (27) ('R'), S.Nothing); 70 | eq (S.parseInt (28) ('R'), S.Just (27)); 71 | eq (S.parseInt (28) ('S'), S.Nothing); 72 | eq (S.parseInt (29) ('S'), S.Just (28)); 73 | eq (S.parseInt (29) ('T'), S.Nothing); 74 | eq (S.parseInt (30) ('T'), S.Just (29)); 75 | eq (S.parseInt (30) ('U'), S.Nothing); 76 | eq (S.parseInt (31) ('U'), S.Just (30)); 77 | eq (S.parseInt (31) ('V'), S.Nothing); 78 | eq (S.parseInt (32) ('V'), S.Just (31)); 79 | eq (S.parseInt (32) ('W'), S.Nothing); 80 | eq (S.parseInt (33) ('W'), S.Just (32)); 81 | eq (S.parseInt (33) ('X'), S.Nothing); 82 | eq (S.parseInt (34) ('X'), S.Just (33)); 83 | eq (S.parseInt (34) ('Y'), S.Nothing); 84 | eq (S.parseInt (35) ('Y'), S.Just (34)); 85 | eq (S.parseInt (35) ('Z'), S.Nothing); 86 | eq (S.parseInt (36) ('Z'), S.Just (35)); 87 | eq (S.parseInt (36) ('['), S.Nothing); 88 | 89 | // Throws if radix is not in [2 .. 36] 90 | throws (() => { S.parseInt (1); }, 91 | new TypeError ('Invalid value\n' + 92 | '\n' + 93 | 'parseInt :: Radix -> String -> Maybe Integer\n' + 94 | ' ^^^^^\n' + 95 | ' 1\n' + 96 | '\n' + 97 | '1) 1 :: Number\n' + 98 | '\n' + 99 | 'The value at position 1 is not a member of ‘Radix’.\n')); 100 | 101 | throws (() => { S.parseInt (37); }, 102 | new TypeError ('Invalid value\n' + 103 | '\n' + 104 | 'parseInt :: Radix -> String -> Maybe Integer\n' + 105 | ' ^^^^^\n' + 106 | ' 1\n' + 107 | '\n' + 108 | '1) 37 :: Number\n' + 109 | '\n' + 110 | 'The value at position 1 is not a member of ‘Radix’.\n')); 111 | 112 | // Is not case-sensitive 113 | eq (S.parseInt (16) ('FF'), S.Just (255)); 114 | eq (S.parseInt (16) ('Ff'), S.Just (255)); 115 | eq (S.parseInt (16) ('fF'), S.Just (255)); 116 | eq (S.parseInt (16) ('ff'), S.Just (255)); 117 | 118 | // Accepts optional "+" or "-" prefix 119 | eq (S.parseInt (10) ('+42'), S.Just (42)); 120 | eq (S.parseInt (16) ('+2A'), S.Just (42)); 121 | eq (S.parseInt (10) ('-42'), S.Just (-42)); 122 | eq (S.parseInt (16) ('-2A'), S.Just (-42)); 123 | 124 | // Accepts optional "0x" or "0X" prefix when radix is 16 125 | eq (S.parseInt (16) ('0xFF'), S.Just (255)); 126 | eq (S.parseInt (16) ('0XFF'), S.Just (255)); 127 | eq (S.parseInt (17) ('0xFF'), S.Nothing); 128 | eq (S.parseInt (17) ('0XFF'), S.Nothing); 129 | eq (S.parseInt (16) ('+0xFF'), S.Just (255)); 130 | eq (S.parseInt (16) ('+0XFF'), S.Just (255)); 131 | eq (S.parseInt (16) ('-0xFF'), S.Just (-255)); 132 | eq (S.parseInt (16) ('-0XFF'), S.Just (-255)); 133 | 134 | // Returns Nothing if one or more characters are invalid 135 | eq (S.parseInt (10) ('12.34'), S.Nothing); // parseInt ('12.34', 10) == 12 136 | eq (S.parseInt (16) ('alice'), S.Nothing); // parseInt ('alice', 16) == 10 137 | 138 | // Restricts to exactly representable range (-2^53 .. 2^53) 139 | eq (S.parseInt (10) ('9007199254740991'), S.Just (9007199254740991)); 140 | eq (S.parseInt (10) ('-9007199254740991'), S.Just (-9007199254740991)); 141 | eq (S.parseInt (10) ('9007199254740992'), S.Nothing); 142 | eq (S.parseInt (10) ('-9007199254740992'), S.Nothing); 143 | eq (S.parseInt (10) ('Infinity'), S.Nothing); 144 | eq (S.parseInt (10) ('-Infinity'), S.Nothing); 145 | 146 | }); 147 | -------------------------------------------------------------------------------- /test/parseJson.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import $ from 'sanctuary-def'; 5 | 6 | import S from '../index.js'; 7 | 8 | 9 | test ('parseJson', () => { 10 | 11 | eq (String (S.parseJson), 'parseJson :: (Any -> Boolean) -> String -> Maybe a'); 12 | 13 | eq (S.parseJson (S.is ($.Any)) ('[Invalid JSON]'), S.Nothing); 14 | eq (S.parseJson (S.is ($.Array ($.Any))) ('{"foo":"bar"}'), S.Nothing); 15 | eq (S.parseJson (S.is ($.Array ($.Any))) ('["foo","bar"]'), S.Just (['foo', 'bar'])); 16 | eq (S.parseJson (S.is ($.Array ($.Number))) ('[1,2]'), S.Just ([1, 2])); 17 | eq (S.parseJson (S.is ($.Array ($.Number))) ('[1,2,null]'), S.Nothing); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/pipe.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('pipe', () => { 11 | 12 | eq (String (S.pipe), 'pipe :: Foldable f => f (Any -> Any) -> a -> b'); 13 | 14 | eq (S.pipe ([]) ('99'), '99'); 15 | eq (S.pipe ([parseInt]) ('99'), 99); 16 | eq (S.pipe ([parseInt, S.add (1)]) ('99'), 100); 17 | eq (S.pipe ([parseInt, S.add (1), Math.sqrt]) ('99'), 10); 18 | eq (S.pipe ([parseInt, S.add (1), Math.sqrt, S.sub (1)]) ('99'), 9); 19 | 20 | eq (S.pipe (Nil) ('99'), '99'); 21 | eq (S.pipe (Cons (parseInt) (Nil)) ('99'), 99); 22 | eq (S.pipe (Cons (parseInt) (Cons (S.add (1)) (Nil))) ('99'), 100); 23 | eq (S.pipe (Cons (parseInt) (Cons (S.add (1)) (Cons (Math.sqrt) (Nil)))) ('99'), 10); 24 | eq (S.pipe (Cons (parseInt) (Cons (S.add (1)) (Cons (Math.sqrt) (Cons (S.sub (1)) (Nil))))) ('99'), 9); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /test/pipeK.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('pipeK', () => { 11 | 12 | eq (String (S.pipeK), 'pipeK :: (Foldable f, Chain m) => f (Any -> m Any) -> m a -> m b'); 13 | 14 | eq (S.pipeK ([]) (S.Just ([1, 2, 3])), S.Just ([1, 2, 3])); 15 | eq (S.pipeK ([S.tail]) (S.Just ([1, 2, 3])), S.Just ([2, 3])); 16 | eq (S.pipeK ([S.tail, S.tail]) (S.Just ([1, 2, 3])), S.Just ([3])); 17 | eq (S.pipeK ([S.tail, S.tail, S.head]) (S.Just ([1, 2, 3])), S.Just (3)); 18 | 19 | eq (S.pipeK (Nil) (S.Just ([1, 2, 3])), S.Just ([1, 2, 3])); 20 | eq (S.pipeK (Cons (S.tail) (Nil)) (S.Just ([1, 2, 3])), S.Just ([2, 3])); 21 | eq (S.pipeK (Cons (S.tail) (Cons (S.tail) (Nil))) (S.Just ([1, 2, 3])), S.Just ([3])); 22 | eq (S.pipeK (Cons (S.tail) (Cons (S.tail) (Cons (S.head) (Nil)))) (S.Just ([1, 2, 3])), S.Just (3)); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/pow.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('pow', () => { 9 | 10 | eq (String (S.pow), 'pow :: FiniteNumber -> FiniteNumber -> FiniteNumber'); 11 | 12 | eq (S.pow (2) (8), 64); 13 | eq (S.map (S.pow (2)) ([-3, -2, -1, 0, 1, 2, 3]), [9, 4, 1, 0, 1, 4, 9]); 14 | eq (S.map (S.pow (0.5)) ([1, 4, 9, 16, 25]), [1, 2, 3, 4, 5]); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /test/prepend.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('prepend', () => { 9 | 10 | eq (String (S.prepend), 'prepend :: (Applicative f, Semigroup f) => a -> f a -> f a'); 11 | 12 | eq (S.prepend (1) ([]), [1]); 13 | eq (S.prepend (1) ([2, 3]), [1, 2, 3]); 14 | eq (S.prepend ([1, 2]) ([[3, 4], [5, 6]]), [[1, 2], [3, 4], [5, 6]]); 15 | 16 | eq (S.prepend ([1]) (S.Nothing), S.Just ([1])); 17 | eq (S.prepend ([1]) (S.Just ([2])), S.Just ([1, 2])); 18 | 19 | eq (S.prepend ([1]) (S.Left ('error')), S.Right ([1])); 20 | eq (S.prepend ([1]) (S.Right ([2])), S.Right ([1, 2])); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /test/product.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('product', () => { 9 | 10 | eq (String (S.product), 'product :: Foldable f => f FiniteNumber -> FiniteNumber'); 11 | 12 | eq (S.product ([]), 1); 13 | eq (S.product ([0, 1, 2, 3]), 0); 14 | eq (S.product ([1, 2, 3, 4, 5]), 120); 15 | eq (S.product ([1, 2, 3, 4, -5]), -120); 16 | 17 | eq (S.product (S.Nothing), 1); 18 | eq (S.product (S.Just (42)), 42); 19 | 20 | eq (S.product (S.Left ('xxx')), 1); 21 | eq (S.product (S.Right (42)), 42); 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /test/promap.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('promap', () => { 9 | 10 | eq (String (S.promap), 'promap :: Profunctor p => (a -> b) -> (c -> d) -> p b c -> p a d'); 11 | 12 | const before = S.map (S.prop ('length')); 13 | const after = S.join (S.mult); 14 | eq (S.promap (before) (after) (S.sum) (['foo', 'bar', 'baz', 'quux']), 169); 15 | 16 | eq (S.promap (Math.abs) (S.add (1)) (Math.sqrt) (-100), 11); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/prop.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq, throws} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('prop', () => { 9 | 10 | eq (String (S.prop), 'prop :: String -> a -> b'); 11 | 12 | throws (() => { S.prop ('xxx') ([1, 2, 3]); }, 13 | new TypeError ('‘prop’ expected object to have a property named ‘xxx’; [1, 2, 3] does not')); 14 | 15 | eq (S.prop ('a') ({a: 0, b: 1}), 0); 16 | eq (S.prop ('0') ([1, 2, 3]), 1); 17 | eq (S.prop ('length') ('abc'), 3); 18 | eq (S.prop ('x') (Object.create ({x: 1, y: 2})), 1); 19 | eq (S.prop ('global') (/x/g), true); 20 | 21 | throws (() => { S.prop ('valueOf') (null); }, 22 | new TypeError ('‘prop’ expected object to have a property named ‘valueOf’; null does not')); 23 | 24 | throws (() => { S.prop ('valueOf') (undefined); }, 25 | new TypeError ('‘prop’ expected object to have a property named ‘valueOf’; undefined does not')); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/props.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq, throws} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('props', () => { 9 | 10 | eq (String (S.props), 'props :: Array String -> a -> b'); 11 | 12 | throws (() => { S.props (['a', 'b', 'c']) ([1, 2, 3]); }, 13 | new TypeError ('‘props’ expected object to have a property at ["a", "b", "c"]; [1, 2, 3] does not')); 14 | 15 | eq (S.props (['a', 'b', 'c']) ({a: {b: {c: 1}}}), 1); 16 | eq (S.props (['a', 'b', 'c', '0']) ({a: {b: {c: [2, 4, 6]}}}), 2); 17 | eq (S.props (['a', 'b', 'c']) (Object.create ({a: {b: {c: 1}}})), 1); 18 | 19 | throws (() => { S.props (['valueOf']) (null); }, 20 | new TypeError ('‘props’ expected object to have a property at ["valueOf"]; null does not')); 21 | 22 | throws (() => { S.props (['valueOf']) (undefined); }, 23 | new TypeError ('‘props’ expected object to have a property at ["valueOf"]; undefined does not')); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /test/range.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('range', () => { 9 | 10 | eq (String (S.range), 'range :: Integer -> Integer -> Array Integer'); 11 | 12 | eq (S.range (0) (0), []); 13 | eq (S.range (0) (10), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 14 | eq (S.range (0) (-10), []); 15 | eq (S.range (-2) (-1), [-2]); 16 | eq (S.range (-2) (3), [-2, -1, 0, 1, 2]); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/reduce.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('reduce', () => { 9 | 10 | eq (String (S.reduce), 'reduce :: Foldable f => (b -> a -> b) -> b -> f a -> b'); 11 | 12 | eq (S.reduce (S.concat) ('x') ([]), 'x'); 13 | eq (S.reduce (S.concat) ('x') (['A', 'B', 'C']), 'xABC'); 14 | eq (S.reduce (S.concat) ('x') ({}), 'x'); 15 | eq (S.reduce (S.concat) ('x') ({a: 'A', b: 'B', c: 'C'}), 'xABC'); 16 | eq (S.reduce (S.concat) ('x') ({c: 'C', b: 'B', a: 'A'}), 'xABC'); 17 | eq (S.reduce (S.concat) ('x') (S.Just ('A')), 'xA'); 18 | eq (S.reduce (S.lift2 (S.concat)) (S.Just ('x')) ([S.Just ('A'), S.Just ('B'), S.Just ('C')]), S.Just ('xABC')); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/reduce_.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('reduce_', () => { 9 | 10 | eq (String (S.reduce_), 'reduce_ :: Foldable f => (a -> b -> b) -> b -> f a -> b'); 11 | 12 | eq (S.reduce_ (S.append) ([]) ([]), []); 13 | eq (S.reduce_ (S.append) ([]) ([1, 2, 3]), [1, 2, 3]); 14 | eq (S.reduce_ (S.prepend) ([]) ([]), []); 15 | eq (S.reduce_ (S.prepend) ([]) ([1, 2, 3]), [3, 2, 1]); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/regex.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('regex', () => { 9 | 10 | eq (String (S.regex), 'regex :: RegexFlags -> String -> RegExp'); 11 | 12 | eq (S.regex ('') ('\\d'), /\d/); 13 | eq (S.regex ('g') ('\\d'), /\d/g); 14 | eq (S.regex ('i') ('\\d'), /\d/i); 15 | eq (S.regex ('m') ('\\d'), /\d/m); 16 | eq (S.regex ('gi') ('\\d'), /\d/gi); 17 | eq (S.regex ('gm') ('\\d'), /\d/gm); 18 | eq (S.regex ('im') ('\\d'), /\d/im); 19 | eq (S.regex ('gim') ('\\d'), /\d/gim); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /test/regexEscape.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | 6 | import S from '../index.js'; 7 | 8 | 9 | test ('regexEscape', () => { 10 | 11 | eq (String (S.regexEscape), 'regexEscape :: String -> String'); 12 | 13 | eq (S.regexEscape ('-=*{XYZ}*=-'), '\\-=\\*\\{XYZ\\}\\*=\\-'); 14 | 15 | jsc.assert ( 16 | jsc.forall ( 17 | jsc.string, 18 | s => S.test (S.regex ('') (S.regexEscape (s))) (s) 19 | ), 20 | {tests: 1000} 21 | ); 22 | 23 | jsc.assert ( 24 | jsc.forall ( 25 | jsc.string, 26 | s => S.test (S.regex ('') ('^' + S.regexEscape (s) + '$')) (s) 27 | ), 28 | {tests: 1000} 29 | ); 30 | 31 | }); 32 | -------------------------------------------------------------------------------- /test/reject.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('reject', () => { 11 | 12 | eq (String (S.reject), 'reject :: Filterable f => (a -> Boolean) -> f a -> f a'); 13 | 14 | eq (S.reject (S.odd) ([]), []); 15 | eq (S.reject (S.odd) ([0, 2, 4, 6, 8]), [0, 2, 4, 6, 8]); 16 | eq (S.reject (S.odd) ([1, 3, 5, 7, 9]), []); 17 | eq (S.reject (S.odd) ([1, 2, 3, 4, 5]), [2, 4]); 18 | 19 | eq (S.reject (S.odd) ({}), {}); 20 | eq (S.reject (S.odd) ({x: 1}), {}); 21 | eq (S.reject (S.odd) ({x: 1, y: 2}), {y: 2}); 22 | eq (S.reject (S.odd) ({x: 1, y: 2, z: 3}), {y: 2}); 23 | 24 | eq (S.reject (S.odd) (S.Nothing), S.Nothing); 25 | eq (S.reject (S.odd) (S.Just (0)), S.Just (0)); 26 | eq (S.reject (S.odd) (S.Just (1)), S.Nothing); 27 | 28 | eq (S.reject (S.odd) (Nil), Nil); 29 | eq (S.reject (S.odd) (Cons (1) (Nil)), Nil); 30 | eq (S.reject (S.odd) (Cons (1) (Cons (2) (Nil))), Cons (2) (Nil)); 31 | eq (S.reject (S.odd) (Cons (1) (Cons (2) (Cons (3) (Nil)))), Cons (2) (Nil)); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /test/remove.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | import Z from 'sanctuary-type-classes'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('remove', () => { 11 | 12 | eq (String (S.remove), 'remove :: String -> StrMap a -> StrMap a'); 13 | 14 | eq (S.remove ('a') ({}), {}); 15 | eq (S.remove ('b') ({a: 1}), {a: 1}); 16 | eq (S.remove ('c') ({a: 1, b: 2, c: 3}), {a: 1, b: 2}); 17 | 18 | jsc.assert (jsc.forall (jsc.string, jsc.dict (jsc.number), (key, map) => { 19 | const remove = S.remove (key); 20 | const lhs = remove (remove (map)); 21 | const rhs = remove (map); 22 | return Z.equals (lhs, rhs); 23 | }), {tests: 1000}); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /test/replace.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('replace', () => { 9 | 10 | eq (String (S.replace), 'replace :: (Array (Maybe String) -> String) -> RegExp -> String -> String'); 11 | 12 | eq (S.replace (([$1]) => S.maybe ('') (S.toUpper) ($1)) (/(\w)/) ('foo'), 'Foo'); 13 | eq (S.replace (([$1]) => S.maybe ('') (S.toUpper) ($1)) (/(\w)/g) ('foo'), 'FOO'); 14 | eq (S.replace (S.show) (/(foo)(bar)?/) ('<>'), '<>'); 15 | eq (S.replace (S.show) (/(foo)(bar)?/) (''), '<[Just ("foo"), Nothing]>'); 16 | eq (S.replace (S.show) (/(foo)(bar)?/) (''), '<[Just ("foo"), Just ("bar")]>'); 17 | eq (S.replace (S.show) (/@(?[-\w]+)/) ('@sanctuary-js'), '[Just ("sanctuary-js")]'); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/reverse.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('reverse', () => { 11 | 12 | eq (String (S.reverse), 'reverse :: (Applicative f, Foldable f, Monoid f) => f a -> f a'); 13 | 14 | eq (S.reverse ([]), []); 15 | eq (S.reverse ([1]), [1]); 16 | eq (S.reverse ([1, 2]), [2, 1]); 17 | eq (S.reverse ([1, 2, 3]), [3, 2, 1]); 18 | 19 | eq (S.reverse (Nil), Nil); 20 | eq (S.reverse (Cons (1) (Nil)), Cons (1) (Nil)); 21 | eq (S.reverse (Cons (1) (Cons (2) (Nil))), Cons (2) (Cons (1) (Nil))); 22 | eq (S.reverse (Cons (1) (Cons (2) (Cons (3) (Nil)))), Cons (3) (Cons (2) (Cons (1) (Nil)))); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/rights.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('rights', () => { 11 | 12 | eq (String (S.rights), 'rights :: (Filterable f, Functor f) => f (Either a b) -> f b'); 13 | 14 | eq (S.rights ([]), []); 15 | eq (S.rights ([S.Left ('a'), S.Left ('b')]), []); 16 | eq (S.rights ([S.Left ('a'), S.Right (1)]), [1]); 17 | eq (S.rights ([S.Right (2), S.Left ('b')]), [2]); 18 | eq (S.rights ([S.Right (2), S.Right (1)]), [2, 1]); 19 | 20 | eq (S.rights ({}), {}); 21 | eq (S.rights ({x: S.Left ('a'), y: S.Left ('b')}), {}); 22 | eq (S.rights ({x: S.Left ('a'), y: S.Right (1)}), {y: 1}); 23 | eq (S.rights ({x: S.Right (2), y: S.Left ('b')}), {x: 2}); 24 | eq (S.rights ({x: S.Right (2), y: S.Right (1)}), {x: 2, y: 1}); 25 | 26 | eq (S.rights (S.Nothing), S.Nothing); 27 | eq (S.rights (S.Just (S.Left ('a'))), S.Nothing); 28 | eq (S.rights (S.Just (S.Right (1))), S.Just (1)); 29 | 30 | eq (S.rights (Nil), Nil); 31 | eq (S.rights (Cons (S.Left ('a')) (Cons (S.Left ('b')) (Nil))), Nil); 32 | eq (S.rights (Cons (S.Left ('a')) (Cons (S.Right (1)) (Nil))), Cons (1) (Nil)); 33 | eq (S.rights (Cons (S.Right (2)) (Cons (S.Left ('b')) (Nil))), Cons (2) (Nil)); 34 | eq (S.rights (Cons (S.Right (2)) (Cons (S.Right (1)) (Nil))), Cons (2) (Cons (1) (Nil))); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/sequence.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import Identity from 'sanctuary-identity'; 5 | 6 | import S from './internal/sanctuary.js'; 7 | 8 | 9 | test ('sequence', () => { 10 | 11 | eq (String (S.sequence), 'sequence :: (Applicative f, Traversable t) => TypeRep (f a) -> t (f a) -> f (t a)'); 12 | 13 | eq (S.sequence (Identity) ([]), Identity ([])); 14 | eq (S.sequence (Identity) ([Identity (1), Identity (2), Identity (3)]), Identity ([1, 2, 3])); 15 | eq (S.sequence (Identity) ({}), Identity ({})); 16 | eq (S.sequence (Identity) ({a: Identity (1), b: Identity (2), c: Identity (3)}), Identity ({a: 1, b: 2, c: 3})); 17 | eq (S.sequence (Identity) (S.Nothing), Identity (S.Nothing)); 18 | eq (S.sequence (Identity) (S.Just (Identity (0))), Identity (S.Just (0))); 19 | eq (S.sequence (Identity) (S.Left ('A')), Identity (S.Left ('A'))); 20 | eq (S.sequence (Identity) (S.Right (Identity (-1))), Identity (S.Right (-1))); 21 | 22 | eq (S.sequence (Array) (Identity ([])), []); 23 | eq (S.sequence (Array) (Identity ([1, 2, 3])), [Identity (1), Identity (2), Identity (3)]); 24 | eq (S.sequence (S.Maybe) (Identity (S.Nothing)), S.Nothing); 25 | eq (S.sequence (S.Maybe) (Identity (S.Just (0))), S.Just (Identity (0))); 26 | eq (S.sequence (S.Either) (Identity (S.Left ('A'))), S.Left ('A')); 27 | eq (S.sequence (S.Either) (Identity (S.Right (-1))), S.Right (Identity (-1))); 28 | 29 | eq (S.sequence (Array) ({a: [1, 2], b: [3, 4]}), [{a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 3}, {a: 2, b: 4}]); 30 | 31 | }); 32 | -------------------------------------------------------------------------------- /test/show.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('show', () => { 9 | 10 | eq (String (S.show), 'show :: Any -> String'); 11 | 12 | eq (S.show (null), 'null'); 13 | eq (S.show (undefined), 'undefined'); 14 | eq (S.show (false), 'false'); 15 | eq (S.show (true), 'true'); 16 | eq (S.show (new Boolean (false)), 'new Boolean (false)'); 17 | eq (S.show (new Boolean (true)), 'new Boolean (true)'); 18 | eq (S.show (0), '0'); 19 | eq (S.show (-0), '-0'); 20 | eq (S.show (NaN), 'NaN'); 21 | eq (S.show (Math.PI), '3.141592653589793'); 22 | eq (S.show (-Math.PI), '-3.141592653589793'); 23 | eq (S.show (Infinity), 'Infinity'); 24 | eq (S.show (-Infinity), '-Infinity'); 25 | eq (S.show (new Number (0)), 'new Number (0)'); 26 | eq (S.show (new Number (-0)), 'new Number (-0)'); 27 | eq (S.show (new Number (NaN)), 'new Number (NaN)'); 28 | eq (S.show (new Number (Math.PI)), 'new Number (3.141592653589793)'); 29 | eq (S.show (new Number (-Math.PI)), 'new Number (-3.141592653589793)'); 30 | eq (S.show (new Number (Infinity)), 'new Number (Infinity)'); 31 | eq (S.show (new Number (-Infinity)), 'new Number (-Infinity)'); 32 | eq (S.show (''), '""'); 33 | eq (S.show ('foo'), '"foo"'); 34 | eq (S.show ('foo "bar" baz'), '"foo \\"bar\\" baz"'); 35 | eq (S.show (new String ('')), 'new String ("")'); 36 | eq (S.show (new String ('foo')), 'new String ("foo")'); 37 | eq (S.show (new String ('foo "bar" baz')), 'new String ("foo \\"bar\\" baz")'); 38 | eq (S.show (new Date (0)), 'new Date ("1970-01-01T00:00:00.000Z")'); 39 | eq (S.show (new Date (42)), 'new Date ("1970-01-01T00:00:00.042Z")'); 40 | eq (S.show (new Date (NaN)), 'new Date (NaN)'); 41 | eq (S.show (new Date ('2001-02-03')), 'new Date ("2001-02-03T00:00:00.000Z")'); 42 | eq (S.show ([]), '[]'); 43 | eq (S.show (['foo']), '["foo"]'); 44 | eq (S.show (['foo', 'bar', 'baz']), '["foo", "bar", "baz"]'); 45 | eq (S.show (['foo "bar" baz']), '["foo \\"bar\\" baz"]'); 46 | eq (S.show ({}), '{}'); 47 | eq (S.show ({x: 1}), '{"x": 1}'); 48 | eq (S.show ({x: 1, y: 2, z: 3}), '{"x": 1, "y": 2, "z": 3}'); 49 | eq (S.show ({'foo "bar" baz': '"quux"'}), '{"foo \\"bar\\" baz": "\\"quux\\""}'); 50 | eq (S.show (S.Nothing), 'Nothing'); 51 | eq (S.show (S.Just (9)), 'Just (9)'); 52 | eq (S.show (S.Left (false)), 'Left (false)'); 53 | eq (S.show (S.Right (true)), 'Right (true)'); 54 | 55 | }); 56 | -------------------------------------------------------------------------------- /test/singleton.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('singleton', () => { 9 | 10 | eq (String (S.singleton), 'singleton :: String -> a -> StrMap a'); 11 | 12 | eq (S.singleton ('foo') (42), {foo: 42}); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/size.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('size', () => { 11 | 12 | eq (String (S.size), 'size :: Foldable f => f a -> NonNegativeInteger'); 13 | 14 | eq (S.size ([]), 0); 15 | eq (S.size (['foo']), 1); 16 | eq (S.size (['foo', 'bar']), 2); 17 | eq (S.size (['foo', 'bar', 'baz']), 3); 18 | 19 | eq (S.size (Nil), 0); 20 | eq (S.size (Cons ('foo') (Nil)), 1); 21 | eq (S.size (Cons ('foo') (Cons ('bar') (Nil))), 2); 22 | eq (S.size (Cons ('foo') (Cons ('bar') (Cons ('baz') (Nil)))), 3); 23 | 24 | eq (S.size (S.Nothing), 0); 25 | eq (S.size (S.Just (0)), 1); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/snd.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('snd', () => { 9 | 10 | eq (String (S.snd), 'snd :: Pair a b -> b'); 11 | 12 | eq (S.snd (S.Pair ('foo') (42)), 42); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/sort.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('sort', () => { 9 | 10 | eq (String (S.sort), 'sort :: (Ord a, Applicative m, Foldable m, Monoid m) => m a -> m a'); 11 | 12 | eq (S.sort ([]), []); 13 | eq (S.sort (['foo', 'bar', 'baz']), ['bar', 'baz', 'foo']); 14 | eq (S.sort ([S.Left (4), S.Right (3), S.Left (2), S.Right (1)]), [S.Left (2), S.Left (4), S.Right (1), S.Right (3)]); 15 | 16 | eq (S.sort (S.range (0) (100)), S.range (0) (100)); 17 | eq (S.sort (S.reverse (S.range (0) (100))), S.range (0) (100)); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/sortBy.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('sortBy', () => { 9 | 10 | eq (String (S.sortBy), 'sortBy :: (Ord b, Applicative m, Foldable m, Monoid m) => (a -> b) -> m a -> m a'); 11 | 12 | eq (S.sortBy (S.I) ([]), []); 13 | eq (S.sortBy (S.I) (['five']), ['five']); 14 | eq (S.sortBy (S.I) (['five', 'six']), ['five', 'six']); 15 | eq (S.sortBy (S.I) (['five', 'six', 'seven']), ['five', 'seven', 'six']); 16 | eq (S.sortBy (S.prop ('length')) (['five', 'six', 'seven']), ['six', 'five', 'seven']); 17 | 18 | const _7s = {rank: 7, suit: 's'}; 19 | const _5h = {rank: 5, suit: 'h'}; 20 | const _2h = {rank: 2, suit: 'h'}; 21 | const _5s = {rank: 5, suit: 's'}; 22 | eq (S.sortBy (S.prop ('rank')) ([_7s, _5h, _2h, _5s]), [_2h, _5h, _5s, _7s]); 23 | eq (S.sortBy (S.prop ('rank')) ([_7s, _5s, _2h, _5h]), [_2h, _5s, _5h, _7s]); 24 | eq (S.sortBy (S.prop ('suit')) ([_7s, _5h, _2h, _5s]), [_5h, _2h, _7s, _5s]); 25 | eq (S.sortBy (S.prop ('suit')) ([_5s, _2h, _5h, _7s]), [_2h, _5h, _5s, _7s]); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/splitOn.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | import Z from 'sanctuary-type-classes'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('splitOn', () => { 11 | 12 | eq (String (S.splitOn), 'splitOn :: String -> String -> Array String'); 13 | 14 | eq (S.splitOn ('') ('abc'), ['a', 'b', 'c']); 15 | eq (S.splitOn (':') (''), ['']); 16 | eq (S.splitOn (':') (':'), ['', '']); 17 | eq (S.splitOn (':') (':foo:'), ['', 'foo', '']); 18 | eq (S.splitOn (':') ('foo:bar:baz'), ['foo', 'bar', 'baz']); 19 | eq (S.splitOn ('::') ('foo::bar::baz'), ['foo', 'bar', 'baz']); 20 | 21 | jsc.assert (jsc.forall (jsc.asciistring, t => { 22 | const min = 0; 23 | const max = t.length; 24 | const i = jsc.random (min, max); 25 | const j = jsc.random (min, max); 26 | const s = t.slice (Math.min (i, j), Math.max (i, j)); 27 | const lhs = S.joinWith (s) (S.splitOn (s) (t)); 28 | const rhs = t; 29 | return Z.equals (lhs, rhs); 30 | }), {tests: 1000}); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /test/splitOnRegex.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import jsc from 'jsverify'; 4 | import test from 'oletus'; 5 | import Z from 'sanctuary-type-classes'; 6 | 7 | import S from '../index.js'; 8 | 9 | 10 | test ('splitOnRegex', () => { 11 | 12 | eq (String (S.splitOnRegex), 'splitOnRegex :: GlobalRegExp -> String -> Array String'); 13 | 14 | eq (S.splitOnRegex (/b/g) ('abc'), ['a', 'c']); 15 | eq (S.splitOnRegex (/d/g) ('abc'), ['abc']); 16 | eq (S.splitOnRegex (/b(?=c)/g) ('abc abd'), ['a', 'c abd']); 17 | eq (S.splitOnRegex (/b(?!c)/g) ('abc abd'), ['abc a', 'd']); 18 | 19 | eq (S.splitOnRegex (/\s+/g) ('foo bar baz qux'), ['foo', 'bar', 'baz', 'qux']); 20 | eq (S.splitOnRegex (/\s+/g) ('foo bar baz\tqux\nquux'), ['foo', 'bar', 'baz', 'qux', 'quux']); 21 | eq (S.splitOnRegex (/\s+/g) ('foobar'), ['foobar']); 22 | eq (S.splitOnRegex (/([:;])\1/g) ('foo::bar:;baz;;quux'), ['foo', 'bar:;baz', 'quux']); 23 | 24 | eq (S.splitOnRegex (/./g) ('a\rb\nc'), ['', '\r', '\n', '']); 25 | eq (S.splitOnRegex (/[^]/g) ('a\nb'), ['', '', '', '']); 26 | 27 | eq (S.splitOnRegex (/^/g) ('foo\nbar\nbaz\n'), ['foo\nbar\nbaz\n']); 28 | eq (S.splitOnRegex (/^/gm) ('foo\nbar\nbaz\n'), ['foo\n', 'bar\n', 'baz\n']); 29 | 30 | eq (S.splitOnRegex (/foo/g) ('FOObar'), ['FOObar']); 31 | eq (S.splitOnRegex (/foo/gi) ('FOObar'), ['', 'bar']); 32 | 33 | eq (S.splitOnRegex (/(?:)/g) (''), []); 34 | eq (S.splitOnRegex (/(?:)/g) ('a'), ['a']); 35 | eq (S.splitOnRegex (/(?:)/g) ('ab'), ['a', 'b']); 36 | eq (S.splitOnRegex (/(?:)/g) ('abc'), ['a', 'b', 'c']); 37 | 38 | eq (S.splitOnRegex (/[^]/g) (''), ['']); 39 | eq (S.splitOnRegex (/[^]/g) ('a'), ['', '']); 40 | eq (S.splitOnRegex (/[^]/g) ('ab'), ['', '', '']); 41 | eq (S.splitOnRegex (/[^]/g) ('abc'), ['', '', '', '']); 42 | 43 | eq (S.splitOnRegex (/.*/g) (''), []); 44 | eq (S.splitOnRegex (/.*/g) ('hello'), ['']); 45 | eq (S.splitOnRegex (/./g) (''), ['']); 46 | eq (S.splitOnRegex (/./g) ('hello'), ['', '', '', '', '', '']); 47 | 48 | { 49 | // `lastIndex` property is respected and preserved 50 | const pattern = /:/g; 51 | eq (pattern.lastIndex, 0); 52 | pattern.exec ('x:y:z'); 53 | eq (pattern.lastIndex, 2); 54 | eq (S.splitOnRegex (pattern) ('x:y:z'), ['x:y', 'z']); 55 | eq (pattern.lastIndex, 2); 56 | } 57 | 58 | jsc.assert (jsc.forall (jsc.asciistring, t => { 59 | const min = 0; 60 | const max = t.length; 61 | const i = jsc.random (min, max); 62 | const j = jsc.random (min, max); 63 | const s = t.slice (Math.min (i, j), Math.max (i, j)); 64 | const lhs = S.joinWith (s) (S.splitOnRegex (S.regex ('g') (S.regexEscape (s))) (t)); 65 | const rhs = t; 66 | return Z.equals (lhs, rhs); 67 | }), {tests: 1000}); 68 | 69 | }); 70 | -------------------------------------------------------------------------------- /test/stripPrefix.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('stripPrefix', () => { 9 | 10 | eq (String (S.stripPrefix), 'stripPrefix :: String -> String -> Maybe String'); 11 | 12 | eq (S.stripPrefix ('') (''), S.Just ('')); 13 | eq (S.stripPrefix ('') ('abc'), S.Just ('abc')); 14 | eq (S.stripPrefix ('a') (''), S.Nothing); 15 | eq (S.stripPrefix ('a') ('abc'), S.Just ('bc')); 16 | eq (S.stripPrefix ('a') ('[abc]'), S.Nothing); 17 | eq (S.stripPrefix ('aaa') ('a'), S.Nothing); 18 | eq (S.stripPrefix ('https://') ('https://sanctuary.js.org'), S.Just ('sanctuary.js.org')); 19 | eq (S.stripPrefix ('https://') ('http://sanctuary.js.org'), S.Nothing); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /test/stripSuffix.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('stripSuffix', () => { 9 | 10 | eq (String (S.stripSuffix), 'stripSuffix :: String -> String -> Maybe String'); 11 | 12 | eq (S.stripSuffix ('') (''), S.Just ('')); 13 | eq (S.stripSuffix ('') ('xyz'), S.Just ('xyz')); 14 | eq (S.stripSuffix ('z') (''), S.Nothing); 15 | eq (S.stripSuffix ('z') ('xyz'), S.Just ('xy')); 16 | eq (S.stripSuffix ('z') ('[xyz]'), S.Nothing); 17 | eq (S.stripSuffix ('zzz') ('z'), S.Nothing); 18 | eq (S.stripSuffix ('.md') ('README.md'), S.Just ('README')); 19 | eq (S.stripSuffix ('.md') ('README'), S.Nothing); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /test/sub.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('sub', () => { 9 | 10 | eq (String (S.sub), 'sub :: FiniteNumber -> FiniteNumber -> FiniteNumber'); 11 | 12 | eq (S.map (S.sub (1)) ([1, 2, 3]), [0, 1, 2]); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/sum.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('sum', () => { 9 | 10 | eq (String (S.sum), 'sum :: Foldable f => f FiniteNumber -> FiniteNumber'); 11 | 12 | eq (S.sum ([]), 0); 13 | eq (S.sum ([0, 1, 2, 3]), 6); 14 | eq (S.sum ([1, 2, 3, 4, 5]), 15); 15 | eq (S.sum ([1, 2, 3, 4, -5]), 5); 16 | 17 | eq (S.sum (S.Nothing), 0); 18 | eq (S.sum (S.Just (42)), 42); 19 | 20 | eq (S.sum (S.Left ('xxx')), 0); 21 | eq (S.sum (S.Right (42)), 42); 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /test/swap.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('swap', () => { 9 | 10 | eq (String (S.swap), 'swap :: Pair a b -> Pair b a'); 11 | 12 | eq (S.swap (S.Pair ('foo') (42)), S.Pair (42) ('foo')); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/tagBy.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('tagBy', () => { 9 | 10 | eq (String (S.tagBy), 'tagBy :: (a -> Boolean) -> a -> Either a a'); 11 | 12 | eq (S.tagBy (S.odd) (5), S.Right (5)); 13 | eq (S.tagBy (S.odd) (6), S.Left (6)); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/tail.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('tail', () => { 11 | 12 | eq (String (S.tail), 'tail :: (Applicative f, Foldable f, Monoid f) => f a -> Maybe (f a)'); 13 | 14 | eq (S.tail ([]), S.Nothing); 15 | eq (S.tail (['foo']), S.Just ([])); 16 | eq (S.tail (['foo', 'bar']), S.Just (['bar'])); 17 | eq (S.tail (['foo', 'bar', 'baz']), S.Just (['bar', 'baz'])); 18 | 19 | eq (S.tail (Nil), S.Nothing); 20 | eq (S.tail (Cons ('foo') (Nil)), S.Just (Nil)); 21 | eq (S.tail (Cons ('foo') (Cons ('bar') (Nil))), S.Just (Cons ('bar') (Nil))); 22 | eq (S.tail (Cons ('foo') (Cons ('bar') (Cons ('baz') (Nil)))), S.Just (Cons ('bar') (Cons ('baz') (Nil)))); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /test/take.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('take', () => { 11 | 12 | eq (String (S.take), 'take :: (Applicative f, Foldable f, Monoid f) => Integer -> f a -> Maybe (f a)'); 13 | 14 | eq (S.take (0) ([1, 2, 3, 4, 5]), S.Just ([])); 15 | eq (S.take (1) ([1, 2, 3, 4, 5]), S.Just ([1])); 16 | eq (S.take (2) ([1, 2, 3, 4, 5]), S.Just ([1, 2])); 17 | eq (S.take (3) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3])); 18 | eq (S.take (4) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3, 4])); 19 | eq (S.take (5) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3, 4, 5])); 20 | eq (S.take (6) ([1, 2, 3, 4, 5]), S.Nothing); 21 | 22 | eq (S.take (-1) ([1, 2, 3, 4, 5]), S.Nothing); 23 | 24 | eq (S.take (0) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Nil)); 25 | eq (S.take (1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Nil))); 26 | eq (S.take (2) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Cons (2) (Nil)))); 27 | eq (S.take (3) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Cons (2) (Cons (3) (Nil))))); 28 | eq (S.take (4) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 29 | 30 | eq (S.take (-1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /test/takeLast.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from './internal/sanctuary.js'; 6 | 7 | import {Nil, Cons} from './internal/List.mjs'; 8 | 9 | 10 | test ('takeLast', () => { 11 | 12 | eq (String (S.takeLast), 'takeLast :: (Applicative f, Foldable f, Monoid f) => Integer -> f a -> Maybe (f a)'); 13 | 14 | eq (S.takeLast (0) ([1, 2, 3, 4, 5]), S.Just ([])); 15 | eq (S.takeLast (1) ([1, 2, 3, 4, 5]), S.Just ([5])); 16 | eq (S.takeLast (2) ([1, 2, 3, 4, 5]), S.Just ([4, 5])); 17 | eq (S.takeLast (3) ([1, 2, 3, 4, 5]), S.Just ([3, 4, 5])); 18 | eq (S.takeLast (4) ([1, 2, 3, 4, 5]), S.Just ([2, 3, 4, 5])); 19 | eq (S.takeLast (5) ([1, 2, 3, 4, 5]), S.Just ([1, 2, 3, 4, 5])); 20 | eq (S.takeLast (6) ([1, 2, 3, 4, 5]), S.Nothing); 21 | 22 | eq (S.takeLast (-1) ([1, 2, 3, 4, 5]), S.Nothing); 23 | 24 | eq (S.takeLast (0) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Nil)); 25 | eq (S.takeLast (1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (3) (Nil))); 26 | eq (S.takeLast (2) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (2) (Cons (3) (Nil)))); 27 | eq (S.takeLast (3) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Just (Cons (1) (Cons (2) (Cons (3) (Nil))))); 28 | eq (S.takeLast (4) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 29 | 30 | eq (S.takeLast (-1) (Cons (1) (Cons (2) (Cons (3) (Nil)))), S.Nothing); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /test/takeWhile.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('takeWhile', () => { 9 | 10 | eq (String (S.takeWhile), 'takeWhile :: (a -> Boolean) -> Array a -> Array a'); 11 | 12 | eq (S.takeWhile (S.odd) ([3, 3, 3, 7, 6, 3, 5, 4]), [3, 3, 3, 7]); 13 | eq (S.takeWhile (S.even) ([3, 3, 3, 7, 6, 3, 5, 4]), []); 14 | eq (S.takeWhile (S.odd) ([]), []); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('test', () => { 9 | 10 | eq (String (S.test), 'test :: RegExp -> String -> Boolean'); 11 | 12 | eq (S.test (/^a/) ('abacus'), true); 13 | eq (S.test (/^a/) ('banana'), false); 14 | 15 | const pattern = /x/g; 16 | eq (pattern.lastIndex, 0); 17 | eq (S.test (pattern) ('xyz'), true); 18 | eq (pattern.lastIndex, 0); 19 | eq (S.test (pattern) ('xyz'), true); 20 | 21 | { 22 | // `lastIndex` property is respected and preserved 23 | const pattern = /x/g; 24 | eq (pattern.lastIndex, 0); 25 | pattern.exec ('xyz'); 26 | eq (pattern.lastIndex, 1); 27 | eq (S.test (pattern) ('xyz'), false); 28 | eq (pattern.lastIndex, 1); 29 | } 30 | 31 | }); 32 | -------------------------------------------------------------------------------- /test/toLower.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('toLower', () => { 9 | 10 | eq (String (S.toLower), 'toLower :: String -> String'); 11 | 12 | eq (S.toLower (''), ''); 13 | eq (S.toLower ('ABC def 123'), 'abc def 123'); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/toUpper.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('toUpper', () => { 9 | 10 | eq (String (S.toUpper), 'toUpper :: String -> String'); 11 | 12 | eq (S.toUpper (''), ''); 13 | eq (S.toUpper ('ABC def 123'), 'ABC DEF 123'); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/traverse.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | import Identity from 'sanctuary-identity'; 5 | 6 | import S from './internal/sanctuary.js'; 7 | 8 | 9 | test ('traverse', () => { 10 | 11 | eq (String (S.traverse), 'traverse :: (Applicative f, Traversable t) => TypeRep (f b) -> (a -> f b) -> t a -> f (t b)'); 12 | 13 | eq (S.traverse (S.Maybe) (S.parseInt (16)) (['A', 'B', 'C']), S.Just ([10, 11, 12])); 14 | eq (S.traverse (S.Maybe) (S.parseInt (16)) (['A', 'B', 'C', 'X']), S.Nothing); 15 | eq (S.traverse (S.Maybe) (S.parseInt (16)) ({a: 'A', b: 'B', c: 'C'}), S.Just ({a: 10, b: 11, c: 12})); 16 | eq (S.traverse (S.Maybe) (S.parseInt (16)) ({a: 'A', b: 'B', c: 'C', x: 'X'}), S.Nothing); 17 | 18 | eq (S.traverse (Array) (S.I) ([]), [[]]); 19 | eq (S.traverse (Array) (S.I) ([['A', 'a']]), [['A'], ['a']]); 20 | eq (S.traverse (Array) (S.I) ([['A', 'a'], ['B']]), [['A', 'B'], ['a', 'B']]); 21 | eq (S.traverse (Array) (S.I) ([['A', 'a'], ['B', 'b']]), [['A', 'B'], ['A', 'b'], ['a', 'B'], ['a', 'b']]); 22 | 23 | eq (S.traverse (Array) (S.words) (Identity ('')), []); 24 | eq (S.traverse (Array) (S.words) (Identity ('foo')), [Identity ('foo')]); 25 | eq (S.traverse (Array) (S.words) (Identity ('foo bar')), [Identity ('foo'), Identity ('bar')]); 26 | eq (S.traverse (Array) (S.words) (Identity ('foo bar baz')), [Identity ('foo'), Identity ('bar'), Identity ('baz')]); 27 | 28 | eq (S.traverse (Identity) (S.I) ([]), Identity ([])); 29 | eq (S.traverse (Identity) (S.I) ([Identity (1)]), Identity ([1])); 30 | eq (S.traverse (Identity) (S.I) ([Identity (1), Identity (2)]), Identity ([1, 2])); 31 | eq (S.traverse (Identity) (S.I) ([Identity (1), Identity (2), Identity (3)]), Identity ([1, 2, 3])); 32 | 33 | eq (S.traverse (Array) (S.I) ({a: [1, 2], b: [3, 4]}), [{a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 3}, {a: 2, b: 4}]); 34 | 35 | }); 36 | -------------------------------------------------------------------------------- /test/trim.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('trim', () => { 9 | 10 | eq (String (S.trim), 'trim :: String -> String'); 11 | 12 | eq (S.trim (''), ''); 13 | eq (S.trim (' '), ''); 14 | eq (S.trim ('x'), 'x'); 15 | eq (S.trim (' x'), 'x'); 16 | eq (S.trim ('x '), 'x'); 17 | eq (S.trim (' x '), 'x'); 18 | eq (S.trim ('\n\r\t x \n\r\t x \n\r\t'), 'x \n\r\t x'); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/type.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | import vm from 'node:vm'; 3 | 4 | import test from 'oletus'; 5 | 6 | import S from '../index.js'; 7 | 8 | 9 | test ('type', () => { 10 | 11 | eq (String (S.type), 'type :: Any -> { name :: String, namespace :: Maybe String, version :: NonNegativeInteger }'); 12 | 13 | // eslint-disable-next-line prefer-rest-params 14 | eq (S.type (function() { return arguments; } ()), 15 | {namespace: S.Nothing, name: 'Arguments', version: 0}); 16 | eq (S.type ([]), 17 | {namespace: S.Nothing, name: 'Array', version: 0}); 18 | eq (S.type (false), 19 | {namespace: S.Nothing, name: 'Boolean', version: 0}); 20 | eq (S.type (new Date (0)), 21 | {namespace: S.Nothing, name: 'Date', version: 0}); 22 | eq (S.type (new TypeError ()), 23 | {namespace: S.Nothing, name: 'Error', version: 0}); 24 | eq (S.type (() => {}), 25 | {namespace: S.Nothing, name: 'Function', version: 0}); 26 | eq (S.type (null), 27 | {namespace: S.Nothing, name: 'Null', version: 0}); 28 | eq (S.type (0), 29 | {namespace: S.Nothing, name: 'Number', version: 0}); 30 | eq (S.type (/(?:)/), 31 | {namespace: S.Nothing, name: 'RegExp', version: 0}); 32 | eq (S.type (''), 33 | {namespace: S.Nothing, name: 'String', version: 0}); 34 | eq (S.type (undefined), 35 | {namespace: S.Nothing, name: 'Undefined', version: 0}); 36 | eq (S.type (new Boolean (false)), 37 | {namespace: S.Nothing, name: 'Boolean', version: 0}); 38 | eq (S.type (new Number (0)), 39 | {namespace: S.Nothing, name: 'Number', version: 0}); 40 | eq (S.type (new String ('')), 41 | {namespace: S.Nothing, name: 'String', version: 0}); 42 | 43 | eq (S.type (S.Left (42)), 44 | {namespace: S.Just ('sanctuary-either'), name: 'Either', version: 1}); 45 | eq (S.type (S.Right (42)), 46 | {namespace: S.Just ('sanctuary-either'), name: 'Either', version: 1}); 47 | eq (S.type (S.Nothing), 48 | {namespace: S.Just ('sanctuary-maybe'), name: 'Maybe', version: 1}); 49 | eq (S.type (S.Just (42)), 50 | {namespace: S.Just ('sanctuary-maybe'), name: 'Maybe', version: 1}); 51 | 52 | function Gizmo() {} 53 | Gizmo.prototype['@@type'] = 'gadgets/Gizmo@42'; 54 | 55 | eq (S.type (new Gizmo ()), 56 | {namespace: S.Just ('gadgets'), name: 'Gizmo', version: 42}); 57 | eq (S.type (Gizmo), 58 | {namespace: S.Nothing, name: 'Function', version: 0}); 59 | eq (S.type (Gizmo.prototype), 60 | {namespace: S.Nothing, name: 'Object', version: 0}); 61 | 62 | eq (S.type (vm.runInNewContext ('[1, 2, 3]')), 63 | {namespace: S.Nothing, name: 'Array', version: 0}); 64 | 65 | }); 66 | -------------------------------------------------------------------------------- /test/unchecked.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('unchecked', () => { 9 | 10 | eq (S.unchecked.add (2) (2), 4); 11 | eq (S.unchecked.add (2) ('2'), '22'); 12 | eq (S.unchecked.add ('2') (2), '22'); 13 | eq (S.unchecked.add ('2') ('2'), '22'); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/unfold.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('unfold', () => { 9 | 10 | eq (String (S.unfold), 'unfold :: (b -> Maybe (Pair a b)) -> b -> Array a'); 11 | 12 | const f = n => n >= 5 ? S.Nothing : S.Just (S.Pair (n) (n + 1)); 13 | eq (S.unfold (f) (5), []); 14 | eq (S.unfold (f) (4), [4]); 15 | eq (S.unfold (f) (1), [1, 2, 3, 4]); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/unless.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('unless', () => { 9 | 10 | eq (String (S.unless), 'unless :: (a -> Boolean) -> (a -> a) -> a -> a'); 11 | 12 | eq (S.unless (S.lt (0)) (Math.sqrt) (16), 4); 13 | eq (S.unless (S.lt (0)) (Math.sqrt) (-1), -1); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/unlines.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('unlines', () => { 9 | 10 | eq (String (S.unlines), 'unlines :: Array String -> String'); 11 | 12 | eq (S.unlines ([]), ''); 13 | eq (S.unlines (['']), '\n'); 14 | eq (S.unlines (['', '']), '\n\n'); 15 | eq (S.unlines (['\n']), '\n\n'); 16 | eq (S.unlines (['\n', '\n']), '\n\n\n\n'); 17 | eq (S.unlines (['foo', 'bar', 'baz']), 'foo\nbar\nbaz\n'); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/unwords.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('unwords', () => { 9 | 10 | eq (String (S.unwords), 'unwords :: Array String -> String'); 11 | 12 | eq (S.unwords ([]), ''); 13 | eq (S.unwords (['']), ''); 14 | eq (S.unwords (['', '']), ' '); 15 | eq (S.unwords ([' ']), ' '); 16 | eq (S.unwords ([' ', ' ']), ' '); 17 | eq (S.unwords (['foo', 'bar', 'baz']), 'foo bar baz'); 18 | eq (S.unwords ([' foo ', ' bar ', ' baz ']), ' foo bar baz '); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/value.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import strMap from './internal/strMap.js'; 8 | 9 | 10 | test ('value', () => { 11 | 12 | eq (String (S.value), 'value :: String -> StrMap a -> Maybe a'); 13 | 14 | eq (S.value ('foo') ({foo: 1, bar: 2}), S.Just (1)); 15 | eq (S.value ('bar') ({foo: 1, bar: 2}), S.Just (2)); 16 | eq (S.value ('baz') ({foo: 1, bar: 2}), S.Nothing); 17 | 18 | eq (S.value ('valueOf') ({}), S.Nothing); 19 | 20 | eq (S.value ('non-enumerable inherited property') (strMap), S.Nothing); 21 | eq (S.value ('enumerable inherited property') (strMap), S.Nothing); 22 | eq (S.value ('non-enumerable own property') (strMap), S.Nothing); 23 | eq (S.value ('enumerable own property') (strMap), S.Just ('enumerable own property')); 24 | 25 | }); 26 | -------------------------------------------------------------------------------- /test/values.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | import strMap from './internal/strMap.js'; 8 | 9 | 10 | test ('values', () => { 11 | 12 | eq (String (S.values), 'values :: StrMap a -> Array a'); 13 | 14 | eq (S.sort (S.values ({})), []); 15 | eq (S.sort (S.values ({a: 1, b: 2, c: 3})), [1, 2, 3]); 16 | 17 | eq (S.values (strMap), ['enumerable own property']); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/when.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('when', () => { 9 | 10 | eq (String (S.when), 'when :: (a -> Boolean) -> (a -> a) -> a -> a'); 11 | 12 | eq (S.when (S.gte (0)) (Math.sqrt) (16), 4); 13 | eq (S.when (S.gte (0)) (Math.sqrt) (-1), -1); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/words.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('words', () => { 9 | 10 | eq (String (S.words), 'words :: String -> Array String'); 11 | 12 | eq (S.words (''), []); 13 | eq (S.words (' '), []); 14 | eq (S.words (' \t\r\n'), []); 15 | eq (S.words ('foo bar baz'), ['foo', 'bar', 'baz']); 16 | eq (S.words (' foo bar baz '), ['foo', 'bar', 'baz']); 17 | eq (S.words ('\tfoo\r\n\tbar\r\n\tbaz\r\n'), ['foo', 'bar', 'baz']); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/zero.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('zero', () => { 9 | 10 | eq (String (S.zero), 'zero :: Plus f => TypeRep (f a) -> f a'); 11 | 12 | eq (S.zero (Array), []); 13 | eq (S.zero (Object), {}); 14 | eq (S.zero (S.Maybe), S.Nothing); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /test/zip.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('zip', () => { 9 | 10 | eq (String (S.zip), 'zip :: Array a -> Array b -> Array (Pair a b)'); 11 | 12 | eq (S.zip (['a', 'b']) (['x', 'y', 'z']), 13 | [S.Pair ('a') ('x'), S.Pair ('b') ('y')]); 14 | eq (S.zip ([1, 3, 5]) ([2, 4]), 15 | [S.Pair (1) (2), S.Pair (3) (4)]); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/zipWith.js: -------------------------------------------------------------------------------- 1 | import {deepStrictEqual as eq} from 'node:assert'; 2 | 3 | import test from 'oletus'; 4 | 5 | import S from '../index.js'; 6 | 7 | 8 | test ('zipWith', () => { 9 | 10 | eq (String (S.zipWith), 'zipWith :: (a -> b -> c) -> Array a -> Array b -> Array c'); 11 | 12 | eq (S.zipWith (x => y => x + y) (['a', 'b']) (['x', 'y', 'z']), ['ax', 'by']); 13 | eq (S.zipWith (x => y => [x, y]) ([1, 3, 5]) ([2, 4]), [[1, 2], [3, 4]]); 14 | 15 | }); 16 | --------------------------------------------------------------------------------