diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..ea997c1 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-2"] +} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..cd1d91a --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +**/dist/* +**/node_modules/* +**/server.js +**/webpack.config*.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..99c5dbd --- /dev/null +++ b/.eslintrc @@ -0,0 +1,14 @@ +{ + "extends": "rackt", + "rules": { + "valid-jsdoc": 2, + // Disable until Flow supports let and const + "no-var": 0, + "react/jsx-uses-react": 1, + "react/jsx-no-undef": 2, + "react/wrap-multilines": 2 + }, + "plugins": [ + "react" + ] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b10e446 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +*.log +*.sw? +node_modules +dist +lib +coverage +_book diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..af2353d --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Dan Abramov + +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/package.json b/package.json new file mode 100644 index 0000000..35d9c9f --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "redux-reactions", + "version": "0.1.0", + "description": "reactions library for redux", + "main": "index.js", + "scripts": { + "test": "mocha --compilers js:babel-register --recursive", + "lint": "eslint src test examples", + "check": "npm run lint && npm run test", + "build:lib": "babel src --out-dir lib", + "build:umd": "webpack src/index.js dist/redux.js --config webpack.config.development.js", + "build:umd:min": "webpack src/index.js dist/redux.min.js --config webpack.config.production.js", + "build": "npm run build:lib && npm run build:umd && npm run build:umd:min" + }, + "author": "Winston Ewert ", + "license": "MIT", + "devDependencies": { + "babel-cli": "^6.3.17", + "babel-core": "^6.3.26", + "babel-eslint": "^5.0.0-beta6", + "babel-loader": "^6.2.1", + "babel-preset-es2015": "^6.3.13", + "babel-preset-stage-2": "^6.3.13", + "babel-register": "^6.3.13", + "eslint": "^1.10.3", + "eslint-config-rackt": "^1.1.1", + "eslint-plugin-react": "^3.14.0", + "mocha": "^2.3.4", + "redux": "^3.0.5" + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..615d2d8 --- /dev/null +++ b/src/index.js @@ -0,0 +1,11 @@ +export function startReactions(store, reactions, taskTypes) { + function updateReactions() { + for (var reaction of reactions(store.getState())) { + if (reaction) { + taskTypes[reaction.type](undefined, () => store.dispatch({ type: 'FINISH' })) + } + } + } + + store.subscribe(updateReactions) +} diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 0000000..7eeefc3 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "mocha": true + } +} diff --git a/test/startReactions.spec.js b/test/startReactions.spec.js new file mode 100644 index 0000000..e92b814 --- /dev/null +++ b/test/startReactions.spec.js @@ -0,0 +1,47 @@ +import { createStore } from 'redux' +import { strictEqual, deepEqual } from 'assert' +import { startReactions } from '../src' + +describe('startReactions', () => { + it('applies reactions', () => { + + function reducer(state = { started: false, finished: false }, action) { + switch (action.type) { + case 'START': + return { ...state, started: true } + case 'FINISH': + return { ...state, finished: true } + default: + return state + } + } + var store = createStore(reducer) + + function reactions(state) { + return [ + state.started && !state.finished && { type: 'TASK', events: { finished: () => {type: 'FINISH'} } } + ] + } + + var waiting = [] + + function taskImplementation(details, emitter) { + waiting.push(() => emitter('FINISH')) + } + + startReactions(store, reactions,{ TASK: taskImplementation }) + + strictEqual(waiting.length, 0) + deepEqual(store.getState(), { started: false, finished: false }) + + store.dispatch({ type: 'START' }) + + strictEqual(waiting.length, 1) + deepEqual(store.getState(), { started: true, finished: false }) + + waiting[0]() + + strictEqual(waiting.length, 1) + deepEqual(store.getState(), { started: true, finished: true }) + }) +}) diff --git a/webpack.config.base.js b/webpack.config.base.js new file mode 100644 index 0000000..0dd203d --- /dev/null +++ b/webpack.config.base.js @@ -0,0 +1,16 @@ +'use strict'; + +module.exports = { + module: { + loaders: [ + { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ } + ] + }, + output: { + library: 'Redux', + libraryTarget: 'umd' + }, + resolve: { + extensions: ['', '.js'] + } +}; diff --git a/webpack.config.development.js b/webpack.config.development.js new file mode 100644 index 0000000..e509d7c --- /dev/null +++ b/webpack.config.development.js @@ -0,0 +1,14 @@ +'use strict'; + +var webpack = require('webpack'); +var baseConfig = require('./webpack.config.base'); + +var config = Object.create(baseConfig); +config.plugins = [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('development') + }) +]; + +module.exports = config; diff --git a/webpack.config.production.js b/webpack.config.production.js new file mode 100644 index 0000000..f4589cc --- /dev/null +++ b/webpack.config.production.js @@ -0,0 +1,20 @@ +'use strict'; + +var webpack = require('webpack'); +var baseConfig = require('./webpack.config.base'); + +var config = Object.create(baseConfig); +config.plugins = [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production') + }), + new webpack.optimize.UglifyJsPlugin({ + compressor: { + screw_ie8: true, + warnings: false + } + }) +]; + +module.exports = config;