From 8d38fafa5635c2d9bbd860ff2ea4f272bb16e2f3 Mon Sep 17 00:00:00 2001 From: Aldwin Vlasblom Date: Wed, 11 Jul 2018 16:15:21 +0200 Subject: [PATCH] Add everything! --- .config | 4 +++ .eslintrc.json | 18 ++++++++++++++ .gitignore | 3 +++ .npmrc | 1 + .travis.yml | 4 +++ CONTRIBUTING.md | 18 ++++++++++++++ index.mjs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 35 ++++++++++++++++++++++++++ scripts/doctest | 2 ++ scripts/test | 9 +++++++ test/index.js | 54 ++++++++++++++++++++++++++++++++++++++++ test/mocha.opts | 3 +++ 12 files changed, 216 insertions(+) create mode 100644 .config create mode 100644 .eslintrc.json create mode 100644 .npmrc create mode 100644 .travis.yml create mode 100644 CONTRIBUTING.md create mode 100644 index.mjs create mode 100644 package.json create mode 100755 scripts/doctest create mode 100755 scripts/test create mode 100644 test/index.js create mode 100644 test/mocha.opts diff --git a/.config b/.config new file mode 100644 index 0000000..7dbf5f6 --- /dev/null +++ b/.config @@ -0,0 +1,4 @@ +author-name = WEAREREASONABLEPEOPLE +repo-owner = wearereasonablepeople +repo-name = warped-reducers +source-files = index.mjs diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..4315822 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "root": true, + "extends": ["./node_modules/sanctuary-style/eslint-es3.json"], + "parserOptions": { + "sourceType": "module" + }, + "overrides": [ + { + "files": ["*.md"], + "plugins": ["markdown"], + "env": {"es6": true}, + "globals": {"createReducer": false}, + "rules": { + "strict": ["off"] + } + } + ] +} diff --git a/.gitignore b/.gitignore index 2ccbe46..9aaaa4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ +/.nyc_output/ +/coverage.lcov +/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/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c3a79c4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "10" +after_success: npm run coverage diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c4b0342 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,18 @@ +# Contribution Guideline + +## Making a contribution + +1. Fork the repo if you do not have write access +1. Clone the remote (fork) from GitHub +1. Create a branch named `/` +1. Make one or more atomic commits +1. Make sure the tests pass locally +1. Create a pull-request on GitHub + +## Publishing a new version + +1. Make sure you have write access to the module on npm +1. Make sure you have write access to the master branch on GitHub +1. Checkout `master` and make sure it's up to date with the remote +1. Run `npm run release `, where `` can be any of: 'major', + 'minor', 'patch', 'premajor', 'preminor', 'prepatch', or 'prerelease'. diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..9a5486d --- /dev/null +++ b/index.mjs @@ -0,0 +1,65 @@ +//. # Warped Reducers +//. +//. [![Build Status](https://travis-ci.com/wearereasonablepeople/warped-reducers.svg?branch=master)](https://travis-ci.com/wearereasonablepeople/warped-reducers) +//. +//. Compile a standard Redux reducer from a brief definition. +//. +//. Works nicely with [Warped Components][1]. +//. +//. Usage in Node depends on `--experimental-modules`. +//. With older Node versions, use [std/esm][2]. + +// createType :: (String, String) -> String +export function createType(namespace, actionName) { + return 'Warped/' + namespace + '/' + actionName; +} + +// compileActionTypes :: (String, StrMap Any) -> StrMap String +export function compileActionTypes(namespace, actions) { + var actionTypes = Object.create (null); + Object.keys (actions).forEach (key => { + actionTypes[key] = createType (namespace, key); + }); + return actionTypes; +} + +// compileReducer :: (String, StrMap b -> a -> a) -> (a, b) -> a +export function compileReducer(namespace, actions) { + const handlers = Object.create (null); + Object.entries (actions).forEach (([key, handler]) => { + handlers[createType (namespace, key)] = handler; + }); + return function(state, action) { + return handlers[action.type] ? + handlers[action.type] (action.payload) (state) : + state; + }; +} + +//. ## API +//. +//# createReducer :: String -> StrMap b -> a -> a -> { reducer :: (a, b) -> a, types :: StrMap String } +//. +//. Given a String representing the namespace, and a StrMap of curried and +//. flipped reducers, returns a Record containing a single reducer, and a new +//. StrMap mapping the original keys to canonical identifiers of the types that +//. the reducer can handle. +//. +//. This is the default export from this module. +//. +//. ```js +//. const setMyProp = myProp => state => Object.assign ({}, {state, myProp}); +//. createReducer ('MyNamespace') ({setMyProp}); +//. ``` +export default createReducer; +export function createReducer(namespace) { + return function(actions) { + return { + reducer: compileReducer (namespace, actions), + types: compileActionTypes (namespace, actions) + }; + }; +} + +//. [1]: https://github.com/wearereasonablepeople/warped-components +//. [2]: https://github.com/standard-things/esm diff --git a/package.json b/package.json new file mode 100644 index 0000000..884e2e9 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "warped-reducers", + "version": "0.0.1", + "description": "Compile a standard Redux reducer from a brief definition", + "main": "index.mjs", + "module": "index.mjs", + "scripts": { + "coverage": "nyc report --reporter=text-lcov | coveralls", + "doctest": "sanctuary-doctest", + "lint": "sanctuary-lint", + "release": "sanctuary-release", + "test": "npm run lint && sanctuary-test && npm run doctest" + }, + "repository": { + "type": "git", + "url": "git://github.com/wearereasonablepeople/warped-reducers.git" + }, + "files": [ + "/index.mjs", + "/LICENSE", + "/package.json", + "/README.md" + ], + "author": "Aldwin Vlasblom (https://github.com/Avaq)", + "license": "MIT", + "dependencies": {}, + "devDependencies": { + "coveralls": "^3.0.2", + "esm": "^3.0.66", + "nyc": "^12.0.2", + "sanctuary-scripts": "^2.0.0", + "sanctuary-show": "^1.0.0", + "sanctuary-type-classes": "^9.0.0" + } +} diff --git a/scripts/doctest b/scripts/doctest new file mode 100755 index 0000000..b747c2e --- /dev/null +++ b/scripts/doctest @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo 'Doctests cannot run on mjs files. Skipping :(' diff --git a/scripts/test b/scripts/test new file mode 100755 index 0000000..276fba8 --- /dev/null +++ b/scripts/test @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euf -o pipefail + +source "${BASH_SOURCE%/*}/../node_modules/sanctuary-scripts/functions" + +branches="$(get min-branch-coverage)" + +node_modules/.bin/nyc --extension .mjs node_modules/.bin/mocha +node_modules/.bin/nyc check-coverage --branches $branches diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..786ef22 --- /dev/null +++ b/test/index.js @@ -0,0 +1,54 @@ +import assert from 'assert'; +import show from 'sanctuary-show'; +import Z from 'sanctuary-type-classes'; + +import { + createType, + compileActionTypes, + compileReducer, + createReducer +} from '..'; + + +function eq(actual) { + return function eqq(expected) { + assert.strictEqual (show (actual), show (expected)); + assert.strictEqual (Z.equals (actual, expected), true); + }; +} + +function mockHandler(payload) { + return function(state) { + return Object.assign ({}, state, {actionPayload: payload}); + }; +} + +test ('createType', function() { + eq (createType ('Test', 'foo')) + ('Warped/Test/foo'); +}); + +test ('compileActionTypes', function() { + eq (compileActionTypes ('Test', {})) ({}); + eq (compileActionTypes ('Test', {foo: mockHandler, bar: mockHandler})) + ({foo: 'Warped/Test/foo', bar: 'Warped/Test/bar'}); +}); + +test ('compileReducer', function() { + var reducer = compileReducer ('Test', {foo: mockHandler}); + eq (typeof reducer) ('function'); + eq (reducer.length) (2); + eq (reducer ({}, {type: 'NotHandled'})) ({}); + eq (reducer ({}, {type: 'Warped/Test/foo', payload: 'test'})) + ({actionPayload: 'test'}); +}); + +test ('createReducer', function() { + var result = createReducer ('Test') ({foo: mockHandler}); + eq (typeof result) ('object'); + eq (typeof result.reducer) ('function'); + eq (typeof result.types) ('object'); + eq (result.reducer ({}, {type: 'Warped/Test/foo', payload: 'test'})) + ({actionPayload: 'test'}); + eq (result.types) ({foo: 'Warped/Test/foo'}); +}); diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..e67d97f --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,3 @@ +--bail +--ui tdd +--require esm