From c1474b4879da3a6fad34c32113864f58dc5ea3c1 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Fri, 1 Mar 2019 12:05:37 +0100 Subject: [PATCH 01/42] everything --- .circleci/config.yml | 36 +++++ .config | 2 + .eslintrc.json | 16 ++ .gitignore | 2 + .npmrc | 1 + CONTRIBUTING.md | 27 ++++ LICENSE | 24 +++ index.js | 330 ++++++++++++++++++++++++++++++++++++++++ package.json | 37 +++++ test/.eslintrc.json | 6 + test/index.js | 353 +++++++++++++++++++++++++++++++++++++++++++ test/mocha.opts | 1 + 12 files changed, 835 insertions(+) create mode 100644 .circleci/config.yml create mode 100644 .config create mode 100644 .eslintrc.json create mode 100644 .npmrc create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 index.js create mode 100644 package.json create mode 100644 test/.eslintrc.json create mode 100644 test/index.js create mode 100644 test/mocha.opts diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..aeff0ee --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,36 @@ +version: 2 + +jobs: + build: + docker: + - image: circleci/node:6 + environment: + NPM_CONFIG_COLOR: false + NPM_CONFIG_LOGLEVEL: warn + NPM_CONFIG_PROGRESS: false + NVM_DIR: /home/circleci/.nvm + parallelism: 3 + steps: + - checkout + - restore_cache: + keys: + - nvm-cache-{{ checksum ".circleci/config.yml" }} + - run: curl https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash + - save_cache: + key: nvm-cache-{{ checksum ".circleci/config.yml" }} + paths: + - /home/circleci/.nvm + - run: + name: npm install && npm test + command: | + test_with_version() { + source "$NVM_DIR/nvm.sh" + nvm install $1 + nvm exec $1 npm install + nvm exec $1 npm test + } + case $CIRCLE_NODE_INDEX in + 0) npm install && npm test ;; + 1) test_with_version 8 ;; + 2) test_with_version 10 ;; + esac diff --git a/.config b/.config new file mode 100644 index 0000000..f6cd23a --- /dev/null +++ b/.config @@ -0,0 +1,2 @@ +repo-owner = sanctuary-js +repo-name = sanctuary-constant diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..062a65d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,16 @@ +{ + "root": true, + "extends": ["./node_modules/sanctuary-style/eslint-es3.json"], + "overrides": [ + { + "files": ["*.md"], + "globals": {"$": false, "Constant": false, "S": false, "Z": false, "show": false, "type": false} + }, + { + "files": ["index.js"], + "rules": { + "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^S$"}] + } + } + ] +} diff --git a/.gitignore b/.gitignore index e69de29..cba87a3 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +/coverage/ +/node_modules/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..dd7edee --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing + +Note: __README.md__ is generated from comments in __index.js__. Do not modify +__README.md__ directly. + +1. Update local master branch: + + $ git checkout master + $ git pull upstream master + +2. Create feature branch: + + $ git checkout -b feature-x + +3. Make one or more atomic commits, and ensure that each commit has a + descriptive commit message. Commit messages should be line wrapped + at 72 characters. + +4. Run `npm test`, and address any errors. Preferably, fix commits in place + using `git rebase` or `git commit --amend` to make the changes easier to + review. + +5. Push: + + $ git push origin feature-x + +6. Open a pull request. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ab65140 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) 2019 Sanctuary + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/index.js b/index.js new file mode 100644 index 0000000..4911ddb --- /dev/null +++ b/index.js @@ -0,0 +1,330 @@ +/* _____ _____ _____ _____ ______ _____ _____ ______ */ +/* | | | | | | | | | | | | | | | | */ +/* | |__| | | | | | | | |__| '-, ,-' | | | | | | '-, ,-' */ +/* | |__ | | | | | | |__ | | | | | | | | | | */ +/* | | | | | | | | | | | | | | | | | | | | | | */ +/* |_____| |_____| |__|__| |_____| |__| |__|__| |__|__| |__| */ + +//. Fantasy Land +//. +//. # sanctuary-constant +//. +//. A value of type `Constant a b` always contains exactly one value, +//. of type `a`. Mapping over a `Constant a b` has no effect because +//. the `b -> c` function is never applied. + +(function(f) { + + 'use strict'; + + var util = {inspect: {}}; + + /* istanbul ignore else */ + if (typeof module === 'object' && typeof module.exports === 'object') { + module.exports = f (require ('util'), + require ('sanctuary-show'), + require ('sanctuary-type-classes')); + } else if (typeof define === 'function' && define.amd != null) { + define (['sanctuary-show', 'sanctuary-type-classes'], function(show, Z) { + return f (util, show, Z); + }); + } else { + self.sanctuaryConstant = f (util, + self.sanctuaryShow, + self.sanctuaryTypeClasses); + } + +} (function(util, show, Z) { + + 'use strict'; + + /* istanbul ignore if */ + if (typeof __doctest !== 'undefined') { + var $ = __doctest.require ('sanctuary-def'); + var type = __doctest.require ('sanctuary-type-identifiers'); + var S = (function() { + var S = __doctest.require ('sanctuary'); + var typeIdent = (Constant (Array))['@@type']; + var ConstantType = $.BinaryType + ('sanctuary-constant/Constant') + ('') + (function(x) { return type (x) === typeIdent; }) + (function(c) { return [c.value]; }) + (function(c) { return []; }); + var env = Z.concat ( + S.env, + [$.TypeClass, ConstantType ($.Unknown) ($.Unknown)] + ); + return S.create ({checkTypes: true, env: env}); + } ()); + } + + //. `Constant a b` satisfies the following [Fantasy Land][] specifications: + //. + //. ```javascript + //. > const Useless = require ('sanctuary-useless') + //. + //. > S.map (k => + //. . k + ' '.repeat (16 - k.length) + + //. . (Z[k].test (Constant (Useless.constructor) (Useless)) ? '\u2705 ' : + //. . Z[k].test (Constant (Array) (['foo', 'bar', 'baz'])) ? '\u2705 * ' : + //. . /* otherwise */ '\u274C ') + //. . ) (S.keys (Z.filter ($.test ([]) ($.TypeClass), Z))) + //. [ 'Setoid ✅ * ', // if ‘a’ satisfies Setoid + //. . 'Ord ✅ * ', // if ‘a’ satisfies Ord + //. . 'Semigroupoid ❌ ', + //. . 'Category ❌ ', + //. . 'Semigroup ✅ * ', // if ‘a’ satisfies Semigroup + //. . 'Monoid ❌ ', + //. . 'Group ❌ ', + //. . 'Filterable ❌ ', + //. . 'Functor ✅ ', + //. . 'Bifunctor ✅ ', + //. . 'Profunctor ❌ ', + //. . 'Apply ✅ * ', // if ‘a’ satisfies Semigroup + //. . 'Applicative ✅ * ', // if ‘a’ satisfies Monoid + //. . 'Chain ❌ ', + //. . 'ChainRec ❌ ', + //. . 'Monad ❌ ', + //. . 'Alt ❌ ', + //. . 'Plus ❌ ', + //. . 'Alternative ❌ ', + //. . 'Foldable ✅ ', + //. . 'Traversable ✅ ', + //. . 'Extend ❌ ', + //. . 'Comonad ❌ ', + //. . 'Contravariant ❌ ' ] + //. ``` + + //# Constant :: TypeRep a -> a -> Constant a b + //. + //. Constant's sole data constructor. The [type representative][] makes + //. `Constant (M)` an [Applicative][]-compatible type representative if + //. `M` represents some monoidal type. + //. + //. ```javascript + //. > Constant (String) ('abc') + //. Constant (String) ('abc') + //. + //. > Constant (Number) (123) + //. Constant (Number) (123) + //. ``` + function Constant(A) { + var prototype = { + /* eslint-disable key-spacing */ + 'constructor': Constant$bound, + '@@show': Constant$prototype$show, + 'fantasy-land/map': Constant$prototype$map, + 'fantasy-land/bimap': Constant$prototype$bimap, + 'fantasy-land/reduce': Constant$prototype$reduce, + 'fantasy-land/traverse': Constant$prototype$traverse + /* eslint-enable key-spacing */ + }; + + var custom = util.inspect.custom; + /* istanbul ignore else */ + if (typeof custom === 'symbol') { + prototype[custom] = Constant$prototype$show; + } else { + prototype.inspect = Constant$prototype$show; + } + + function Constant$bound(value) { + var identity = Object.create (prototype); + if (Z.Setoid.test (value)) { + identity['fantasy-land/equals'] = Constant$prototype$equals; + if (Z.Ord.test (value)) { + identity['fantasy-land/lte'] = Constant$prototype$lte; + } + } + if (Z.Semigroup.test (value)) { + identity['fantasy-land/concat'] = Constant$prototype$concat; + identity['fantasy-land/ap'] = Constant$prototype$ap; + } + identity.value = value; + return identity; + } + + Constant$bound.toString = function() { + if (A['@@type'] === Constant$bound['@@type']) { + return 'Constant (' + show (A) + ')'; + } else if (Object.prototype.hasOwnProperty.call (A, 'name')) { + return 'Constant (' + A.name + ')'; + } else { + var source = String (A); + var match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source); + return 'Constant (' + (match == null ? source : match[1]) + ')'; + } + }; + + //# Constant.@@type :: String + //. + //. Constant [type identifier][]. + //. + //. ```javascript + //. > type (Constant (Number) (42)) + //. 'sanctuary-constant/Constant@1' + //. + //. > type.parse (type (Constant (Number) (42))) + //. {namespace: 'sanctuary-constant', name: 'Constant', version: 1} + //. ``` + Constant$bound['@@type'] = 'sanctuary-constant/Constant@1'; + + //# Constant.fantasy-land/of :: Monoid m => a -> Constant m a + //. + //. `of (Constant (M)) (x)` is equivalent to `Constant (M) (empty (M))`. + //. + //. ```javascript + //. > S.of (Constant (Array)) (42) + //. Constant (Array) ([]) + //. + //. > S.of (Constant (String)) (42) + //. Constant (String) ('') + //. ``` + (function() { + var empty; + try { empty = Z.empty (A); } catch (err) { return; } + Constant$bound['fantasy-land/of'] = function Constant$of(x) { + return Constant$bound (empty); + }; + } ()); + + //# Constant#@@show :: Showable a => Constant a b ~> () -> String + //. + //. `show (Constant (A) (x))` is equivalent to + //. `'Constant (' + A.name + ') (' + show (x) + ')'`. + //. + //. ```javascript + //. > show (Constant (Array) (['foo', 'bar', 'baz'])) + //. 'Constant (Array) (["foo", "bar", "baz"])' + //. ``` + function Constant$prototype$show() { + return String (Constant$bound) + ' (' + show (this.value) + ')'; + } + + //# Constant#fantasy-land/equals :: Setoid a => Constant a b ~> Constant a b -> Boolean + //. + //. `Constant (A) (x)` is equal to `Constant (A) (y)` [iff][] `x` is + //. equal to `y` according to [`Z.equals`][]. + //. + //. ```javascript + //. > S.equals (Constant (Array) ([1, 2, 3])) + //. . (Constant (Array) ([1, 2, 3])) + //. true + //. + //. > S.equals (Constant (Array) ([1, 2, 3])) + //. . (Constant (Array) ([3, 2, 1])) + //. false + //. ``` + function Constant$prototype$equals(other) { + return Z.equals (this.value, other.value); + } + + //# Constant#fantasy-land/lte :: Ord a => Constant a b ~> Constant a b -> Boolean + //. + //. `Constant (A) (x)` is less than or equal to `Constant (A) (y)` [iff][] + //. `x` is less than or equal to `y` according to [`Z.lte`][]. + //. + //. ```javascript + //. > S.filter (S.lte (Constant (Number) (1))) + //. . ([Constant (Number) (0), + //. . Constant (Number) (1), + //. . Constant (Number) (2)]) + //. [Constant (Number) (0), Constant (Number) (1)] + //. ``` + function Constant$prototype$lte(other) { + return Z.lte (this.value, other.value); + } + + //# Constant#fantasy-land/concat :: Semigroup a => Constant a b ~> Constant a b -> Constant a b + //. + //. `concat (Constant (A) (x)) (Constant (A) (y))` is equivalent to + //. `Constant (A) (concat (x) (y))`. + //. + //. ```javascript + //. > S.concat (Constant (Array) ([1, 2, 3])) + //. . (Constant (Array) ([4, 5, 6])) + //. Constant (Array) ([1, 2, 3, 4, 5, 6]) + //. ``` + function Constant$prototype$concat(other) { + return Constant$bound (Z.concat (this.value, other.value)); + } + + //# Constant#fantasy-land/map :: Constant a b ~> (b -> c) -> Constant a c + //. + //. `map (f) (Constant (A) (x))` is equivalent to `Constant (A) (x)`. + //. + //. ```javascript + //. > S.map (Math.sqrt) (Constant (Number) (64)) + //. Constant (Number) (64) + //. ``` + function Constant$prototype$map(f) { + return this; + } + + //# Constant#fantasy-land/bimap :: Constant a c ~> (a -> b, c -> d) -> Constant b d + //. + //. `bimap (f) (g) (Constant (A) (x))` is equivalent to + //. `Constant (A) (f (x))`. + //. + //. ```javascript + //. > S.bimap (s => s.length) (Math.sqrt) (Constant (String) ('abc')) + //. Constant (Number) (3) + //. ``` + function Constant$prototype$bimap(f, g) { + var x = f (this.value); + return Constant (x.constructor) (x); + } + + //# Constant#fantasy-land/ap :: Semigroup a => Constant a b ~> Constant a (b -> c) -> Constant a c + //. + //. `ap (Constant (A) (x)) (Constant (A) (y))` is equivalent to + //. `concat (Constant (A) (x)) (Constant (A) (y))`. + //. + //. ```javascript + //. > S.ap (Constant (Array) ([1, 2, 3])) (Constant (Array) ([4, 5, 6])) + //. Constant (Array) ([1, 2, 3, 4, 5, 6]) + //. ``` + function Constant$prototype$ap(other) { + return Z.concat (other, this); + } + + //# Constant#fantasy-land/reduce :: Constant a b ~> ((c, b) -> c, c) -> c + //. + //. `reduce (f) (x) (Constant (A) (y))` is equivalent to `x`. + //. + //. ```javascript + //. > S.reduce (S.add) (100) (Constant (Number) (42)) + //. 100 + //. ``` + function Constant$prototype$reduce(f, x) { + return x; + } + + //# Constant#fantasy-land/traverse :: Applicative f => Constant a b ~> (TypeRep f, b -> f c) -> f (Constant a c) + //. + //. `traverse (A) (f) (Constant (X) (x))` is equivalent to + //. `of (A) (Constant (X) (x))`. + //. + //. ```javascript + //. > S.traverse (Array) (Math.sqrt) (Constant (Number) (64)) + //. [Constant (Number) (64)] + //. ``` + function Constant$prototype$traverse(typeRep, f) { + return Z.of (typeRep, this); + } + + return Constant$bound; + } + + return Constant; + +})); + +//. [Applicative]: v:fantasyland/fantasy-land#Applicative +//. [Fantasy Land]: v:fantasyland/fantasy-land +//. [`Z.equals`]: v:sanctuary-js/sanctuary-type-classes#equals +//. [`Z.lte`]: v:sanctuary-js/sanctuary-type-classes#lte +//. [iff]: https://en.wikipedia.org/wiki/If_and_only_if +//. [type identifier]: v:sanctuary-js/sanctuary-type-identifiers +//. [type representative]: v:fantasyland/fantasy-land#type-representatives diff --git a/package.json b/package.json new file mode 100644 index 0000000..8e54776 --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "sanctuary-constant", + "version": "0.0.0", + "description": "Fantasy Land -compliant Constant type", + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/sanctuary-js/sanctuary-constant.git" + }, + "files": [ + "/LICENSE", + "/README.md", + "/index.js", + "/package.json" + ], + "dependencies": { + "sanctuary-show": "1.0.x", + "sanctuary-type-classes": "10.0.0" + }, + "devDependencies": { + "fantasy-land": "3.5.0", + "fantasy-laws": "1.2.x", + "jsverify": "0.8.x", + "sanctuary": "0.14.1", + "sanctuary-def": "0.19.x", + "sanctuary-identity": "1.1.x", + "sanctuary-scripts": "2.0.x", + "sanctuary-type-identifiers": "2.0.1", + "sanctuary-useless": "1.0.x" + }, + "scripts": { + "doctest": "sanctuary-doctest", + "lint": "sanctuary-lint", + "release": "sanctuary-release", + "test": "npm run lint && sanctuary-test && npm run doctest" + } +} diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 0000000..249d948 --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "root": true, + "extends": ["../node_modules/sanctuary-style/eslint-es6.json"], + "env": {"node": true}, + "globals": {"suite": false, "test": false} +} diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..69437b5 --- /dev/null +++ b/test/index.js @@ -0,0 +1,353 @@ +'use strict'; + +const assert = require ('assert'); + +const laws = require ('fantasy-laws'); +const jsc = require ('jsverify'); +const Identity = require ('sanctuary-identity'); +const show = require ('sanctuary-show'); +const Z = require ('sanctuary-type-classes'); +const type = require ('sanctuary-type-identifiers'); +const Useless = require ('sanctuary-useless'); + +const Constant = require ('..'); + + +// ConstantArb :: Monoid m => TypeRep m -> Arbitrary a -> Arbitrary (Constant a b) +const ConstantArb = M => arb => arb.smap (Constant (M), c => c.value, show); + +// IdentityArb :: Arbitrary a -> Arbitrary (Identity a) +const IdentityArb = arb => arb.smap (Identity, Z.extract, show); + +// NonEmpty :: Arbitrary a -> Arbitrary (NonEmpty a) +const NonEmpty = arb => jsc.suchthat (arb, x => not (empty (x))); + +// NumberArb :: Arbitrary Number +const NumberArb = jsc.oneof ( + jsc.constant (NaN), + jsc.constant (-Infinity), + jsc.constant (Number.MIN_SAFE_INTEGER), + jsc.constant (-10000), + jsc.constant (-9999), + jsc.constant (-0.5), + jsc.constant (-0), + jsc.constant (0), + jsc.constant (0.5), + jsc.constant (9999), + jsc.constant (10000), + jsc.constant (Number.MAX_SAFE_INTEGER), + jsc.constant (Infinity) +); + +// empty :: Monoid m => m -> Boolean +const empty = m => Z.equals (m, Z.empty (m.constructor)); + +// not :: Boolean -> Boolean +const not = b => !b; + +// testLaws :: Object -> Object -> Undefined +const testLaws = laws => arbs => { + (Object.keys (laws)).forEach (name => { + eq (laws[name].length) (arbs[name].length); + test (name.replace (/[A-Z]/g, c => ' ' + c.toLowerCase ()), + laws[name] (...arbs[name])); + }); +}; + +// eq :: a -> b -> Undefined ! +function eq(actual) { + assert.strictEqual (arguments.length, eq.length); + return function eq$1(expected) { + assert.strictEqual (arguments.length, eq$1.length); + assert.strictEqual (show (actual), show (expected)); + assert.strictEqual (Z.equals (actual, expected), true); + }; +} + + +suite ('Constant', () => { + + test ('metadata', () => { + eq (typeof Constant) ('function'); + eq (Constant.name) ('Constant'); + eq (Constant.length) (1); + }); + + test ('@@type', () => { + eq (type (Constant (Number) (0))) ('sanctuary-constant/Constant@1'); + eq (type.parse (type (Constant (Number) (0)))) + ({namespace: 'sanctuary-constant', name: 'Constant', version: 1}); + }); + + test ('@@show', () => { + eq (show (Constant (Array) (['foo', 'bar', 'baz']))) + ('Constant (Array) (["foo", "bar", "baz"])'); + eq (show (Constant (Constant (Constant (Number))) + (Constant (Constant (Number)) + (Constant (Number) + (-0))))) + ('Constant (Constant (Constant (Number)))' + + ' (Constant (Constant (Number))' + + ' (Constant (Number)' + + ' (-0)))'); + + // Foo :: String -> Foo + function Foo(value) { + return { + 'constructor': Foo, + '@@show': function Foo$show() { return 'Foo (' + show (value) + ')'; }, + }; + } + delete Foo.name; + eq (show (Constant (Foo) (Foo ('foo')))) + ('Constant (Foo) (Foo ("foo"))'); + + // Bar :: String -> Bar + const Bar = value => ({ + 'constructor': Bar, + '@@show': function Bar$show() { return 'Bar (' + show (value) + ')'; }, + }); + delete Bar.name; + eq (show (Constant (Bar) (Bar ('bar')))) + ('Constant (' + String (Bar) + ') (Bar ("bar"))'); + }); + +}); + +suite ('type-class predicates', () => { + + test ('Setoid', () => { + eq (Z.Setoid.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Setoid.test (Constant (RegExp) (/(?:)/))) (true); + }); + + test ('Ord', () => { + eq (Z.Ord.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Ord.test (Constant (RegExp) (/(?:)/))) (false); + eq (Z.Ord.test (Constant (Number) (0))) (true); + }); + + test ('Semigroupoid', () => { + eq (Z.Semigroupoid.test (Constant (Array) ([]))) (false); + }); + + test ('Category', () => { + eq (Z.Category.test (Constant (Array) ([]))) (false); + }); + + test ('Semigroup', () => { + eq (Z.Semigroup.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Semigroup.test (Constant (Number) (0))) (false); + eq (Z.Semigroup.test (Constant (Array) ([]))) (true); + }); + + test ('Monoid', () => { + eq (Z.Monoid.test (Constant (Array) ([]))) (false); + }); + + test ('Group', () => { + eq (Z.Group.test (Constant (Array) ([]))) (false); + }); + + test ('Filterable', () => { + eq (Z.Filterable.test (Constant (Array) ([]))) (false); + }); + + test ('Functor', () => { + eq (Z.Functor.test (Constant (Useless.constructor) (Useless))) (true); + }); + + test ('Bifunctor', () => { + eq (Z.Bifunctor.test (Constant (Useless.constructor) (Useless))) (true); + }); + + test ('Profunctor', () => { + eq (Z.Profunctor.test (Constant (Function) (Math.sqrt))) (false); + }); + + test ('Apply', () => { + eq (Z.Apply.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Apply.test (Constant (Number) (0))) (false); + eq (Z.Apply.test (Constant (Array) ([]))) (true); + }); + + test ('Applicative', () => { + eq (Z.Applicative.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Applicative.test (Constant (Number) (0))) (false); + eq (Z.Applicative.test (Constant (Array) ([]))) (true); + }); + + test ('Chain', () => { + eq (Z.Chain.test (Constant (Array) ([]))) (false); + }); + + test ('ChainRec', () => { + eq (Z.ChainRec.test (Constant (Array) ([]))) (false); + }); + + test ('Monad', () => { + eq (Z.Monad.test (Constant (Array) ([]))) (false); + }); + + test ('Alt', () => { + eq (Z.Alt.test (Constant (Array) ([]))) (false); + }); + + test ('Plus', () => { + eq (Z.Plus.test (Constant (Array) ([]))) (false); + }); + + test ('Alternative', () => { + eq (Z.Alternative.test (Constant (Array) ([]))) (false); + }); + + test ('Foldable', () => { + eq (Z.Foldable.test (Constant (Useless.constructor) (Useless))) (true); + }); + + test ('Traversable', () => { + eq (Z.Traversable.test (Constant (Useless.constructor) (Useless))) (true); + }); + + test ('Extend', () => { + eq (Z.Extend.test (Constant (Array) ([]))) (false); + }); + + test ('Comonad', () => { + eq (Z.Comonad.test (Constant (Array) ([]))) (false); + }); + + test ('Contravariant', () => { + eq (Z.Contravariant.test (Constant (Function) (Math.sqrt))) (false); + }); + +}); + +suite ('Setoid laws', () => { + testLaws (laws.Setoid) ({ + reflexivity: [ + ConstantArb (Number) (NumberArb), + ], + symmetry: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + transitivity: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + }); +}); + +suite ('Ord laws', () => { + testLaws (laws.Ord) ({ + totality: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + antisymmetry: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + transitivity: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + }); +}); + +suite ('Semigroup laws', () => { + testLaws (laws.Semigroup (Z.equals)) ({ + associativity: [ + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ], + }); +}); + +suite ('Functor laws', () => { + testLaws (laws.Functor (Z.equals)) ({ + identity: [ + ConstantArb (String) (jsc.string), + ], + composition: [ + ConstantArb (String) (jsc.string), + jsc.constant (Math.sqrt), + jsc.constant (Math.abs), + ], + }); +}); + +suite ('Bifunctor laws', () => { + testLaws (laws.Bifunctor (Z.equals)) ({ + identity: [ + ConstantArb (String) (jsc.string), + ], + composition: [ + ConstantArb (String) (jsc.string), + jsc.constant (Math.sqrt), + jsc.constant (s => s.length), + jsc.constant (Math.sqrt), + jsc.constant (Math.abs), + ], + }); +}); + +suite ('Apply laws', () => { + testLaws (laws.Apply (Z.equals)) ({ + composition: [ + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ], + }); +}); + +suite ('Applicative laws', () => { + testLaws (laws.Applicative (Z.equals, Constant (Array))) ({ + identity: [ + ConstantArb (Array) (jsc.array (jsc.number)), + ], + homomorphism: [ + jsc.constant (Math.abs), + jsc.number, + ], + interchange: [ + ConstantArb (Array) (jsc.array (jsc.number)), + jsc.string, + ], + }); +}); + +suite ('Foldable laws', () => { + testLaws (laws.Foldable (Z.equals)) ({ + associativity: [ + jsc.constant (s => x => s + s), + jsc.string, + ConstantArb (Number) (jsc.number), + ], + }); +}); + +suite ('Traversable laws', () => { + testLaws (laws.Traversable (Z.equals)) ({ + naturality: [ + jsc.constant (Array), + jsc.constant (Identity), + jsc.constant (xs => Identity (xs[0])), + ConstantArb (Array) (NonEmpty (jsc.array (jsc.number))), + ], + identity: [ + jsc.constant (Array), + ConstantArb (String) (jsc.string), + ], + composition: [ + jsc.constant (Array), + jsc.constant (Identity), + ConstantArb (Array) (jsc.array (IdentityArb (jsc.string))), + ], + }); +}); diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..5efaf24 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1 @@ +--ui tdd From 7d322caf72627a7b54ad0c98baadc5eefe5a4077 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Tue, 5 Mar 2019 19:58:54 +0100 Subject: [PATCH 02/42] fantasy-land@4.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e54776..30fc53c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "sanctuary-type-classes": "10.0.0" }, "devDependencies": { - "fantasy-land": "3.5.0", + "fantasy-land": "4.0.1", "fantasy-laws": "1.2.x", "jsverify": "0.8.x", "sanctuary": "0.14.1", From 3145b1bb01d725a9c5116277278d8c9b8d905867 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sat, 9 Mar 2019 21:06:12 +0100 Subject: [PATCH 03/42] sanctuary-scripts@3.0.x --- .gitignore | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index cba87a3..bd53bbe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +/.nyc_output/ /coverage/ /node_modules/ diff --git a/package.json b/package.json index 30fc53c..a3ba55e 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "sanctuary": "0.14.1", "sanctuary-def": "0.19.x", "sanctuary-identity": "1.1.x", - "sanctuary-scripts": "2.0.x", + "sanctuary-scripts": "3.0.x", "sanctuary-type-identifiers": "2.0.1", "sanctuary-useless": "1.0.x" }, From 4c087c8cc8cd0e7e06f519fe2601eee94abda393 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sun, 10 Mar 2019 00:38:21 +0100 Subject: [PATCH 04/42] sanctuary@1.0.0 --- index.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 4911ddb..ed67e2f 100644 --- a/index.js +++ b/index.js @@ -69,7 +69,7 @@ //. . (Z[k].test (Constant (Useless.constructor) (Useless)) ? '\u2705 ' : //. . Z[k].test (Constant (Array) (['foo', 'bar', 'baz'])) ? '\u2705 * ' : //. . /* otherwise */ '\u274C ') - //. . ) (S.keys (Z.filter ($.test ([]) ($.TypeClass), Z))) + //. . ) (S.keys (S.unchecked.filter (S.is ($.TypeClass)) (Z))) //. [ 'Setoid ✅ * ', // if ‘a’ satisfies Setoid //. . 'Ord ✅ * ', // if ‘a’ satisfies Ord //. . 'Semigroupoid ❌ ', diff --git a/package.json b/package.json index a3ba55e..600f680 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "fantasy-land": "4.0.1", "fantasy-laws": "1.2.x", "jsverify": "0.8.x", - "sanctuary": "0.14.1", + "sanctuary": "1.0.0", "sanctuary-def": "0.19.x", "sanctuary-identity": "1.1.x", "sanctuary-scripts": "3.0.x", From 08e0b5befb80b0c52ff3f9520910cd08ac8a160f Mon Sep 17 00:00:00 2001 From: David Chambers Date: Thu, 21 Mar 2019 11:11:22 +0100 Subject: [PATCH 05/42] sanctuary-scripts@3.1.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 600f680..db77ae8 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "sanctuary": "1.0.0", "sanctuary-def": "0.19.x", "sanctuary-identity": "1.1.x", - "sanctuary-scripts": "3.0.x", + "sanctuary-scripts": "3.1.x", "sanctuary-type-identifiers": "2.0.1", "sanctuary-useless": "1.0.x" }, From b4a89ad6856ad98444099e96ed293a0d088d8797 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Tue, 2 Apr 2019 16:56:40 +0200 Subject: [PATCH 06/42] sanctuary-scripts@3.2.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index db77ae8..c5e9bad 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "sanctuary": "1.0.0", "sanctuary-def": "0.19.x", "sanctuary-identity": "1.1.x", - "sanctuary-scripts": "3.1.x", + "sanctuary-scripts": "sanctuary-js/sanctuary-scripts#ae8bfe9acca55bd583d65b920127f6726cf3e192", "sanctuary-type-identifiers": "2.0.1", "sanctuary-useless": "1.0.x" }, From e16d2f596d3193d5458e428fc05c02f89951a67b Mon Sep 17 00:00:00 2001 From: David Chambers Date: Thu, 4 Apr 2019 19:43:44 +0200 Subject: [PATCH 07/42] sanctuary-scripts@3.2.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c5e9bad..7ae6678 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "sanctuary": "1.0.0", "sanctuary-def": "0.19.x", "sanctuary-identity": "1.1.x", - "sanctuary-scripts": "sanctuary-js/sanctuary-scripts#ae8bfe9acca55bd583d65b920127f6726cf3e192", + "sanctuary-scripts": "3.2.x", "sanctuary-type-identifiers": "2.0.1", "sanctuary-useless": "1.0.x" }, From fbad40028e1812970fa40be9e19bd595893559b8 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Fri, 5 Apr 2019 18:18:51 +0200 Subject: [PATCH 08/42] sanctuary-type-classes@11.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ae6678..112f294 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ ], "dependencies": { "sanctuary-show": "1.0.x", - "sanctuary-type-classes": "10.0.0" + "sanctuary-type-classes": "11.0.0" }, "devDependencies": { "fantasy-land": "4.0.1", From 63db317ba04f7c2e1532bd14d1be26af48b008d0 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Fri, 26 Apr 2019 00:20:27 +0200 Subject: [PATCH 09/42] sanctuary-def@0.20.x --- index.js | 31 +++++++++---------------------- package.json | 2 +- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index ed67e2f..bb1844e 100644 --- a/index.js +++ b/index.js @@ -44,21 +44,20 @@ var type = __doctest.require ('sanctuary-type-identifiers'); var S = (function() { var S = __doctest.require ('sanctuary'); - var typeIdent = (Constant (Array))['@@type']; var ConstantType = $.BinaryType - ('sanctuary-constant/Constant') + ('Constant') ('') - (function(x) { return type (x) === typeIdent; }) + ([]) + (function(x) { return type (x) === constantTypeIdent; }) (function(c) { return [c.value]; }) (function(c) { return []; }); - var env = Z.concat ( - S.env, - [$.TypeClass, ConstantType ($.Unknown) ($.Unknown)] - ); - return S.create ({checkTypes: true, env: env}); + var env = Z.concat (S.env, [ConstantType ($.Unknown) ($.Unknown)]); + return S.create ({checkTypes: false, env: env}); } ()); } + var constantTypeIdent = 'sanctuary-constant/Constant@1'; + //. `Constant a b` satisfies the following [Fantasy Land][] specifications: //. //. ```javascript @@ -69,7 +68,7 @@ //. . (Z[k].test (Constant (Useless.constructor) (Useless)) ? '\u2705 ' : //. . Z[k].test (Constant (Array) (['foo', 'bar', 'baz'])) ? '\u2705 * ' : //. . /* otherwise */ '\u274C ') - //. . ) (S.keys (S.unchecked.filter (S.is ($.TypeClass)) (Z))) + //. . ) (S.filter (S.test (/^(?=[A-Z])(?!TypeClass$)/)) (Object.keys (Z))) //. [ 'Setoid ✅ * ', // if ‘a’ satisfies Setoid //. . 'Ord ✅ * ', // if ‘a’ satisfies Ord //. . 'Semigroupoid ❌ ', @@ -157,18 +156,7 @@ } }; - //# Constant.@@type :: String - //. - //. Constant [type identifier][]. - //. - //. ```javascript - //. > type (Constant (Number) (42)) - //. 'sanctuary-constant/Constant@1' - //. - //. > type.parse (type (Constant (Number) (42))) - //. {namespace: 'sanctuary-constant', name: 'Constant', version: 1} - //. ``` - Constant$bound['@@type'] = 'sanctuary-constant/Constant@1'; + Constant$bound['@@type'] = constantTypeIdent; //# Constant.fantasy-land/of :: Monoid m => a -> Constant m a //. @@ -326,5 +314,4 @@ //. [`Z.equals`]: v:sanctuary-js/sanctuary-type-classes#equals //. [`Z.lte`]: v:sanctuary-js/sanctuary-type-classes#lte //. [iff]: https://en.wikipedia.org/wiki/If_and_only_if -//. [type identifier]: v:sanctuary-js/sanctuary-type-identifiers //. [type representative]: v:fantasyland/fantasy-land#type-representatives diff --git a/package.json b/package.json index 112f294..3639c3b 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "fantasy-laws": "1.2.x", "jsverify": "0.8.x", "sanctuary": "1.0.0", - "sanctuary-def": "0.19.x", + "sanctuary-def": "0.20.x", "sanctuary-identity": "1.1.x", "sanctuary-scripts": "3.2.x", "sanctuary-type-identifiers": "2.0.1", From 89c922c21dff5909e08b8bcdb843d02bf7f52ab9 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 4 Nov 2019 00:43:07 +0100 Subject: [PATCH 10/42] sanctuary@2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3639c3b..7d7dd7b 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "fantasy-land": "4.0.1", "fantasy-laws": "1.2.x", "jsverify": "0.8.x", - "sanctuary": "1.0.0", + "sanctuary": "2.0.1", "sanctuary-def": "0.20.x", "sanctuary-identity": "1.1.x", "sanctuary-scripts": "3.2.x", From 7b221f0c5afaaf3d65fd2eb321e46a5009ff229f Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 4 Nov 2019 00:43:52 +0100 Subject: [PATCH 11/42] sanctuary-type-identifiers@3.0.0 --- index.js | 13 ++++++------- package.json | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index bb1844e..680ba5b 100644 --- a/index.js +++ b/index.js @@ -112,6 +112,7 @@ var prototype = { /* eslint-disable key-spacing */ 'constructor': Constant$bound, + '@@type': constantTypeIdent, '@@show': Constant$prototype$show, 'fantasy-land/map': Constant$prototype$map, 'fantasy-land/bimap': Constant$prototype$bimap, @@ -145,19 +146,17 @@ } Constant$bound.toString = function() { - if (A['@@type'] === Constant$bound['@@type']) { - return 'Constant (' + show (A) + ')'; - } else if (Object.prototype.hasOwnProperty.call (A, 'name')) { - return 'Constant (' + A.name + ')'; - } else { + if (!(Object.prototype.hasOwnProperty.call (A, 'name'))) { var source = String (A); var match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source); return 'Constant (' + (match == null ? source : match[1]) + ')'; + } else if (A.name === Constant$bound.name) { + return 'Constant (' + show (A) + ')'; + } else { + return 'Constant (' + A.name + ')'; } }; - Constant$bound['@@type'] = constantTypeIdent; - //# Constant.fantasy-land/of :: Monoid m => a -> Constant m a //. //. `of (Constant (M)) (x)` is equivalent to `Constant (M) (empty (M))`. diff --git a/package.json b/package.json index 7d7dd7b..e82d558 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ ], "dependencies": { "sanctuary-show": "1.0.x", - "sanctuary-type-classes": "11.0.0" + "sanctuary-type-classes": "12.0.0" }, "devDependencies": { "fantasy-land": "4.0.1", @@ -23,10 +23,10 @@ "jsverify": "0.8.x", "sanctuary": "2.0.1", "sanctuary-def": "0.20.x", - "sanctuary-identity": "1.1.x", + "sanctuary-identity": "2.0.x", "sanctuary-scripts": "3.2.x", - "sanctuary-type-identifiers": "2.0.1", - "sanctuary-useless": "1.0.x" + "sanctuary-type-identifiers": "3.0.0", + "sanctuary-useless": "2.0.x" }, "scripts": { "doctest": "sanctuary-doctest", From 254bd7758bb380ef1a59fd7f70ed1f4b31cadd14 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 1 Jan 2020 15:04:57 +0100 Subject: [PATCH 12/42] add FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..ef08538 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [davidchambers] From eb27a56ae0c30e978ca999c13fb69851405b9a95 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Thu, 2 Jan 2020 22:03:39 +0100 Subject: [PATCH 13/42] circle: housekeeping --- .circleci/config.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index aeff0ee..2ec1162 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,15 +1,13 @@ -version: 2 +version: 2.1 jobs: build: docker: - - image: circleci/node:6 + - image: circleci/node:12 environment: NPM_CONFIG_COLOR: false - NPM_CONFIG_LOGLEVEL: warn - NPM_CONFIG_PROGRESS: false NVM_DIR: /home/circleci/.nvm - parallelism: 3 + parallelism: 4 steps: - checkout - restore_cache: @@ -30,7 +28,8 @@ jobs: nvm exec $1 npm test } case $CIRCLE_NODE_INDEX in - 0) npm install && npm test ;; + 0) test_with_version 6 ;; 1) test_with_version 8 ;; 2) test_with_version 10 ;; + 3) npm install && npm test ;; esac From 828e36d88533137420ae70407e82e55dc73534f6 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Fri, 3 Jan 2020 13:59:25 +0100 Subject: [PATCH 14/42] sanctuary-scripts@4.0.x --- .circleci/config.yml | 9 ++++----- .config | 1 + CONTRIBUTING.md => .github/CONTRIBUTING.md | 0 package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2ec1162..2ee728d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ jobs: environment: NPM_CONFIG_COLOR: false NVM_DIR: /home/circleci/.nvm - parallelism: 4 + parallelism: 3 steps: - checkout - restore_cache: @@ -28,8 +28,7 @@ jobs: nvm exec $1 npm test } case $CIRCLE_NODE_INDEX in - 0) test_with_version 6 ;; - 1) test_with_version 8 ;; - 2) test_with_version 10 ;; - 3) npm install && npm test ;; + 0) test_with_version 8 ;; + 1) test_with_version 10 ;; + 2) npm install && npm test ;; esac diff --git a/.config b/.config index f6cd23a..68751e9 100644 --- a/.config +++ b/.config @@ -1,2 +1,3 @@ repo-owner = sanctuary-js repo-name = sanctuary-constant +contributing-file = .github/CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/package.json b/package.json index e82d558..d70352b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "sanctuary": "2.0.1", "sanctuary-def": "0.20.x", "sanctuary-identity": "2.0.x", - "sanctuary-scripts": "3.2.x", + "sanctuary-scripts": "4.0.x", "sanctuary-type-identifiers": "3.0.0", "sanctuary-useless": "2.0.x" }, From 0985701bc68218eb0060a069e2ea1ba7248dba14 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 15 Jan 2020 22:58:12 +0100 Subject: [PATCH 15/42] sanctuary@2.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d70352b..86397d1 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "fantasy-land": "4.0.1", "fantasy-laws": "1.2.x", "jsverify": "0.8.x", - "sanctuary": "2.0.1", + "sanctuary": "2.0.2", "sanctuary-def": "0.20.x", "sanctuary-identity": "2.0.x", "sanctuary-scripts": "4.0.x", From 79b0e9d80339e4030d97e5231955d87c3cc377cc Mon Sep 17 00:00:00 2001 From: David Chambers Date: Fri, 17 Jan 2020 16:33:30 +0100 Subject: [PATCH 16/42] sanctuary-show@2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 86397d1..cda0dc6 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "/package.json" ], "dependencies": { - "sanctuary-show": "1.0.x", + "sanctuary-show": "2.0.0", "sanctuary-type-classes": "12.0.0" }, "devDependencies": { From 0cf9726daa996e075398dca319ef266f5ac3c2f3 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sat, 18 Jan 2020 16:29:37 +0100 Subject: [PATCH 17/42] sanctuary-type-classes@12.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cda0dc6..4e24ae9 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ ], "dependencies": { "sanctuary-show": "2.0.0", - "sanctuary-type-classes": "12.0.0" + "sanctuary-type-classes": "12.1.0" }, "devDependencies": { "fantasy-land": "4.0.1", From aa97ae8a4ca51f92d60d05ce5684787c09b8d6af Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sun, 19 Jan 2020 14:59:10 +0100 Subject: [PATCH 18/42] sanctuary-identity@2.1.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e24ae9..9b71e54 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "jsverify": "0.8.x", "sanctuary": "2.0.2", "sanctuary-def": "0.20.x", - "sanctuary-identity": "2.0.x", + "sanctuary-identity": "2.1.x", "sanctuary-scripts": "4.0.x", "sanctuary-type-identifiers": "3.0.0", "sanctuary-useless": "2.0.x" From 58ba764f132459d83edfb849dd309a1aaf6ff5d0 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 20 Jan 2020 01:48:15 +0100 Subject: [PATCH 19/42] sanctuary@3.0.0 --- index.js | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 680ba5b..2dcaf2d 100644 --- a/index.js +++ b/index.js @@ -68,7 +68,7 @@ //. . (Z[k].test (Constant (Useless.constructor) (Useless)) ? '\u2705 ' : //. . Z[k].test (Constant (Array) (['foo', 'bar', 'baz'])) ? '\u2705 * ' : //. . /* otherwise */ '\u274C ') - //. . ) (S.filter (S.test (/^(?=[A-Z])(?!TypeClass$)/)) (Object.keys (Z))) + //. . ) (S.keys (S.unchecked.filter (S.is ($.TypeClass)) (Z))) //. [ 'Setoid ✅ * ', // if ‘a’ satisfies Setoid //. . 'Ord ✅ * ', // if ‘a’ satisfies Ord //. . 'Semigroupoid ❌ ', diff --git a/package.json b/package.json index 9b71e54..82d6ccf 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "fantasy-land": "4.0.1", "fantasy-laws": "1.2.x", "jsverify": "0.8.x", - "sanctuary": "2.0.2", - "sanctuary-def": "0.20.x", + "sanctuary": "3.0.0", + "sanctuary-def": "0.21.1", "sanctuary-identity": "2.1.x", "sanctuary-scripts": "4.0.x", "sanctuary-type-identifiers": "3.0.0", From ca5ad651deef4007a4a72bfc00e24e521ef94fb9 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 10 Aug 2020 07:19:40 +0200 Subject: [PATCH 20/42] sanctuary@3.1.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 82d6ccf..cc64c15 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "fantasy-land": "4.0.1", "fantasy-laws": "1.2.x", "jsverify": "0.8.x", - "sanctuary": "3.0.0", - "sanctuary-def": "0.21.1", + "sanctuary": "3.1.0", + "sanctuary-def": "0.22.0", "sanctuary-identity": "2.1.x", "sanctuary-scripts": "4.0.x", "sanctuary-type-identifiers": "3.0.0", From 139105069f825dc0e428ed3f22c09f8aa32cd876 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sat, 29 Aug 2020 14:26:47 +0200 Subject: [PATCH 21/42] =?UTF-8?q?remove=20=E2=80=98inspect=E2=80=99=20fall?= =?UTF-8?q?back?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 4 +--- package.json | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 2dcaf2d..b7094e4 100644 --- a/index.js +++ b/index.js @@ -121,12 +121,10 @@ /* eslint-enable key-spacing */ }; - var custom = util.inspect.custom; + var custom = util.inspect.custom; // added in Node.js v6.6.0 /* istanbul ignore else */ if (typeof custom === 'symbol') { prototype[custom] = Constant$prototype$show; - } else { - prototype.inspect = Constant$prototype$show; } function Constant$bound(value) { diff --git a/package.json b/package.json index cc64c15..d106f8c 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "/index.js", "/package.json" ], + "engines": { + "node": ">=6.6.0" + }, "dependencies": { "sanctuary-show": "2.0.0", "sanctuary-type-classes": "12.1.0" From 3fcecc87f97d0b877acafb71219c1db2a27c23d6 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 28 Apr 2021 12:59:00 +0200 Subject: [PATCH 22/42] use ES6 syntax --- .eslintrc.json | 2 +- index.js | 93 +++++++++++++++++++++++---------------------- test/.eslintrc.json | 6 --- 3 files changed, 48 insertions(+), 53 deletions(-) delete mode 100644 test/.eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json index 062a65d..792c7e5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "extends": ["./node_modules/sanctuary-style/eslint-es3.json"], + "extends": ["./node_modules/sanctuary-style/eslint-es6.json"], "overrides": [ { "files": ["*.md"], diff --git a/index.js b/index.js index b7094e4..873427f 100644 --- a/index.js +++ b/index.js @@ -13,11 +13,11 @@ //. of type `a`. Mapping over a `Constant a b` has no effect because //. the `b -> c` function is never applied. -(function(f) { +(f => { 'use strict'; - var util = {inspect: {}}; + const util = {inspect: {}}; /* istanbul ignore else */ if (typeof module === 'object' && typeof module.exports === 'object') { @@ -25,38 +25,39 @@ require ('sanctuary-show'), require ('sanctuary-type-classes')); } else if (typeof define === 'function' && define.amd != null) { - define (['sanctuary-show', 'sanctuary-type-classes'], function(show, Z) { - return f (util, show, Z); - }); + define (['sanctuary-show', 'sanctuary-type-classes'], + (show, Z) => f (util, show, Z)); } else { self.sanctuaryConstant = f (util, self.sanctuaryShow, self.sanctuaryTypeClasses); } -} (function(util, show, Z) { +}) ((util, show, Z) => { 'use strict'; /* istanbul ignore if */ if (typeof __doctest !== 'undefined') { + const {create, env} = __doctest.require ('sanctuary'); + // eslint-disable-next-line no-var var $ = __doctest.require ('sanctuary-def'); - var type = __doctest.require ('sanctuary-type-identifiers'); - var S = (function() { - var S = __doctest.require ('sanctuary'); - var ConstantType = $.BinaryType - ('Constant') - ('') - ([]) - (function(x) { return type (x) === constantTypeIdent; }) - (function(c) { return [c.value]; }) - (function(c) { return []; }); - var env = Z.concat (S.env, [ConstantType ($.Unknown) ($.Unknown)]); - return S.create ({checkTypes: false, env: env}); - } ()); + const type = __doctest.require ('sanctuary-type-identifiers'); + const Constant = $.BinaryType + ('Constant') + ('') + ([]) + (x => type (x) === constantTypeIdent) + (c => [c.value]) + (c => []); + // eslint-disable-next-line no-var + var S = create ({ + checkTypes: false, + env: Z.concat (env, [Constant ($.Unknown) ($.Unknown)]), + }); } - var constantTypeIdent = 'sanctuary-constant/Constant@1'; + const constantTypeIdent = 'sanctuary-constant/Constant@1'; //. `Constant a b` satisfies the following [Fantasy Land][] specifications: //. @@ -108,8 +109,8 @@ //. > Constant (Number) (123) //. Constant (Number) (123) //. ``` - function Constant(A) { - var prototype = { + const Constant = A => { + const prototype = { /* eslint-disable key-spacing */ 'constructor': Constant$bound, '@@type': constantTypeIdent, @@ -117,36 +118,38 @@ 'fantasy-land/map': Constant$prototype$map, 'fantasy-land/bimap': Constant$prototype$bimap, 'fantasy-land/reduce': Constant$prototype$reduce, - 'fantasy-land/traverse': Constant$prototype$traverse + 'fantasy-land/traverse': Constant$prototype$traverse, /* eslint-enable key-spacing */ }; - var custom = util.inspect.custom; // added in Node.js v6.6.0 - /* istanbul ignore else */ - if (typeof custom === 'symbol') { - prototype[custom] = Constant$prototype$show; + { + const {custom} = util.inspect; // added in Node.js v6.6.0 + /* istanbul ignore else */ + if (typeof custom === 'symbol') { + prototype[custom] = Constant$prototype$show; + } } function Constant$bound(value) { - var identity = Object.create (prototype); + const constant = Object.create (prototype); if (Z.Setoid.test (value)) { - identity['fantasy-land/equals'] = Constant$prototype$equals; + constant['fantasy-land/equals'] = Constant$prototype$equals; if (Z.Ord.test (value)) { - identity['fantasy-land/lte'] = Constant$prototype$lte; + constant['fantasy-land/lte'] = Constant$prototype$lte; } } if (Z.Semigroup.test (value)) { - identity['fantasy-land/concat'] = Constant$prototype$concat; - identity['fantasy-land/ap'] = Constant$prototype$ap; + constant['fantasy-land/concat'] = Constant$prototype$concat; + constant['fantasy-land/ap'] = Constant$prototype$ap; } - identity.value = value; - return identity; + constant.value = value; + return constant; } - Constant$bound.toString = function() { + Constant$bound.toString = () => { if (!(Object.prototype.hasOwnProperty.call (A, 'name'))) { - var source = String (A); - var match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source); + const source = String (A); + const match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source); return 'Constant (' + (match == null ? source : match[1]) + ')'; } else if (A.name === Constant$bound.name) { return 'Constant (' + show (A) + ')'; @@ -166,13 +169,11 @@ //. > S.of (Constant (String)) (42) //. Constant (String) ('') //. ``` - (function() { - var empty; + (() => { + let empty; try { empty = Z.empty (A); } catch (err) { return; } - Constant$bound['fantasy-land/of'] = function Constant$of(x) { - return Constant$bound (empty); - }; - } ()); + Constant$bound['fantasy-land/of'] = x => Constant$bound (empty); + }) (); //# Constant#@@show :: Showable a => Constant a b ~> () -> String //. @@ -257,7 +258,7 @@ //. Constant (Number) (3) //. ``` function Constant$prototype$bimap(f, g) { - var x = f (this.value); + const x = f (this.value); return Constant (x.constructor) (x); } @@ -300,11 +301,11 @@ } return Constant$bound; - } + }; return Constant; -})); +}); //. [Applicative]: v:fantasyland/fantasy-land#Applicative //. [Fantasy Land]: v:fantasyland/fantasy-land diff --git a/test/.eslintrc.json b/test/.eslintrc.json deleted file mode 100644 index 249d948..0000000 --- a/test/.eslintrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "root": true, - "extends": ["../node_modules/sanctuary-style/eslint-es6.json"], - "env": {"node": true}, - "globals": {"suite": false, "test": false} -} From ca95f9e39793ad15844236e1670f72a57f29cbbb Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 28 Apr 2021 13:00:56 +0200 Subject: [PATCH 23/42] documentation: use S.show in doctest --- .eslintrc.json | 2 +- index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 792c7e5..90ea1d3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,7 @@ "overrides": [ { "files": ["*.md"], - "globals": {"$": false, "Constant": false, "S": false, "Z": false, "show": false, "type": false} + "globals": {"$": false, "Constant": false, "S": false, "Z": false} }, { "files": ["index.js"], diff --git a/index.js b/index.js index 873427f..c64f2db 100644 --- a/index.js +++ b/index.js @@ -181,7 +181,7 @@ //. `'Constant (' + A.name + ') (' + show (x) + ')'`. //. //. ```javascript - //. > show (Constant (Array) (['foo', 'bar', 'baz'])) + //. > S.show (Constant (Array) (['foo', 'bar', 'baz'])) //. 'Constant (Array) (["foo", "bar", "baz"])' //. ``` function Constant$prototype$show() { From b351ccdfb438d6c9fb2bc68687a87797d239ead7 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 28 Apr 2021 13:34:08 +0200 Subject: [PATCH 24/42] fantasy-land@5.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d106f8c..89211e6 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "sanctuary-type-classes": "12.1.0" }, "devDependencies": { - "fantasy-land": "4.0.1", + "fantasy-land": "5.0.0", "fantasy-laws": "1.2.x", "jsverify": "0.8.x", "sanctuary": "3.1.0", From 9601e975e35028f7c3d50de1f64b37d6407df990 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Thu, 13 May 2021 18:10:42 +0200 Subject: [PATCH 25/42] support Deno.inspect --- .eslintrc.json | 1 + index.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/.eslintrc.json b/.eslintrc.json index 90ea1d3..5f49a59 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,6 +8,7 @@ }, { "files": ["index.js"], + "globals": {"Deno": false}, "rules": { "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^S$"}] } diff --git a/index.js b/index.js index c64f2db..cb818e9 100644 --- a/index.js +++ b/index.js @@ -128,6 +128,12 @@ if (typeof custom === 'symbol') { prototype[custom] = Constant$prototype$show; } + /* istanbul ignore if */ + if (typeof Deno !== 'undefined') { + if (Deno != null && typeof Deno.customInspect === 'symbol') { + prototype[Deno.customInspect] = Constant$prototype$show; + } + } } function Constant$bound(value) { From 8af3f8b4c56e375f3a82d9b70e513c3e70a801bc Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sat, 5 Jun 2021 17:01:03 +0200 Subject: [PATCH 26/42] circle: create test matrix without nvm --- .circleci/config.yml | 53 ++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2ee728d..1dfcc79 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,34 +1,29 @@ version: 2.1 +orbs: + node: circleci/node@4.3.0 + jobs: - build: - docker: - - image: circleci/node:12 - environment: - NPM_CONFIG_COLOR: false - NVM_DIR: /home/circleci/.nvm - parallelism: 3 + test: + executor: + name: node/default + tag: <> + parameters: + version: + type: string steps: - checkout - - restore_cache: - keys: - - nvm-cache-{{ checksum ".circleci/config.yml" }} - - run: curl https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash - - save_cache: - key: nvm-cache-{{ checksum ".circleci/config.yml" }} - paths: - - /home/circleci/.nvm - - run: - name: npm install && npm test - command: | - test_with_version() { - source "$NVM_DIR/nvm.sh" - nvm install $1 - nvm exec $1 npm install - nvm exec $1 npm test - } - case $CIRCLE_NODE_INDEX in - 0) test_with_version 8 ;; - 1) test_with_version 10 ;; - 2) npm install && npm test ;; - esac + - run: npm install + - run: npm test + +workflows: + test: + jobs: + - test: + version: 10.14.2 + - test: + version: 12.0.0 + - test: + version: 14.0.0 + - test: + version: 16.0.0 From af4ebccb7df5f0b384eb0bb1e76334a180be9109 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sun, 8 Aug 2021 19:23:55 +0200 Subject: [PATCH 27/42] sanctuary-scripts@5.0.x --- package.json | 5 ++++- test/mocha.opts | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) delete mode 100644 test/mocha.opts diff --git a/package.json b/package.json index 89211e6..4dd9a53 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "sanctuary": "3.1.0", "sanctuary-def": "0.22.0", "sanctuary-identity": "2.1.x", - "sanctuary-scripts": "4.0.x", + "sanctuary-scripts": "5.0.x", "sanctuary-type-identifiers": "3.0.0", "sanctuary-useless": "2.0.x" }, @@ -36,5 +36,8 @@ "lint": "sanctuary-lint", "release": "sanctuary-release", "test": "npm run lint && sanctuary-test && npm run doctest" + }, + "mocha": { + "ui": "tdd" } } diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index 5efaf24..0000000 --- a/test/mocha.opts +++ /dev/null @@ -1 +0,0 @@ ---ui tdd From b2628953bf2327ec5b3986497bb7b242cf2c2de7 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Thu, 21 Oct 2021 09:09:28 +0200 Subject: [PATCH 28/42] eslint: use "readonly" for globals in place of deprecated value --- .eslintrc.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 5f49a59..56441a5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,11 +4,11 @@ "overrides": [ { "files": ["*.md"], - "globals": {"$": false, "Constant": false, "S": false, "Z": false} + "globals": {"$": "readonly", "Constant": "readonly", "S": "readonly", "Z": "readonly"} }, { "files": ["index.js"], - "globals": {"Deno": false}, + "globals": {"Deno": "readonly"}, "rules": { "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^S$"}] } From 9221f730abbf83dc7fa7522694955a0454f58b1d Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 6 Dec 2023 16:08:44 +0100 Subject: [PATCH 29/42] circle: update Node versions --- .circleci/config.yml | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1dfcc79..6082ee9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,29 +1,19 @@ version: 2.1 orbs: - node: circleci/node@4.3.0 - -jobs: - test: - executor: - name: node/default - tag: <> - parameters: - version: - type: string - steps: - - checkout - - run: npm install - - run: npm test + node: circleci/node@5.1.0 workflows: test: jobs: - - test: - version: 10.14.2 - - test: - version: 12.0.0 - - test: - version: 14.0.0 - - test: - version: 16.0.0 + - node/test: + setup: + # derive cache key from package.json + - run: cp package.json package-lock.json + override-ci-command: rm package-lock.json && npm install && git checkout -- package.json + matrix: + parameters: + version: + - 18.0.0 + - 20.0.0 + - 21.0.0 From 4faa68c30f0192eaf4bc669c805d101cfc489e22 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 6 Dec 2023 19:39:58 +0100 Subject: [PATCH 30/42] update references to default branch --- .config | 1 + .github/CONTRIBUTING.md | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.config b/.config index 68751e9..3ab89bb 100644 --- a/.config +++ b/.config @@ -1,3 +1,4 @@ repo-owner = sanctuary-js repo-name = sanctuary-constant +default-branch = main contributing-file = .github/CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index dd7edee..e22d931 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -3,10 +3,10 @@ Note: __README.md__ is generated from comments in __index.js__. Do not modify __README.md__ directly. -1. Update local master branch: +1. Update local main branch: - $ git checkout master - $ git pull upstream master + $ git checkout main + $ git pull upstream main 2. Create feature branch: From ea3d022e7a40458ce9564c4d70fc44b94302fb95 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 11 Dec 2023 21:12:36 +0100 Subject: [PATCH 31/42] sanctuary-scripts@6.0.x --- .config | 2 +- .eslintrc.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.config b/.config index 3ab89bb..b404d3a 100644 --- a/.config +++ b/.config @@ -1,4 +1,4 @@ repo-owner = sanctuary-js repo-name = sanctuary-constant -default-branch = main contributing-file = .github/CONTRIBUTING.md +module-type = commonjs diff --git a/.eslintrc.json b/.eslintrc.json index 56441a5..4f6c42f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "extends": ["./node_modules/sanctuary-style/eslint-es6.json"], + "extends": ["./node_modules/sanctuary-style/eslint.json"], "overrides": [ { "files": ["*.md"], diff --git a/package.json b/package.json index 4dd9a53..c542577 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "sanctuary": "3.1.0", "sanctuary-def": "0.22.0", "sanctuary-identity": "2.1.x", - "sanctuary-scripts": "5.0.x", + "sanctuary-scripts": "6.0.x", "sanctuary-type-identifiers": "3.0.0", "sanctuary-useless": "2.0.x" }, From 2eec761f348e8b19580ec092a0759559277207f8 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 8 Jan 2024 14:38:47 +0100 Subject: [PATCH 32/42] convert test modules to ES modules --- .eslintrc.json | 4 ++++ test/index.js | 20 +++++++++----------- test/package.json | 3 +++ 3 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 test/package.json diff --git a/.eslintrc.json b/.eslintrc.json index 4f6c42f..0017cc7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,6 +12,10 @@ "rules": { "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^S$"}] } + }, + { + "files": ["test/**/*.js"], + "parserOptions": {"sourceType": "module"} } ] } diff --git a/test/index.js b/test/index.js index 69437b5..d182be8 100644 --- a/test/index.js +++ b/test/index.js @@ -1,16 +1,14 @@ -'use strict'; +import assert from 'assert'; -const assert = require ('assert'); +import laws from 'fantasy-laws'; +import jsc from 'jsverify'; +import Identity from 'sanctuary-identity'; +import show from 'sanctuary-show'; +import Z from 'sanctuary-type-classes'; +import type from 'sanctuary-type-identifiers'; +import Useless from 'sanctuary-useless'; -const laws = require ('fantasy-laws'); -const jsc = require ('jsverify'); -const Identity = require ('sanctuary-identity'); -const show = require ('sanctuary-show'); -const Z = require ('sanctuary-type-classes'); -const type = require ('sanctuary-type-identifiers'); -const Useless = require ('sanctuary-useless'); - -const Constant = require ('..'); +import Constant from '../index.js'; // ConstantArb :: Monoid m => TypeRep m -> Arbitrary a -> Arbitrary (Constant a b) diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..3dbc1ca --- /dev/null +++ b/test/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} From bcd5ca1d82cb901478d89f98a75fd217ac706a64 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 8 Jan 2024 14:56:50 +0100 Subject: [PATCH 33/42] sanctuary-scripts@7.0.x --- .eslintrc.json | 6 +- .gitignore | 1 - index.js | 21 ++- package.json | 5 +- test/index.js | 462 +++++++++++++++++++++++-------------------------- 5 files changed, 233 insertions(+), 262 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 0017cc7..b4d1488 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,13 +2,9 @@ "root": true, "extends": ["./node_modules/sanctuary-style/eslint.json"], "overrides": [ - { - "files": ["*.md"], - "globals": {"$": "readonly", "Constant": "readonly", "S": "readonly", "Z": "readonly"} - }, { "files": ["index.js"], - "globals": {"Deno": "readonly"}, + "globals": {"Deno": "readonly", "__doctest": "readonly", "define": "readonly", "module": "readonly", "require": "readonly", "self": "readonly"}, "rules": { "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^S$"}] } diff --git a/.gitignore b/.gitignore index bd53bbe..cba87a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -/.nyc_output/ /coverage/ /node_modules/ diff --git a/index.js b/index.js index cb818e9..9ba408f 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,7 @@ const util = {inspect: {}}; - /* istanbul ignore else */ + /* c8 ignore start */ if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = f (require ('util'), require ('sanctuary-show'), @@ -32,12 +32,13 @@ self.sanctuaryShow, self.sanctuaryTypeClasses); } + /* c8 ignore stop */ }) ((util, show, Z) => { 'use strict'; - /* istanbul ignore if */ + /* c8 ignore start */ if (typeof __doctest !== 'undefined') { const {create, env} = __doctest.require ('sanctuary'); // eslint-disable-next-line no-var @@ -56,6 +57,7 @@ env: Z.concat (env, [Constant ($.Unknown) ($.Unknown)]), }); } + /* c8 ignore stop */ const constantTypeIdent = 'sanctuary-constant/Constant@1'; @@ -124,16 +126,17 @@ { const {custom} = util.inspect; // added in Node.js v6.6.0 - /* istanbul ignore else */ if (typeof custom === 'symbol') { prototype[custom] = Constant$prototype$show; } - /* istanbul ignore if */ - if (typeof Deno !== 'undefined') { - if (Deno != null && typeof Deno.customInspect === 'symbol') { - prototype[Deno.customInspect] = Constant$prototype$show; - } - } + + /* c8 ignore start */ + if ( + typeof Deno !== 'undefined' && + Deno != null && + typeof Deno.customInspect === 'symbol' + ) prototype[Deno.customInspect] = Constant$prototype$show; + /* c8 ignore stop */ } function Constant$bound(value) { diff --git a/package.json b/package.json index c542577..7298811 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "sanctuary": "3.1.0", "sanctuary-def": "0.22.0", "sanctuary-identity": "2.1.x", - "sanctuary-scripts": "6.0.x", + "sanctuary-scripts": "7.0.x", "sanctuary-type-identifiers": "3.0.0", "sanctuary-useless": "2.0.x" }, @@ -36,8 +36,5 @@ "lint": "sanctuary-lint", "release": "sanctuary-release", "test": "npm run lint && sanctuary-test && npm run doctest" - }, - "mocha": { - "ui": "tdd" } } diff --git a/test/index.js b/test/index.js index d182be8..63395e3 100644 --- a/test/index.js +++ b/test/index.js @@ -2,6 +2,7 @@ import assert from 'assert'; import laws from 'fantasy-laws'; import jsc from 'jsverify'; +import test from 'oletus'; import Identity from 'sanctuary-identity'; import show from 'sanctuary-show'; import Z from 'sanctuary-type-classes'; @@ -43,11 +44,12 @@ const empty = m => Z.equals (m, Z.empty (m.constructor)); // not :: Boolean -> Boolean const not = b => !b; -// testLaws :: Object -> Object -> Undefined -const testLaws = laws => arbs => { +// testLaws :: String -> Object -> Object -> Undefined +const testLaws = typeClass => laws => arbs => { (Object.keys (laws)).forEach (name => { eq (laws[name].length) (arbs[name].length); - test (name.replace (/[A-Z]/g, c => ' ' + c.toLowerCase ()), + const prettyName = name.replace (/[A-Z]/g, c => ' ' + c.toLowerCase ()); + test (`${typeClass} laws \x1B[2m›\x1B[0m ${prettyName}`, laws[name] (...arbs[name])); }); }; @@ -63,289 +65,263 @@ function eq(actual) { } -suite ('Constant', () => { - - test ('metadata', () => { - eq (typeof Constant) ('function'); - eq (Constant.name) ('Constant'); - eq (Constant.length) (1); - }); - - test ('@@type', () => { - eq (type (Constant (Number) (0))) ('sanctuary-constant/Constant@1'); - eq (type.parse (type (Constant (Number) (0)))) - ({namespace: 'sanctuary-constant', name: 'Constant', version: 1}); - }); - - test ('@@show', () => { - eq (show (Constant (Array) (['foo', 'bar', 'baz']))) - ('Constant (Array) (["foo", "bar", "baz"])'); - eq (show (Constant (Constant (Constant (Number))) - (Constant (Constant (Number)) - (Constant (Number) - (-0))))) - ('Constant (Constant (Constant (Number)))' + - ' (Constant (Constant (Number))' + - ' (Constant (Number)' + - ' (-0)))'); - - // Foo :: String -> Foo - function Foo(value) { - return { - 'constructor': Foo, - '@@show': function Foo$show() { return 'Foo (' + show (value) + ')'; }, - }; - } - delete Foo.name; - eq (show (Constant (Foo) (Foo ('foo')))) - ('Constant (Foo) (Foo ("foo"))'); - - // Bar :: String -> Bar - const Bar = value => ({ - 'constructor': Bar, - '@@show': function Bar$show() { return 'Bar (' + show (value) + ')'; }, - }); - delete Bar.name; - eq (show (Constant (Bar) (Bar ('bar')))) - ('Constant (' + String (Bar) + ') (Bar ("bar"))'); - }); - +test ('metadata', () => { + eq (typeof Constant) ('function'); + eq (Constant.name) ('Constant'); + eq (Constant.length) (1); }); -suite ('type-class predicates', () => { +test ('@@type', () => { + eq (type (Constant (Number) (0))) ('sanctuary-constant/Constant@1'); + eq (type.parse (type (Constant (Number) (0)))) + ({namespace: 'sanctuary-constant', name: 'Constant', version: 1}); +}); - test ('Setoid', () => { - eq (Z.Setoid.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Setoid.test (Constant (RegExp) (/(?:)/))) (true); - }); +test ('@@show', () => { + eq (show (Constant (Array) (['foo', 'bar', 'baz']))) + ('Constant (Array) (["foo", "bar", "baz"])'); + eq (show (Constant (Constant (Constant (Number))) + (Constant (Constant (Number)) + (Constant (Number) + (-0))))) + ('Constant (Constant (Constant (Number)))' + + ' (Constant (Constant (Number))' + + ' (Constant (Number)' + + ' (-0)))'); + + // Foo :: String -> Foo + function Foo(value) { + return { + 'constructor': Foo, + '@@show': function Foo$show() { return 'Foo (' + show (value) + ')'; }, + }; + } + delete Foo.name; + eq (show (Constant (Foo) (Foo ('foo')))) + ('Constant (Foo) (Foo ("foo"))'); + + // Bar :: String -> Bar + const Bar = value => ({ + 'constructor': Bar, + '@@show': function Bar$show() { return 'Bar (' + show (value) + ')'; }, + }); + delete Bar.name; + eq (show (Constant (Bar) (Bar ('bar')))) + ('Constant (' + String (Bar) + ') (Bar ("bar"))'); +}); - test ('Ord', () => { - eq (Z.Ord.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Ord.test (Constant (RegExp) (/(?:)/))) (false); - eq (Z.Ord.test (Constant (Number) (0))) (true); - }); +test ('Setoid', () => { + eq (Z.Setoid.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Setoid.test (Constant (RegExp) (/(?:)/))) (true); +}); - test ('Semigroupoid', () => { - eq (Z.Semigroupoid.test (Constant (Array) ([]))) (false); - }); +test ('Ord', () => { + eq (Z.Ord.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Ord.test (Constant (RegExp) (/(?:)/))) (false); + eq (Z.Ord.test (Constant (Number) (0))) (true); +}); - test ('Category', () => { - eq (Z.Category.test (Constant (Array) ([]))) (false); - }); +test ('Semigroupoid', () => { + eq (Z.Semigroupoid.test (Constant (Array) ([]))) (false); +}); - test ('Semigroup', () => { - eq (Z.Semigroup.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Semigroup.test (Constant (Number) (0))) (false); - eq (Z.Semigroup.test (Constant (Array) ([]))) (true); - }); +test ('Category', () => { + eq (Z.Category.test (Constant (Array) ([]))) (false); +}); - test ('Monoid', () => { - eq (Z.Monoid.test (Constant (Array) ([]))) (false); - }); +test ('Semigroup', () => { + eq (Z.Semigroup.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Semigroup.test (Constant (Number) (0))) (false); + eq (Z.Semigroup.test (Constant (Array) ([]))) (true); +}); - test ('Group', () => { - eq (Z.Group.test (Constant (Array) ([]))) (false); - }); +test ('Monoid', () => { + eq (Z.Monoid.test (Constant (Array) ([]))) (false); +}); - test ('Filterable', () => { - eq (Z.Filterable.test (Constant (Array) ([]))) (false); - }); +test ('Group', () => { + eq (Z.Group.test (Constant (Array) ([]))) (false); +}); - test ('Functor', () => { - eq (Z.Functor.test (Constant (Useless.constructor) (Useless))) (true); - }); +test ('Filterable', () => { + eq (Z.Filterable.test (Constant (Array) ([]))) (false); +}); - test ('Bifunctor', () => { - eq (Z.Bifunctor.test (Constant (Useless.constructor) (Useless))) (true); - }); +test ('Functor', () => { + eq (Z.Functor.test (Constant (Useless.constructor) (Useless))) (true); +}); - test ('Profunctor', () => { - eq (Z.Profunctor.test (Constant (Function) (Math.sqrt))) (false); - }); +test ('Bifunctor', () => { + eq (Z.Bifunctor.test (Constant (Useless.constructor) (Useless))) (true); +}); - test ('Apply', () => { - eq (Z.Apply.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Apply.test (Constant (Number) (0))) (false); - eq (Z.Apply.test (Constant (Array) ([]))) (true); - }); +test ('Profunctor', () => { + eq (Z.Profunctor.test (Constant (Function) (Math.sqrt))) (false); +}); - test ('Applicative', () => { - eq (Z.Applicative.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Applicative.test (Constant (Number) (0))) (false); - eq (Z.Applicative.test (Constant (Array) ([]))) (true); - }); +test ('Apply', () => { + eq (Z.Apply.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Apply.test (Constant (Number) (0))) (false); + eq (Z.Apply.test (Constant (Array) ([]))) (true); +}); - test ('Chain', () => { - eq (Z.Chain.test (Constant (Array) ([]))) (false); - }); +test ('Applicative', () => { + eq (Z.Applicative.test (Constant (Useless.constructor) (Useless))) (false); + eq (Z.Applicative.test (Constant (Number) (0))) (false); + eq (Z.Applicative.test (Constant (Array) ([]))) (true); +}); - test ('ChainRec', () => { - eq (Z.ChainRec.test (Constant (Array) ([]))) (false); - }); +test ('Chain', () => { + eq (Z.Chain.test (Constant (Array) ([]))) (false); +}); - test ('Monad', () => { - eq (Z.Monad.test (Constant (Array) ([]))) (false); - }); +test ('ChainRec', () => { + eq (Z.ChainRec.test (Constant (Array) ([]))) (false); +}); - test ('Alt', () => { - eq (Z.Alt.test (Constant (Array) ([]))) (false); - }); +test ('Monad', () => { + eq (Z.Monad.test (Constant (Array) ([]))) (false); +}); - test ('Plus', () => { - eq (Z.Plus.test (Constant (Array) ([]))) (false); - }); +test ('Alt', () => { + eq (Z.Alt.test (Constant (Array) ([]))) (false); +}); - test ('Alternative', () => { - eq (Z.Alternative.test (Constant (Array) ([]))) (false); - }); +test ('Plus', () => { + eq (Z.Plus.test (Constant (Array) ([]))) (false); +}); - test ('Foldable', () => { - eq (Z.Foldable.test (Constant (Useless.constructor) (Useless))) (true); - }); +test ('Alternative', () => { + eq (Z.Alternative.test (Constant (Array) ([]))) (false); +}); - test ('Traversable', () => { - eq (Z.Traversable.test (Constant (Useless.constructor) (Useless))) (true); - }); +test ('Foldable', () => { + eq (Z.Foldable.test (Constant (Useless.constructor) (Useless))) (true); +}); - test ('Extend', () => { - eq (Z.Extend.test (Constant (Array) ([]))) (false); - }); +test ('Traversable', () => { + eq (Z.Traversable.test (Constant (Useless.constructor) (Useless))) (true); +}); - test ('Comonad', () => { - eq (Z.Comonad.test (Constant (Array) ([]))) (false); - }); +test ('Extend', () => { + eq (Z.Extend.test (Constant (Array) ([]))) (false); +}); - test ('Contravariant', () => { - eq (Z.Contravariant.test (Constant (Function) (Math.sqrt))) (false); - }); +test ('Comonad', () => { + eq (Z.Comonad.test (Constant (Array) ([]))) (false); +}); +test ('Contravariant', () => { + eq (Z.Contravariant.test (Constant (Function) (Math.sqrt))) (false); }); -suite ('Setoid laws', () => { - testLaws (laws.Setoid) ({ - reflexivity: [ - ConstantArb (Number) (NumberArb), - ], - symmetry: [ - ConstantArb (Number) (NumberArb), - ConstantArb (Number) (NumberArb), - ], - transitivity: [ - ConstantArb (Number) (NumberArb), - ConstantArb (Number) (NumberArb), - ConstantArb (Number) (NumberArb), - ], - }); +testLaws ('Setoid') (laws.Setoid) ({ + reflexivity: [ + ConstantArb (Number) (NumberArb), + ], + symmetry: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + transitivity: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], }); -suite ('Ord laws', () => { - testLaws (laws.Ord) ({ - totality: [ - ConstantArb (Number) (NumberArb), - ConstantArb (Number) (NumberArb), - ], - antisymmetry: [ - ConstantArb (Number) (NumberArb), - ConstantArb (Number) (NumberArb), - ], - transitivity: [ - ConstantArb (Number) (NumberArb), - ConstantArb (Number) (NumberArb), - ConstantArb (Number) (NumberArb), - ], - }); +testLaws ('Ord') (laws.Ord) ({ + totality: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + antisymmetry: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], + transitivity: [ + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ConstantArb (Number) (NumberArb), + ], }); -suite ('Semigroup laws', () => { - testLaws (laws.Semigroup (Z.equals)) ({ - associativity: [ - ConstantArb (String) (jsc.string), - ConstantArb (String) (jsc.string), - ConstantArb (String) (jsc.string), - ], - }); +testLaws ('Semigroup') (laws.Semigroup (Z.equals)) ({ + associativity: [ + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ], }); -suite ('Functor laws', () => { - testLaws (laws.Functor (Z.equals)) ({ - identity: [ - ConstantArb (String) (jsc.string), - ], - composition: [ - ConstantArb (String) (jsc.string), - jsc.constant (Math.sqrt), - jsc.constant (Math.abs), - ], - }); +testLaws ('Functor') (laws.Functor (Z.equals)) ({ + identity: [ + ConstantArb (String) (jsc.string), + ], + composition: [ + ConstantArb (String) (jsc.string), + jsc.constant (Math.sqrt), + jsc.constant (Math.abs), + ], }); -suite ('Bifunctor laws', () => { - testLaws (laws.Bifunctor (Z.equals)) ({ - identity: [ - ConstantArb (String) (jsc.string), - ], - composition: [ - ConstantArb (String) (jsc.string), - jsc.constant (Math.sqrt), - jsc.constant (s => s.length), - jsc.constant (Math.sqrt), - jsc.constant (Math.abs), - ], - }); +testLaws ('Bifunctor') (laws.Bifunctor (Z.equals)) ({ + identity: [ + ConstantArb (String) (jsc.string), + ], + composition: [ + ConstantArb (String) (jsc.string), + jsc.constant (Math.sqrt), + jsc.constant (s => s.length), + jsc.constant (Math.sqrt), + jsc.constant (Math.abs), + ], }); -suite ('Apply laws', () => { - testLaws (laws.Apply (Z.equals)) ({ - composition: [ - ConstantArb (String) (jsc.string), - ConstantArb (String) (jsc.string), - ConstantArb (String) (jsc.string), - ], - }); +testLaws ('Apply') (laws.Apply (Z.equals)) ({ + composition: [ + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ConstantArb (String) (jsc.string), + ], }); -suite ('Applicative laws', () => { - testLaws (laws.Applicative (Z.equals, Constant (Array))) ({ - identity: [ - ConstantArb (Array) (jsc.array (jsc.number)), - ], - homomorphism: [ - jsc.constant (Math.abs), - jsc.number, - ], - interchange: [ - ConstantArb (Array) (jsc.array (jsc.number)), - jsc.string, - ], - }); +testLaws ('Applicative') (laws.Applicative (Z.equals, Constant (Array))) ({ + identity: [ + ConstantArb (Array) (jsc.array (jsc.number)), + ], + homomorphism: [ + jsc.constant (Math.abs), + jsc.number, + ], + interchange: [ + ConstantArb (Array) (jsc.array (jsc.number)), + jsc.string, + ], }); -suite ('Foldable laws', () => { - testLaws (laws.Foldable (Z.equals)) ({ - associativity: [ - jsc.constant (s => x => s + s), - jsc.string, - ConstantArb (Number) (jsc.number), - ], - }); +testLaws ('Foldable') (laws.Foldable (Z.equals)) ({ + associativity: [ + jsc.constant (s => x => s + s), + jsc.string, + ConstantArb (Number) (jsc.number), + ], }); -suite ('Traversable laws', () => { - testLaws (laws.Traversable (Z.equals)) ({ - naturality: [ - jsc.constant (Array), - jsc.constant (Identity), - jsc.constant (xs => Identity (xs[0])), - ConstantArb (Array) (NonEmpty (jsc.array (jsc.number))), - ], - identity: [ - jsc.constant (Array), - ConstantArb (String) (jsc.string), - ], - composition: [ - jsc.constant (Array), - jsc.constant (Identity), - ConstantArb (Array) (jsc.array (IdentityArb (jsc.string))), - ], - }); +testLaws ('Traversable') (laws.Traversable (Z.equals)) ({ + naturality: [ + jsc.constant (Array), + jsc.constant (Identity), + jsc.constant (xs => Identity (xs[0])), + ConstantArb (Array) (NonEmpty (jsc.array (jsc.number))), + ], + identity: [ + jsc.constant (Array), + ConstantArb (String) (jsc.string), + ], + composition: [ + jsc.constant (Array), + jsc.constant (Identity), + ConstantArb (Array) (jsc.array (IdentityArb (jsc.string))), + ], }); From 0ed036c14c48dd01126628c4544f785bb94da102 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Mon, 8 Jan 2024 15:02:08 +0100 Subject: [PATCH 34/42] use `globalThis` and `?.` operator to simplify feature detection --- .eslintrc.json | 4 +++- index.js | 21 +++++++++------------ package.json | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index b4d1488..f73ba86 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,10 +1,12 @@ { "root": true, "extends": ["./node_modules/sanctuary-style/eslint.json"], + "parserOptions": {"ecmaVersion": 2020}, + "globals": {"globalThis": "readonly"}, "overrides": [ { "files": ["index.js"], - "globals": {"Deno": "readonly", "__doctest": "readonly", "define": "readonly", "module": "readonly", "require": "readonly", "self": "readonly"}, + "globals": {"__doctest": "readonly", "define": "readonly", "module": "readonly", "require": "readonly", "self": "readonly"}, "rules": { "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^S$"}] } diff --git a/index.js b/index.js index 9ba408f..0a567d3 100644 --- a/index.js +++ b/index.js @@ -124,20 +124,17 @@ /* eslint-enable key-spacing */ }; - { - const {custom} = util.inspect; // added in Node.js v6.6.0 - if (typeof custom === 'symbol') { - prototype[custom] = Constant$prototype$show; - } + if (globalThis.process?.versions?.node != null) { + const inspect = Symbol.for ('nodejs.util.inspect.custom'); + prototype[inspect] = Constant$prototype$show; + } - /* c8 ignore start */ - if ( - typeof Deno !== 'undefined' && - Deno != null && - typeof Deno.customInspect === 'symbol' - ) prototype[Deno.customInspect] = Constant$prototype$show; - /* c8 ignore stop */ + /* c8 ignore start */ + if (typeof globalThis.Deno?.customInspect === 'symbol') { + const inspect = globalThis.Deno.customInspect; + prototype[inspect] = Constant$prototype$show; } + /* c8 ignore stop */ function Constant$bound(value) { const constant = Object.create (prototype); diff --git a/package.json b/package.json index 7298811..94eb1e7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "/package.json" ], "engines": { - "node": ">=6.6.0" + "node": ">=14.0.0" }, "dependencies": { "sanctuary-show": "2.0.0", From 45ce4bd7c8ed221538980de423af27f8ea0b47a1 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Tue, 9 Jan 2024 09:13:03 +0100 Subject: [PATCH 35/42] use `assert.deepStrictEqual` --- test/index.js | 126 +++++++++++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 68 deletions(-) diff --git a/test/index.js b/test/index.js index 63395e3..88aee72 100644 --- a/test/index.js +++ b/test/index.js @@ -1,15 +1,15 @@ -import assert from 'assert'; +import {deepStrictEqual as eq} from 'assert'; -import laws from 'fantasy-laws'; -import jsc from 'jsverify'; -import test from 'oletus'; -import Identity from 'sanctuary-identity'; -import show from 'sanctuary-show'; -import Z from 'sanctuary-type-classes'; -import type from 'sanctuary-type-identifiers'; -import Useless from 'sanctuary-useless'; +import laws from 'fantasy-laws'; +import jsc from 'jsverify'; +import test from 'oletus'; +import Identity from 'sanctuary-identity'; +import show from 'sanctuary-show'; +import Z from 'sanctuary-type-classes'; +import type from 'sanctuary-type-identifiers'; +import Useless from 'sanctuary-useless'; -import Constant from '../index.js'; +import Constant from '../index.js'; // ConstantArb :: Monoid m => TypeRep m -> Arbitrary a -> Arbitrary (Constant a b) @@ -47,44 +47,34 @@ const not = b => !b; // testLaws :: String -> Object -> Object -> Undefined const testLaws = typeClass => laws => arbs => { (Object.keys (laws)).forEach (name => { - eq (laws[name].length) (arbs[name].length); + eq (laws[name].length, arbs[name].length); const prettyName = name.replace (/[A-Z]/g, c => ' ' + c.toLowerCase ()); test (`${typeClass} laws \x1B[2m›\x1B[0m ${prettyName}`, laws[name] (...arbs[name])); }); }; -// eq :: a -> b -> Undefined ! -function eq(actual) { - assert.strictEqual (arguments.length, eq.length); - return function eq$1(expected) { - assert.strictEqual (arguments.length, eq$1.length); - assert.strictEqual (show (actual), show (expected)); - assert.strictEqual (Z.equals (actual, expected), true); - }; -} - test ('metadata', () => { - eq (typeof Constant) ('function'); - eq (Constant.name) ('Constant'); - eq (Constant.length) (1); + eq (typeof Constant, 'function'); + eq (Constant.name, 'Constant'); + eq (Constant.length, 1); }); test ('@@type', () => { - eq (type (Constant (Number) (0))) ('sanctuary-constant/Constant@1'); - eq (type.parse (type (Constant (Number) (0)))) - ({namespace: 'sanctuary-constant', name: 'Constant', version: 1}); + eq (type (Constant (Number) (0)), 'sanctuary-constant/Constant@1'); + eq (type.parse (type (Constant (Number) (0))), + {namespace: 'sanctuary-constant', name: 'Constant', version: 1}); }); test ('@@show', () => { - eq (show (Constant (Array) (['foo', 'bar', 'baz']))) - ('Constant (Array) (["foo", "bar", "baz"])'); + eq (show (Constant (Array) (['foo', 'bar', 'baz'])), + 'Constant (Array) (["foo", "bar", "baz"])'); eq (show (Constant (Constant (Constant (Number))) (Constant (Constant (Number)) (Constant (Number) - (-0))))) - ('Constant (Constant (Constant (Number)))' + + (-0)))), + 'Constant (Constant (Constant (Number)))' + ' (Constant (Constant (Number))' + ' (Constant (Number)' + ' (-0)))'); @@ -97,8 +87,8 @@ test ('@@show', () => { }; } delete Foo.name; - eq (show (Constant (Foo) (Foo ('foo')))) - ('Constant (Foo) (Foo ("foo"))'); + eq (show (Constant (Foo) (Foo ('foo'))), + 'Constant (Foo) (Foo ("foo"))'); // Bar :: String -> Bar const Bar = value => ({ @@ -106,113 +96,113 @@ test ('@@show', () => { '@@show': function Bar$show() { return 'Bar (' + show (value) + ')'; }, }); delete Bar.name; - eq (show (Constant (Bar) (Bar ('bar')))) - ('Constant (' + String (Bar) + ') (Bar ("bar"))'); + eq (show (Constant (Bar) (Bar ('bar'))), + 'Constant (' + String (Bar) + ') (Bar ("bar"))'); }); test ('Setoid', () => { - eq (Z.Setoid.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Setoid.test (Constant (RegExp) (/(?:)/))) (true); + eq (Z.Setoid.test (Constant (Useless.constructor) (Useless)), false); + eq (Z.Setoid.test (Constant (RegExp) (/(?:)/)), true); }); test ('Ord', () => { - eq (Z.Ord.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Ord.test (Constant (RegExp) (/(?:)/))) (false); - eq (Z.Ord.test (Constant (Number) (0))) (true); + eq (Z.Ord.test (Constant (Useless.constructor) (Useless)), false); + eq (Z.Ord.test (Constant (RegExp) (/(?:)/)), false); + eq (Z.Ord.test (Constant (Number) (0)), true); }); test ('Semigroupoid', () => { - eq (Z.Semigroupoid.test (Constant (Array) ([]))) (false); + eq (Z.Semigroupoid.test (Constant (Array) ([])), false); }); test ('Category', () => { - eq (Z.Category.test (Constant (Array) ([]))) (false); + eq (Z.Category.test (Constant (Array) ([])), false); }); test ('Semigroup', () => { - eq (Z.Semigroup.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Semigroup.test (Constant (Number) (0))) (false); - eq (Z.Semigroup.test (Constant (Array) ([]))) (true); + eq (Z.Semigroup.test (Constant (Useless.constructor) (Useless)), false); + eq (Z.Semigroup.test (Constant (Number) (0)), false); + eq (Z.Semigroup.test (Constant (Array) ([])), true); }); test ('Monoid', () => { - eq (Z.Monoid.test (Constant (Array) ([]))) (false); + eq (Z.Monoid.test (Constant (Array) ([])), false); }); test ('Group', () => { - eq (Z.Group.test (Constant (Array) ([]))) (false); + eq (Z.Group.test (Constant (Array) ([])), false); }); test ('Filterable', () => { - eq (Z.Filterable.test (Constant (Array) ([]))) (false); + eq (Z.Filterable.test (Constant (Array) ([])), false); }); test ('Functor', () => { - eq (Z.Functor.test (Constant (Useless.constructor) (Useless))) (true); + eq (Z.Functor.test (Constant (Useless.constructor) (Useless)), true); }); test ('Bifunctor', () => { - eq (Z.Bifunctor.test (Constant (Useless.constructor) (Useless))) (true); + eq (Z.Bifunctor.test (Constant (Useless.constructor) (Useless)), true); }); test ('Profunctor', () => { - eq (Z.Profunctor.test (Constant (Function) (Math.sqrt))) (false); + eq (Z.Profunctor.test (Constant (Function) (Math.sqrt)), false); }); test ('Apply', () => { - eq (Z.Apply.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Apply.test (Constant (Number) (0))) (false); - eq (Z.Apply.test (Constant (Array) ([]))) (true); + eq (Z.Apply.test (Constant (Useless.constructor) (Useless)), false); + eq (Z.Apply.test (Constant (Number) (0)), false); + eq (Z.Apply.test (Constant (Array) ([])), true); }); test ('Applicative', () => { - eq (Z.Applicative.test (Constant (Useless.constructor) (Useless))) (false); - eq (Z.Applicative.test (Constant (Number) (0))) (false); - eq (Z.Applicative.test (Constant (Array) ([]))) (true); + eq (Z.Applicative.test (Constant (Useless.constructor) (Useless)), false); + eq (Z.Applicative.test (Constant (Number) (0)), false); + eq (Z.Applicative.test (Constant (Array) ([])), true); }); test ('Chain', () => { - eq (Z.Chain.test (Constant (Array) ([]))) (false); + eq (Z.Chain.test (Constant (Array) ([])), false); }); test ('ChainRec', () => { - eq (Z.ChainRec.test (Constant (Array) ([]))) (false); + eq (Z.ChainRec.test (Constant (Array) ([])), false); }); test ('Monad', () => { - eq (Z.Monad.test (Constant (Array) ([]))) (false); + eq (Z.Monad.test (Constant (Array) ([])), false); }); test ('Alt', () => { - eq (Z.Alt.test (Constant (Array) ([]))) (false); + eq (Z.Alt.test (Constant (Array) ([])), false); }); test ('Plus', () => { - eq (Z.Plus.test (Constant (Array) ([]))) (false); + eq (Z.Plus.test (Constant (Array) ([])), false); }); test ('Alternative', () => { - eq (Z.Alternative.test (Constant (Array) ([]))) (false); + eq (Z.Alternative.test (Constant (Array) ([])), false); }); test ('Foldable', () => { - eq (Z.Foldable.test (Constant (Useless.constructor) (Useless))) (true); + eq (Z.Foldable.test (Constant (Useless.constructor) (Useless)), true); }); test ('Traversable', () => { - eq (Z.Traversable.test (Constant (Useless.constructor) (Useless))) (true); + eq (Z.Traversable.test (Constant (Useless.constructor) (Useless)), true); }); test ('Extend', () => { - eq (Z.Extend.test (Constant (Array) ([]))) (false); + eq (Z.Extend.test (Constant (Array) ([])), false); }); test ('Comonad', () => { - eq (Z.Comonad.test (Constant (Array) ([]))) (false); + eq (Z.Comonad.test (Constant (Array) ([])), false); }); test ('Contravariant', () => { - eq (Z.Contravariant.test (Constant (Function) (Math.sqrt))) (false); + eq (Z.Contravariant.test (Constant (Function) (Math.sqrt)), false); }); testLaws ('Setoid') (laws.Setoid) ({ From 0ee27cf21d8f5a437f303e1002169d6194a4ea60 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 10 Jan 2024 08:58:12 +0100 Subject: [PATCH 36/42] use `node:` imports --- index.js | 13 ++++--------- test/index.js | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 0a567d3..c010717 100644 --- a/index.js +++ b/index.js @@ -17,24 +17,19 @@ 'use strict'; - const util = {inspect: {}}; - /* c8 ignore start */ if (typeof module === 'object' && typeof module.exports === 'object') { - module.exports = f (require ('util'), - require ('sanctuary-show'), + module.exports = f (require ('sanctuary-show'), require ('sanctuary-type-classes')); } else if (typeof define === 'function' && define.amd != null) { - define (['sanctuary-show', 'sanctuary-type-classes'], - (show, Z) => f (util, show, Z)); + define (['sanctuary-show', 'sanctuary-type-classes'], f); } else { - self.sanctuaryConstant = f (util, - self.sanctuaryShow, + self.sanctuaryConstant = f (self.sanctuaryShow, self.sanctuaryTypeClasses); } /* c8 ignore stop */ -}) ((util, show, Z) => { +}) ((show, Z) => { 'use strict'; diff --git a/test/index.js b/test/index.js index 88aee72..e0542c2 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,4 @@ -import {deepStrictEqual as eq} from 'assert'; +import {deepStrictEqual as eq} from 'node:assert'; import laws from 'fantasy-laws'; import jsc from 'jsverify'; From 8b733b7c1be9d2765b696441124e38f7fd0c2cc8 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sat, 13 Jan 2024 10:24:13 +0100 Subject: [PATCH 37/42] test `util.inspect` compatibility --- test/index.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/index.js b/test/index.js index e0542c2..8cf5d73 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,5 @@ import {deepStrictEqual as eq} from 'node:assert'; +import {inspect} from 'node:util'; import laws from 'fantasy-laws'; import jsc from 'jsverify'; @@ -100,6 +101,19 @@ test ('@@show', () => { 'Constant (' + String (Bar) + ') (Bar ("bar"))'); }); +test ('util.inspect', () => { + eq (inspect (Constant (Array) (['foo', 'bar', 'baz'])), + 'Constant (Array) (["foo", "bar", "baz"])'); + eq (inspect (Constant (Constant (Constant (Number))) + (Constant (Constant (Number)) + (Constant (Number) + (-0)))), + 'Constant (Constant (Constant (Number)))' + + ' (Constant (Constant (Number))' + + ' (Constant (Number)' + + ' (-0)))'); +}); + test ('Setoid', () => { eq (Z.Setoid.test (Constant (Useless.constructor) (Useless)), false); eq (Z.Setoid.test (Constant (RegExp) (/(?:)/)), true); From f6ba464191baad7a8034b908deb61069c6d44907 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 17 Jan 2024 14:15:21 +0100 Subject: [PATCH 38/42] sanctuary-show@3.0.0 --- index.js | 7 +++++-- package.json | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index c010717..183d859 100644 --- a/index.js +++ b/index.js @@ -147,7 +147,10 @@ return constant; } - Constant$bound.toString = () => { + // XXX: sanctuary-show@3 only respects @@show on "objects". Fool it. + Constant$bound[Symbol.toStringTag] = 'Object'; + + Constant$bound['@@show'] = () => { if (!(Object.prototype.hasOwnProperty.call (A, 'name'))) { const source = String (A); const match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source); @@ -186,7 +189,7 @@ //. 'Constant (Array) (["foo", "bar", "baz"])' //. ``` function Constant$prototype$show() { - return String (Constant$bound) + ' (' + show (this.value) + ')'; + return show (Constant$bound) + ' (' + show (this.value) + ')'; } //# Constant#fantasy-land/equals :: Setoid a => Constant a b ~> Constant a b -> Boolean diff --git a/package.json b/package.json index 94eb1e7..0354005 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "node": ">=14.0.0" }, "dependencies": { - "sanctuary-show": "2.0.0", + "sanctuary-show": "3.0.0", "sanctuary-type-classes": "12.1.0" }, "devDependencies": { From 0f6c194314d7e272447d7f23629eb088566a7843 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 17 Jan 2024 14:20:35 +0100 Subject: [PATCH 39/42] sanctuary-type-classes@13.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0354005..70d17a5 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "sanctuary-show": "3.0.0", - "sanctuary-type-classes": "12.1.0" + "sanctuary-type-classes": "13.0.0" }, "devDependencies": { "fantasy-land": "5.0.0", From e7cd612372ecc5141925f7390ec5f56391bcf423 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Wed, 17 Jan 2024 14:38:51 +0100 Subject: [PATCH 40/42] use ES modules --- .config | 1 - .eslintrc.json | 17 +- index.js | 502 +++++++++++++++++++++------------------------- package.json | 7 +- test/index.js | 2 +- test/package.json | 3 - 6 files changed, 242 insertions(+), 290 deletions(-) delete mode 100644 test/package.json diff --git a/.config b/.config index b404d3a..68751e9 100644 --- a/.config +++ b/.config @@ -1,4 +1,3 @@ repo-owner = sanctuary-js repo-name = sanctuary-constant contributing-file = .github/CONTRIBUTING.md -module-type = commonjs diff --git a/.eslintrc.json b/.eslintrc.json index f73ba86..243d513 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,19 +1,6 @@ { "root": true, "extends": ["./node_modules/sanctuary-style/eslint.json"], - "parserOptions": {"ecmaVersion": 2020}, - "globals": {"globalThis": "readonly"}, - "overrides": [ - { - "files": ["index.js"], - "globals": {"__doctest": "readonly", "define": "readonly", "module": "readonly", "require": "readonly", "self": "readonly"}, - "rules": { - "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^S$"}] - } - }, - { - "files": ["test/**/*.js"], - "parserOptions": {"sourceType": "module"} - } - ] + "parserOptions": {"ecmaVersion": 2020, "sourceType": "module"}, + "globals": {"globalThis": "readonly"} } diff --git a/index.js b/index.js index 183d859..7329f54 100644 --- a/index.js +++ b/index.js @@ -13,303 +13,267 @@ //. of type `a`. Mapping over a `Constant a b` has no effect because //. the `b -> c` function is never applied. -(f => { +import show from 'sanctuary-show'; +import Z from 'sanctuary-type-classes'; - 'use strict'; +export {Constant}; - /* c8 ignore start */ - if (typeof module === 'object' && typeof module.exports === 'object') { - module.exports = f (require ('sanctuary-show'), - require ('sanctuary-type-classes')); - } else if (typeof define === 'function' && define.amd != null) { - define (['sanctuary-show', 'sanctuary-type-classes'], f); - } else { - self.sanctuaryConstant = f (self.sanctuaryShow, - self.sanctuaryTypeClasses); - } - /* c8 ignore stop */ +const constantTypeIdent = 'sanctuary-constant/Constant@1'; -}) ((show, Z) => { +//. ```javascript +//. > import S from 'sanctuary' +//. > import $ from 'sanctuary-def' +//. > import Useless from 'sanctuary-useless' +//. ``` +//. +//. `Constant a b` satisfies the following [Fantasy Land][] specifications: +//. +//. ```javascript +//. > S.map (k => +//. . k + ' '.repeat (16 - k.length) + +//. . (Z[k].test (Constant (Useless.constructor) (Useless)) ? '\u2705 ' : +//. . Z[k].test (Constant (Array) (['foo', 'bar', 'baz'])) ? '\u2705 * ' : +//. . /* otherwise */ '\u274C ') +//. . ) (S.keys (S.unchecked.filter (S.is ($.TypeClass)) (Z))) +//. [ 'Setoid ✅ * ', // if ‘a’ satisfies Setoid +//. . 'Ord ✅ * ', // if ‘a’ satisfies Ord +//. . 'Semigroupoid ❌ ', +//. . 'Category ❌ ', +//. . 'Semigroup ✅ * ', // if ‘a’ satisfies Semigroup +//. . 'Monoid ❌ ', +//. . 'Group ❌ ', +//. . 'Filterable ❌ ', +//. . 'Functor ✅ ', +//. . 'Bifunctor ✅ ', +//. . 'Profunctor ❌ ', +//. . 'Apply ✅ * ', // if ‘a’ satisfies Semigroup +//. . 'Applicative ✅ * ', // if ‘a’ satisfies Monoid +//. . 'Chain ❌ ', +//. . 'ChainRec ❌ ', +//. . 'Monad ❌ ', +//. . 'Alt ❌ ', +//. . 'Plus ❌ ', +//. . 'Alternative ❌ ', +//. . 'Foldable ✅ ', +//. . 'Traversable ✅ ', +//. . 'Extend ❌ ', +//. . 'Comonad ❌ ', +//. . 'Contravariant ❌ ' ] +//. ``` - 'use strict'; +//# Constant :: TypeRep a -> a -> Constant a b +//. +//. Constant's sole data constructor. The [type representative][] makes +//. `Constant (M)` an [Applicative][]-compatible type representative if +//. `M` represents some monoidal type. +//. +//. ```javascript +//. > Constant (String) ('abc') +//. Constant (String) ('abc') +//. +//. > Constant (Number) (123) +//. Constant (Number) (123) +//. ``` +const Constant = A => { + const prototype = { + /* eslint-disable key-spacing */ + 'constructor': Constant$bound, + '@@type': constantTypeIdent, + '@@show': Constant$prototype$show, + 'fantasy-land/map': Constant$prototype$map, + 'fantasy-land/bimap': Constant$prototype$bimap, + 'fantasy-land/reduce': Constant$prototype$reduce, + 'fantasy-land/traverse': Constant$prototype$traverse, + /* eslint-enable key-spacing */ + }; + + if (globalThis.process?.versions?.node != null) { + const inspect = Symbol.for ('nodejs.util.inspect.custom'); + prototype[inspect] = Constant$prototype$show; + } /* c8 ignore start */ - if (typeof __doctest !== 'undefined') { - const {create, env} = __doctest.require ('sanctuary'); - // eslint-disable-next-line no-var - var $ = __doctest.require ('sanctuary-def'); - const type = __doctest.require ('sanctuary-type-identifiers'); - const Constant = $.BinaryType - ('Constant') - ('') - ([]) - (x => type (x) === constantTypeIdent) - (c => [c.value]) - (c => []); - // eslint-disable-next-line no-var - var S = create ({ - checkTypes: false, - env: Z.concat (env, [Constant ($.Unknown) ($.Unknown)]), - }); + if (typeof globalThis.Deno?.customInspect === 'symbol') { + const inspect = globalThis.Deno.customInspect; + prototype[inspect] = Constant$prototype$show; } /* c8 ignore stop */ - const constantTypeIdent = 'sanctuary-constant/Constant@1'; + function Constant$bound(value) { + const constant = Object.create (prototype); + if (Z.Setoid.test (value)) { + constant['fantasy-land/equals'] = Constant$prototype$equals; + if (Z.Ord.test (value)) { + constant['fantasy-land/lte'] = Constant$prototype$lte; + } + } + if (Z.Semigroup.test (value)) { + constant['fantasy-land/concat'] = Constant$prototype$concat; + constant['fantasy-land/ap'] = Constant$prototype$ap; + } + constant.value = value; + return constant; + } + + // XXX: sanctuary-show@3 only respects @@show on "objects". Fool it. + Constant$bound[Symbol.toStringTag] = 'Object'; - //. `Constant a b` satisfies the following [Fantasy Land][] specifications: + Constant$bound['@@show'] = () => { + if (!(Object.prototype.hasOwnProperty.call (A, 'name'))) { + const source = String (A); + const match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source); + return 'Constant (' + (match == null ? source : match[1]) + ')'; + } else if (A.name === Constant$bound.name) { + return 'Constant (' + show (A) + ')'; + } else { + return 'Constant (' + A.name + ')'; + } + }; + + //# Constant.fantasy-land/of :: Monoid m => a -> Constant m a + //. + //. `of (Constant (M)) (x)` is equivalent to `Constant (M) (empty (M))`. //. //. ```javascript - //. > const Useless = require ('sanctuary-useless') + //. > S.of (Constant (Array)) (42) + //. Constant (Array) ([]) //. - //. > S.map (k => - //. . k + ' '.repeat (16 - k.length) + - //. . (Z[k].test (Constant (Useless.constructor) (Useless)) ? '\u2705 ' : - //. . Z[k].test (Constant (Array) (['foo', 'bar', 'baz'])) ? '\u2705 * ' : - //. . /* otherwise */ '\u274C ') - //. . ) (S.keys (S.unchecked.filter (S.is ($.TypeClass)) (Z))) - //. [ 'Setoid ✅ * ', // if ‘a’ satisfies Setoid - //. . 'Ord ✅ * ', // if ‘a’ satisfies Ord - //. . 'Semigroupoid ❌ ', - //. . 'Category ❌ ', - //. . 'Semigroup ✅ * ', // if ‘a’ satisfies Semigroup - //. . 'Monoid ❌ ', - //. . 'Group ❌ ', - //. . 'Filterable ❌ ', - //. . 'Functor ✅ ', - //. . 'Bifunctor ✅ ', - //. . 'Profunctor ❌ ', - //. . 'Apply ✅ * ', // if ‘a’ satisfies Semigroup - //. . 'Applicative ✅ * ', // if ‘a’ satisfies Monoid - //. . 'Chain ❌ ', - //. . 'ChainRec ❌ ', - //. . 'Monad ❌ ', - //. . 'Alt ❌ ', - //. . 'Plus ❌ ', - //. . 'Alternative ❌ ', - //. . 'Foldable ✅ ', - //. . 'Traversable ✅ ', - //. . 'Extend ❌ ', - //. . 'Comonad ❌ ', - //. . 'Contravariant ❌ ' ] + //. > S.of (Constant (String)) (42) + //. Constant (String) ('') //. ``` + (() => { + let empty; + try { empty = Z.empty (A); } catch (err) { return; } + Constant$bound['fantasy-land/of'] = x => Constant$bound (empty); + }) (); - //# Constant :: TypeRep a -> a -> Constant a b + //# Constant#@@show :: Showable a => Constant a b ~> () -> String //. - //. Constant's sole data constructor. The [type representative][] makes - //. `Constant (M)` an [Applicative][]-compatible type representative if - //. `M` represents some monoidal type. + //. `show (Constant (A) (x))` is equivalent to + //. `'Constant (' + A.name + ') (' + show (x) + ')'`. //. //. ```javascript - //. > Constant (String) ('abc') - //. Constant (String) ('abc') - //. - //. > Constant (Number) (123) - //. Constant (Number) (123) + //. > S.show (Constant (Array) (['foo', 'bar', 'baz'])) + //. 'Constant (Array) (["foo", "bar", "baz"])' //. ``` - const Constant = A => { - const prototype = { - /* eslint-disable key-spacing */ - 'constructor': Constant$bound, - '@@type': constantTypeIdent, - '@@show': Constant$prototype$show, - 'fantasy-land/map': Constant$prototype$map, - 'fantasy-land/bimap': Constant$prototype$bimap, - 'fantasy-land/reduce': Constant$prototype$reduce, - 'fantasy-land/traverse': Constant$prototype$traverse, - /* eslint-enable key-spacing */ - }; - - if (globalThis.process?.versions?.node != null) { - const inspect = Symbol.for ('nodejs.util.inspect.custom'); - prototype[inspect] = Constant$prototype$show; - } - - /* c8 ignore start */ - if (typeof globalThis.Deno?.customInspect === 'symbol') { - const inspect = globalThis.Deno.customInspect; - prototype[inspect] = Constant$prototype$show; - } - /* c8 ignore stop */ - - function Constant$bound(value) { - const constant = Object.create (prototype); - if (Z.Setoid.test (value)) { - constant['fantasy-land/equals'] = Constant$prototype$equals; - if (Z.Ord.test (value)) { - constant['fantasy-land/lte'] = Constant$prototype$lte; - } - } - if (Z.Semigroup.test (value)) { - constant['fantasy-land/concat'] = Constant$prototype$concat; - constant['fantasy-land/ap'] = Constant$prototype$ap; - } - constant.value = value; - return constant; - } - - // XXX: sanctuary-show@3 only respects @@show on "objects". Fool it. - Constant$bound[Symbol.toStringTag] = 'Object'; - - Constant$bound['@@show'] = () => { - if (!(Object.prototype.hasOwnProperty.call (A, 'name'))) { - const source = String (A); - const match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source); - return 'Constant (' + (match == null ? source : match[1]) + ')'; - } else if (A.name === Constant$bound.name) { - return 'Constant (' + show (A) + ')'; - } else { - return 'Constant (' + A.name + ')'; - } - }; - - //# Constant.fantasy-land/of :: Monoid m => a -> Constant m a - //. - //. `of (Constant (M)) (x)` is equivalent to `Constant (M) (empty (M))`. - //. - //. ```javascript - //. > S.of (Constant (Array)) (42) - //. Constant (Array) ([]) - //. - //. > S.of (Constant (String)) (42) - //. Constant (String) ('') - //. ``` - (() => { - let empty; - try { empty = Z.empty (A); } catch (err) { return; } - Constant$bound['fantasy-land/of'] = x => Constant$bound (empty); - }) (); - - //# Constant#@@show :: Showable a => Constant a b ~> () -> String - //. - //. `show (Constant (A) (x))` is equivalent to - //. `'Constant (' + A.name + ') (' + show (x) + ')'`. - //. - //. ```javascript - //. > S.show (Constant (Array) (['foo', 'bar', 'baz'])) - //. 'Constant (Array) (["foo", "bar", "baz"])' - //. ``` - function Constant$prototype$show() { - return show (Constant$bound) + ' (' + show (this.value) + ')'; - } - - //# Constant#fantasy-land/equals :: Setoid a => Constant a b ~> Constant a b -> Boolean - //. - //. `Constant (A) (x)` is equal to `Constant (A) (y)` [iff][] `x` is - //. equal to `y` according to [`Z.equals`][]. - //. - //. ```javascript - //. > S.equals (Constant (Array) ([1, 2, 3])) - //. . (Constant (Array) ([1, 2, 3])) - //. true - //. - //. > S.equals (Constant (Array) ([1, 2, 3])) - //. . (Constant (Array) ([3, 2, 1])) - //. false - //. ``` - function Constant$prototype$equals(other) { - return Z.equals (this.value, other.value); - } - - //# Constant#fantasy-land/lte :: Ord a => Constant a b ~> Constant a b -> Boolean - //. - //. `Constant (A) (x)` is less than or equal to `Constant (A) (y)` [iff][] - //. `x` is less than or equal to `y` according to [`Z.lte`][]. - //. - //. ```javascript - //. > S.filter (S.lte (Constant (Number) (1))) - //. . ([Constant (Number) (0), - //. . Constant (Number) (1), - //. . Constant (Number) (2)]) - //. [Constant (Number) (0), Constant (Number) (1)] - //. ``` - function Constant$prototype$lte(other) { - return Z.lte (this.value, other.value); - } + function Constant$prototype$show() { + return show (Constant$bound) + ' (' + show (this.value) + ')'; + } - //# Constant#fantasy-land/concat :: Semigroup a => Constant a b ~> Constant a b -> Constant a b - //. - //. `concat (Constant (A) (x)) (Constant (A) (y))` is equivalent to - //. `Constant (A) (concat (x) (y))`. - //. - //. ```javascript - //. > S.concat (Constant (Array) ([1, 2, 3])) - //. . (Constant (Array) ([4, 5, 6])) - //. Constant (Array) ([1, 2, 3, 4, 5, 6]) - //. ``` - function Constant$prototype$concat(other) { - return Constant$bound (Z.concat (this.value, other.value)); - } + //# Constant#fantasy-land/equals :: Setoid a => Constant a b ~> Constant a b -> Boolean + //. + //. `Constant (A) (x)` is equal to `Constant (A) (y)` [iff][] `x` is + //. equal to `y` according to [`Z.equals`][]. + //. + //. ```javascript + //. > S.equals (Constant (Array) ([1, 2, 3])) + //. . (Constant (Array) ([1, 2, 3])) + //. true + //. + //. > S.equals (Constant (Array) ([1, 2, 3])) + //. . (Constant (Array) ([3, 2, 1])) + //. false + //. ``` + function Constant$prototype$equals(other) { + return Z.equals (this.value, other.value); + } - //# Constant#fantasy-land/map :: Constant a b ~> (b -> c) -> Constant a c - //. - //. `map (f) (Constant (A) (x))` is equivalent to `Constant (A) (x)`. - //. - //. ```javascript - //. > S.map (Math.sqrt) (Constant (Number) (64)) - //. Constant (Number) (64) - //. ``` - function Constant$prototype$map(f) { - return this; - } + //# Constant#fantasy-land/lte :: Ord a => Constant a b ~> Constant a b -> Boolean + //. + //. `Constant (A) (x)` is less than or equal to `Constant (A) (y)` [iff][] + //. `x` is less than or equal to `y` according to [`Z.lte`][]. + //. + //. ```javascript + //. > S.filter (S.lte (Constant (Number) (1))) + //. . ([Constant (Number) (0), + //. . Constant (Number) (1), + //. . Constant (Number) (2)]) + //. [Constant (Number) (0), Constant (Number) (1)] + //. ``` + function Constant$prototype$lte(other) { + return Z.lte (this.value, other.value); + } - //# Constant#fantasy-land/bimap :: Constant a c ~> (a -> b, c -> d) -> Constant b d - //. - //. `bimap (f) (g) (Constant (A) (x))` is equivalent to - //. `Constant (A) (f (x))`. - //. - //. ```javascript - //. > S.bimap (s => s.length) (Math.sqrt) (Constant (String) ('abc')) - //. Constant (Number) (3) - //. ``` - function Constant$prototype$bimap(f, g) { - const x = f (this.value); - return Constant (x.constructor) (x); - } + //# Constant#fantasy-land/concat :: Semigroup a => Constant a b ~> Constant a b -> Constant a b + //. + //. `concat (Constant (A) (x)) (Constant (A) (y))` is equivalent to + //. `Constant (A) (concat (x) (y))`. + //. + //. ```javascript + //. > S.concat (Constant (Array) ([1, 2, 3])) + //. . (Constant (Array) ([4, 5, 6])) + //. Constant (Array) ([1, 2, 3, 4, 5, 6]) + //. ``` + function Constant$prototype$concat(other) { + return Constant$bound (Z.concat (this.value, other.value)); + } - //# Constant#fantasy-land/ap :: Semigroup a => Constant a b ~> Constant a (b -> c) -> Constant a c - //. - //. `ap (Constant (A) (x)) (Constant (A) (y))` is equivalent to - //. `concat (Constant (A) (x)) (Constant (A) (y))`. - //. - //. ```javascript - //. > S.ap (Constant (Array) ([1, 2, 3])) (Constant (Array) ([4, 5, 6])) - //. Constant (Array) ([1, 2, 3, 4, 5, 6]) - //. ``` - function Constant$prototype$ap(other) { - return Z.concat (other, this); - } + //# Constant#fantasy-land/map :: Constant a b ~> (b -> c) -> Constant a c + //. + //. `map (f) (Constant (A) (x))` is equivalent to `Constant (A) (x)`. + //. + //. ```javascript + //. > S.map (Math.sqrt) (Constant (Number) (64)) + //. Constant (Number) (64) + //. ``` + function Constant$prototype$map(f) { + return this; + } - //# Constant#fantasy-land/reduce :: Constant a b ~> ((c, b) -> c, c) -> c - //. - //. `reduce (f) (x) (Constant (A) (y))` is equivalent to `x`. - //. - //. ```javascript - //. > S.reduce (S.add) (100) (Constant (Number) (42)) - //. 100 - //. ``` - function Constant$prototype$reduce(f, x) { - return x; - } + //# Constant#fantasy-land/bimap :: Constant a c ~> (a -> b, c -> d) -> Constant b d + //. + //. `bimap (f) (g) (Constant (A) (x))` is equivalent to + //. `Constant (A) (f (x))`. + //. + //. ```javascript + //. > S.bimap (s => s.length) (Math.sqrt) (Constant (String) ('abc')) + //. Constant (Number) (3) + //. ``` + function Constant$prototype$bimap(f, g) { + const x = f (this.value); + return Constant (x.constructor) (x); + } - //# Constant#fantasy-land/traverse :: Applicative f => Constant a b ~> (TypeRep f, b -> f c) -> f (Constant a c) - //. - //. `traverse (A) (f) (Constant (X) (x))` is equivalent to - //. `of (A) (Constant (X) (x))`. - //. - //. ```javascript - //. > S.traverse (Array) (Math.sqrt) (Constant (Number) (64)) - //. [Constant (Number) (64)] - //. ``` - function Constant$prototype$traverse(typeRep, f) { - return Z.of (typeRep, this); - } + //# Constant#fantasy-land/ap :: Semigroup a => Constant a b ~> Constant a (b -> c) -> Constant a c + //. + //. `ap (Constant (A) (x)) (Constant (A) (y))` is equivalent to + //. `concat (Constant (A) (x)) (Constant (A) (y))`. + //. + //. ```javascript + //. > S.ap (Constant (Array) ([1, 2, 3])) (Constant (Array) ([4, 5, 6])) + //. Constant (Array) ([1, 2, 3, 4, 5, 6]) + //. ``` + function Constant$prototype$ap(other) { + return Z.concat (other, this); + } - return Constant$bound; - }; + //# Constant#fantasy-land/reduce :: Constant a b ~> ((c, b) -> c, c) -> c + //. + //. `reduce (f) (x) (Constant (A) (y))` is equivalent to `x`. + //. + //. ```javascript + //. > S.reduce (S.add) (100) (Constant (Number) (42)) + //. 100 + //. ``` + function Constant$prototype$reduce(f, x) { + return x; + } - return Constant; + //# Constant#fantasy-land/traverse :: Applicative f => Constant a b ~> (TypeRep f, b -> f c) -> f (Constant a c) + //. + //. `traverse (A) (f) (Constant (X) (x))` is equivalent to + //. `of (A) (Constant (X) (x))`. + //. + //. ```javascript + //. > S.traverse (Array) (Math.sqrt) (Constant (Number) (64)) + //. [Constant (Number) (64)] + //. ``` + function Constant$prototype$traverse(typeRep, f) { + return Z.of (typeRep, this); + } -}); + return Constant$bound; +}; //. [Applicative]: v:fantasyland/fantasy-land#Applicative //. [Fantasy Land]: v:fantasyland/fantasy-land diff --git a/package.json b/package.json index 70d17a5..7cf6e62 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,11 @@ "type": "git", "url": "git://github.com/sanctuary-js/sanctuary-constant.git" }, + "type": "module", + "exports": { + ".": "./index.js", + "./package.json": "./package.json" + }, "files": [ "/LICENSE", "/README.md", @@ -14,7 +19,7 @@ "/package.json" ], "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" }, "dependencies": { "sanctuary-show": "3.0.0", diff --git a/test/index.js b/test/index.js index 8cf5d73..88d6352 100644 --- a/test/index.js +++ b/test/index.js @@ -10,7 +10,7 @@ import Z from 'sanctuary-type-classes'; import type from 'sanctuary-type-identifiers'; import Useless from 'sanctuary-useless'; -import Constant from '../index.js'; +import {Constant} from '../index.js'; // ConstantArb :: Monoid m => TypeRep m -> Arbitrary a -> Arbitrary (Constant a b) diff --git a/test/package.json b/test/package.json deleted file mode 100644 index 3dbc1ca..0000000 --- a/test/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} From 5bdb4d23542fad8d7c524bdb1700c1361f3a3195 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sun, 27 Oct 2024 10:52:12 +0100 Subject: [PATCH 41/42] use `\x1B[22m` to reset intensity but not colour --- test/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/index.js b/test/index.js index 88d6352..a3fc6e5 100644 --- a/test/index.js +++ b/test/index.js @@ -50,7 +50,7 @@ const testLaws = typeClass => laws => arbs => { (Object.keys (laws)).forEach (name => { eq (laws[name].length, arbs[name].length); const prettyName = name.replace (/[A-Z]/g, c => ' ' + c.toLowerCase ()); - test (`${typeClass} laws \x1B[2m›\x1B[0m ${prettyName}`, + test (`${typeClass} laws \x1B[2m›\x1B[22m ${prettyName}`, laws[name] (...arbs[name])); }); }; From 042bd4681d9838a43e8fbaa52f4c012a551a0096 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sun, 27 Oct 2024 11:12:27 +0100 Subject: [PATCH 42/42] circle: update Node versions --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6082ee9..0960fae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 orbs: - node: circleci/node@5.1.0 + node: circleci/node@6.3.0 workflows: test: @@ -16,4 +16,4 @@ workflows: version: - 18.0.0 - 20.0.0 - - 21.0.0 + - 22.0.0