Comparing version 1.3.1 to 2.0.0
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
"use strict";function _classCallCheck(i,a){if(!(i instanceof a))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function i(i,a){for(var t=0;t<a.length;t++){var n=a[t];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(i,n.key,n)}}return function(a,t,n){return t&&i(a.prototype,t),n&&i(a,n),a}}(),invariant=require("./invariant"),_lastID=1,_prefix="ID_",Dispatcher=function(){function i(){_classCallCheck(this,i),this._callbacks={},this._isPending={},this._isHandled={},this._isDispatching=!1,this._pendingPayload=null}return _createClass(i,[{key:"register",value:function(i){var a=_prefix+_lastID++;return this._callbacks[a]=i,a}},{key:"unregister",value:function(i){invariant(this._callbacks[i],"Dispatcher.unregister(...): `%s` does not map to a registered callback.",i),delete this._callbacks[i]}},{key:"waitFor",value:function(i){invariant(this._isDispatching,"Dispatcher.waitFor(...): Must be invoked while dispatching.");for(var a=0;a<i.length;a++){var t=i[a];this._isPending[t]?invariant(this._isHandled[t],"Dispatcher.waitFor(...): Circular dependency detected while waiting for `%s`.",t):(invariant(this._callbacks[t],"Dispatcher.waitFor(...): `%s` does not map to a registered callback.",t),this._invokeCallback(t))}}},{key:"dispatch",value:function(i){invariant(!this._isDispatching,"Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch."),this._startDispatching(i);try{for(var a in this._callbacks)this._isPending[a]||this._invokeCallback(a)}finally{this._stopDispatching()}}},{key:"isDispatching",value:function(){return this._isDispatching}},{key:"_invokeCallback",value:function(i){this._isPending[i]=!0,this._callbacks[i](this._pendingPayload),this._isHandled[i]=!0}},{key:"_startDispatching",value:function(i){for(var a in this._callbacks)this._isPending[a]=!1,this._isHandled[a]=!1;this._pendingPayload=i,this._isDispatching=!0}},{key:"_stopDispatching",value:function(){this._pendingPayload=null,this._isDispatching=!1}}]),i}();module.exports=Dispatcher; | ||
},{"./invariant":3}],2:[function(require,module,exports){ | ||
(function (process){ | ||
"use strict";function _dispatch(e,t){if("string"==typeof e)dispatcher.dispatch({type:e,data:t});else{if("object"!==("undefined"==typeof e?"undefined":_typeof(e)))throw"type must be string or object";dispatcher.dispatch(e)}}function createStore(e,t,r){var n=arguments.length<=3||void 0===arguments[3]?{}:arguments[3],o="function"!=typeof t?"object"===("undefined"==typeof t?"undefined":_typeof(t))?Object.freeze(t):t:Object.freeze({}),c=new EventEmitter,i={},a=void 0;if("function"==typeof t&&(n=r,r=t),"object"===("undefined"==typeof r?"undefined":_typeof(r)))a=function(e,t){return t&&"string"==typeof t.type&&r.hasOwnProperty(t.type)?r[t.type](e,t.data,waitFor):e},i=Object.keys(r).reduce(function(e,t){return e[t]=function(e){return dispatcher.dispatch({type:t,data:e})},e},{});else{if("function"!=typeof r)throw new Error("reducer must be object or function");a=r}var f=Object.keys(n).reduce(function(e,t,r){var c={};return c[t]=function(){for(var e,r=arguments.length,c=Array(r),i=0;i<r;i++)c[i]=arguments[i];return(e=n)[t].apply(e,[o].concat(c))},Object.assign(e,c)},{});return Object.freeze(Object.assign({},f,i,{name:e,dispatchToken:dispatcher.register(function(e){var t=a(o,e,waitFor);o!==t&&(o="object"===("undefined"==typeof t?"undefined":_typeof(t))?Object.freeze(t):t,c.emit("changed"))}),subscribe:function(e){if("function"!=typeof e)throw"Callback must be a function";return c.addListener("changed",e),count+=1,function(){c.removeListener("changed",e)}},replaceState:"development"===process.env.NODE_ENV?function(e){o=e}:void 0,replaceReducer:"development"===process.env.NODE_ENV?function(e){a=e}:void 0,dispatch:function(){return _dispatch.apply(void 0,arguments)},getState:function(e){return o}}))}Object.defineProperty(exports,"__esModule",{value:!0});var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};exports.createStore=createStore;var EventEmitter=require("events").EventEmitter,Dispatcher=require("./Dispatcher"),count=0;Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(void 0===e||null===e)throw new TypeError("Cannot convert first argument to object");for(var t=Object(e),r=1;r<arguments.length;r++){var n=arguments[r];if(void 0!==n&&null!==n){n=Object(n);for(var o=Object.keys(n),c=0,i=o.length;c<i;c++){var a=o[c],f=Object.getOwnPropertyDescriptor(n,a);void 0!==f&&f.enumerable&&(t[a]=n[a])}}}return t}}),Object.freeze||(Object.freeze=function(e){if(Object(e)!==e)throw new TypeError("Object.freeze can only be called on Objects.");return e});var dispatcher=new Dispatcher,waitFor=dispatcher.waitFor.bind(dispatcher);exports.dispatch=_dispatch; | ||
}).call(this,require('_process')) | ||
},{"./Dispatcher":1,"_process":5,"events":4}],3:[function(require,module,exports){ | ||
"use strict";var invariant=function(r,e,n,i,o,a,t,f){if(!r){var s;if(void 0===e)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var d=[n,i,o,a,t,f],l=0;s=new Error("Invariant Violation: "+e.replace(/%s/g,function(){return d[l++]}))}throw s.framesToPop=1,s}};module.exports=invariant; | ||
},{}],4:[function(require,module,exports){ | ||
window&&(window.fluxury=require("./lib/fluxury")); | ||
},{"./lib/fluxury":2}],2:[function(require,module,exports){ | ||
"use strict";function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _dispatch(e,t){if("string"==typeof e)dispatcher.dispatch({type:e,data:t});else{if("object"!==("undefined"==typeof e?"undefined":_typeof(e)))throw"type must be string or object";dispatcher.dispatch(e)}}function createStore(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],n=void 0,i=new _events.EventEmitter,r={},a=void 0,o=function(){};if("function"==typeof e)n=e(void 0,{},o),a=e;else{if("object"!==("undefined"==typeof e?"undefined":_typeof(e)))throw new Error("first argument must be object or function",e);n="function"==typeof e.getInitialState?e.getInitialState(void 0,{},o):void 0,a=function(t,n){return n&&"string"==typeof n.type&&e.hasOwnProperty(n.type)?e[n.type](t,n.data,waitFor):t},r=Object.keys(e).reduce(function(e,t){return e[t]=function(e){return dispatcher.dispatch({type:t,data:e})},e},{})}var c=Object.keys(t).reduce(function(e,i,r){var a={};return a[i]=function(){for(var e=arguments.length,r=Array(e),a=0;a<e;a++)r[a]=arguments[a];return t[i].apply(t,[n].concat(r))},Object.assign(e,a)},{});return Object.freeze(Object.assign({},c,r,{dispatchToken:dispatcher.register(function(e){var t=a(n,e,waitFor);n!==t&&(n="object"===("undefined"==typeof t?"undefined":_typeof(t))?Object.freeze(t):t,i.emit("changed"))}),subscribe:function(e){if("function"!=typeof e)throw"Callback must be a function";return i.addListener("changed",e),count+=1,function(){i.removeListener("changed",e)}},reduce:function(e,t){return a(e,t,waitFor)},setState:function(e){n=e},dispatch:function(){return _dispatch.apply(void 0,arguments)},getState:function(e){return n}}))}function composeStore(){function e(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];return 1===t.length&&"object"===_typeof(t[0])&&"undefined"==typeof t[0].getState}function t(t){for(var n=arguments.length,i=Array(n>1?n-1:0),r=1;r<n;r++)i[r-1]=arguments[r];return e.apply(void 0,i)?Object.keys(i[0]).reduce(function(e,t){return e[t]=i[0][t].getState(),e},{}):i.map(function(e){return e.getState()})}function n(e){for(var t=arguments.length,n=Array(t>1?t-1:0),i=1;i<t;i++)n[i-1]=arguments[i];return e?Object.keys(n[0]).reduce(function(e,t){return e.concat(n[0][t])},[]):(n.forEach(function(e){"function"!=typeof e.getState&&console&&console.log&&console.log("ERROR: invalid store")}),n)}for(var i=arguments.length,r=Array(i),a=0;a<i;a++)r[a]=arguments[a];var o=e.apply(void 0,r),c=t.apply(void 0,[o].concat(r)),s=n.apply(void 0,[o].concat(r)),u=s.map(function(e){return e.dispatchToken});return createStore(function(){var e=arguments.length<=0||void 0===arguments[0]?c:arguments[0],n=(arguments[1],arguments[2]);n(u);var i=t.apply(void 0,[o].concat(r));if(o){if(Object.keys(r[0]).reduce(function(t,n){return t&&e[n]===i[n]},!0))return e}else if(e.length===i.length&&e.every(function(e,t){return e===i[t]}))return e;return i},{getState:function(e){return t.apply(void 0,[o].concat(_toConsumableArray(e)))}})}Object.defineProperty(exports,"__esModule",{value:!0}),exports.composeStore=exports.createStore=exports.dispatch=void 0;var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e},_createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),_events=require("events"),invariant=function(e,t,n,i,r,a,o,c){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,i,r,a,o,c],f=0;s=new Error("Invariant Violation: "+t.replace(/%s/g,function(){return u[f++]}))}throw s.framesToPop=1,s}},_lastID=1,_prefix="ID_",Dispatcher=function(){function e(){_classCallCheck(this,e),this._callbacks={},this._isPending={},this._isHandled={},this._isDispatching=!1,this._pendingPayload=null}return _createClass(e,[{key:"register",value:function(e){var t=_prefix+_lastID++;return this._callbacks[t]=e,t}},{key:"unregister",value:function(e){invariant(this._callbacks[e],"Dispatcher.unregister(...): `%s` does not map to a registered callback.",e),delete this._callbacks[e]}},{key:"waitFor",value:function(e){invariant(this._isDispatching,"Dispatcher.waitFor(...): Must be invoked while dispatching.");for(var t=0;t<e.length;t++){var n=e[t];this._isPending[n]?invariant(this._isHandled[n],"Dispatcher.waitFor(...): Circular dependency detected while waiting for `%s`.",n):(invariant(this._callbacks[n],"Dispatcher.waitFor(...): `%s` does not map to a registered callback.",n),this._invokeCallback(n))}}},{key:"dispatch",value:function(e){invariant(!this._isDispatching,"Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch."),this._startDispatching(e);try{for(var t in this._callbacks)this._isPending[t]||this._invokeCallback(t)}finally{this._stopDispatching()}}},{key:"isDispatching",value:function(){return this._isDispatching}},{key:"_invokeCallback",value:function(e){this._isPending[e]=!0,this._callbacks[e](this._pendingPayload),this._isHandled[e]=!0}},{key:"_startDispatching",value:function(e){for(var t in this._callbacks)this._isPending[t]=!1,this._isHandled[t]=!1;this._pendingPayload=e,this._isDispatching=!0}},{key:"_stopDispatching",value:function(){this._pendingPayload=null,this._isDispatching=!1}}]),e}(),count=0;Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(void 0===e||null===e)throw new TypeError("Cannot convert first argument to object");for(var t=Object(e),n=1;n<arguments.length;n++){var i=arguments[n];if(void 0!==i&&null!==i){i=Object(i);for(var r=Object.keys(i),a=0,o=r.length;a<o;a++){var c=r[a],s=Object.getOwnPropertyDescriptor(i,c);void 0!==s&&s.enumerable&&(t[c]=i[c])}}}return t}}),Object.freeze||(Object.freeze=function(e){if(Object(e)!==e)throw new TypeError("Object.freeze can only be called on Objects.");return e});var dispatcher=new Dispatcher,waitFor=dispatcher.waitFor.bind(dispatcher);exports.dispatch=_dispatch,exports.createStore=createStore,exports.composeStore=composeStore; | ||
},{"events":3}],3:[function(require,module,exports){ | ||
function EventEmitter(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function isFunction(e){return"function"==typeof e}function isNumber(e){return"number"==typeof e}function isObject(e){return"object"==typeof e&&null!==e}function isUndefined(e){return void 0===e}module.exports=EventEmitter,EventEmitter.EventEmitter=EventEmitter,EventEmitter.prototype._events=void 0,EventEmitter.prototype._maxListeners=void 0,EventEmitter.defaultMaxListeners=10,EventEmitter.prototype.setMaxListeners=function(e){if(!isNumber(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},EventEmitter.prototype.emit=function(e){var t,i,n,s,r,o;if(this._events||(this._events={}),"error"===e&&(!this._events.error||isObject(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(i=this._events[e],isUndefined(i))return!1;if(isFunction(i))switch(arguments.length){case 1:i.call(this);break;case 2:i.call(this,arguments[1]);break;case 3:i.call(this,arguments[1],arguments[2]);break;default:s=Array.prototype.slice.call(arguments,1),i.apply(this,s)}else if(isObject(i))for(s=Array.prototype.slice.call(arguments,1),o=i.slice(),n=o.length,r=0;r<n;r++)o[r].apply(this,s);return!0},EventEmitter.prototype.addListener=function(e,t){var i;if(!isFunction(t))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,isFunction(t.listener)?t.listener:t),this._events[e]?isObject(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,isObject(this._events[e])&&!this._events[e].warned&&(i=isUndefined(this._maxListeners)?EventEmitter.defaultMaxListeners:this._maxListeners,i&&i>0&&this._events[e].length>i&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())),this},EventEmitter.prototype.on=EventEmitter.prototype.addListener,EventEmitter.prototype.once=function(e,t){function i(){this.removeListener(e,i),n||(n=!0,t.apply(this,arguments))}if(!isFunction(t))throw TypeError("listener must be a function");var n=!1;return i.listener=t,this.on(e,i),this},EventEmitter.prototype.removeListener=function(e,t){var i,n,s,r;if(!isFunction(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(i=this._events[e],s=i.length,n=-1,i===t||isFunction(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(isObject(i)){for(r=s;r-- >0;)if(i[r]===t||i[r].listener&&i[r].listener===t){n=r;break}if(n<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(n,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},EventEmitter.prototype.removeAllListeners=function(e){var t,i;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(i=this._events[e],isFunction(i))this.removeListener(e,i);else if(i)for(;i.length;)this.removeListener(e,i[i.length-1]);return delete this._events[e],this},EventEmitter.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?isFunction(this._events[e])?[this._events[e]]:this._events[e].slice():[]},EventEmitter.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(isFunction(t))return 1;if(t)return t.length}return 0},EventEmitter.listenerCount=function(e,t){return e.listenerCount(t)}; | ||
},{}],5:[function(require,module,exports){ | ||
function cleanUpNextTick(){draining&¤tQueue&&(draining=!1,currentQueue.length?queue=currentQueue.concat(queue):queueIndex=-1,queue.length&&drainQueue())}function drainQueue(){if(!draining){var e=cachedSetTimeout(cleanUpNextTick);draining=!0;for(var r=queue.length;r;){for(currentQueue=queue,queue=[];++queueIndex<r;)currentQueue&¤tQueue[queueIndex].run();queueIndex=-1,r=queue.length}currentQueue=null,draining=!1,cachedClearTimeout(e)}}function Item(e,r){this.fun=e,this.array=r}function noop(){}var process=module.exports={},cachedSetTimeout,cachedClearTimeout;!function(){try{cachedSetTimeout=setTimeout}catch(e){cachedSetTimeout=function(){throw new Error("setTimeout is not defined")}}try{cachedClearTimeout=clearTimeout}catch(e){cachedClearTimeout=function(){throw new Error("clearTimeout is not defined")}}}();var queue=[],draining=!1,currentQueue,queueIndex=-1;process.nextTick=function(e){var r=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)r[n-1]=arguments[n];queue.push(new Item(e,r)),1!==queue.length||draining||cachedSetTimeout(drainQueue,0)},Item.prototype.run=function(){this.fun.apply(null,this.array)},process.title="browser",process.browser=!0,process.env={},process.argv=[],process.version="",process.versions={},process.on=noop,process.addListener=noop,process.once=noop,process.off=noop,process.removeListener=noop,process.removeAllListeners=noop,process.emit=noop,process.binding=function(e){throw new Error("process.binding is not supported")},process.cwd=function(){return"/"},process.chdir=function(e){throw new Error("process.chdir is not supported")},process.umask=function(){return 0}; | ||
},{}]},{},[2]); | ||
},{}]},{},[1]); |
{ | ||
"name": "fluxury", | ||
"version": "1.3.1", | ||
"description": "Add luxury sugar to simplify implementing Facebook's flavor of Flux architecture.", | ||
"main": "./lib/index.js", | ||
"jsnext:main": "index.js", | ||
"version": "2.0.0", | ||
"description": "High level store builder for Flux architecture", | ||
"main": "./lib/fluxury.js", | ||
"jsnext:main": "./lib/fluxury.es6", | ||
"scripts": { | ||
"build": "babel src/invariant.js -o lib/invariant.js && babel src/Dispatcher.js -o lib/Dispatcher.js && babel src/index.js -o lib/index.js", | ||
"bundle": "browserify -g uglifyify ./lib/index.js > dist/fluxury.js", | ||
"test": "node test", | ||
"all": "npm run build && npm test && npm run bundle" | ||
"build": "rollup src/index.js > lib/fluxury.es6 && babel lib/fluxury.es6 -o lib/fluxury.js && browserify -g uglifyify ./browserify.js > dist/fluxury.js", | ||
"test": "node test" | ||
}, | ||
"engines": { | ||
"node": ">=6.0" | ||
}, | ||
"author": "Peter Moresi", | ||
@@ -22,2 +23,3 @@ "license": "MIT", | ||
"immutable": "^3.7.5", | ||
"rollup": "^0.34.10", | ||
"tape": "^4.2.2", | ||
@@ -24,0 +26,0 @@ "uglifyify": "^3.0.1", |
163
README.md
# fluxury | ||
[](https://circleci.com/gh/FunctionFoundry/fluxury/tree/master) | ||
[](https://circleci.com/gh/websitehq/fluxury/tree/master) | ||
@@ -12,3 +12,3 @@ Quick start: | ||
```js | ||
import {dispatch, createStore} from 'fluxury' | ||
import {dispatch, createStore, composeStore} from 'fluxury' | ||
``` | ||
@@ -18,18 +18,19 @@ | ||
This library forks Flux 2.0.2; enforcing the `(state, action) -> state` pattern. | ||
This library forks Facbook's Flux (v2.0.2) focusing on ease of use and promoting the `(state, action) => state` made popular by Redux. | ||
This Flux fork focuses around 2 functions: | ||
This library includes functions: | ||
- dispatch(action) or dispatch(type, data) | ||
- createStore(name, actionHandler, selectors) or createStore(name, defaultValue, actionHandler, selectors) | ||
- dispatch(type, data) or dispatch(action) | ||
- createStore(reducer, selectors) or createStore(configObjct, selectors) | ||
- composeStore(...spec) | ||
Of course it is compatible with React. Please see [React-Fluxury](https://github.com/FunctionFoundry/react-fluxury) for more information. | ||
For react bindings please checkout [react-fluxury](https://github.com/FunctionFoundry/react-fluxury). | ||
It is compatible with Redux. Please see [Fluxury-Redux](https://github.com/FunctionFoundry/fluxury-redux) for integration. | ||
For redux bindings please checkout [fluxury-redux](https://github.com/FunctionFoundry/fluxury-redux). | ||
## API Reference | ||
1. dispatch( type, data ) or dispatch( action ) | ||
### dispatch( type, data ) or dispatch( action ) | ||
Submit an action into the stores. | ||
Dispatch an action to all stores. | ||
@@ -40,24 +41,21 @@ ```js | ||
// dispatch an action with a string | ||
dispatch('REQUEST_SETTINGS') // => { type: 'LOAD_SETTINGS', data: undefined } | ||
dispatch('requestSettings') // => { type: 'loadSettings', data: undefined } | ||
// or with data | ||
dispatch('LOAD_SETTINGS', { a: 1, b: 2 }) // => { type: 'LOAD_SETTINGS', data: { a: 1, b: 2 } } | ||
dispatch('loadSettings', { a: 1, b: 2 }) // => { type: 'loadSettings', data: { a: 1, b: 2 } } | ||
// or with a custom object | ||
dispatch({ type: 'move', mode: 'off the rails' }) | ||
dispatch({ type: 'move', mode: 'over rails' }) | ||
``` | ||
3. createStore(name, initialState, reducer, methods) | ||
### createStore(reducerOrConfig, selectors) | ||
Creating a store is to Flux what creating a class is to React. | ||
Define stores which respond to actions and manage state. | ||
```js | ||
// actions | ||
const INC = 'INC' | ||
// fluxury magic | ||
const inc = 'inc' | ||
import {createStore} from 'fluxury'; | ||
// a simple counting store | ||
export default createStore('CountStore', (state=0, action) => { | ||
var countStore = createStore((state=0, action, waitFor) => { | ||
switch (action.type) | ||
case INC: | ||
case inc: | ||
return state + 1; | ||
@@ -69,20 +67,32 @@ default: | ||
If you do not prefer the switch boilerplate then you may specify an object with reducers. | ||
If you do not prefer the `switch case` then may use a config object. | ||
The config object uses the life cycle method `getInitialState` to configure | ||
the initial value stored. This should look familiar to React programmers. | ||
```js | ||
const INC = 'INC' | ||
const inc = 'inc' | ||
import {createStore} from 'fluxury'; | ||
export default createStore( | ||
'Count Store', | ||
0, | ||
{ | ||
increment: (state) => state + 1, | ||
decrement: (state) => state - 1 | ||
} | ||
) | ||
export default createStore({ | ||
getInitialState: () => 0 | ||
increment: (state) => state + 1, | ||
incrementN: (state, data, waitFor) => state + data, | ||
decrement: (state) => state - 1 | ||
}) | ||
``` | ||
In addition to the state and action the reducer function receives _waitFor_ as the third argument. The waitFor function can be used to enforce the order in store updates. See Facebook Flux documentation for more information. | ||
`waitFor` is used to control the order which store process actions. | ||
### composeStore(...spec) | ||
Compose one or more stores into composite store. | ||
The spec may either be an array of stores or an Object with stores. | ||
```js | ||
composeStores(MessageStore, CountStore) | ||
composeStores({ count: CountStore, message: MessageStore }) | ||
``` | ||
## Store Properties and Methods | ||
@@ -94,7 +104,7 @@ | ||
| dispatch | Another method to access the dispatch function | | ||
| dispatchToken | A number used with waitFor | | ||
| subscribe | A function to register listeners | | ||
| dispatchToken | A number used to identity each store | | ||
| subscribe | Register listener and return a function to remove listener | | ||
| getState | A function that returns the current state | | ||
| replaceState | Replace the state; development only | | ||
| replaceReducer | Replace the reducer; development only | | ||
| setState | Replace the current store state | | ||
| reduce | Run the reduce directly | | ||
@@ -107,11 +117,19 @@ ## Put it all together | ||
var countStore = createStore('CountStore', 0, { | ||
increment: (state) => state + 1, | ||
decrement: (state) => state - 1 | ||
var messageStore = createStore({ | ||
getInitialState: () => [], | ||
addMessage: (state) => state + 1, | ||
}); | ||
var messageCountStore = createStore({ | ||
getInitialState: () => 0, | ||
addMessage: (state, data, waitFor) => { | ||
waitFor([messageStore.dispatchToken]) | ||
return state + 1 | ||
} | ||
}); | ||
var MyComponent = React.createClass({ | ||
componentDidMount: function() { | ||
this.unsubscribe = countStore.subscribe( this.handleStoreChange ); | ||
this.unsubscribe = messageCountStore.subscribe( this.handleStoreChange ); | ||
}, | ||
@@ -124,14 +142,10 @@ | ||
handleStoreChange: function() { | ||
this.setState({ count: countStore.getState() }) | ||
this.setState({ count: messageCountStore.getState() }) | ||
}, | ||
handleUpClick: function() { | ||
handleAdd: function() { | ||
/* Call dispatch to submit the action to the stores */ | ||
countStore.increment()) | ||
messageStore.addMessage(this.refs.message_text.value) | ||
}, | ||
handleDownClick: function() { | ||
/* Call dispatch to submit the action to the stores */ | ||
countStore.decrement() | ||
}, | ||
@@ -142,4 +156,4 @@ render: function() { | ||
<p>{this.state.count}</p> | ||
<button onClick={this.handleUpClick}>+1</button> | ||
<button onClick={this.handleDownClick}>-1</button> | ||
<input ref="message_text"> | ||
<button onClick={this.handleAdd}>Add</button> | ||
</div> | ||
@@ -152,53 +166,2 @@ ); | ||
module.exports = MyComponent; | ||
``` | ||
## MapStore with defensive copies | ||
A simple store that accumulates data on each `SET` action. | ||
```js | ||
const SET = 'SET'; | ||
var {dispatch, createStore } = require('fluxury'); | ||
var mapStore = createStore('MapStore', {}, { | ||
SET: (state, data) => Object.assign({}, state, data) | ||
}, { | ||
getStates: (state) => state.states, | ||
getPrograms: (state) => state.programs, | ||
getSelectedState: (state) => state.selectedState | ||
}); | ||
dispatch(SET, { states: ['CA', 'OR', 'WA'] }) | ||
// store.getStates() => { states: ['CA', 'OR', 'WA'] } | ||
dispatch(SET, { programs: [{ name: 'A', states: ['CA']}] }) | ||
// store.getPrograms() => { programs: [{ name: 'A', states: ['CA']}] } | ||
// or use the sugar: | ||
mapStore.SET({ selectedState: 'CA' }) | ||
// store.getSelectedState() => 'CA' | ||
// store.getState() => { states: ['CA', 'OR', 'WA'], { states: ['CA', 'OR', 'WA'], programs: [{ name: 'A', states: ['CA']}] }, selectedState: 'CA' } | ||
``` | ||
## MapStore with Immutable data structures | ||
Here is a similar MapStore with Immutable.js. | ||
```js | ||
var {dispatch, createStore } = require('fluxury'); | ||
var {Map} = require('Immutable'); | ||
var store = createStore('MapStore', Map(), { | ||
set: (state, data) => state.merge(data) | ||
}, { | ||
get: (state, param) => state.get(param), | ||
has: (state, param) => state.has(param), | ||
includes: (state, param) => state.includes(param), | ||
first: (state) => state.first(), | ||
last: (state) => state.last(), | ||
all: (state) => state.toJS(), | ||
}); | ||
``` |
@@ -15,3 +15,3 @@ /* | ||
var invariant = require('./invariant'); | ||
import invariant from './invariant'; | ||
@@ -251,2 +251,2 @@ var _lastID = 1; | ||
module.exports = Dispatcher; | ||
export default Dispatcher; |
123
src/index.js
/* fluxury - Copyright 2015 Peter Moresi */ | ||
"use strict"; | ||
var EventEmitter = require( 'events' ).EventEmitter; | ||
var Dispatcher = require('./Dispatcher'); | ||
import {EventEmitter} from 'events'; | ||
import Dispatcher from './Dispatcher'; | ||
@@ -74,23 +74,22 @@ let count = 0; | ||
export function createStore(name, initialState, reducer, methods={}) { | ||
var currentState = ( | ||
typeof initialState !== 'function' ? | ||
(typeof initialState === 'object' ? Object.freeze(initialState) : initialState) : | ||
Object.freeze({})); | ||
export function createStore(reducerOrConfig, selectors={}) { | ||
let currentState; | ||
var emitter = new EventEmitter(); | ||
let actions = {}; | ||
let reduce = undefined; | ||
let noop = () => {} | ||
if (typeof initialState === 'function') { | ||
methods = reducer | ||
reducer = initialState | ||
} | ||
if (typeof reducerOrConfig === 'function') { | ||
currentState = reducerOrConfig(undefined, {}, noop) | ||
reduce = reducerOrConfig | ||
} else if (typeof reducerOrConfig === 'object') { | ||
if (typeof reducer === 'object') { | ||
currentState = typeof reducerOrConfig.getInitialState === 'function' ? | ||
reducerOrConfig.getInitialState(undefined, {}, noop) : undefined; | ||
// construct a reduce method with the object | ||
reduce = ((state, action) => { | ||
if (action && typeof action.type === 'string' && reducer.hasOwnProperty(action.type)) { | ||
return reducer[action.type](state, action.data, waitFor); | ||
if (action && typeof action.type === 'string' && reducerOrConfig.hasOwnProperty(action.type)) { | ||
return reducerOrConfig[action.type](state, action.data, waitFor); | ||
} | ||
@@ -101,3 +100,3 @@ return state; | ||
// create helpful action methods | ||
actions = Object.keys(reducer) | ||
actions = Object.keys(reducerOrConfig) | ||
.reduce((a, b) => { | ||
@@ -111,12 +110,10 @@ a[b] = (data) => dispatcher.dispatch({ | ||
} else if (typeof reducer === 'function') { | ||
reduce = reducer | ||
} else { | ||
throw new Error('reducer must be object or function') | ||
throw new Error('first argument must be object or function', reducerOrConfig) | ||
} | ||
let boundMethods = Object.keys(methods).reduce(function(a, b, i) { | ||
let boundMethods = Object.keys(selectors).reduce(function(a, b, i) { | ||
var newFunc = {}; | ||
newFunc[b] = function(...params) { | ||
return methods[b](currentState, ...params); | ||
return selectors[b](currentState, ...params); | ||
} | ||
@@ -132,3 +129,2 @@ return Object.assign(a, newFunc) | ||
{ | ||
name: name, | ||
dispatchToken: dispatcher.register( function(action) { | ||
@@ -154,6 +150,4 @@ var newState = reduce(currentState, action, waitFor); | ||
}, | ||
replaceState: ((process.env.NODE_ENV === 'development') ? (state) => { | ||
currentState = state }: undefined), | ||
replaceReducer: ((process.env.NODE_ENV === 'development') ? (reducer) => { | ||
reduce = reducer }: undefined), | ||
reduce: (state, action) => reduce(state, action, waitFor), | ||
setState: (state) => { currentState = state }, | ||
dispatch: (...action) => dispatch(...action), | ||
@@ -167,1 +161,80 @@ getState: function(cb) { | ||
} | ||
// Compose | ||
export function composeStore(...spec) { | ||
function isMappedObject(...spec) { | ||
return (spec.length === 1 && | ||
typeof spec[0] === 'object' && | ||
typeof spec[0].getState === 'undefined') | ||
} | ||
function getState(isMapped, ...spec) { | ||
if (isMappedObject(...spec)) { | ||
return Object.keys(spec[0]).reduce((acc, key) => { | ||
acc[key] = spec[0][key].getState() | ||
return acc; | ||
}, {}) | ||
} | ||
return spec.map(n => n.getState()) | ||
} | ||
function getStores(isMapped, ...spec) { | ||
if (isMapped) { | ||
return Object.keys(spec[0]).reduce((acc, key) => acc.concat(spec[0][key]), []) | ||
} else { | ||
spec.forEach( store => { | ||
if (typeof store.getState !== 'function') { | ||
if (console && console.log) { | ||
console.log('ERROR: invalid store') | ||
} | ||
} | ||
}) | ||
return spec | ||
} | ||
} | ||
let isMapped = isMappedObject(...spec) | ||
let defaultState = getState(isMapped, ...spec) | ||
let stores = getStores(isMapped, ...spec) | ||
let dispatchTokens = stores.map(n => n.dispatchToken ) | ||
return createStore( | ||
(state=defaultState, action, waitFor) => { | ||
waitFor(dispatchTokens) | ||
let newState = getState(isMapped, ...spec) | ||
if (isMapped){ // object specified | ||
if ( Object.keys(spec[0]).reduce( | ||
(current, key) => | ||
(current && state[key] === newState[key]), true | ||
)) { | ||
return state; | ||
} | ||
} else { // array specified | ||
// not changed | ||
if ( | ||
state.length === newState.length && | ||
state.every( (n, i) => n === newState[i] ) | ||
) { | ||
return state | ||
} | ||
} | ||
return newState | ||
}, | ||
{ | ||
getState:(state) => getState(isMapped, ...state) | ||
} | ||
) | ||
} |
@@ -47,2 +47,2 @@ /** | ||
module.exports = invariant; | ||
export default invariant; |
171
test.js
var test = require('tape'); | ||
var fluxury = require('./lib/index.js') | ||
var fluxury = require('./lib/fluxury') | ||
var composeStore = fluxury.composeStore | ||
var createStore = fluxury.createStore | ||
var dispatch = fluxury.dispatch | ||
@@ -12,13 +14,13 @@ test( 'fluxury', function(t) { | ||
var INC = 'INC' | ||
var DEC = 'DEC' | ||
var SET = 'SET' | ||
var inc = 'inc' | ||
var dec = 'dec' | ||
var set = 'set' | ||
process.env.NODE_ENV = 'development' | ||
var store = fluxury.createStore('MapStore', function(state, action) { | ||
var store = fluxury.createStore((state, action) => { | ||
state = typeof state === 'undefined' ? {} : state | ||
switch (action.type) { | ||
case SET: | ||
case set: | ||
// combine both objects into a single new object | ||
@@ -38,11 +40,11 @@ return Object.assign({}, state, action.data) | ||
store.subscribe( () => listenerCount++ ) | ||
fluxury.dispatch(SET, { foo: 1, bar: 2 }) | ||
fluxury.dispatch(set, { foo: 1, bar: 2 }) | ||
t.deepEqual(store.getState(), { foo: 1, bar: 2 }) | ||
t.equal(store.getFoo(), 1) | ||
t.equal(store.getBar(), 2) | ||
fluxury.dispatch(SET, { foo: 2 }) | ||
fluxury.dispatch(set, { foo: 2 }) | ||
t.deepEqual(store.getState(), { foo: 2, bar: 2 }) | ||
fluxury.dispatch(SET, { hey: ['ho', 'let\'s', 'go'] }) | ||
fluxury.dispatch(set, { hey: ['ho', 'let\'s', 'go'] }) | ||
t.deepEqual(store.getState(), { foo: 2, bar: 2, hey: ['ho', 'let\'s', 'go'] }) | ||
store.dispatch(SET, { foo: 3 }) | ||
store.dispatch(set, { foo: 3 }) | ||
t.deepEqual(store.getState(), { foo: 3, bar: 2, hey: ['ho', 'let\'s', 'go'] }) | ||
@@ -54,7 +56,7 @@ t.deepEqual(store.filterHey('go'), ['go']); | ||
var store = fluxury.createStore('CountStore', 0, function(state, action) { | ||
var store = fluxury.createStore((state=0, action) => { | ||
switch (action.type) { | ||
case INC: | ||
case inc: | ||
return state+1; | ||
case DEC: | ||
case dec: | ||
return state-1; | ||
@@ -66,15 +68,15 @@ default: | ||
fluxury.dispatch(INC) | ||
fluxury.dispatch(inc) | ||
t.equal(store.getState(), 1) | ||
fluxury.dispatch(INC) | ||
fluxury.dispatch(inc) | ||
t.equal(store.getState(), 2) | ||
fluxury.dispatch(DEC) | ||
fluxury.dispatch(dec) | ||
t.equal(store.getState(), 1) | ||
fluxury.dispatch(DEC) | ||
fluxury.dispatch(dec) | ||
t.equal(store.getState(), 0) | ||
t.deepEqual( Object.keys(store).sort(), [ 'dispatch', 'dispatchToken', 'getState', 'name', 'replaceReducer', 'replaceState', 'subscribe' ].sort() ); | ||
t.deepEqual( Object.keys(store).sort(), [ 'dispatch', 'dispatchToken', 'getState', 'reduce', 'setState', 'subscribe' ].sort() ); | ||
}) | ||
@@ -85,9 +87,6 @@ | ||
var MessageCountStore = createStore( | ||
'Message Count Store', | ||
0, | ||
{ | ||
receiveMessage: (count) => count + 1 | ||
} | ||
) | ||
var MessageCountStore = createStore({ | ||
getInitialState: () => 0, | ||
receiveMessage: (count) => count + 1 | ||
}) | ||
@@ -107,5 +106,3 @@ t.plan(3) | ||
var fluxury = require('./lib/index'), | ||
dispatch = fluxury.dispatch, | ||
SET = 'SET', | ||
var dispatch = fluxury.dispatch, | ||
Immutable = require('immutable'); | ||
@@ -116,4 +113,5 @@ | ||
// For when switch cases seem like overkill. | ||
var store = fluxury.createStore('MapStore', Immutable.Map(), { | ||
SET: (state, data) => state.merge(data) | ||
var store = fluxury.createStore({ | ||
getInitialState: () => Immutable.Map(), | ||
set: (state, data) => state.merge(data) | ||
}, { | ||
@@ -129,7 +127,6 @@ get: (state, param) => state.get(param), | ||
// should only be when | ||
console.log(process.env.NODE_ENV === 'development' ) | ||
t.equal(typeof store.replaceState, 'undefined') | ||
t.equal(typeof store.SET, 'function') | ||
t.equal(typeof store.set, 'function') | ||
t.deepEqual( Object.keys(store), [ | ||
t.deepEqual( Object.keys(store).sort(), [ | ||
'get', | ||
@@ -141,15 +138,15 @@ 'has', | ||
'all', | ||
'SET', | ||
'name', | ||
'getInitialState', | ||
'set', | ||
'dispatchToken', | ||
'subscribe', | ||
'replaceState', | ||
'replaceReducer', | ||
'reduce', | ||
'setState', | ||
'dispatch', | ||
'getState' | ||
]); | ||
].sort()); | ||
dispatch(SET, { states: ['CA', 'OR', 'WA'] }) | ||
dispatch(SET, { programs: [{ name: 'A', states: ['CA']}] }) | ||
dispatch(SET, { selectedState: 'CA' }) | ||
dispatch('set', { states: ['CA', 'OR', 'WA'] }) | ||
dispatch('set', { programs: [{ name: 'A', states: ['CA']}] }) | ||
dispatch('set', { selectedState: 'CA' }) | ||
@@ -168,11 +165,9 @@ t.deepEqual( store.get('states').toJS(), ['CA', 'OR', 'WA'] ); | ||
test('waitFor works correctly', function(t) { | ||
test('waitFor and compose works correctly', function(t) { | ||
var createStore = require('./lib/index').createStore | ||
var dispatch = require('./lib/index').dispatch | ||
var dispatchCount = 0; | ||
t.plan(11) | ||
t.plan(14) | ||
var MessageStore = createStore('MessageStore', [], function(state, action) { | ||
var MessageStore = createStore(function(state=[], action) { | ||
switch(action.type) { | ||
@@ -186,40 +181,66 @@ case 'loadMessage': | ||
var MessageCountStore = createStore( 'MessageCountStore', 0, | ||
function(state, action, waitFor) { | ||
// ensure that MessageStore reducer is executed before continuing | ||
waitFor([MessageStore.dispatchToken]) | ||
switch(action.type) { | ||
case 'loadMessage': | ||
return state+1 | ||
default: | ||
return state | ||
var MessageCountStore = createStore( | ||
function(state=0, action, waitFor) { | ||
// ensure that MessageStore reducer is executed before continuing | ||
waitFor([MessageStore.dispatchToken]) | ||
switch(action.type) { | ||
case 'loadMessage': | ||
return state+1 | ||
default: | ||
return state | ||
} | ||
} | ||
} | ||
) | ||
) | ||
var unsubscribe = MessageStore.subscribe(function() { | ||
dispatchCount += 1 | ||
}) | ||
var Combined1 = composeStore(MessageCountStore, MessageStore) | ||
var Combined2 = composeStore([MessageCountStore, MessageStore]) | ||
t.equals( typeof unsubscribe, 'function') | ||
var Combined3 = composeStore({ | ||
count: MessageCountStore, | ||
messages: MessageStore | ||
}) | ||
dispatch('loadMessage', 'Test') | ||
t.equals(MessageStore.getState().length, 1) | ||
t.equals(MessageCountStore.getState(), 1) | ||
t.deepEqual(MessageStore.getState(), ['Test']) | ||
var unsubscribe = MessageStore.subscribe(function() { | ||
dispatchCount += 1 | ||
}) | ||
dispatch('loadMessage', 'Test2') | ||
t.equals(MessageStore.getState().length, 2) | ||
t.equals(MessageCountStore.getState(), 2) | ||
t.deepEqual(MessageStore.getState(), ['Test', 'Test2']) | ||
t.equals( typeof unsubscribe, 'function') | ||
unsubscribe() | ||
dispatch('loadMessage', 'Test') | ||
t.equals(MessageStore.getState().length, 1) | ||
t.equals(MessageCountStore.getState(), 1) | ||
t.deepEqual(MessageStore.getState(), ['Test']) | ||
dispatch('loadMessage', 'Test3') | ||
t.equals(MessageStore.getState().length, 3) | ||
t.equals(MessageCountStore.getState(), 3) | ||
t.deepEqual(MessageStore.getState(), ['Test', 'Test2', 'Test3']) | ||
dispatch('loadMessage', 'Test2') | ||
t.equals(MessageStore.getState().length, 2) | ||
t.equals(MessageCountStore.getState(), 2) | ||
t.deepEqual(MessageStore.getState(), ['Test', 'Test2']) | ||
t.equal(dispatchCount, 2) | ||
unsubscribe() | ||
dispatch('loadMessage', 'Test3') | ||
t.equals(MessageStore.getState().length, 3) | ||
t.equals(MessageCountStore.getState(), 3) | ||
t.deepEqual(MessageStore.getState(), ['Test', 'Test2', 'Test3']) | ||
t.deepEqual(Combined1.getState(), [3, ['Test', 'Test2', 'Test3']]) | ||
t.deepEqual(Combined2.getState(), [3, ['Test', 'Test2', 'Test3']]) | ||
t.deepEqual(Combined3.getState(), { count: 3, messages: ['Test', 'Test2', 'Test3'] }) | ||
t.equal(dispatchCount, 2) | ||
}) | ||
test('reduce works correctly', function(t) { | ||
var dispatchCount = 0; | ||
t.plan(1) | ||
var MessageStore = createStore({ | ||
loadMessage: (state, data) => state.concat(data) | ||
}) | ||
t.deepEqual( MessageStore.reduce(['a'], { type: 'loadMessage', data: ['b'] }), ['a', 'b']) | ||
}) |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
70091
1223
4
10
159
1