From a0b0b52505f4f851aa024117ab01da0dd5f0c5a4 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Sun, 30 Aug 2015 17:08:04 -0400 Subject: [PATCH 1/9] New API tentative #2x --- examples/counter/components/counter.js | 3 +- package.json | 1 + src/components/connector.js | 69 +++++++++++---------- src/utils/findControllerAsKey.js | 11 ---- test/components/connector.spec.js | 83 ++++++++++++++++---------- test/utils/findControllerAs.spec.js | 21 ------- 6 files changed, 91 insertions(+), 97 deletions(-) delete mode 100644 src/utils/findControllerAsKey.js delete mode 100644 test/utils/findControllerAs.spec.js diff --git a/examples/counter/components/counter.js b/examples/counter/components/counter.js index 540db83..f6d69c2 100644 --- a/examples/counter/components/counter.js +++ b/examples/counter/components/counter.js @@ -13,7 +13,8 @@ export default function counter() { class CounterController { constructor($ngRedux, $scope) { - $ngRedux.connect($scope, this.mapStateToScope, CounterActions, 'vm'); + const unsubscribe = $ngRedux.connect(this.mapStateToScope, CounterActions)(this); + $scope.$on('$destroy', unsubscribe); } // Which part of the Redux global state does our component want to receive on $scope? diff --git a/package.json b/package.json index e6acccb..7fb089a 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "babel-loader": "^5.3.2", "expect": "^1.8.0", "mocha": "^2.2.5", + "sinon": "^1.16.1", "webpack": "^1.10.5" }, "peerDependencies": { diff --git a/src/components/connector.js b/src/components/connector.js index c43b623..111bb27 100644 --- a/src/components/connector.js +++ b/src/components/connector.js @@ -1,53 +1,58 @@ import shallowEqual from '../utils/shallowEqual'; import wrapActionCreators from '../utils/wrapActionCreators'; -import findControllerAsKey from '../utils/findControllerAsKey'; import invariant from 'invariant'; import _ from 'lodash'; export default function Connector(store) { - return (scope, mapStateToScope, mapDispatchToScope = {}) => { - - invariant( - scope && _.isFunction(scope.$on) && _.isFunction(scope.$destroy), - 'The scope parameter passed to connect must be an instance of $scope.' - ); + return (mapStateToTarget, mapDispatchToTarget = dispatch => ({dispatch})) => { invariant( - _.isFunction(mapStateToScope), - 'mapStateToScope must be a Function. Instead received $s.', mapStateToScope + _.isFunction(mapStateToTarget), + 'mapStateToTarget must be a Function. Instead received $s.', mapStateToTarget ); + invariant( - _.isPlainObject(mapDispatchToScope) || _.isFunction(mapDispatchToScope), - 'mapDispatchToScope must be a plain Object or a Function. Instead received $s.', mapDispatchToScope + _.isPlainObject(mapDispatchToTarget) || _.isFunction(mapDispatchToTarget), + 'mapDispatchToTarget must be a plain Object or a Function. Instead received $s.', mapDispatchToTarget ); - const propertyKey = findControllerAsKey(scope); + let slice = getStateSlice(store.getState(), mapStateToTarget); + + const finalMapDispatchToTarget = _.isPlainObject(mapDispatchToTarget) ? + wrapActionCreators(mapDispatchToTarget) : + mapDispatchToTarget; - let slice = getStateSlice(store.getState(), mapStateToScope); - let target = propertyKey ? scope[propertyKey] : scope; + //find better name + const actions = finalMapDispatchToTarget(store.dispatch); - const finalMapDispatchToScope = _.isPlainObject(mapDispatchToScope) ? - wrapActionCreators(mapDispatchToScope) : - mapDispatchToScope; + return (target) => { - //Initial update - _.assign(target, slice, finalMapDispatchToScope(store.dispatch)); + invariant( + _.isFunction(target) || _.isObject(target), + 'The target parameter passed to connect must be a Function or a plain object.' + ); + + //Initial update + updateTarget(target, slice, actions); + + const unsubscribe = store.subscribe(() => { + const nextSlice = getStateSlice(store.getState(), mapStateToTarget); + if (!shallowEqual(slice, nextSlice)) { + slice = nextSlice; + updateTarget(target, slice, actions); + } + }); + return unsubscribe; + } - subscribe(scope, store, () => { - const nextSlice = getStateSlice(store.getState(), mapStateToScope); - if (!shallowEqual(slice, nextSlice)) { - slice = nextSlice; - _.assign(target, slice); - } - }); } } -function subscribe(scope, store, callback) { - const unsubscribe = store.subscribe(callback); - - scope.$on('$destroy', () => { - unsubscribe(); - }); +function updateTarget(target, StateSlice, dispatch) { + if(_.isFunction(target)) { + target(StateSlice, dispatch); + } else { + _.assign(target, StateSlice, dispatch); + } } function getStateSlice(state, mapStateToScope) { diff --git a/src/utils/findControllerAsKey.js b/src/utils/findControllerAsKey.js deleted file mode 100644 index 92c833a..0000000 --- a/src/utils/findControllerAsKey.js +++ /dev/null @@ -1,11 +0,0 @@ -import _ from 'lodash'; - -export default function findControllerAsKey(scope) { - let propertyKey; - _.forOwn(scope, (v, k) => { - if (scope[k] && scope[k].constructor && scope[k].constructor.$inject) { - propertyKey = k; - } - }); - return propertyKey; -} diff --git a/test/components/connector.spec.js b/test/components/connector.spec.js index 7cfd82e..37874d9 100644 --- a/test/components/connector.spec.js +++ b/test/components/connector.spec.js @@ -1,4 +1,5 @@ import expect from 'expect'; +let sinon = require('sinon'); import { createStore } from 'redux'; import Connector from '../../src/components/connector'; import _ from 'lodash'; @@ -6,76 +7,94 @@ import _ from 'lodash'; describe('Connector', () => { let store; let connect; - let scopeStub; + let targetObj; beforeEach(() => { store = createStore((state, action) => ({ foo: 'bar', baz: action.payload })); - scopeStub = { - $on: () => {}, - $destroy: () => {} - }; + targetObj = {}; connect = Connector(store); }); - it('Should throw when not passed a $scope object', () => { - expect(connect.bind(connect, () => { }, () => ({}))).toThrow(); - expect(connect.bind(connect, 15, () => ({}))).toThrow(); - expect(connect.bind(connect, undefined, () => ({}))).toThrow(); - expect(connect.bind(connect, {}, () => ({}))).toThrow(); + it('Should throw when target is not a Function or a plain object', () => { + expect(connect(() => ({})).bind(connect, 15)).toThrow(); + expect(connect(() => ({})).bind(connect, undefined)).toThrow(); + expect(connect(() => ({})).bind(connect, 'test')).toThrow(); + + expect(connect(() => ({})).bind(connect, {})).toNotThrow(); + expect(connect(() => ({})).bind(connect, () => {})).toNotThrow(); - expect(connect.bind(connect, scopeStub, () => ({}))).toNotThrow(); }); - it('Should throw when selector does not return a plain object as target', () => { - expect(connect.bind(connect, scopeStub, state => state.foo)).toThrow(); + it('Should throw when selector does not return a plain object', () => { + expect(connect.bind(connect, state => state.foo)).toThrow(); }); - it('Should extend scope with selected state once directly after creation', () => { - connect( - scopeStub, + it('Should extend target (Object) with selected state once directly after creation', () => { + connect( () => ({ vm: { test: 1 } - })); + }))(targetObj); - expect(scopeStub.vm).toEqual({ test: 1 }); + expect(targetObj.vm).toEqual({ test: 1 }); }); - it('Should update the scope passed to connect when the store updates', () => { - connect(scopeStub, state => state); + it('Should update the target (Object) passed to connect when the store updates', () => { + connect(state => state)(targetObj); store.dispatch({ type: 'ACTION', payload: 0 }); - expect(scopeStub.baz).toBe(0); + expect(targetObj.baz).toBe(0); store.dispatch({ type: 'ACTION', payload: 1 }); - expect(scopeStub.baz).toBe(1); + expect(targetObj.baz).toBe(1); }); it('Should prevent unnecessary updates when state does not change (shallowly)', () => { - connect(scopeStub, state => state); + connect(state => state)(targetObj); store.dispatch({ type: 'ACTION', payload: 5 }); - expect(scopeStub.baz).toBe(5); + expect(targetObj.baz).toBe(5); - scopeStub.baz = 0; + targetObj.baz = 0; //this should not replace our mutation, since the state didn't change store.dispatch({ type: 'ACTION', payload: 5 }); - expect(scopeStub.baz).toBe(0); + expect(targetObj.baz).toBe(0); + + }); + it('Should extend target (object) with actionCreators', () => { + connect(() => ({}), { ac1: () => { }, ac2: () => { } })(targetObj); + expect(_.isFunction(targetObj.ac1)).toBe(true); + expect(_.isFunction(targetObj.ac2)).toBe(true); }); - it('Should extend scope with actionCreators', () => { - connect(scopeStub, () => ({}), { ac1: () => { }, ac2: () => { } }); - expect(_.isFunction(scopeStub.ac1)).toBe(true); - expect(_.isFunction(scopeStub.ac2)).toBe(true); + it('Should return an unsubscribing function', () => { + const unsubscribe = connect(state => state)(targetObj); + store.dispatch({ type: 'ACTION', payload: 5 }); + + expect(targetObj.baz).toBe(5); + + unsubscribe(); + + store.dispatch({ type: 'ACTION', payload: 7 }); + + expect(targetObj.baz).toBe(5); + }); - it('Should provide dispatch to mapDispatchToScope when receiving a Function', () => { + it('Should provide dispatch to mapDispatchToTarget when receiving a Function', () => { let receivedDispatch; - connect(scopeStub, () => ({}), dispatch => { receivedDispatch = dispatch }); + connect(() => ({}), dispatch => { receivedDispatch = dispatch })(targetObj); expect(receivedDispatch).toBe(store.dispatch); }); + it('Should call target (Function) with mapStateToTarget and mapDispatchToTarget results ', () => { + + //let targetFunc = sinon.spy(); + //connect(targetFunc, state => state.pojo); + expect(false).toBe(true); + }); + }); \ No newline at end of file diff --git a/test/utils/findControllerAs.spec.js b/test/utils/findControllerAs.spec.js deleted file mode 100644 index 5eb41f7..0000000 --- a/test/utils/findControllerAs.spec.js +++ /dev/null @@ -1,21 +0,0 @@ -import expect from 'expect'; -import findControllerAsKey from '../../src/utils/findControllerAsKey'; - -describe('Utils', () => { - describe('findControllerAsKey', () => { - it('Should return the property key of the controller', () => { - - let controllerStub = () => {}; - controllerStub.constructor.$inject = ['$scope', '$ngRedux']; - - let propertyKey = findControllerAsKey({ - $apply: () => {}, - $on: () => {}, - $$id: 2, - vm: controllerStub - }); - - expect(propertyKey).toBe('vm'); - }); - }); -}); \ No newline at end of file From 02d31756718a0b7063e99ff4d44e2d0f53411d36 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Sun, 30 Aug 2015 17:30:17 -0400 Subject: [PATCH 2/9] Tests --- test/components/connector.spec.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/test/components/connector.spec.js b/test/components/connector.spec.js index 37874d9..b32eb74 100644 --- a/test/components/connector.spec.js +++ b/test/components/connector.spec.js @@ -8,12 +8,16 @@ describe('Connector', () => { let store; let connect; let targetObj; + let defaultState; beforeEach(() => { - store = createStore((state, action) => ({ + defaultState = { foo: 'bar', - baz: action.payload - })); + baz: -1 + }; + store = createStore((state = defaultState, action) => { + return {...state, baz: action.payload}; + }); targetObj = {}; connect = Connector(store); }); @@ -45,8 +49,8 @@ describe('Connector', () => { connect(state => state)(targetObj); store.dispatch({ type: 'ACTION', payload: 0 }); expect(targetObj.baz).toBe(0); - store.dispatch({ type: 'ACTION', payload: 1 }); - expect(targetObj.baz).toBe(1); + store.dispatch({ type: 'ACTION', payload: 7 }); + expect(targetObj.baz).toBe(7); }); it('Should prevent unnecessary updates when state does not change (shallowly)', () => { @@ -90,11 +94,4 @@ describe('Connector', () => { expect(receivedDispatch).toBe(store.dispatch); }); - it('Should call target (Function) with mapStateToTarget and mapDispatchToTarget results ', () => { - - //let targetFunc = sinon.spy(); - //connect(targetFunc, state => state.pojo); - expect(false).toBe(true); - }); - }); \ No newline at end of file From e586d6811606fee9bbd32a5500e0b818c6ca89a7 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Sun, 30 Aug 2015 18:04:24 -0400 Subject: [PATCH 3/9] Update README.md --- README.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c9ed837..d4d778f 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,15 @@ import * as CounterActions from '../actions/counter'; class CounterController { constructor($ngRedux, $scope) { - /* ngRedux will merge the requested state's slice and actions onto the $scope, + /* ngRedux will merge the requested state's slice and actions onto this, you don't need to redefine them in your controller */ - $ngRedux.connect($scope, this.mapStateToScope, CounterActions); + let unsubscribe = $ngRedux.connect(this.mapStateToTarget, CounterActions)(this); + $scope.$on('$destroy', unsubscribe); } // Which part of the Redux global state does our component want to receive on $scope? - mapStateToScope(state) { + mapStateToTarget(state) { return { counter: state.counter }; @@ -84,17 +85,29 @@ Creates the Redux store, and allow `connect()` to access it. * [`storeEnhancers`] \(*Function[]*): Optional, this will be used to create the store, in most cases you don't need to pass anything, see [Store Enhancer official documentation.](http://rackt.github.io/redux/docs/Glossary.html#store-enhancer) -### `connect([scope], [mapStateToScope], [mapDispatchToScope])` +### `connect([scope], [mapStateToTarget], [mapDispatchToTarget])([target])` Connects an Angular component to Redux. #### Arguments -* [`scope`] \(*Object*): The `$scope` of your controller. -* [`mapStateToScope`] \(*Function*): connect will subscribe to Redux store updates. Any time it updates, mapStateToTarget will be called. Its result must be a plain object, and it will be merged into `target`. -* [`mapDispatchToScope`] \(*Object* or *Function*): If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but bound to a Redux store, will be merged into your component `$scope`. If a function is passed, it will be given `dispatch`. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](http://gaearon.github.io/redux/docs/api/bindActionCreators.html) helper from Redux.). +* [`mapStateToTarget`] \(*Function*): connect will subscribe to Redux store updates. Any time it updates, mapStateToTarget will be called. Its result must be a plain object, and it will be merged into `target`. +* [`mapDispatchToTarget`] \(*Object* or *Function*): Optional. If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but bound to a Redux store, will be merged onto `target`. If a function is passed, it will be given `dispatch`. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](http://gaearon.github.io/redux/docs/api/bindActionCreators.html) helper from Redux.). + +*You then need to invoke the function a second time, with `target` as parameter:* +* [`target`] \(*Object* or *Function*): If passed an object, the results of `mapStateToTarget` and `mapDispatchToTarget` will be merged onto it. If passed a function, the function will receive the results of `mapStateToTarget` and `mapDispatchToTarget` as parameter. + +e.g: +```JS +connect(this.mapState, this.mapDispatch)(this); +//Or +connect(this.mapState, this.mapDispatch)((selectedState, actions) => {/* ... */}); +``` + #### Remarks -* As `$scope` is passed to `connect`, ngRedux will listen to the `$destroy` event and unsubscribe the change listener itself, you don't need to keep track of your subscribtions. +* The `mapStateToTarget` function takes a single argument of the entire Redux store’s state and returns an object to be passed as props. It is often called a selector. Use reselect to efficiently compose selectors and compute derived data. + + ### Store API All of redux's store methods (i.e. `dispatch`, `subscribe` and `getState`) are exposed by $ngRedux and can be accessed directly. For example: From b3ddeb3bae82cfb9b675228266f79d181ae6dec5 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Sun, 30 Aug 2015 18:05:11 -0400 Subject: [PATCH 4/9] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d4d778f..490e602 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ angular.module('app', ['ngRedux']) #### Usage +*Using controllerAs syntax* ```JS import * as CounterActions from '../actions/counter'; From 9b49d0654c69ae725d89f69b24e890ca307bc5d0 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Sun, 30 Aug 2015 18:05:55 -0400 Subject: [PATCH 5/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 490e602..c072ad0 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Connects an Angular component to Redux. * [`mapDispatchToTarget`] \(*Object* or *Function*): Optional. If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but bound to a Redux store, will be merged onto `target`. If a function is passed, it will be given `dispatch`. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](http://gaearon.github.io/redux/docs/api/bindActionCreators.html) helper from Redux.). *You then need to invoke the function a second time, with `target` as parameter:* -* [`target`] \(*Object* or *Function*): If passed an object, the results of `mapStateToTarget` and `mapDispatchToTarget` will be merged onto it. If passed a function, the function will receive the results of `mapStateToTarget` and `mapDispatchToTarget` as parameter. +* [`target`] \(*Object* or *Function*): If passed an object, the results of `mapStateToTarget` and `mapDispatchToTarget` will be merged onto it. If passed a function, the function will receive the results of `mapStateToTarget` and `mapDispatchToTarget` as parameters. e.g: ```JS From dd468c295953cdf1d9ea7770d6dc5b1463906be1 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Mon, 31 Aug 2015 23:15:08 -0400 Subject: [PATCH 6/9] Default parameters --- src/components/connector.js | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/components/connector.js b/src/components/connector.js index 111bb27..ae31855 100644 --- a/src/components/connector.js +++ b/src/components/connector.js @@ -3,26 +3,31 @@ import wrapActionCreators from '../utils/wrapActionCreators'; import invariant from 'invariant'; import _ from 'lodash'; +const defaultMapStateToTarget = () => ({}); +const defaultMapDispatchToTarget = dispatch => ({dispatch}); + export default function Connector(store) { - return (mapStateToTarget, mapDispatchToTarget = dispatch => ({dispatch})) => { + return (mapStateToTarget, mapDispatchToTarget) => { + + const finalMapStateToTarget = mapStateToTarget || defaultMapStateToTarget; + + const finalMapDispatchToTarget = _.isPlainObject(mapDispatchToTarget) ? + wrapActionCreators(mapDispatchToTarget) : + mapDispatchToTarget || defaultMapDispatchToTarget; + invariant( - _.isFunction(mapStateToTarget), - 'mapStateToTarget must be a Function. Instead received $s.', mapStateToTarget + _.isFunction(finalMapStateToTarget), + 'mapStateToTarget must be a Function. Instead received $s.', finalMapStateToTarget ); invariant( - _.isPlainObject(mapDispatchToTarget) || _.isFunction(mapDispatchToTarget), - 'mapDispatchToTarget must be a plain Object or a Function. Instead received $s.', mapDispatchToTarget + _.isPlainObject(finalMapDispatchToTarget) || _.isFunction(finalMapDispatchToTarget), + 'mapDispatchToTarget must be a plain Object or a Function. Instead received $s.', finalMapDispatchToTarget ); - let slice = getStateSlice(store.getState(), mapStateToTarget); - - const finalMapDispatchToTarget = _.isPlainObject(mapDispatchToTarget) ? - wrapActionCreators(mapDispatchToTarget) : - mapDispatchToTarget; + let slice = getStateSlice(store.getState(), finalMapStateToTarget); - //find better name - const actions = finalMapDispatchToTarget(store.dispatch); + const boundActionCreators = finalMapDispatchToTarget(store.dispatch); return (target) => { @@ -31,14 +36,14 @@ export default function Connector(store) { 'The target parameter passed to connect must be a Function or a plain object.' ); - //Initial update - updateTarget(target, slice, actions); + //Initial update + updateTarget(target, slice, boundActionCreators); const unsubscribe = store.subscribe(() => { - const nextSlice = getStateSlice(store.getState(), mapStateToTarget); + const nextSlice = getStateSlice(store.getState(), finalMapStateToTarget); if (!shallowEqual(slice, nextSlice)) { slice = nextSlice; - updateTarget(target, slice, actions); + updateTarget(target, slice, boundActionCreators); } }); return unsubscribe; From 2f395bfe5ccf892ea6783a497fad879811c03629 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Tue, 1 Sep 2015 22:29:14 -0400 Subject: [PATCH 7/9] 2.0.0 bump, fix #15 --- examples/counter/package.json | 5 ++--- package.json | 6 +++--- src/components/ngRedux.js | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/counter/package.json b/examples/counter/package.json index 52c803a..674815f 100644 --- a/examples/counter/package.json +++ b/examples/counter/package.json @@ -22,14 +22,13 @@ "html-loader": "^0.3.0", "html-webpack-plugin": "^1.6.1", "react": "^0.13.3", - "redux-devtools": "^1.1.1", "webpack": "^1.11.0", "webpack-dev-server": "^1.10.1" }, "dependencies": { "angular": "^1.4.4", - "ng-redux": "^1.0.0-rc.2", - "redux": "^1.0.1", + "ng-redux": "2.0.0", + "redux": "^2.0.0", "redux-thunk": "^0.1.0" } } diff --git a/package.json b/package.json index 7fb089a..f65448a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ng-redux", - "version": "1.0.0-rc.4", + "version": "2.0.0", "description": "Redux bindings for Angular.js", "main": "./lib/index.js", "scripts": { @@ -27,11 +27,11 @@ "webpack": "^1.10.5" }, "peerDependencies": { - "redux": "^1.0.0" + "redux": "^2.0.0" }, "dependencies": { "invariant": "^2.1.0", "lodash": "^3.10.1", - "redux": "^1.0.1" + "redux": "^2.0.0" } } diff --git a/src/components/ngRedux.js b/src/components/ngRedux.js index 57f4977..92097c7 100644 --- a/src/components/ngRedux.js +++ b/src/components/ngRedux.js @@ -38,7 +38,7 @@ export default function ngReduxProvider() { } } - let finalCreateStore = _storeEnhancers ? compose(..._storeEnhancers, createStore) : createStore; + let finalCreateStore = _storeEnhancers ? compose(..._storeEnhancers)(createStore) : createStore; //digestMiddleware needs to be the last one. resolvedMiddleware.push(digestMiddleware($injector.get('$rootScope'))); From 88bf64eae5a6bcd21125cfe941d7138639395cc3 Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Wed, 2 Sep 2015 08:08:30 -0400 Subject: [PATCH 8/9] Revert version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f65448a..81e03ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ng-redux", - "version": "2.0.0", + "version": "1.0.0", "description": "Redux bindings for Angular.js", "main": "./lib/index.js", "scripts": { From 8912e7d1cd93840bea33a53979178582975efafa Mon Sep 17 00:00:00 2001 From: William Buchwalter Date: Wed, 2 Sep 2015 08:09:07 -0400 Subject: [PATCH 9/9] v2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 81e03ab..f65448a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ng-redux", - "version": "1.0.0", + "version": "2.0.0", "description": "Redux bindings for Angular.js", "main": "./lib/index.js", "scripts": {