<commit_before>import mapValues from 'lodash/object/mapValues';
import invariant from 'invariant';

// An action dispatched to init store state
const BOOTSTRAP_STORE = {
  type: 'BOOTSTRAP_STORE'
};

export default function createDispatcher() {
  const observers = {};
  const stores = {};
  const storeKeys = new Map();
  let currentState = {};

  // To compute the next state, combine the next states of every store
  function computeNextState(state, action) {
    return mapValues(stores,
      (store, key) => {
        const nextStoreState = store(state[key], action);
        invariant(
          nextStoreState != null,
          'State returned by %s is null or undefined.',
          key
        );
        return nextStoreState;
      }
    );
  }

  // Notify observers about the changed stores
  function emitChange(changedKeys) {
    if (!changedKeys.length) {
      return;
    }

    // Gather the affected observers
    const notifyObservers = [];
    changedKeys.forEach(key => {
      observers[key].forEach(o => {
        if (notifyObservers.indexOf(o) === -1) {
          notifyObservers.push(o);
        }
      });
    });

    // Emit change
    notifyObservers.forEach(o => o());
  }

  // Update state and emit change if needed
  function updateState(nextState) {
    // Swap the state
    const previousState = currentState;
    currentState = nextState;

    // Notify the observers
    const changedKeys = Object.keys(currentState).filter(key =>
      currentState[key] !== previousState[key]
    );
    emitChange(changedKeys);
  }

  // Reassign the current state on each dispatch
  function dispatch(action) {
    invariant(
      typeof action.type === 'string',
      'Action type must be a string.'
    );

    const nextState = computeNextState(currentState, action);
    updateState(nextState);
  }

  // Merge the newly added stores
  function receiveStores(nextStores) {
    Object.keys(nextStores).forEach(key => {
      stores[key] = nextStores[key];
      observers[key] = observers[key] || [];
      storeKeys[stores[key]] = key;
    });
    dispatch(BOOTSTRAP_STORE);
  }

  // Get the key a store was registered with
  function getStoreKey(store) {
    const key = storeKeys[store];
    invariant(key, 'This store is not registered with the Redux root: %s', store);
    return key;
  }

  // Provide subscription and unsubscription
  function observeStores(observedStores, onChange) {
    const observedKeys = observedStores.map(getStoreKey);

    // Emit the state update
    function handleChange() {
      onChange(currentState);
    }

    // Synchronously emit the initial value
    handleChange();

    // Register the observer for each relevant key
    observedKeys.forEach(key =>
      observers[key].push(handleChange)
    );<commit_msg>Correct ES6 map usage. Fixes #35<commit_after>import mapValues from 'lodash/object/mapValues';
import invariant from 'invariant';

// An action dispatched to init store state
const BOOTSTRAP_STORE = {
  type: 'BOOTSTRAP_STORE'
};

export default function createDispatcher() {
  const observers = {};
  const stores = {};
  const storeKeys = new Map();
  let currentState = {};

  // To compute the next state, combine the next states of every store
  function computeNextState(state, action) {
    return mapValues(stores,
      (store, key) => {
        const nextStoreState = store(state[key], action);
        invariant(
          nextStoreState != null,
          'State returned by %s is null or undefined.',
          key
        );
        return nextStoreState;
      }
    );
  }

  // Notify observers about the changed stores
  function emitChange(changedKeys) {
    if (!changedKeys.length) {
      return;
    }

    // Gather the affected observers
    const notifyObservers = [];
    changedKeys.forEach(key => {
      observers[key].forEach(o => {
        if (notifyObservers.indexOf(o) === -1) {
          notifyObservers.push(o);
        }
      });
    });

    // Emit change
    notifyObservers.forEach(o => o());
  }

  // Update state and emit change if needed
  function updateState(nextState) {
    // Swap the state
    const previousState = currentState;
    currentState = nextState;

    // Notify the observers
    const changedKeys = Object.keys(currentState).filter(key =>
      currentState[key] !== previousState[key]
    );
    emitChange(changedKeys);
  }

  // Reassign the current state on each dispatch
  function dispatch(action) {
    invariant(
      typeof action.type === 'string',
      'Action type must be a string.'
    );

    const nextState = computeNextState(currentState, action);
    updateState(nextState);
  }

  // Merge the newly added stores
  function receiveStores(nextStores) {
    Object.keys(nextStores).forEach(key => {
      storeKeys.delete(stores[key]);
      stores[key] = nextStores[key];
      observers[key] = observers[key] || [];
      storeKeys.set(stores[key], key);
    });
    dispatch(BOOTSTRAP_STORE);
  }

  // Get the key a store was registered with
  function getStoreKey(store) {
    const key = storeKeys.get(store);
    invariant(key, 'This store is not registered with the Redux root: %s', store);
    return key;
  }

  // Provide subscription and unsubscription
  function observeStores(observedStores, onChange) {
    const observedKeys = observedStores.map(getStoreKey);

    // Emit the state update
    function handleChange() {
      onChange(currentState);
    }

    // Synchronously emit the initial value
    handleChange();

    // Register the observer for each relevant key
    observedKeys.forEach(key =>
      observers[key].push(handleChange)
    );
{'fraction_non_alphanumeric': 0.10809852915116074, 'fraction_numerical': 0.000886053517632465, 'mean_word_length': 2.8342391304347827, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6055351', 'n_tokens_mistral': 1645, 'n_tokens_neox': 1600, 'n_words': 448}