├── .gitignore
├── src
├── index.js
├── storeShape.js
├── Provider.js
└── Connector.js
├── .babelrc
├── test
├── setup.js
└── Connector-spec.js
├── LICENSE
├── package.json
├── README.md
└── .eslintrc
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib
3 | temp
4 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export { Connector } from './Connector';
2 | export { Provider } from './Provider';
3 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "es2015", "react" ],
3 | "plugins": [
4 | "transform-function-bind",
5 | "transform-es2015-modules-commonjs",
6 | "transform-object-rest-spread"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/test/setup.js:
--------------------------------------------------------------------------------
1 | /* globals global */
2 | import { jsdom } from 'jsdom';
3 |
4 | global.document = jsdom('
');
5 | global.window = document.defaultView;
6 | global.navigator = global.window.navigator;
7 |
--------------------------------------------------------------------------------
/src/storeShape.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'react';
2 |
3 | export const storeShape = PropTypes.shape({
4 | getState$: PropTypes.func.isRequired,
5 | dispatch: PropTypes.func.isRequired,
6 | hydrate: PropTypes.func.isRequired,
7 | clearState: PropTypes.func.isRequired,
8 | });
9 |
--------------------------------------------------------------------------------
/src/Provider.js:
--------------------------------------------------------------------------------
1 | import { Component, PropTypes, Children } from 'react';
2 | import { storeShape } from './storeShape';
3 |
4 | export class Provider extends Component {
5 | getChildContext() {
6 | return { store: this.store };
7 | }
8 |
9 | constructor(props, context) {
10 | super(props, context);
11 | this.store = props.store;
12 | }
13 |
14 | render() {
15 | return Children.only(this.props.children);
16 | }
17 | }
18 |
19 | Provider.propTypes = {
20 | store: storeShape.isRequired,
21 | children: PropTypes.element.isRequired
22 | };
23 |
24 | Provider.childContextTypes = {
25 | store: storeShape.isRequired
26 | };
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Markus Coetzee
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-udeo",
3 | "version": "0.0.0-alpha.2",
4 | "description": "React bindings for Udeo",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "lint": "eslint src && eslint test",
8 | "build": "npm run lint && rm -rf lib && babel src -d lib",
9 | "build_tests": "rm -rf temp && babel test -d temp",
10 | "clean": "rimraf ./lib; rimraf ./temp;",
11 | "test": "npm run build && npm run build_tests && mocha --require ./temp/setup.js temp",
12 | "prepublish": "npm test"
13 | },
14 | "files": [
15 | "lib",
16 | "README.md",
17 | "LICENSE"
18 | ],
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/mcoetzee/react-udeo.git"
22 | },
23 | "keywords": [
24 | "Rx",
25 | "RxJS",
26 | "state",
27 | "streams",
28 | "unidirectional",
29 | "data",
30 | "flow",
31 | "observable",
32 | "reactive",
33 | "programming"
34 | ],
35 | "author": "Markus Coetzee ",
36 | "license": "MIT",
37 | "bugs": {
38 | "url": "https://github.com/mcoetzee/react-udeo/issues"
39 | },
40 | "homepage": "https://github.com/mcoetzee/react-udeo#readme",
41 | "peerDependencies": {
42 | "rxjs": "^5.0.0-beta.6",
43 | "react": "^0.14.0 || ^15.0.0-0"
44 | },
45 | "dependencies": {
46 | "invariant": "^2.0.0"
47 | },
48 | "devDependencies": {
49 | "babel-cli": "^6.7.5",
50 | "babel-eslint": "^6.0.3",
51 | "babel-plugin-transform-es2015-modules-commonjs": "^6.7.4",
52 | "babel-plugin-transform-function-bind": "^6.5.2",
53 | "babel-plugin-transform-object-rest-spread": "^6.6.5",
54 | "babel-polyfill": "^6.7.4",
55 | "babel-preset-es2015": "^6.6.0",
56 | "babel-preset-react": "6.5.0",
57 | "babel-register": "^6.7.2",
58 | "chai": "^3.5.0",
59 | "enzyme": "2.3.0",
60 | "eslint": "^2.10.2",
61 | "eslint-plugin-react": "^3.6.3",
62 | "jsdom": "9.2.0",
63 | "mocha": "^2.4.5",
64 | "react": "^0.14.0",
65 | "react-addons-test-utils": "^0.14.0",
66 | "react-dom": "^0.14.0",
67 | "rimraf": "^2.5.2",
68 | "rxjs": "^5.0.0-beta.6",
69 | "udeo": "^0.0.0-alpha.2"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-udeo (experimental)
2 | React bindings for [Udeo](https://github.com/mcoetzee/udeo)
3 |
4 | Provides:
5 |
6 | - A Connector to connect React components to the Udeo store
7 | - A Provider (ala Redux) to provide the Udeo store to the connected components
8 |
9 | ## Install
10 |
11 | NOTE: This has peer dependencies of `rxjs@5.0.*` and React 0.14 or later
12 |
13 | ```sh
14 | npm install --save react-udeo
15 | ```
16 | ## Connector
17 | ### Basic Usage
18 | Subscribing to a single state stream:
19 | ```js
20 | import { Connector } from 'react-udeo';
21 | import React from 'react';
22 |
23 | class Finder extends React.Component {
24 | render() {
25 | ...
26 | }
27 | }
28 |
29 | export default new Connector(Finder)
30 | // Subscribe to single module's state stream
31 | .withStateFrom('finder')
32 | // By default will clear module's state on unmount
33 | .build();
34 | ```
35 | Only mapping the store's dispatch to props (no state stream subscription):
36 | ```js
37 | export default new Connector(SearchBox)
38 | // Map the store's dispatch to props
39 | .mapDispatchTo(
40 | dispatch => ({
41 | onSearch(query) {
42 | dispatch({ type: 'SEARCH', payload: query });
43 | }
44 | })
45 | )
46 | .build();
47 | ```
48 |
49 | ### More Advanced Usage
50 | Subscribing to multiple state streams and selectively clearing state on unmount:
51 | ```js
52 | export default new Connector(Finder)
53 | // Subscribe to multiple state streams
54 | .withStateFrom('finder', 'shoppingCart')
55 | // Map the state from multiple modules to props
56 | .mapStateTo(
57 | (finderState, cartState) => ({
58 | ...finderState,
59 | totalCost: cartState.totalCost,
60 | })
61 | )
62 | // Map the store's dispatch to props
63 | .mapDispatchTo(
64 | dispatch => ({
65 | onSearch(query) {
66 | dispatch({ type: 'SEARCH', payload: query });
67 | }
68 | })
69 | )
70 | // Specify what to do with the state when component unmounts
71 | .clearStateOnUnmount({
72 | finder: true,
73 | shoppingCart: false,
74 | })
75 | .build();
76 | ```
77 | Hydrating the state stream with computed props:
78 | ```js
79 | export default new Connector(AvailabilityChecker)
80 | .withStateFrom('availability')
81 | .hydrateWith(
82 | props => ({
83 | availability: {
84 | arrival: props.vacationStartDate,
85 | departure: new Moment(props.vacationStartDate).add(3, 'days')
86 | }
87 | })
88 | )
89 | .build();
90 | ```
91 | ## Provider
92 | ```js
93 | import React from 'react';
94 | import { render } from 'react-dom';
95 | import App from './components/App';
96 | import { createStore } from 'udeo';
97 | import { Provider } from 'react-udeo';
98 | ...
99 |
100 | const store = createStore(...);
101 |
102 | render(
103 |
104 |
105 | ,
106 | document.getElementById('root')
107 | );
108 | ```
109 |
--------------------------------------------------------------------------------
/src/Connector.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Observable } from 'rxjs';
3 | import invariant from 'invariant';
4 | import { storeShape } from './storeShape';
5 |
6 | /**
7 | * Connects the provided component to the Udeo store.
8 | * @param Component - The React component to be connected to the store
9 | * @param [store] - The Udeo store. Optionally provided in order to use the Connector without
10 | * the Provider
11 | */
12 | export function Connector(Component, store) {
13 | this.Component = Component;
14 | this.store = store;
15 | this.moduleNames = [];
16 | this.mapper = state => state;
17 | this.dispatchMapper = undefined;
18 | this.clearOnUnmount = true;
19 | }
20 |
21 | Connector.prototype.withStateFrom = function(...moduleNames) {
22 | this.moduleNames = moduleNames;
23 | return this;
24 | };
25 |
26 | Connector.prototype.hydrateWith = function(hydrator) {
27 | this.hydrator = hydrator;
28 | return this;
29 | };
30 |
31 | Connector.prototype.mapStateTo = function(mapper) {
32 | this.mapper = mapper;
33 | return this;
34 | };
35 |
36 | Connector.prototype.mapDispatchTo = function(dispatchMapper) {
37 | this.dispatchMapper = dispatchMapper;
38 | return this;
39 | };
40 |
41 | Connector.prototype.clearStateOnUnmount = function(clearOnUnmount) {
42 | this.clearOnUnmount = clearOnUnmount;
43 | return this;
44 | };
45 |
46 | function getSingeState$(store, builder, hdrt) {
47 | let state$ = store.getState$(builder.moduleNames[0]);
48 | if (hdrt) {
49 | state$ = state$.filter(state => state.hydrated);
50 | }
51 | return state$.map(builder.mapper);
52 | }
53 |
54 | function getCombinedState$(store, builder, hdrt) {
55 | const state$s = builder.moduleNames.map(moduleName => {
56 | let state$ = store.getState$(moduleName);
57 | if (hdrt && hdrt[moduleName]) {
58 | state$ = state$.filter(state => state.hydrated);
59 | }
60 | return state$;
61 | });
62 | return Observable.combineLatest(...state$s, builder.mapper);
63 | }
64 |
65 | Connector.prototype.build = function() {
66 | const builder = this;
67 | const connectorDisplayName = 'Connector(' + (builder.Component.displayName || builder.Component.name || 'Unknown') + ')';
68 |
69 | class Connected extends React.Component {
70 | constructor(props, context) {
71 | super(props, context);
72 | this.store = builder.store || context.store;
73 | invariant(this.store,
74 | `The "store" was neither provided to the Connector or found in the context of "${connectorDisplayName}". ` +
75 | 'Either wrap the root component in a , or explicitly pass the "store" to the Connector.'
76 | );
77 | }
78 |
79 | componentWillMount() {
80 | this.dispatchProps = builder.dispatchMapper ? builder.dispatchMapper(this.store.dispatch) : {};
81 |
82 | if (!builder.moduleNames.length) {
83 | return;
84 | }
85 |
86 | const hdrt = builder.hydrator ? builder.hydrator(this.props) : undefined;
87 |
88 | const state$ = builder.moduleNames.length === 1
89 | ? getSingeState$(this.store, builder, hdrt)
90 | : getCombinedState$(this.store, builder, hdrt);
91 |
92 | this.subscription = state$.subscribe(state => this.setState(state));
93 |
94 | if (hdrt) {
95 | builder.moduleNames.forEach(moduleName => {
96 | if (hdrt[moduleName]) {
97 | this.store.hydrate(moduleName, hdrt[moduleName]);
98 | }
99 | });
100 | }
101 | }
102 |
103 | componentWillUnmount() {
104 | if (!builder.moduleNames.length) {
105 | return;
106 | }
107 |
108 | if (builder.clearOnUnmount) {
109 | const defined = typeof builder.clearOnUnmount === 'object';
110 | builder.moduleNames.forEach(moduleName => {
111 | if (defined && !builder.clearOnUnmount[moduleName]) {
112 | return;
113 | }
114 | this.store.clearState(moduleName);
115 | });
116 | }
117 | this.subscription.unsubscribe();
118 | }
119 |
120 | render() {
121 | const { Component } = builder;
122 | return ;
123 | }
124 | }
125 | Connected.displayName = connectorDisplayName;
126 | Connected.contextTypes = {
127 | store: storeShape
128 | };
129 | return Connected;
130 | };
131 |
--------------------------------------------------------------------------------
/test/Connector-spec.js:
--------------------------------------------------------------------------------
1 | /* globals describe it */
2 | import React from 'react';
3 | import { expect } from 'chai';
4 | import { createStore } from 'udeo';
5 | import { Connector, Provider } from '../';
6 | import { mount } from 'enzyme';
7 |
8 | const FOO = '@test/FOO';
9 | const BAR = '@test/BAR';
10 |
11 | describe('Connector', () => {
12 | describe('with state from a single module', () => {
13 | it('receives state updates', () => {
14 | const initialState = { foos: ['Tommy'] };
15 | const fooModule = {
16 | flow(dispatch$) {
17 | return [
18 | dispatch$.filterAction(FOO)
19 | ];
20 | },
21 | reducer(state = initialState, action) {
22 | switch (action.type) {
23 | case FOO:
24 | return {
25 | ...state,
26 | foos: state.foos.concat(action.payload)
27 | };
28 | default:
29 | return state;
30 | }
31 | }
32 | };
33 |
34 | const store = createStore({ fooModule });
35 |
36 | const Component = ({ foos }) => (
37 |
38 | {foos.map((f, i) =>
-{f}-
)}
39 |
40 | );
41 |
42 | const Connected = new Connector(Component)
43 | .withStateFrom('fooModule')
44 | .build();
45 |
46 | const mounted = mount(
47 |
48 |
49 |
50 | );
51 |
52 | expect(mounted.text()).to.eq('-Tommy-');
53 |
54 | store.dispatch({ type: FOO, payload: 'Shelby' });
55 | expect(mounted.text()).to.eq('-Tommy--Shelby-');
56 |
57 | store.dispatch({ type: BAR, payload: 'Arthur' });
58 | expect(mounted.text()).to.eq('-Tommy--Shelby-');
59 | });
60 |
61 | it('hydrates with computed props', () => {
62 | const initialState = { value: 0 };
63 | const fooModule = {
64 | flow(dispatch$) {
65 | return [
66 | dispatch$.filterAction(FOO)
67 | ];
68 | },
69 | reducer(state = initialState, action) {
70 | return state;
71 | }
72 | };
73 |
74 | const store = createStore({ fooModule });
75 |
76 | const Component = ({ value }) => (
77 |
78 | The answer is {value}
79 |
80 | );
81 |
82 | const Connected = new Connector(Component)
83 | .withStateFrom('fooModule')
84 | .hydrateWith(
85 | props => ({
86 | fooModule: { value: props.initialValue + 10 }
87 | })
88 | )
89 | .build();
90 |
91 | const mounted = mount(
92 |
93 |
94 |
95 | );
96 |
97 | expect(mounted.text()).to.eq('The answer is 42');
98 | });
99 |
100 | it('maps state', () => {
101 | const initialState = { valueA: 21, valueB: 42 };
102 | const fooModule = {
103 | flow(dispatch$) {
104 | return [
105 | dispatch$.filterAction(FOO)
106 | ];
107 | },
108 | reducer(state = initialState, action) {
109 | return state;
110 | }
111 | };
112 |
113 | const store = createStore({ fooModule });
114 |
115 | const Component = ({ valueA }) => (
116 |
117 | Value A is {valueA}
118 |
119 | );
120 |
121 | const Connected = new Connector(Component)
122 | .withStateFrom('fooModule')
123 | .mapStateTo(
124 | fooState => ({
125 | valueA: fooState.valueA,
126 | })
127 | )
128 | .build();
129 |
130 | const mounted = mount(
131 |
132 |
133 |
134 | );
135 |
136 | expect(mounted.find(Component).props()).to.have.all.keys(['valueA']);
137 | expect(mounted.find(Component).text()).to.eq('Value A is 21');
138 | });
139 |
140 | it('maps dispatch', () => {
141 | const initialState = { valueA: 20, valueB: 42 };
142 | const fooModule = {
143 | flow(dispatch$) {
144 | return [
145 | dispatch$.filterAction(FOO)
146 | ];
147 | },
148 | reducer(state = initialState, action) {
149 | switch (action.type) {
150 | case FOO:
151 | return {
152 | ...state,
153 | valueA: state.valueA * 2,
154 | valueB: state.valueB * 2,
155 | };
156 | default:
157 | return state;
158 | }
159 | }
160 | };
161 |
162 | const store = createStore({ fooModule });
163 |
164 | const Component = ({ valueA, valueB, onDubble }) => (
165 |
166 | A: {valueA} B: {valueB}
167 |
168 |
169 | );
170 |
171 | const Connected = new Connector(Component)
172 | .withStateFrom('fooModule')
173 | .mapDispatchTo(
174 | dispatch => ({
175 | onDubble() {
176 | dispatch({ type: FOO });
177 | }
178 | })
179 | )
180 | .build();
181 |
182 | const mounted = mount(
183 |
184 |
185 |
186 | );
187 |
188 | expect(mounted.find(Component).props()).to.have.all.keys(['valueA', 'valueB', 'onDubble']);
189 | expect(mounted.find('.values').text()).to.eq('A: 20 B: 42');
190 |
191 | mounted.find('#dubble').simulate('click');
192 | expect(mounted.find('.values').text()).to.eq('A: 40 B: 84');
193 |
194 | mounted.find('#dubble').simulate('click');
195 | expect(mounted.find('.values').text()).to.eq('A: 80 B: 168');
196 | });
197 |
198 | it('clears state on unmount', () => {
199 | const initialState = { valueA: 20, valueB: 42 };
200 | const fooModule = {
201 | flow(dispatch$) {
202 | return [
203 | dispatch$.filterAction(FOO)
204 | ];
205 | },
206 | reducer(state = initialState, action) {
207 | switch (action.type) {
208 | case FOO:
209 | return {
210 | ...state,
211 | valueA: state.valueA * 2,
212 | valueB: state.valueB * 2,
213 | };
214 | default:
215 | return state;
216 | }
217 | }
218 | };
219 |
220 | const store = createStore({ fooModule });
221 |
222 | const Component = ({ onDubble }) => (
223 |
224 | );
225 |
226 | const Connected = new Connector(Component)
227 | .withStateFrom('fooModule')
228 | .mapDispatchTo(
229 | dispatch => ({
230 | onDubble() {
231 | dispatch({ type: FOO });
232 | }
233 | })
234 | )
235 | .build();
236 |
237 | const mounted = mount(
238 |
239 |
240 |
241 | );
242 |
243 | let fooState;
244 | store.getState$('fooModule').subscribe(state => {
245 | fooState = state;
246 | });
247 |
248 | mounted.find('#dubble').simulate('click');
249 | mounted.find('#dubble').simulate('click');
250 |
251 | expect(fooState).to.deep.eq({ valueA: 80, valueB: 168 });
252 |
253 | mounted.unmount();
254 | expect(fooState).to.deep.eq({ valueA: 20, valueB: 42 });
255 | });
256 | });
257 | });
258 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "plugins": [
4 | "react"
5 | ],
6 | "rules": {
7 | // Enforces getter/setter pairs in objects
8 | "accessor-pairs": 0,
9 | // treat var statements as if they were block scoped
10 | "block-scoped-var": 2,
11 | // specify the maximum cyclomatic complexity allowed in a program
12 | "complexity": [0, 11],
13 | // require return statements to either always or never specify values
14 | "consistent-return": 0,
15 | // specify curly brace conventions for all control statements
16 | "curly": [2, "multi-line"],
17 | // require default case in switch statements
18 | "default-case": 2,
19 | // encourages use of dot notation whenever possible
20 | "dot-notation": [2, {
21 | "allowKeywords": true
22 | }],
23 | // enforces consistent newlines before or after dots
24 | "dot-location": 0,
25 | // require the use of === and !==
26 | "eqeqeq": 2,
27 | // make sure for-in loops have an if statement
28 | "guard-for-in": 2,
29 | // disabled use of an undefined variable
30 | "no-undef": 2,
31 | // disallow the use of console
32 | "no-console": 0,
33 | // disallow the use of alert, confirm, and prompt
34 | "no-alert": 0,
35 | // disallow use of arguments.caller or arguments.callee
36 | "no-caller": 2,
37 | // disallow division operators explicitly at beginning of regular expression
38 | "no-div-regex": 0,
39 | // disallow else after a return in an if
40 | "no-else-return": 0,
41 | // disallow comparisons to null without a type-checking operator
42 | "no-eq-null": 2,
43 | // disallow use of eval()
44 | "no-eval": 2,
45 | // disallow adding to native types
46 | "no-extend-native": 2,
47 | // disallow unnecessary function binding
48 | "no-extra-bind": 2,
49 | // disallow fallthrough of case statements
50 | "no-fallthrough": 2,
51 | // disallow the use of leading or trailing decimal points in numeric literals
52 | "no-floating-decimal": 2,
53 | // disallow the type conversions with shorter notations
54 | "no-implicit-coercion": 0,
55 | // disallow use of eval()-like methods
56 | "no-implied-eval": 2,
57 | // disallow this keywords outside of classes or class-like objects
58 | "no-invalid-this": 0,
59 | // disallow usage of __iterator__ property
60 | "no-iterator": 2,
61 | // disallow use of labeled statements
62 | "no-labels": 2,
63 | // disallow unnecessary nested blocks
64 | "no-lone-blocks": 2,
65 | // disallow creation of functions within loops
66 | "no-loop-func": 2,
67 | // disallow use of multiple spaces
68 | "no-multi-spaces": 2,
69 | // disallow use of multiline strings
70 | "no-multi-str": 2,
71 | // disallow reassignments of native objects
72 | "no-native-reassign": 2,
73 | // disallow use of new operator when not part of the assignment or comparison
74 | "no-new": 2,
75 | // disallow use of new operator for Function object
76 | "no-new-func": 2,
77 | // disallows creating new instances of String,Number, and Boolean
78 | "no-new-wrappers": 2,
79 | // disallow use of (old style) octal literals
80 | "no-octal": 2,
81 | // disallow use of octal escape sequences in string literals, such as
82 | // var foo = "Copyright \251";
83 | "no-octal-escape": 2,
84 | // disallow reassignment of function parameters
85 | "no-param-reassign": 0,
86 | // disallow use of process.env
87 | "no-process-env": 0,
88 | // disallow usage of __proto__ property
89 | "no-proto": 2,
90 | // disallow declaring the same variable more then once
91 | "no-redeclare": 2,
92 | // disallow use of assignment in return statement
93 | "no-return-assign": 2,
94 | // disallow use of `javascript:` urls.
95 | "no-script-url": 2,
96 | // disallow comparisons where both sides are exactly the same
97 | "no-self-compare": 2,
98 | // disallow use of comma operator
99 | "no-sequences": 2,
100 | // restrict what can be thrown as an exception
101 | "no-throw-literal": 2,
102 | // disallow usage of expressions in statement position
103 | "no-unused-expressions": 2,
104 | // disallow unused variables/imports
105 | "no-unused-vars": [2, { "vars": "all", "args": "none" }],
106 | // disallow unnecessary .call() and .apply()
107 | "no-useless-call": 0,
108 | // disallow use of void operator
109 | "no-void": 0,
110 | // disallow usage of configurable warning terms in comments: e.g. todo
111 | "no-warning-comments": [0, {
112 | "terms": ["todo", "fixme", "xxx"],
113 | "location": "start"
114 | }],
115 | // disallow use of the with statement
116 | "no-with": 2,
117 | // require use of the second argument for parseInt()
118 | "radix": 2,
119 | // requires to declare all vars on top of their containing scope
120 | "vars-on-top": 2,
121 | // require immediate function invocation to be wrapped in parentheses
122 | "wrap-iife": [2, "any"],
123 | // require or disallow Yoda conditions
124 | "yoda": 2,
125 | // enforce spacing inside array brackets
126 | "array-bracket-spacing": 2,
127 | // enforce one true brace style
128 | "brace-style": [2, "1tbs", {
129 | "allowSingleLine": true
130 | }],
131 | // require camel case names
132 | "camelcase": [2, {
133 | "properties": "never"
134 | }],
135 | // enforce spacing before and after comma
136 | "comma-spacing": [2, {
137 | "before": false,
138 | "after": true
139 | }],
140 | // enforce one true comma style
141 | "comma-style": [2, "last"],
142 | // require or disallow padding inside computed properties
143 | "computed-property-spacing": 2,
144 | // enforces consistent naming when capturing the current execution context
145 | "consistent-this": 0,
146 | // enforce newline at the end of file, with no multiple empty lines
147 | "eol-last": 2,
148 | // require function expressions to have a name
149 | "func-names": 0,
150 | // enforces use of function declarations or expressions
151 | "func-style": 0,
152 | // this option enforces minimum and maximum identifier lengths (variable names, property names etc.)
153 | "id-length": 0,
154 | // this option sets a specific tab width for your code
155 | "indent": [2, 2, { "SwitchCase": 1 }],
156 | // enforces spacing between keys and values in object literal properties
157 | "key-spacing": [2, {
158 | "beforeColon": false,
159 | "afterColon": true
160 | }],
161 | "keyword-spacing": 2,
162 | // enforces empty lines around comments
163 | "lines-around-comment": 0,
164 | // disallow mixed "LF" and "CRLF" as linebreaks
165 | "linebreak-style": [2, "unix"],
166 | // specify the maximum depth callbacks can be nested
167 | "max-nested-callbacks": 0,
168 | // require a capital letter for constructors
169 | "new-cap": [2, {
170 | "newIsCap": true
171 | }],
172 | // disallow the omission of parentheses when invoking a constructor with no arguments
173 | "new-parens": 2,
174 | // allow/disallow an empty newline after var statement
175 | "newline-after-var": 0,
176 | // disallow use of the Array constructor
177 | "no-array-constructor": 0,
178 | // disallow use of the continue statement
179 | "no-continue": 0,
180 | // disallow comments inline after code
181 | "no-inline-comments": 0,
182 | // disallow if as the only statement in an else block
183 | "no-lonely-if": 0,
184 | // disallow mixed spaces and tabs for indentation
185 | "no-mixed-spaces-and-tabs": 2,
186 | // disallow multiple empty lines
187 | "no-multiple-empty-lines": [2, {
188 | "max": 2
189 | }],
190 | // disallow nested ternary expressions
191 | "no-nested-ternary": 2,
192 | // disallow use of the Object constructor
193 | "no-new-object": 2,
194 | // disallow space between function identifier and application
195 | "no-spaced-func": 2,
196 | // disallow the use of ternary operators
197 | "no-ternary": 0,
198 | // disallow trailing whitespace at the end of lines
199 | "no-trailing-spaces": 2,
200 | // disallow dangling underscores in identifiers
201 | "no-underscore-dangle": 0,
202 | // disallow the use of Boolean literals in conditional expressions
203 | "no-unneeded-ternary": 2,
204 | // require or disallow padding inside curly braces
205 | "object-curly-spacing": [2, "always"],
206 | // allow just one var statement per function
207 | "one-var": [2, "never"],
208 | // require assignment operator shorthand where possible or prohibit it entirely
209 | "operator-assignment": 0,
210 | // enforce operators to be placed before or after line breaks
211 | "operator-linebreak": 0,
212 | // enforce padding within blocks
213 | "padded-blocks": [2, "never"],
214 | // require quotes around object literal property names
215 | "quote-props": [2, "as-needed"],
216 | // specify whether double or single quotes should be used
217 | "quotes": [2, "single", "avoid-escape"],
218 | // require identifiers to match the provided regular expression
219 | "id-match": 0,
220 | // enforce spacing before and after semicolons
221 | "semi-spacing": [2, {
222 | "before": false,
223 | "after": true
224 | }],
225 | // require or disallow use of semicolons instead of ASI
226 | "semi": [2, "always"],
227 | // sort variables within the same declaration block
228 | "sort-vars": 0,
229 | // require or disallow space before blocks
230 | "space-before-blocks": 2,
231 | // require or disallow space before function opening parenthesis
232 | "space-before-function-paren": [0, { "anonymous": "always", "named": "never" }],
233 | // require or disallow spaces inside parentheses
234 | "space-in-parens": 0,
235 | // require spaces around operators
236 | "space-infix-ops": 2,
237 | // Require or disallow spaces before/after unary operators
238 | "space-unary-ops": 2,
239 |
240 | /* ES6+ */
241 | // disallow using `var`. Must use `let` or `const`
242 | "no-var": 2,
243 | "no-class-assign": 2,
244 | "no-const-assign": 2,
245 | "no-dupe-class-members": 2,
246 | "no-this-before-super": 2,
247 | "prefer-const": 0,
248 | "prefer-spread": 2,
249 | // require object literal shorthand
250 | "object-shorthand": [2, "always"],
251 | "arrow-spacing": 2,
252 | "prefer-arrow-callback": 2,
253 | "arrow-parens": [0, "as-needed"],
254 |
255 | "react/jsx-uses-vars": 2,
256 | "react/jsx-uses-react": 2
257 | },
258 | "env": {
259 | "browser": true,
260 | "es6": true,
261 | "mocha": true
262 | },
263 | "globals": {
264 | "require": true
265 | },
266 | "ecmaFeatures": {
267 | "jsx": true
268 | }
269 | }
270 |
--------------------------------------------------------------------------------