Skip to content

Commit 5ff58c7

Browse files
SethDavenportEvan Schultz
authored and
Evan Schultz
committed
Remove lodash as a dependency (#115)
* Remove lodash as a dependency Apart from making the lib less complex, it also makes it easier to handle with SystemJS. This is important given that the Angular-CLI has embraced SystemJS instead of our usual webpack toolchain. Also rejigged the deps a bit: - typings should be a devdepedency - Angular and RxJS should be peer deps Connected to #113 * Changed rxjs imports to pull in the parts we need. This is needed to match the default way Angular-CLI sets up the SystemJS import mappings for RxJs. Arguably this is the right way to do it anyway; we already switched to this in the v3.x branch.
1 parent fb16c62 commit 5ff58c7

File tree

11 files changed

+227
-26
lines changed

11 files changed

+227
-26
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ ng2-redux lets you easily connect your Angular 2 components with Redux.
1616
- [Installation](#installation)
1717
- [Quick Start](#quick-start)
1818
- [Usage](#usage)
19+
- [A Note about Internet Explorer](#a-note-about-internet-explorer)
1920
- [Cookbooks](#cookbooks)
2021
- [Using Angular 2 Services in your Action Creators](#using-angular-2-services-in-your-action-creators)
2122
- [Using Angular 2 Services in your Middleware](#using-angular-2-services-in-your-middleware)
@@ -195,6 +196,14 @@ export class App {
195196
}
196197
```
197198

199+
## A Note about Internet Explorer
200+
201+
This library relies on the presence of `Object.assign` and `Array.forEach`.
202+
Internet Explorer requires polyfills for these; however these same functions
203+
are also needed for Angular 2 itself to work. Just make sure you include
204+
[core-js](https://npmjs.com/package/core-js) or [es6-shim](https://npmjs.com/packages/es6-shim)
205+
if you need to support IE.
206+
198207
## Cookbooks
199208

200209
### Using Angular 2 Services in your Action Creators

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
},
4242
"homepage": "https://github.com/angular-redux/ng2-redux#readme",
4343
"devDependencies": {
44+
"@angular/core": "2.0.0-rc.1",
4445
"chai": "^3.5.0",
4546
"expect": "^1.8.0",
4647
"mocha": "^2.4.5",
@@ -50,15 +51,15 @@
5051
"ts-loader": "^0.8.1",
5152
"ts-node": "^0.5.5",
5253
"typescript": "^1.8.10",
53-
"@angular/core": "2.0.0-rc.1",
5454
"es6-shim": "^0.35.0",
5555
"redux": "^3.4.0",
5656
"reflect-metadata": "0.1.3",
5757
"rxjs": "5.0.0-beta.6",
58+
"typings": "^0.7.4",
5859
"zone.js": "0.6.12"
5960
},
60-
"dependencies": {
61-
"lodash": "^3.10.1",
62-
"typings": "^0.7.4"
61+
"peerDependencies": {
62+
"rxjs": "5.0.0-beta.6",
63+
"@angular/core": "2.0.0-rc.1"
6364
}
6465
}

src/___tests___/components/ng-redux.spec.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import 'reflect-metadata';
2-
import {expect, use} from 'chai';
2+
import 'es6-shim';
3+
import { expect, use } from 'chai';
34
import { createStore } from 'redux';
4-
import {NgRedux} from '../../components/ng-redux';
5+
import { NgRedux } from '../../components/ng-redux';
56
import * as sinon from 'sinon';
67
import * as sinonChai from 'sinon-chai';
7-
import * as _ from 'lodash';
8+
89
use(sinonChai);
910

1011
function returnPojo() {
@@ -88,8 +89,8 @@ describe('Connector', () => {
8889
it('Should extend target (object) with actionCreators', () => {
8990
connector.connect(returnPojo,
9091
{ ac1: returnPojo, ac2: () => { } })(targetObj);
91-
expect(_.isFunction(targetObj.ac1)).to.equal(true);
92-
expect(_.isFunction(targetObj.ac2)).to.equal(true);
92+
expect(targetObj.ac1).to.be.a('Function');
93+
expect(targetObj.ac2).to.be.a('Function');
9394
});
9495

9596
it('Should return an unsubscribing function', () => {

src/___tests___/tests.entry.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/___tests___/utils/omit.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import 'reflect-metadata';
2+
import { expect, use } from 'chai';
3+
4+
import { omit } from '../../utils/omit';
5+
6+
describe('omit', () => {
7+
it('should omit the specified properties', () => {
8+
const input = { a: 1, b: 2, c:3, d: 4 };
9+
const output = omit(input, [ 'b', 'd' ]);
10+
11+
expect(output.hasOwnProperty('b')).to.be.false;
12+
expect(output.hasOwnProperty('d')).to.be.false;
13+
expect(output).to.eql({ a: 1, c: 3 });
14+
});
15+
16+
it('should not mutate its input', () => {
17+
const input = { a: 1, b: 2, c:3, d: 4 };
18+
const output = omit(input, [ 'b', 'd' ]);
19+
20+
expect(input).to.eql({ a: 1, b: 2, c:3, d: 4 });
21+
});
22+
});
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { expect, use } from 'chai';
2+
3+
import { isObject, isFunction, isPlainObject} from '../../utils/type-checks';
4+
5+
describe('typeChecks', () => {
6+
describe('isObject', () => {
7+
it('should return true for an object literal', () => {
8+
expect(isObject({})).to.be.true;
9+
});
10+
11+
it('should return true for a new Object', () => {
12+
expect(isObject(new Object())).to.be.true;
13+
});
14+
15+
it('should return true for an instance of a class', () => {
16+
class Foo {};
17+
expect(isObject(new Foo())).to.be.true;
18+
});
19+
20+
it('should return false for null', () => {
21+
expect(isObject(null)).to.be.false;
22+
});
23+
24+
it('should return false for undefined', () => {
25+
expect(isObject(undefined)).to.be.false;
26+
});
27+
28+
it('should return false for a function', () => {
29+
expect(isObject(function foo() {})).to.be.false;
30+
});
31+
32+
it('should return false for an arrow function', () => {
33+
expect(isObject(() => undefined)).to.be.false;
34+
});
35+
36+
it('should return false for a constructor function', () => {
37+
class Foo {};
38+
expect(isObject(Foo)).to.be.false;
39+
});
40+
41+
it('should return false for a string', () => {
42+
expect(isObject('foo')).to.be.false;
43+
});
44+
45+
it('should return false for a number', () => {
46+
expect(isObject(1)).to.be.false;
47+
});
48+
});
49+
50+
describe('isFunction', () => {
51+
it('should return true for a function', () => {
52+
expect(isFunction(function () {})).to.be.true;
53+
});
54+
55+
it('should return true for an arrow function', () => {
56+
expect(isFunction(() => undefined)).to.be.true;
57+
});
58+
59+
it('should return true for a constructor function', () => {
60+
class Foo {};
61+
expect(isFunction(Foo)).to.be.true;
62+
});
63+
64+
it('should return false for null', () => {
65+
expect(isFunction(null)).to.be.false;
66+
});
67+
68+
it('should return false for undefined', () => {
69+
expect(isFunction(undefined)).to.be.false;
70+
});
71+
72+
it('should return false for an object literal', () => {
73+
expect(isFunction({})).to.be.false;
74+
});
75+
76+
it('should return false for an instance of a class', () => {
77+
class Foo {};
78+
expect(isFunction(new Foo())).to.be.false;
79+
});
80+
81+
it('should return false for a string', () => {
82+
expect(isFunction('foo')).to.be.false;
83+
});
84+
85+
it('should return false for a number', () => {
86+
expect(isFunction(1)).to.be.false;
87+
});
88+
89+
it('should return false for a list', () => {
90+
expect(isFunction([])).to.be.false;
91+
});
92+
});
93+
94+
describe('isPlainObject', () => {
95+
it('should return true for an object literal', () => {
96+
expect(isPlainObject({})).to.be.true;
97+
});
98+
99+
it('should return true for a new Object', () => {
100+
expect(isPlainObject(new Object())).to.be.true;
101+
});
102+
103+
it('should return false for an instance of a class', () => {
104+
class Foo {};
105+
expect(isPlainObject(new Foo())).to.be.false;
106+
});
107+
108+
it('should return false for null', () => {
109+
expect(isPlainObject(null)).to.be.false;
110+
});
111+
112+
it('should return false for undefined', () => {
113+
expect(isPlainObject(undefined)).to.be.false;
114+
});
115+
116+
it('should return false for a function', () => {
117+
expect(isPlainObject(function foo() {})).to.be.false;
118+
});
119+
120+
it('should return false for an arrow function', () => {
121+
expect(isPlainObject(() => undefined)).to.be.false;
122+
});
123+
124+
it('should return false for a constructor function', () => {
125+
class Foo {};
126+
expect(isPlainObject(Foo)).to.be.false;
127+
});
128+
129+
it('should return false for a string', () => {
130+
expect(isPlainObject('foo')).to.be.false;
131+
});
132+
133+
it('should return false for a number', () => {
134+
expect(isObject(1)).to.be.false;
135+
});
136+
});
137+
});

src/components/ng-redux.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import shallowEqual from '../utils/shallowEqual';
22
import wrapActionCreators from '../utils/wrapActionCreators';
33
import * as Redux from 'redux';
4-
import * as _ from 'lodash';
5-
import { BehaviorSubject, Observable } from 'rxjs';
4+
import { Observable } from 'rxjs/Observable';
5+
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
6+
import 'rxjs/add/operator/map';
7+
import 'rxjs/add/operator/distinctUntilChanged';
68
import { Store, Action, ActionCreator, Reducer } from 'redux';
79
import { Injectable } from '@angular/core';
810
import { invariant } from '../utils/invariant';
11+
import { isObject, isFunction, isPlainObject} from '../utils/type-checks';
12+
import { omit } from '../utils/omit';
913

1014
const VALID_SELECTORS = ['string', 'number', 'symbol', 'function'];
1115
const ERROR_MESSAGE = `Expected selector to be one of:
@@ -31,13 +35,13 @@ export class NgRedux<RootState> {
3135
this._store.subscribe(() => this._store$.next(this._store.getState()));
3236
this._defaultMapStateToTarget = () => ({});
3337
this._defaultMapDispatchToTarget = dispatch => ({ dispatch });
34-
const cleanedStore = _.omit(store, ['dispatch', 'getState', 'subscribe', 'replaceReducer'])
38+
const cleanedStore = omit(store, ['dispatch', 'getState', 'subscribe', 'replaceReducer'])
3539
Object.assign(this, cleanedStore);
3640
}
3741

3842
/**
3943
* Create an observable from a Redux store.
40-
*
44+
*
4145
* @param {Store<RootState>} store Redux store to create an observable from
4246
* @returns {BehaviorSubject<RootState>}
4347
*/
@@ -96,7 +100,7 @@ export class NgRedux<RootState> {
96100
|| this._defaultMapStateToTarget;
97101

98102
invariant(
99-
_.isFunction(finalMapStateToTarget),
103+
isFunction(finalMapStateToTarget),
100104
'mapStateToTarget must be a Function. Instead received %s.',
101105
finalMapStateToTarget);
102106

@@ -108,7 +112,7 @@ export class NgRedux<RootState> {
108112
return (target) => {
109113

110114
invariant(
111-
_.isFunction(target) || _.isObject(target),
115+
isFunction(target) || isObject(target),
112116
'The target parameter passed to connect must be a Function or' +
113117
'a plain object.'
114118
);
@@ -174,18 +178,18 @@ export class NgRedux<RootState> {
174178
};
175179

176180
private updateTarget(target, StateSlice, dispatch) {
177-
if (_.isFunction(target)) {
181+
if (isFunction(target)) {
178182
target(StateSlice, dispatch);
179183
} else {
180-
_.assign(target, StateSlice, dispatch);
184+
Object.assign(target, StateSlice, dispatch);
181185
}
182186
}
183187

184188
private getStateSlice(state, mapStateToScope) {
185189
const slice = mapStateToScope(state);
186190

187191
invariant(
188-
_.isPlainObject(slice),
192+
isPlainObject(slice),
189193
'`mapStateToScope` must return an object. Instead received %s.',
190194
slice
191195
);
@@ -194,16 +198,16 @@ export class NgRedux<RootState> {
194198
}
195199

196200
private getBoundActions = (actions) => {
197-
const finalMapDispatchToTarget = _.isPlainObject(actions) ?
201+
const finalMapDispatchToTarget = isPlainObject(actions) ?
198202
wrapActionCreators(actions) :
199203
actions || this._defaultMapDispatchToTarget;
200204
invariant(
201-
_.isPlainObject(finalMapDispatchToTarget)
202-
|| _.isFunction(finalMapDispatchToTarget),
205+
isPlainObject(finalMapDispatchToTarget)
206+
|| isFunction(finalMapDispatchToTarget),
203207
'mapDispatchToTarget must be a plain Object or a Function. ' +
204208
'Instead received % s.',
205209
finalMapDispatchToTarget);
206210

207211
return finalMapDispatchToTarget(this._store.dispatch);
208212
};
209-
}
213+
}

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export {provider} from './components/provider';
2-
export { NgRedux } from './components/ng-redux';
1+
export { provider } from './components/provider';
2+
export { NgRedux } from './components/ng-redux';

src/utils/omit.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Creates a copy of object, but with properties matching 'props'
3+
* omitted.
4+
*
5+
* @param {Object} object: the object to be copied and filtered.
6+
* @param {string[]} props: a list of property names to be excluded
7+
* from the filtered copy.
8+
*/
9+
export function omit(object: Object, props: string[]): Object {
10+
const clone = Object.assign({}, object);
11+
props.forEach(prop => delete clone[prop]);
12+
return clone;
13+
};

src/utils/type-checks.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export function isFunction(thing: any): boolean {
2+
return !!(thing &&
3+
thing.constructor &&
4+
thing.call &&
5+
thing.apply);
6+
}
7+
8+
export function isObject(thing: any): boolean {
9+
return !!(thing &&
10+
typeof thing === 'object' &&
11+
!isFunction(thing));
12+
}
13+
14+
export function isPlainObject(thing: any): boolean {
15+
return isObject(thing) && thing.constructor === Object;
16+
}

typings.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"ambientDependencies": {
55
"chai": "registry:dt/chai#3.4.0+20160317120654",
66
"es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
7-
"lodash": "github:DefinitelyTyped/DefinitelyTyped/lodash/lodash.d.ts#70bf7e2bfeb0d5b1b651ef3219bcc65c8eec117e",
87
"mocha": "registry:dt/mocha#2.2.5+20160317120654",
98
"node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#20e1eb9616922d382d918cc5a21870a9dbe255f5",
109
"sinon": "registry:dt/sinon#1.16.0+20160317120654",

0 commit comments

Comments
 (0)