[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\"es2015\", \"react\", \"babel-preset-stage-0\"]\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.sw*\nnode_modules\ndist\nlib\nes\n"
  },
  {
    "path": ".npmignore",
    "content": "*.sw*\n"
  },
  {
    "path": "README.md",
    "content": "# Write better Redux code faster v0.0.5\n\n<em>Big changes from 0.0.4! API has been completely rewritten on top of [ImmutableJS](http://facebook.github.io/immutable-js).</em>\n\n![Codeship build status](https://codeship.com/projects/857492d0-ec53-0132-251c-1a6982ed746d/status?branch=master)\n\nA collection of generic functions on top of [ImmutableJS](http://facebook.github.io/immutable-js) and [Redux Actions](https://github.com/acdlite/redux-actions) for simplifying your reducers. Declare your reducers and state as plain old javascript objects, but take advantage of `Immutable` guarantees and data structure traversal utilities.\n\nExample reducer:\n\n```js\nimport { reducer, push, updateIn, removeIn } from 'redux-modifiers'\n\nconst reducer = reducer({\n  'ADD_ITEM_TO_LIST': push,\n  'UPDATE': updateIn,\n  'ADD_NESTED_ITEM': (state, action)=>{\n    let { selected, value } = action.payload; //Index of nested item (could be deeply nested, i.e. [0, 'key', 1])\n    return state.updateIn(selected, item => item.push(value) ); //Using ImmutableJS API\n  },\n  'REMOVE': removeIn\n}, []);\n```\n\nYou can call `toJS` on any structure you get out of the reducer to convert it back to vanilla js, i.e. in a react component where you want to use spread operators, normal object accessors, etc. Anything you put in the reducer will automatically be converted to an ImmutableJS structure, which means you can do things like adding items to state from plain javascript objects without worrying about references sticking around.\n\n## Notes\n\n### FSA\n`redux-modifiers` does expect that actions are dispatched as [Flux Standard Actions](https://github.com/acdlite/flux-standard-action). Essentially, this means every action looks like:\n\n```js\n{\n  type: YOUR_ACTION_TYPE,\n  payload: YOUR_PAYLOAD\n}\n```\n\n### State and ImmutableJS\n`state` is converted to an `Immutable` data structure, so you are free to use any `ImmutableJS` function you like on state. If you find you perform a particular option frequently, consider submitting a *pull request* and adding it to `redux-modifiers`!\n\n# Targeting specific parts of state\n\nUse `updateIn`, to target specific parts of state, passing the update function the path that you want to update. Example state:\n\n```js\n{\n  foo: [\n    {\n      id: 1,\n      name: 'Calvin'\n    }\n  ]\n}\n```\n\nExample reducer function:\n\n```js\n'UPDATE': updateIn\n```\n\nExample dispatch:\n\n```js\ndispatch({selected: ['foo', 'name'], value: 'Calvin Froedge'});\n```\n\n\n# API\n\n### push(state, action)\n\nPayload can take any value, but you must call `push` on an array (`List` in ImmutableJS).\n\n```js\n'ADD': push\n```\n\n### updateIn(state, action)\n\nPayload must include a selection path `selected` and a `value` or `fn`. State (or targeted key) will be replaced with value if `value`, or `fn` will be applied to the existing value.\n\nExample payload:\n```\n{selected: [0, 'nested_array', 1], fn: value => value * 2}\n```\n\n### removeIn(state, action)\n\nPayload must include a selection path. Example payload:\n```\n[0, 'nested_array', 1]\n```\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"redux-modifiers\",\n  \"version\": \"0.0.6\",\n  \"description\": \"A collection of generic functions for writing redux reducers to operate on various data structures\",\n  \"main\": \"lib/index.js\",\n  \"jsnext:main\": \"es/index.js\",\n  \"scripts\": {\n    \"clean\": \"rimraf lib dist es\",\n    \"test\": \"cross-env BABEL_ENV=commonjs mocha --compilers js:babel-register --recursive\",\n    \"build:commonjs\": \"./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs ./node_modules/babel-cli/bin/babel.js src --out-dir lib\",\n    \"build:es\": \"./node_modules/cross-env/bin/cross-env.js BABEL_ENV=es ./node_modules/babel-cli/bin/babel.js src --out-dir es\",\n    \"build:umd\": \"./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs NODE_ENV=development ./node_modules/webpack/bin/webpack.js src/index.js dist/redux-modifiers.js\",\n    \"build:umd:min\": \"./node_modules/cross-env/bin/cross-env.js BABEL_ENV=commonjs NODE_ENV=production ./node_modules/webpack/bin/webpack.js src/index.js dist/redux-modifiers.min.js\",\n    \"build\": \"npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min\",\n    \"prepublish\": \"npm run clean && npm run build\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/calvinfroedge/redux-modifiers.git\"\n  },\n  \"keywords\": [\n    \"react\",\n    \"redux\",\n    \"helpers\",\n    \"state\",\n    \"modifiers\"\n  ],\n  \"author\": \"Calvin Froedge <calvinfroedge@gmail.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/calvinfroedge/redux-modifiers/issues\"\n  },\n  \"homepage\": \"https://github.com/calvinfroedge/redux-modifiers#readme\",\n  \"dependencies\": {\n    \"immutable\": \"^3.8.1\",\n    \"redux-actions\": \"^0.9.1\"\n  },\n  \"devDependencies\": {\n    \"babel-cli\": \"^6.7.5\",\n    \"babel-core\": \"^6.7.4\",\n    \"babel-loader\": \"^6.2.4\",\n    \"babel-plugin-transform-runtime\": \"^6.6.0\",\n    \"babel-preset-es2015\": \"^6.6.0\",\n    \"babel-preset-react\": \"^6.5.0\",\n    \"babel-preset-stage-0\": \"^6.5.0\",\n    \"babel-register\": \"^6.7.2\",\n    \"cross-env\": \"^1.0.7\",\n    \"expect\": \"^1.16.0\",\n    \"jsdom\": \"^8.1.0\",\n    \"mocha\": \"^2.4.5\",\n    \"mocha-jsdom\": \"^1.1.0\",\n    \"redux\": \"^3.4.0\",\n    \"redux-actions\": \"^0.9.1\",\n    \"rimraf\": \"^2.5.2\",\n    \"webpack\": \"^1.12.14\"\n  }\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import Immutable from 'immutable'\nimport { handleActions } from 'redux-actions'\nimport { checkPayload, checkUpdate, modifier, isUndefined } from './utility'\n\n/**\n * Create a reducer\n */\nexport function reducer(handlers, state){\n  return handleActions(handlers, Immutable.fromJS(state));\n}\n\n/**\n * Push item to state \n */\nexport function push(state, action){\n  checkPayload(action);\n\n  let value = action.payload;\n  return state.push(Immutable.fromJS(value));\n}\n\n/**\n * Update a specific key or index\n */\nexport function update(state, action){\n  checkPayload(action);\n  checkUpdate(action);\n\n  let { key, value, fn } = action.payload;\n\n  if(isUndefined(key)) throw new Error('\"key\" must be present in payload!');\n\n  return state.update(key, modifier(value, fn));\n}\n\n/**\n * Update at a selection path\n */\nexport function updateIn(state, action){\n  checkPayload(action);\n  checkUpdate(action);\n\n  let { selected, value, fn } = action.payload;\n\n  if(isUndefined(selected)) throw new Error('\"selected\" must be present in payload!');\n\n  return state.updateIn(selected, modifier(value, fn));\n}\n\n/**\n * Remove a specific index or key\n */\nexport function remove(state, action){\n  checkPayload(action);\n\n  return state.remove(action.payload);\n}\n\n/**\n * Remove at a selection path\n */\nexport function removeIn(state, action){\n  checkPayload(action);\n\n  return state.removeIn(action.payload);\n}\n"
  },
  {
    "path": "src/utility.js",
    "content": "import Immutable from 'immutable'\n\nexport function isUndefined(check){\n  return typeof(check) == 'undefined';\n}\n\nexport function checkPayload(action){\n  if(isUndefined(action.payload)) throw new Error(\"Action must contain a payload!\");\n}\n\nexport function checkUpdate(action){\n  let { payload } = action;\n  let { value, fn } = payload;\n\n  if(isUndefined(value) && isUndefined(value)) throw new Error(\"Either 'value' or 'fn' must be present in payload!\");\n\n  if(!isUndefined(value) && !isUndefined(fn)) throw new Error(\"Both 'value' and 'fn' cannot be present in payload!\");\n}\n\nexport function modifier(value, fn){\n  return !isUndefined(value) ? val => Immutable.fromJS(value) : fn;\n}\n"
  },
  {
    "path": "test/redux.spec.js",
    "content": "import expect from 'expect'\nimport { reducer, push, update, updateIn, remove, removeIn } from '../src'\nimport { createAction as action } from 'redux-actions'\nimport { createStore } from 'redux'\nimport { List, Map } from 'immutable'\n\ndescribe('Test with actual reducer', ()=>{\n  var store;\n\n  let getJSON = ()=>{\n    return [\n      {\n        foo: 'bar',\n        nested: [\n          {bar: 'bop'}\n        ]\n      }\n    ]\n  }\n\n  beforeEach(()=>{\n    let testReducer = reducer({\n      'push': push,\n      'update': update,\n      'updateIn': updateIn,\n      'remove': remove,\n      'removeIn': removeIn\n    }, getJSON());\n    store = createStore(testReducer);\n  });\n\n  it('Push should create an immutable list, with an item that is an immutable map', ()=>{\n    store.dispatch(\n      action('push')(\n        {foo: 'bar'}\n      )\n    );\n    let state = store.getState();\n    expect(List.isList(state)).toBe(true);\n    expect(Map.isMap(state.last())).toBe(true);\n  });\n\n  it('Should update a nested item with updateIn', ()=>{\n    let path = [0, 'nested', 0, 'bar']\n    store.dispatch(\n      action('updateIn')(\n        {selected: path, value: 'baz'}\n      )\n    );\n    let state = store.getState();\n    expect(state.getIn(path)).toBe('baz');\n  });\n\n  it('Should remove a nested item with removeIn', ()=>{\n    let path = [0, 'nested', 0];\n    store.dispatch(\n      action('removeIn')(path)\n    );\n    let state = store.getState();\n    expect(state.getIn(path)).toBe(undefined);\n  });\n\n  it('Should remove an item', ()=>{\n    store.dispatch(\n      action('remove')(0)\n    );\n\n    let state = store.getState();\n    expect(state.size).toBe(0);\n  });\n\n  it('Should update an item with update', ()=>{\n    store.dispatch(\n      action('update')({\n        key: 0,\n        value: false\n      })\n    );\n\n    let state = store.getState();\n    expect(state.first()).toBe(false);\n  });\n});\n"
  },
  {
    "path": "webpack.config.js",
    "content": "'use strict'; //This file was lifted from Redux source code. Thanks!\n\nvar webpack = require('webpack')\n\nvar env = process.env.NODE_ENV\nvar config = {\n  module: {\n    loaders: [\n      { test: /\\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }\n    ]\n  },\n  output: {\n    library: 'ReduxModifiers',\n    libraryTarget: 'umd'\n  },\n  plugins: [\n    new webpack.optimize.OccurenceOrderPlugin(),\n    new webpack.DefinePlugin({\n      'process.env.NODE_ENV': JSON.stringify(env)\n    })\n  ]\n};\n\nif (env === 'production') {\n  config.plugins.push(\n    new webpack.optimize.UglifyJsPlugin({\n      compressor: {\n        pure_getters: true,\n        unsafe: true,\n        unsafe_comps: true,\n        screw_ie8: true,\n        warnings: false\n      }\n    })\n  )\n}\n\nmodule.exports = config\n"
  }
]