Skip to content

Commit 99b55b7

Browse files
committed
Breakup debug option into individual option flags
TODO: add tests
1 parent 77ced5e commit 99b55b7

File tree

6 files changed

+115
-65
lines changed

6 files changed

+115
-65
lines changed

src/logging.js

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
import { getOption } from './reactor/fns'
2+
13
/* eslint-disable no-console */
24
/**
35
* Wraps a Reactor.react invocation in a console.group
6+
* @param {ReactorState} reactorState
7+
* @param {String} type
8+
* @param {*} payload
49
*/
5-
exports.dispatchStart = function(type, payload) {
10+
exports.dispatchStart = function(reactorState, type, payload) {
11+
if (!getOption(reactorState, 'logDispatches')) {
12+
return
13+
}
14+
615
if (console.group) {
716
console.groupCollapsed('Dispatch: %s', type)
817
console.group('payload')
@@ -11,24 +20,31 @@ exports.dispatchStart = function(type, payload) {
1120
}
1221
}
1322

14-
exports.dispatchError = function(error) {
23+
exports.dispatchError = function(reactorState, error) {
24+
console.log('dispatchError, shoud do', getOption(reactorState, 'logDispatches'))
25+
if (!getOption(reactorState, 'logDispatches')) {
26+
return
27+
}
28+
1529
if (console.group) {
1630
console.debug('Dispatch error: ' + error)
1731
console.groupEnd()
1832
}
1933
}
2034

21-
exports.storeHandled = function(id, before, after) {
22-
if (console.group) {
23-
if (before !== after) {
24-
console.debug('Store ' + id + ' handled action')
25-
}
35+
exports.dispatchEnd = function(reactorState, state, dirtyStores) {
36+
if (!getOption(reactorState, 'logDispatches')) {
37+
return
2638
}
27-
}
2839

29-
exports.dispatchEnd = function(state) {
3040
if (console.group) {
31-
console.debug('Dispatch done, new state: ', state.toJS())
41+
if (getOption(reactorState, 'logDirtyStores')) {
42+
console.log('Stores updated:', dirtyStores.toList().toJS())
43+
}
44+
45+
if (getOption(reactorState, 'logAppState')) {
46+
console.debug('Dispatch done, new state: ', state.toJS())
47+
}
3248
console.groupEnd()
3349
}
3450
}

src/reactor.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import Immutable from 'immutable'
22
import createReactMixin from './create-react-mixin'
3-
import fns from './reactor/fns'
3+
import * as fns from './reactor/fns'
44
import { isKeyPath } from './key-path'
55
import { isGetter } from './getter'
66
import { toJS } from './immutable-helpers'
77
import { toFactory } from './utils'
8-
import { ReactorState, ObserverState } from './reactor/records'
8+
import {
9+
ReactorState,
10+
ObserverState,
11+
DEBUG_OPTIONS,
12+
PROD_OPTIONS,
13+
} from './reactor/records'
914

1015
/**
1116
* State is stored in NuclearJS Reactors. Reactors
@@ -18,8 +23,11 @@ import { ReactorState, ObserverState } from './reactor/records'
1823
*/
1924
class Reactor {
2025
constructor(config = {}) {
26+
const baseOptions = config.debug ? DEBUG_OPTIONS : PROD_OPTIONS
2127
const initialReactorState = new ReactorState({
2228
debug: config.debug,
29+
// merge config options with the defaults
30+
options: baseOptions.merge(config.options || {}),
2331
})
2432

2533
this.prevReactorState = initialReactorState
@@ -101,9 +109,11 @@ class Reactor {
101109
*/
102110
dispatch(actionType, payload) {
103111
if (this.__batchDepth === 0) {
104-
if (this.__isDispatching) {
105-
this.__isDispatching = false
106-
throw new Error('Dispatch may not be called while a dispatch is in progress')
112+
if (!fns.getOption(this.reactorState, 'allowDispatchInDispatch')) {
113+
if (this.__isDispatching) {
114+
this.__isDispatching = false
115+
throw new Error('Dispatch may not be called while a dispatch is in progress')
116+
}
107117
}
108118
this.__isDispatching = true
109119
}

src/reactor/fns.js

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ function evaluateResult(result, reactorState) {
2323
* @param {Object<String, Store>} stores
2424
* @return {ReactorState}
2525
*/
26-
exports.registerStores = function(reactorState, stores) {
27-
const debug = reactorState.get('debug')
28-
26+
export function registerStores(reactorState, stores) {
2927
return reactorState.withMutations((reactorState) => {
3028
each(stores, (store, id) => {
3129
if (reactorState.getIn(['stores', id])) {
@@ -36,7 +34,7 @@ exports.registerStores = function(reactorState, stores) {
3634

3735
const initialState = store.getInitialState()
3836

39-
if (debug && !isImmutableValue(initialState)) {
37+
if (!getOption(reactorState, 'allowNonImmutableStores') && !isImmutableValue(initialState)) {
4038
throw new Error('Store getInitialState() must return an immutable value, did you forget to call toImmutable')
4139
}
4240

@@ -56,15 +54,12 @@ exports.registerStores = function(reactorState, stores) {
5654
* @param {*} payload
5755
* @return {ReactorState}
5856
*/
59-
exports.dispatch = function(reactorState, actionType, payload) {
57+
export function dispatch(reactorState, actionType, payload) {
6058
const currState = reactorState.get('state')
61-
const debug = reactorState.get('debug')
6259
let dirtyStores = reactorState.get('dirtyStores')
6360

6461
const nextState = currState.withMutations(state => {
65-
if (debug) {
66-
logging.dispatchStart(actionType, payload)
67-
}
62+
logging.dispatchStart(reactorState, actionType, payload)
6863

6964
// let each store handle the message
7065
reactorState.get('stores').forEach((store, id) => {
@@ -75,13 +70,13 @@ exports.dispatch = function(reactorState, actionType, payload) {
7570
newState = store.handle(currState, actionType, payload)
7671
} catch(e) {
7772
// ensure console.group is properly closed
78-
logging.dispatchError(e.message)
73+
logging.dispatchError(reactorState, e.message)
7974
throw e
8075
}
8176

82-
if (debug && newState === undefined) {
77+
if (!getOption(reactorState, 'allowUndefinedDispatch') && newState === undefined) {
8378
const errorMsg = 'Store handler must return a value, did you forget a return statement'
84-
logging.dispatchError(errorMsg)
79+
logging.dispatchError(reactorState, errorMsg)
8580
throw new Error(errorMsg)
8681
}
8782

@@ -91,15 +86,9 @@ exports.dispatch = function(reactorState, actionType, payload) {
9186
// if the store state changed add store to list of dirty stores
9287
dirtyStores = dirtyStores.add(id)
9388
}
94-
95-
if (debug) {
96-
logging.storeHandled(id, currState, newState)
97-
}
9889
})
9990

100-
if (debug) {
101-
logging.dispatchEnd(state)
102-
}
91+
logging.dispatchEnd(reactorState, state, dirtyStores)
10392
})
10493

10594
const nextReactorState = reactorState
@@ -115,7 +104,7 @@ exports.dispatch = function(reactorState, actionType, payload) {
115104
* @param {Immutable.Map} state
116105
* @return {ReactorState}
117106
*/
118-
exports.loadState = function(reactorState, state) {
107+
export function loadState(reactorState, state) {
119108
let dirtyStores = []
120109
const stateToLoad = toImmutable({}).withMutations(stateToLoad => {
121110
each(state, (serializedStoreState, storeId) => {
@@ -154,7 +143,7 @@ exports.loadState = function(reactorState, state) {
154143
* @param {function} handler
155144
* @return {ObserveResult}
156145
*/
157-
exports.addObserver = function(observerState, getter, handler) {
146+
export function addObserver(observerState, getter, handler) {
158147
// use the passed in getter as the key so we can rely on a byreference call for unobserve
159148
const getterKey = getter
160149
if (isKeyPath(getter)) {
@@ -180,7 +169,7 @@ exports.addObserver = function(observerState, getter, handler) {
180169
storeDeps.forEach(storeId => {
181170
let path = ['stores', storeId]
182171
if (!map.hasIn(path)) {
183-
map.setIn(path, Immutable.Set([]))
172+
map.setIn(path, Immutable.Set())
184173
}
185174
map.updateIn(['stores', storeId], observerIds => observerIds.add(currId))
186175
})
@@ -197,6 +186,15 @@ exports.addObserver = function(observerState, getter, handler) {
197186
}
198187
}
199188

189+
/**
190+
* @param {ReactorState} reactorState
191+
* @param {String} option
192+
* @return {Boolean}
193+
*/
194+
export function getOption(reactorState, option) {
195+
return reactorState.getIn(['options', option], false)
196+
}
197+
200198
/**
201199
* Use cases
202200
* removeObserver(observerState, [])
@@ -210,7 +208,7 @@ exports.addObserver = function(observerState, getter, handler) {
210208
* @param {Function} handler
211209
* @return {ObserverState}
212210
*/
213-
exports.removeObserver = function(observerState, getter, handler) {
211+
export function removeObserver(observerState, getter, handler) {
214212
const entriesToRemove = observerState.get('observersMap').filter(entry => {
215213
// use the getterKey in the case of a keyPath is transformed to a getter in addObserver
216214
let entryGetter = entry.get('getterKey')
@@ -227,7 +225,7 @@ exports.removeObserver = function(observerState, getter, handler) {
227225
})
228226

229227
return observerState.withMutations(map => {
230-
entriesToRemove.forEach(entry => exports.removeObserverByEntry(map, entry))
228+
entriesToRemove.forEach(entry => removeObserverByEntry(map, entry))
231229
})
232230
}
233231

@@ -237,7 +235,7 @@ exports.removeObserver = function(observerState, getter, handler) {
237235
* @param {Immutable.Map} entry
238236
* @return {ObserverState}
239237
*/
240-
exports.removeObserverByEntry = function(observerState, entry) {
238+
export function removeObserverByEntry(observerState, entry) {
241239
return observerState.withMutations(map => {
242240
const id = entry.get('id')
243241
const storeDeps = entry.get('storeDeps')
@@ -264,8 +262,7 @@ exports.removeObserverByEntry = function(observerState, entry) {
264262
* @param {ReactorState} reactorState
265263
* @return {ReactorState}
266264
*/
267-
exports.reset = function(reactorState) {
268-
const debug = reactorState.get('debug')
265+
export function reset(reactorState) {
269266
const prevState = reactorState.get('state')
270267

271268
return reactorState.withMutations(reactorState => {
@@ -274,17 +271,17 @@ exports.reset = function(reactorState) {
274271
storeMap.forEach((store, id) => {
275272
const storeState = prevState.get(id)
276273
const resetStoreState = store.handleReset(storeState)
277-
if (debug && resetStoreState === undefined) {
274+
if (!getOption(reactorState, 'allowUndefinedDispatch') && resetStoreState === undefined) {
278275
throw new Error('Store handleReset() must return a value, did you forget a return statement')
279276
}
280-
if (debug && !isImmutableValue(resetStoreState)) {
277+
if (!getOption(reactorState, 'allowNonImmutableStores') && !isImmutableValue(resetStoreState)) {
281278
throw new Error('Store reset state must be an immutable value, did you forget to call toImmutable')
282279
}
283280
reactorState.setIn(['state', id], resetStoreState)
284281
})
285282

286283
reactorState.update('storeStates', storeStates => incrementStoreStates(storeStates, storeIds))
287-
exports.resetDirtyStores(reactorState)
284+
resetDirtyStores(reactorState)
288285
})
289286
}
290287

@@ -293,7 +290,7 @@ exports.reset = function(reactorState) {
293290
* @param {KeyPath|Gettter} keyPathOrGetter
294291
* @return {EvaluateResult}
295292
*/
296-
exports.evaluate = function evaluate(reactorState, keyPathOrGetter) {
293+
export function evaluate(reactorState, keyPathOrGetter) {
297294
const state = reactorState.get('state')
298295

299296
if (isKeyPath(keyPathOrGetter)) {
@@ -331,7 +328,7 @@ exports.evaluate = function evaluate(reactorState, keyPathOrGetter) {
331328
* @param {ReactorState} reactorState
332329
* @return {Object}
333330
*/
334-
exports.serialize = function(reactorState) {
331+
export function serialize(reactorState) {
335332
let serialized = {}
336333
reactorState.get('stores').forEach((store, id) => {
337334
let storeState = reactorState.getIn(['state', id])
@@ -348,7 +345,7 @@ exports.serialize = function(reactorState) {
348345
* @param {ReactorState} reactorState
349346
* @return {ReactorState}
350347
*/
351-
exports.resetDirtyStores = function(reactorState) {
348+
export function resetDirtyStores(reactorState) {
352349
return reactorState.set('dirtyStores', Immutable.Set())
353350
}
354351

src/reactor/records.js

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,55 @@
1-
import Immutable from 'immutable'
1+
import { Map, Set, Record } from 'immutable'
22

3-
const ReactorState = Immutable.Record({
3+
export const ReactorState = Record({
44
dispatchId: 0,
5-
state: Immutable.Map(),
6-
stores: Immutable.Map(),
7-
cache: Immutable.Map(),
5+
state: Map(),
6+
stores: Map(),
7+
cache: Map(),
88
// maintains a mapping of storeId => state id (monotomically increasing integer whenever store state changes)
9-
storeStates: Immutable.Map(),
10-
dirtyStores: Immutable.Set(),
9+
storeStates: Map(),
10+
dirtyStores: Set(),
1111
debug: false,
12+
// production defaults
13+
options: Map({}),
1214
})
1315

14-
const ObserverState = Immutable.Record({
16+
export const ObserverState = Record({
1517
// observers registered to any store change
16-
any: Immutable.Set([]),
18+
any: Set(),
1719
// observers registered to specific store changes
18-
stores: Immutable.Map({}),
20+
stores: Map({}),
1921

20-
observersMap: Immutable.Map({}),
22+
observersMap: Map({}),
2123

2224
nextId: 1,
2325
})
2426

25-
export default {
26-
ReactorState,
27-
ObserverState,
28-
}
27+
export const DEBUG_OPTIONS = Map({
28+
// logs information for each dispatch
29+
logDispatches: true,
30+
// log the entire app state after each dispatch
31+
logAppState: true,
32+
// logs what stores changed after a dispatch
33+
logDirtyStores: true,
34+
// if false, throw an error if a store returns undefined
35+
allowUndefinedDispatch: false,
36+
// if false, throw an error if a store returns undefined
37+
allowNonImmutableStores: false,
38+
// if false throw when dispatching in dispatch
39+
allowDispatchInDispatch: false,
40+
})
41+
42+
export const PROD_OPTIONS = Map({
43+
// logs information for each dispatch
44+
logDispatches: false,
45+
// log the entire app state after each dispatch
46+
logAppState: false,
47+
// logs what stores changed after a dispatch
48+
logDirtyStores: false,
49+
// if false, throw an error if a store returns undefined
50+
allowUndefinedDispatch: true,
51+
// if false, throw an error if a store returns undefined
52+
allowNonImmutableStores: true,
53+
// if false throw when dispatching in dispatch
54+
allowDispatchInDispatch: true,
55+
})

tests/reactor-fns-tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*eslint-disable one-var, comma-dangle*/
22
import { Map, Set, is } from 'immutable'
33
import { Store } from '../src/main'
4-
import fns from '../src/reactor/fns'
4+
import * as fns from '../src/reactor/fns'
55
import { ReactorState, ObserverState } from '../src/reactor/records'
66
import { toImmutable } from '../src/immutable-helpers'
77

tests/reactor-tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ describe('Reactor', () => {
764764
expect(function() {
765765
reactor.dispatch('set', 'foo')
766766
}).toThrow(new Error('Error during action handling'))
767-
expect(logging.dispatchError).toHaveBeenCalledWith('Error during action handling')
767+
expect(logging.dispatchError).toHaveBeenCalledWith(reactor.reactorState, 'Error during action handling')
768768
})
769769
})
770770

0 commit comments

Comments
 (0)