[
  {
    "path": "CommonJs.md",
    "content": "## Common JS Example\n\n```javascript\n// widgets.js\n\nconst LOAD   = 'my-app/widgets/LOAD';\nconst CREATE = 'my-app/widgets/CREATE';\nconst UPDATE = 'my-app/widgets/UPDATE';\nconst REMOVE = 'my-app/widgets/REMOVE';\n\nfunction reducer(state = {}, action = {}) {\n  switch (action.type) {\n    // do reducer stuff\n    default: return state;\n  }\n}\n\nreducer.loadWidgets = function() {\n  return { type: LOAD };\n}\n\nreducer.createWidget = function(widget) {\n  return { type: CREATE, widget };\n}\n\nreducer.updateWidget = function(widget) {\n  return { type: UPDATE, widget };\n}\n\nreducer.removeWidget = function(widget) {\n  return { type: REMOVE, widget };\n}\n\nmodule.exports = reducer;\n```\n\n\nOne of the different caveats is that you can't use Redux' `bindActionCreators()` directly with a duck module, as it assumes that when given a function, it's a single action creator, so you need to do something like:\n\n```javascript\nvar actionCreators = require('./ducks/widgets');\nbindActionCreators({ ...actionCreators });\n```\n\nAnother is that if you're also exporting some type constants, you need to attach those to the reducer function too, so you can't unpack just the action creators into another object at import time as easily (no `as` syntax) so the above trick isn't as viable.\n\nYou can avoid getting bitten by both of these by rolling your own dispatch binding function - this is the one I'm using to create a function to be passed as the `mapDispatchToProps` argument to `connect()`:\n\n```javascript\n/**\n * Creates a function which creates same-named action dispatchers from an object\n * whose function properties are action creators. Any non-functions in the actionCreators\n * object are ignored.\n */\nvar createActionDispatchers = actionCreators => dispatch =>\n  Object.keys(actionCreators).reduce((actionDispatchers, name) => {\n    var actionCreator = actionCreators[name];\n    if (typeof actionCreator == 'function') {\n      actionDispatchers[name] = (...args) => dispatch(actionCreator(...args));\n    }\n    return actionDispatchers;\n  }, {})\n\nvar actionCreators = require('./ducks/widgets');\nvar mapStateToProps = state => state.widgets;\nvar mapDispatchToProps = createActionDispatchers(actionCreators);\n\nvar MyComponent = React.createClass({ /* ... */ });\n\nmodule.exports = connect(mapStateToProps , mapDispatchToProps)(MyComponent);\n```\n\n---\nThis document copied almost verbatim from [@insin](https://github.com/insin)'s issue [#2](https://github.com/erikras/ducks-modular-redux/issues/2)."
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n<a href=\"https://codefund.io/properties/555/visit-sponsor\">\n<img src=\"https://codefund.io/properties/555/sponsor\" />\n</a>\n</p>\n    \n# Ducks: Redux Reducer Bundles\n\n<img src=\"duck.jpg\" align=\"right\"/>\n\nI find as I am building my redux app, one piece of functionality at a time, I keep needing to add  `{actionTypes, actions, reducer}` tuples for each use case. I have been keeping these in separate files and even separate folders, however 95% of the time, it's only one reducer/actions pair that ever needs their associated actions.\n\nTo me, it makes more sense for these pieces to be bundled together in an isolated module that is self contained, and can even be packaged easily into a library.\n\n## The Proposal\n\n### Example\n\nSee also: [Common JS Example](CommonJs.md).\n\n```javascript\n// widgets.js\n\n// Actions\nconst LOAD   = 'my-app/widgets/LOAD';\nconst CREATE = 'my-app/widgets/CREATE';\nconst UPDATE = 'my-app/widgets/UPDATE';\nconst REMOVE = 'my-app/widgets/REMOVE';\n\n// Reducer\nexport default function reducer(state = {}, action = {}) {\n  switch (action.type) {\n    // do reducer stuff\n    default: return state;\n  }\n}\n\n// Action Creators\nexport function loadWidgets() {\n  return { type: LOAD };\n}\n\nexport function createWidget(widget) {\n  return { type: CREATE, widget };\n}\n\nexport function updateWidget(widget) {\n  return { type: UPDATE, widget };\n}\n\nexport function removeWidget(widget) {\n  return { type: REMOVE, widget };\n}\n\n// side effects, only as applicable\n// e.g. thunks, epics, etc\nexport function getWidget () {\n  return dispatch => get('/widget').then(widget => dispatch(updateWidget(widget)))\n}\n\n```\n### Rules\n\nA module...\n\n1. MUST `export default` a function called `reducer()`\n2. MUST `export` its action creators as functions\n3. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n3. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nThese same guidelines are recommended for `{actionType, action, reducer}` bundles that are shared as reusable Redux libraries.\n\n### Name\n\nJava has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".\n\n### Usage\n\nYou can still do:\n\n```javascript\nimport { combineReducers } from 'redux';\nimport * as reducers from './ducks/index';\n\nconst rootReducer = combineReducers(reducers);\nexport default rootReducer;\n```\n\nYou can still do:\n\n```javascript\nimport * as widgetActions from './ducks/widgets';\n```\n...and it will only import the action creators, ready to be passed to `bindActionCreators()`.\n\n> Actually, it'll also import `default`, which will be the reducer function. It'll add an action creator named `default` that won't work. If that's a problem for you, you should enumerate each action creator when importing.\n\nThere will be some times when you want to `export` something other than an action creator. That's okay, too. The rules don't say that you can *only* `export` action creators. When that happens, you'll just have to enumerate the action creators that you want. Not a big deal.\n\n```javascript\nimport {loadWidgets, createWidget, updateWidget, removeWidget} from './ducks/widgets';\n// ...\nbindActionCreators({loadWidgets, createWidget, updateWidget, removeWidget}, dispatch);\n```\n\n### Example\n\n[React Redux Universal Hot Example](https://github.com/erikras/react-redux-universal-hot-example) uses ducks. See [`/src/redux/modules`](https://github.com/erikras/react-redux-universal-hot-example/tree/master/src/redux/modules).\n\n[Todomvc using ducks.](https://github.com/goopscoop/ga-react-tutorial/tree/6-reduxActionsAndReducers)\n\n### BattleCry generators\n\nThere are configurable [BattleCry](https://github.com/pedsmoreira/battlecry) generators ready to be downloaded and help scaffolding ducks:\n\n```sh\nnpm install -g battlecry\ncry download generator erikras/ducks-modular-redux\ncry init duck\n```\n\nRun `cry --help` to check more info about the generators available;\n\n### Implementation\n\nThe migration to this code structure was [painless](https://github.com/erikras/react-redux-universal-hot-example/commit/3fdf194683abb7c40f3cb7969fd1f8aa6a4f9c57), and I foresee it reducing much future development misery.\n\nAlthough it's completely feasable to implement it without any extra library, there are some tools that might help you:\n\n * [extensible-duck](https://github.com/investtools/extensible-duck) - Implementation of the Ducks proposal. With this library you can create reusable and extensible ducks.\n * [saga-duck](https://github.com/cyrilluce/saga-duck) - Implementation of the Ducks proposal in Typescript with [sagas](https://github.com/redux-saga/redux-saga) in mind. Results in reusable and extensible ducks.\n * [redux-duck](https://github.com/PlatziDev/redux-duck) - Helper function to create Redux modules using the ducks-modular-redux proposal\n * [modular-redux-thunk](https://github.com/benbeadle/modular-redux-thunk) - A ducks-inspired package to help organize actions, reducers, and selectors together - with built-in redux-thunk support for async actions.\n * [molecular-js](https://www.npmjs.com/package/molecular-js) - Set of utilities to ease the development of modular state management patterns with Redux (also known as ducks).\n * [ducks-reducer](https://github.com/drpicox/ducks-reducer) - Function to combine _ducks object_ reducers into one reducer (equivalent to [combineReducers](https://redux.js.org/docs/api/combineReducers.html)), and function [ducks-middleware](https://github.com/drpicox/ducks-middleware) to combine _ducks object_ middleware into one single middleware compatible with [applyMiddleware](https://redux.js.org/docs/api/applyMiddleware.html).\n * [simple-duck](https://github.com/xander27/simple-duck) - Class based implementation of modules system, inspired by ducks-modular-redux. All OOP benefits like inheritance and composition. Support combining of duck-module classes and regular reducer functions using `combineModules` function.\n\nPlease submit any feedback via an issue or a tweet to [@erikras](https://twitter.com/erikras). It will be much appreciated.\n\nHappy coding!\n\n-- Erik Rasmussen\n\n\n### Translation\n\n[한국어](https://github.com/JisuPark/ducks-modular-redux)\n[中文](https://github.com/deadivan/ducks-modular-redux)\n[Türkçe](https://github.com/mfyz/ducks-modular-redux-tr)\n\n---\n\n![C'mon! Let's migrate all our reducers!](migrate.jpg)\n> Photo credit to [Airwolfhound](https://www.flickr.com/photos/24874528@N04/3453886876/).\n\n---\n\n[![Beerpay](https://beerpay.io/erikras/ducks-modular-redux/badge.svg?style=beer-square)](https://beerpay.io/erikras/ducks-modular-redux)  [![Beerpay](https://beerpay.io/erikras/ducks-modular-redux/make-wish.svg?style=flat-square)](https://beerpay.io/erikras/ducks-modular-redux?focus=wish)\n"
  },
  {
    "path": "battlecry/generators/duck/duck.generator.js",
    "content": "import { Generator, File, namedCasex, casex, log } from 'battlecry';\n\nconst CONFIG_FILE = 'configureStore.js';\nconst REDUX_PATH = 'src/redux';\n\nexport default class DuckGenerator extends Generator {\n  config = { \n    init: {\n      description: 'Create configStore.js file and an example duck'\n    },\n    generate: {\n      args: 'name ...actions?',\n      description: 'Create or modify duck to add actions'\n    }\n  };\n\n  get configFile() {\n    const template = this.template(CONFIG_FILE);\n    const path = `${REDUX_PATH}/${template.filename}`;\n\n    return new File(path);\n  }\n\n  get actions() {\n    return (this.args.actions || ['set']).reverse();\n  }\n\n  init() {\n    const configFile = this.configFile;\n    if(configFile.exists) return log.warn(`Modular ducks have already been initiated. Please check the ${configFile.path} file`);\n\n    this.template(CONFIG_FILE).saveAs(configFile.path);\n    this.generator('duck').setArgs({name: 'todo'}).play('generate');\n  }\n\n  generate() {\n    this.addActionsToDuck();\n    this.addDuckToConfig();\n  }\n\n  addActionsToDuck() {\n    const template = this.template('_*');\n    const path = `${REDUX_PATH}/modules/${template.filename}`;\n\n    let file = new File(path, this.args.name);\n    if(!file.exists) file = template;\n    \n    this.actions.forEach(action => {\n      file.after('// Actions', `const __NA_ME__ = '${casex(this.args.name, 'na-me')}/__NA-ME__';`, action);\n      \n      file.after('switch (action.type) {', [\n        '    case __NA_ME__:',\n        '      // Perform action',\n        '      return state;'\n      ], action);\n      \n      file.after('// Action Creators', [\n        namedCasex('export function __naMe__() {', + `${action}_${this.args.name}`),\n        '  return { type: __NA_ME__ };',\n        '}',\n        ''\n      ], action);\n    });\n\n    file.saveAs(path, this.args.name);\n  }\n\n  addDuckToConfig() {\n    const file = this.configFile;\n    if(!file.exists) return null;\n\n    file\n      .afterLast('import ', \"import __naMe__ from './modules/__naMe__'\", this.args.name)\n      .after('combineReducers({', '  __naMe__,', this.args.name)\n      .save();\n  }\n}\n"
  },
  {
    "path": "battlecry/generators/duck/templates/__naMe__.js",
    "content": "// Actions\n\n// Reducer\nexport default function reducer(state = {}, action = {}) {\n  switch (action.type) {\n    default: return state;\n  }\n}\n\n// Action Creators"
  },
  {
    "path": "battlecry/generators/duck/templates/configureStore.js",
    "content": "import { createStore, applyMiddleware, combineReducers } from 'redux';\nimport createLogger from 'redux-logger';\n\nconst loggerMiddleware = createLogger(); // initialize logger\n\nconst createStoreWithMiddleware = applyMiddleware(loggerMiddleware)(createStore); // apply logger to redux\n\nconst reducer = combineReducers({\n});\n\nconst configureStore = (initialState) => createStoreWithMiddleware(reducer, initialState);\nexport default configureStore;"
  }
]