Bladeren bron

clean up reducers, elim implicit any

Adam Shaw 7 jaren geleden
bovenliggende
commit
f97dbe8e4f

+ 17 - 6
src/Calendar.ts

@@ -16,7 +16,7 @@ import { DateEnv, DateInput } from './datelib/env'
 import { DateMarker, startOfDay } from './datelib/marker'
 import { createFormatter } from './datelib/formatting'
 import { Duration, createDuration } from './datelib/duration'
-import { CalendarState, reduce } from './reducers/main'
+import reduce from './reducers/main'
 import { parseDateSpan, DateSpanInput, DateSpan } from './structs/date-span'
 import reselector from './util/reselector'
 import { assignTo } from './util/object'
@@ -24,6 +24,8 @@ import { RenderForceFlags } from './component/Component'
 import browserContext from './common/browser-context'
 import { rangeContainsMarker } from './datelib/date-range'
 import { DateProfile } from './DateProfileGenerator'
+import { EventSourceInput, parseEventSource } from './structs/event-source'
+import { CalendarState, Action } from './reducers/types'
 
 
 export default class Calendar {
@@ -301,15 +303,21 @@ export default class Calendar {
 
     let rawSources = this.opt('eventSources') || []
     let singleRawSource = this.opt('events')
+    let sources = [] // parsed
 
     if (singleRawSource) {
       rawSources.unshift(singleRawSource)
     }
 
     for (let rawSource of rawSources) {
-      this.dispatch({ type: 'ADD_EVENT_SOURCE', rawSource })
+      let source = parseEventSource(rawSource)
+      if (source) {
+        sources.push(source)
+      }
     }
 
+    this.dispatch({ type: 'ADD_EVENT_SOURCES', sources })
+
     this.setViewType(this.opt('defaultView'), this.getInitialDate())
   }
 
@@ -332,7 +340,7 @@ export default class Calendar {
   }
 
 
-  dispatch(action) {
+  dispatch(action: Action) {
     this.actionQueue.push(action)
 
     if (!this.isReducing) {
@@ -363,7 +371,7 @@ export default class Calendar {
   }
 
 
-  reduce(state: CalendarState, action: object, calendar: Calendar): CalendarState {
+  reduce(state: CalendarState, action: Action, calendar: Calendar): CalendarState {
     return reduce(state, action, calendar)
   }
 
@@ -1063,7 +1071,10 @@ export default class Calendar {
 
 
   addEventSource(sourceInput: EventSourceInput) {
-    this.dispatch({ type: 'ADD_EVENT_SOURCE', rawSource: sourceInput })
+    let eventSource = parseEventSource(sourceInput)
+    if (eventSource) { // TODO: error otherwise?
+      this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [ eventSource ] })
+    }
   }
 
 
@@ -1078,7 +1089,7 @@ export default class Calendar {
 
 
   refetchEvents() {
-    this.dispatch({ type: 'FETCH_ALL_EVENT_SOURCES' })
+    this.dispatch({ type: 'FETCH_EVENT_SOURCES' })
   }
 
 

+ 1 - 1
src/component/DateComponent.ts

@@ -21,7 +21,7 @@ import { DateRange, rangeContainsMarker } from '../datelib/date-range'
 
 
 export interface DateComponentRenderState {
-  dateProfile: DateProfile
+  dateProfile: DateProfile | null
   eventStore: EventStore
   selection: DateSpan | null
   dragState: EventInteractionState | null

+ 1 - 0
src/interactions/EventDragging.ts

@@ -210,6 +210,7 @@ export default class EventDragging {
           dragState: {
             affectedEvents: dragState.affectedEvents,
             mutatedEvents: createEmptyEventStore(),
+            isEvent: true,
             origSeg: dragState.origSeg
           }
         })

+ 156 - 116
src/reducers/event-sources.ts

@@ -1,137 +1,177 @@
-import { assignTo } from '../util/object'
+import { EventSource, EventSourceHash, getEventSourceDef } from '../structs/event-source'
 import Calendar from '../Calendar'
+import { arrayToHash, assignTo, filterHash } from '../util/object'
+import { DateRange } from '../datelib/date-range'
 import { warn } from '../util/misc'
-import { EventSource, EventSourceHash, parseEventSource, getEventSourceDef } from '../structs/event-source'
+import { DateProfile } from '../DateProfileGenerator'
+import { Action, SimpleError } from './types'
 
-let uid = 0
+export default function(eventSourceHash: EventSourceHash, action: Action, dateProfile: DateProfile | null, calendar: Calendar): EventSourceHash {
+  switch (action.type) {
 
-// reducers
+    case 'ADD_EVENT_SOURCES': // already parsed
+      return addSources(eventSourceHash, action.sources, dateProfile, calendar)
 
-export function reduceEventSourceHash(sourceHash: EventSourceHash, action: any, calendar: Calendar): EventSourceHash {
-  let eventSource: EventSource
+    case 'REMOVE_EVENT_SOURCES':
+      if (action.sourceIds) {
+        return removeSources(eventSourceHash, action.sourceIds)
+      } else {
+        return {} // remove all
+      }
 
-  switch (action.type) {
+    case 'SET_DATE_PROFILE':
+      fetchDirtySources(eventSourceHash, action.dateProfile, calendar)
+      return eventSourceHash
 
-    case 'ADD_EVENT_SOURCE':
-      eventSource = parseEventSource(action.rawSource)
-
-      if (eventSource) {
-        if (calendar.state.dateProfile) {
-          calendar.dispatch({
-            type: 'FETCH_EVENT_SOURCE',
-            sourceId: eventSource.sourceId,
-            range: calendar.state.dateProfile.activeRange
-          })
-        }
-        return assignTo({}, sourceHash, {
-          [eventSource.sourceId]: eventSource
-        })
+    case 'FETCH_EVENT_SOURCES':
+      if (dateProfile) {
+        return fetchSourcesById(eventSourceHash, action.sourceIds || null, dateProfile, calendar)
       } else {
-        return sourceHash
+        return eventSourceHash // can't fetch if don't know the framing range
       }
 
-    case 'FETCH_ALL_EVENT_SOURCES':
-      for (let sourceId in sourceHash) {
-        calendar.dispatch({
-          type: 'FETCH_EVENT_SOURCE',
-          sourceId,
-          range: calendar.state.dateProfile.activeRange
-        })
-      }
-      return sourceHash
+    case 'RECEIVE_EVENTS':
+    case 'RECEIVE_EVENT_ERROR':
+      return receiveResponse(eventSourceHash, action.sourceId, action.fetchId, action.fetchRange)
+
+    default:
+      return eventSourceHash
+  }
+}
 
-    case 'FETCH_EVENT_SOURCE':
-      eventSource = sourceHash[action.sourceId]
+let uid = 0
 
+function addSources(eventSourceHash: EventSourceHash, sources: EventSource[], dateProfile: DateProfile | null, calendar: Calendar): EventSourceHash {
+  let hash: EventSourceHash = {}
+
+  for (let source of sources) {
+    hash[source.sourceId] = source
+  }
+
+  if (dateProfile) {
+    fetchDirtySources(hash, dateProfile, calendar)
+  }
+
+  return assignTo({}, eventSourceHash, hash)
+}
+
+function removeSources(eventSourceHash: EventSourceHash, sourceIds: string[]): EventSourceHash {
+  let idHash = arrayToHash(sourceIds)
+
+  return filterHash(eventSourceHash, function(eventSource: EventSource) {
+    return !idHash[eventSource.sourceId]
+  })
+}
+
+function fetchDirtySources(sourceHash: EventSourceHash, dateProfile: DateProfile, calendar: Calendar) {
+  let activeRange = dateProfile.activeRange
+  let dirtySourceIds = []
+
+  for (let sourceId in sourceHash) {
+    let eventSource = sourceHash[sourceId]
+
+    if (
+      !calendar.opt('lazyFetching') ||
+      !eventSource.fetchRange ||
+      eventSource.fetchRange.start < activeRange.start ||
+      eventSource.fetchRange.end > activeRange.end
+    ) {
+      dirtySourceIds.push(eventSource.sourceId)
+    }
+  }
+
+  if (dirtySourceIds.length) {
+    calendar.dispatch({
+      type: 'FETCH_EVENT_SOURCES',
+      sourceIds: dirtySourceIds
+    })
+  }
+}
+
+function fetchSourcesById(
+  prevSources: EventSourceHash,
+  sourceIds: string[] | null,
+  dateProfile: DateProfile,
+  calendar: Calendar
+): EventSourceHash {
+  let sourceIdHash = sourceIds ? arrayToHash(sourceIds) : null
+  let nextSources: EventSourceHash = {}
+  let activeRange = dateProfile.activeRange
+
+  for (let sourceId in prevSources) {
+    let source = prevSources[sourceId]
+
+    if (!sourceIdHash || sourceIdHash[sourceId]) {
       let fetchId = String(uid++)
 
-      getEventSourceDef(eventSource.sourceDefId).fetch(
-        {
-          eventSource,
-          calendar,
-          range: action.range
-        },
-        function(rawEvents) {
-          calendar.dispatch({
-            type: 'RECEIVE_EVENT_SOURCE',
-            sourceId: eventSource.sourceId,
-            fetchId,
-            fetchRange: action.range,
-            rawEvents
-          })
-        },
-        function(errorInput) {
-          let errorObj
-
-          if (typeof errorInput === 'string') {
-            errorObj = { message: errorInput }
-          } else {
-            errorObj = errorInput || {}
-          }
-
-          calendar.dispatch({
-            type: 'ERROR_EVENT_SOURCE',
-            sourceId: eventSource.sourceId,
-            fetchId,
-            fetchRange: action.range,
-            error: errorObj
-          })
-        }
-      )
-
-      return assignTo({}, sourceHash, {
-        [eventSource.sourceId]: assignTo({}, eventSource, {
-          isFetching: true,
-          latestFetchId: fetchId
-        })
+      fetchSource(source, activeRange, fetchId, calendar)
+
+      nextSources[sourceId] = assignTo({}, source, {
+        isFetching: true,
+        latestFetchId: fetchId
       })
+    } else {
+      nextSources[sourceId] = source
+    }
+  }
 
-    case 'RECEIVE_EVENT_SOURCE':
-    case 'ERROR_EVENT_SOURCE':
-      eventSource = sourceHash[action.sourceId]
-
-      if (eventSource.latestFetchId === action.fetchId) {
-
-        if (action.type === 'RECEIVE_EVENT_SOURCE') {
-          eventSource.success(action.rawEvents)
-        } else { // failure
-          warn(action.error.message, action.error)
-          eventSource.failure(action.error)
-        }
-
-        return assignTo({}, sourceHash, {
-          [eventSource.sourceId]: assignTo({}, eventSource, {
-            isFetching: false,
-            fetchRange: action.fetchRange
-          })
-        })
-      } else {
-        return sourceHash
-      }
+  return nextSources
+}
 
-    case 'SET_DATE_PROFILE':
-      let activeRange = action.dateProfile.activeRange
-
-      for (let sourceId in sourceHash) {
-        eventSource = sourceHash[sourceId]
-
-        if (
-          !calendar.opt('lazyFetching') ||
-          !eventSource.fetchRange ||
-          eventSource.fetchRange.start < activeRange.start ||
-          eventSource.fetchRange.end > activeRange.end
-        ) {
-          calendar.dispatch({
-            type: 'FETCH_EVENT_SOURCE',
-            sourceId: eventSource.sourceId,
-            range: activeRange
-          })
-        }
-      }
+function fetchSource(eventSource: EventSource, range: DateRange, fetchId: string, calendar: Calendar) {
+  getEventSourceDef(eventSource.sourceDefId).fetch(
+    {
+      eventSource,
+      calendar,
+      range
+    },
+    function(rawEvents) {
+      eventSource.success(rawEvents)
+
+      calendar.dispatch({
+        type: 'RECEIVE_EVENTS',
+        sourceId: eventSource.sourceId,
+        fetchId,
+        fetchRange: range,
+        rawEvents
+      })
+    },
+    function(errorInput) {
+      let error = normalizeError(errorInput)
+
+      warn(error.message, error)
+      eventSource.failure(error)
+
+      calendar.dispatch({
+        type: 'RECEIVE_EVENT_ERROR',
+        sourceId: eventSource.sourceId,
+        fetchId,
+        fetchRange: range,
+        error
+      })
+    }
+  )
+}
 
-      return sourceHash
+function receiveResponse(sourceHash: EventSourceHash, sourceId: string, fetchId: string, fetchRange: DateRange) {
+  let eventSource: EventSource = sourceHash[sourceId]
 
-    default:
-      return sourceHash
+  if (fetchId === eventSource.latestFetchId) {
+    return assignTo({}, sourceHash, {
+      [sourceId]: assignTo({}, eventSource, {
+        isFetching: false,
+        fetchRange
+      })
+    })
+  }
+
+  return sourceHash
+}
+
+function normalizeError(input: any): SimpleError {
+  if (typeof input === 'string') {
+    return { message: input }
+  } else {
+    return input || {}
   }
 }

+ 72 - 37
src/reducers/event-store.ts

@@ -1,51 +1,73 @@
 import Calendar from '../Calendar'
-import { filterHash } from '../util/object'
+import { filterHash, arrayToHash } from '../util/object'
 import { EventMutation, applyMutationToEventStore } from '../structs/event-mutation'
-import { EventDef, EventInstance } from '../structs/event'
+import { EventDef, EventInstance, EventInput } from '../structs/event'
 import { EventStore, parseEventStore, mergeEventStores, getRelatedEvents } from '../structs/event-store'
+import { Action } from './types'
+import { EventSourceHash, EventSource } from '../structs/event-source'
+import { DateRange } from '../datelib/date-range'
 
-// reducing
-
-export function reduceEventStore(eventStore: EventStore, action: any, calendar: Calendar): EventStore {
-  let eventSource
-
+export default function(eventStore: EventStore, action: Action, sourceHash: EventSourceHash, calendar: Calendar): EventStore {
   switch(action.type) {
 
-    case 'RECEIVE_EVENT_SOURCE':
-      eventSource = calendar.state.eventSources[action.sourceId]
-
-      // TODO: use eventDataTransform
-
-      if (eventSource.latestFetchId === action.fetchId) { // this is checked in event-sources too :(
-        return parseEventStore(
-          action.rawEvents,
-          action.sourceId,
-          action.fetchRange,
-          calendar,
-          excludeSource(eventStore, action.sourceId)
-        )
-      } else {
-        return eventStore
-      }
+    case 'ADD_EVENTS': // already parsed
+      return mergeEventStores(eventStore, action.eventStore)
 
-    case 'CLEAR_EVENT_SOURCE': // TODO: wire up
-      return excludeSource(eventStore, action.sourceId)
+    case 'RECEIVE_EVENTS': // raw
+      return receiveEvents(
+        eventStore,
+        sourceHash[action.sourceId],
+        action.fetchId,
+        action.fetchRange,
+        action.rawEvents,
+        calendar
+      )
 
     case 'MUTATE_EVENTS':
       return applyMutationToRelated(eventStore, action.instanceId, action.mutation, calendar)
 
-    case 'ADD_EVENTS':
-      return mergeEventStores(eventStore, action.eventStore)
-
     case 'REMOVE_EVENTS':
-      return excludeEventInstances(eventStore, action.eventStore)
+      return excludeInstances(eventStore, action.eventStore)
+
+    case 'REMOVE_EVENT_SOURCES':
+      if (action.sourceIds) {
+        return excludeSources(eventStore, action.sourceIds)
+      } else {
+        return excludeNonSticky(eventStore)
+      }
 
     default:
       return eventStore
   }
 }
 
-function excludeEventInstances(eventStore: EventStore, removals: EventStore): EventStore {
+function receiveEvents(
+  eventStore: EventStore,
+  eventSource: EventSource,
+  fetchId: string,
+  fetchRange: DateRange,
+  rawEvents: EventInput[],
+  calendar: Calendar
+): EventStore {
+  if (fetchId === eventSource.latestFetchId) { // TODO: wish this logic was always in event-sources
+
+    rawEvents = rawEvents.map(function(rawEvent: EventInput) {
+      return eventSource.eventDataTransform(rawEvent) || rawEvent
+    })
+
+    return parseEventStore(
+      rawEvents,
+      eventSource.sourceId,
+      fetchRange,
+      calendar,
+      excludeSources(eventStore, [ eventSource.sourceId ]) // dest
+    )
+  }
+
+  return eventStore
+}
+
+function excludeInstances(eventStore: EventStore, removals: EventStore): EventStore {
   return {
     defs: eventStore.defs,
     instances: filterHash(eventStore.instances, function(instance: EventInstance) {
@@ -54,20 +76,33 @@ function excludeEventInstances(eventStore: EventStore, removals: EventStore): Ev
   }
 }
 
-function excludeSource(eventStore: EventStore, sourceId: string): EventStore {
+function excludeSources(eventStore: EventStore, sourceIds: string[]): EventStore {
+  let idHash = arrayToHash(sourceIds)
+
   return {
     defs: filterHash(eventStore.defs, function(def: EventDef) {
-      return def.sourceId !== sourceId
+      return idHash && !idHash[def.sourceId]
     }),
     instances: filterHash(eventStore.instances, function(instance: EventInstance) {
-      return eventStore.defs[instance.defId].sourceId !== sourceId
+      return idHash && !idHash[eventStore.defs[instance.defId].sourceId]
     })
   }
 }
 
-function applyMutationToRelated(eventStore: EventStore, instanceId: string, mutation: EventMutation, calendar: Calendar): EventStore {
-  let relatedStore = getRelatedEvents(eventStore, instanceId)
-  relatedStore = applyMutationToEventStore(relatedStore, mutation, calendar)
-  return mergeEventStores(eventStore, relatedStore)
+// sticky events don't have source IDs
+function excludeNonSticky(eventStore: EventStore): EventStore {
+  return {
+    defs: filterHash(eventStore.defs, function(def: EventDef) {
+      return !def.sourceId // keep sticky
+    }),
+    instances: filterHash(eventStore.instances, function(instance: EventInstance) {
+      return !eventStore.defs[instance.defId].sourceId // keep sticky
+    })
+  }
 }
 
+function applyMutationToRelated(eventStore: EventStore, instanceId: string, mutation: EventMutation, calendar: Calendar): EventStore {
+  let related = getRelatedEvents(eventStore, instanceId)
+  related = applyMutationToEventStore(related, mutation, calendar)
+  return mergeEventStores(eventStore, related)
+}

+ 20 - 23
src/reducers/main.ts

@@ -1,24 +1,21 @@
 import Calendar from '../Calendar'
-import { DateComponentRenderState } from '../component/DateComponent'
-import { EventSourceHash } from '../structs/event-source'
-import { reduceEventSourceHash } from './event-sources'
-import { reduceEventStore } from './event-store'
+import reduceEventSources from './event-sources'
+import reduceEventStore from './event-store'
 import { DateProfile } from '../DateProfileGenerator'
 import { DateSpan } from '../structs/date-span'
 import { EventInteractionState } from '../interactions/event-interaction-state'
+import { CalendarState, Action } from './types'
 
-export interface CalendarState extends DateComponentRenderState {
-  loadingLevel: number
-  eventSources: EventSourceHash
-}
-
-export function reduce(state: CalendarState, action: any, calendar: Calendar): CalendarState {
+export default function(state: CalendarState, action: Action, calendar: Calendar): CalendarState {
   calendar.trigger(action.type, action) // for testing hooks
 
+  let dateProfile = reduceDateProfile(state.dateProfile, action)
+  let eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendar)
+
   return {
-    dateProfile: reduceDateProfile(state.dateProfile, action),
-    eventSources: reduceEventSourceHash(state.eventSources, action, calendar),
-    eventStore: reduceEventStore(state.eventStore, action, calendar),
+    dateProfile,
+    eventSources,
+    eventStore: reduceEventStore(state.eventStore, action, eventSources, calendar),
     businessHoursDef: state.businessHoursDef, // TODO: rename?
     selection: reduceDateSelection(state.selection, action), // TODO: rename
     selectedEventInstanceId: reduceSelectedEvent(state.selectedEventInstanceId, action),
@@ -28,7 +25,7 @@ export function reduce(state: CalendarState, action: any, calendar: Calendar): C
   }
 }
 
-function reduceDateProfile(currentDateProfile: DateProfile, action: any) {
+function reduceDateProfile(currentDateProfile: DateProfile | null, action: Action) {
   switch (action.type) {
     case 'SET_DATE_PROFILE':
       return action.dateProfile
@@ -37,7 +34,7 @@ function reduceDateProfile(currentDateProfile: DateProfile, action: any) {
   }
 }
 
-function reduceDateSelection(currentSelection: DateSpan, action: any) {
+function reduceDateSelection(currentSelection: DateSpan | null, action: Action) {
   switch (action.type) {
     case 'SELECT': // TODO: rename
       return action.selection
@@ -48,7 +45,7 @@ function reduceDateSelection(currentSelection: DateSpan, action: any) {
   }
 }
 
-function reduceSelectedEvent(currentInstanceId: string, action: any): string {
+function reduceSelectedEvent(currentInstanceId: string, action: Action): string {
   switch (action.type) {
     case 'SELECT_EVENT':
       return action.eventInstanceId
@@ -59,7 +56,7 @@ function reduceSelectedEvent(currentInstanceId: string, action: any): string {
   }
 }
 
-function reduceDrag(currentDrag: EventInteractionState, action: any) {
+function reduceDrag(currentDrag: EventInteractionState | null, action: Action) {
   switch (action.type) {
     case 'SET_DRAG':
       return action.dragState
@@ -70,7 +67,7 @@ function reduceDrag(currentDrag: EventInteractionState, action: any) {
   }
 }
 
-function reduceEventResize(currentEventResize: EventInteractionState, action: any) {
+function reduceEventResize(currentEventResize: EventInteractionState | null, action: Action) {
   switch (action.type) {
     case 'SET_EVENT_RESIZE':
       return action.eventResizeState
@@ -81,12 +78,12 @@ function reduceEventResize(currentEventResize: EventInteractionState, action: an
   }
 }
 
-function reduceLoadingLevel(level: number, action): number {
+function reduceLoadingLevel(level: number, action: Action): number {
   switch (action.type) {
-    case 'FETCH_EVENT_SOURCE':
-      return level + 1
-    case 'RECEIVE_EVENT_SOURCE':
-    case 'ERROR_EVENT_SOURCE':
+    case 'FETCH_EVENT_SOURCES':
+      return level + action.sourceIds.length
+    case 'RECEIVE_EVENTS':
+    case 'RECEIVE_EVENT_ERROR':
       return level - 1
     default:
       return level

+ 45 - 0
src/reducers/types.ts

@@ -0,0 +1,45 @@
+import { EventInput } from '../structs/event'
+import { DateRange } from '../datelib/date-range'
+import { EventStore } from '../structs/event-store'
+import { EventMutation } from '../structs/event-mutation'
+import { DateComponentRenderState } from '../component/DateComponent'
+import { EventSource, EventSourceHash } from '../structs/event-source'
+import { DateProfile } from '../DateProfileGenerator'
+import { EventInteractionState } from '../interactions/event-interaction-state'
+import { DateSpan } from '../structs/date-span'
+
+export interface CalendarState extends DateComponentRenderState {
+  loadingLevel: number
+  eventSources: EventSourceHash
+}
+
+export interface SimpleError {
+  message: string
+}
+
+export type Action =
+
+  { type: 'SET_DATE_PROFILE', dateProfile: DateProfile  } |
+
+  { type: 'SELECT', selection: DateSpan } |
+  { type: 'UNSELECT' } |
+
+  { type: 'SELECT_EVENT', eventInstanceId: string } |
+  { type: 'CLEAR_SELECTED_EVENT' } |
+
+  { type: 'SET_DRAG', dragState: EventInteractionState } |
+  { type: 'CLEAR_DRAG' } |
+
+  { type: 'SET_EVENT_RESIZE', eventResizeState: EventInteractionState } |
+  { type: 'CLEAR_EVENT_RESIZE' } |
+
+  { type: 'ADD_EVENT_SOURCES', sources: EventSource[] } |
+  { type: 'REMOVE_EVENT_SOURCES', sourceIds?: string[] } | // if no sourceIds, remove all
+  { type: 'FETCH_EVENT_SOURCES', sourceIds?: string[] } | // if no sourceIds, fetch all
+
+  { type: 'RECEIVE_EVENTS', sourceId: string, fetchId: string, fetchRange: DateRange, rawEvents: EventInput[] } |
+  { type: 'RECEIVE_EVENT_ERROR', sourceId: string, fetchId: string, fetchRange: DateRange, error: SimpleError } |
+
+  { type: 'ADD_EVENTS', eventStore: EventStore, stick: boolean } | // TODO: use stick param
+  { type: 'MUTATE_EVENTS', instanceId: string, mutation: EventMutation } |
+  { type: 'REMOVE_EVENTS', eventStore: EventStore }