<commit_before>import actionToPromise from './action-to-promise'
import PromiseSeries from './promise-series'
import Container from '../container'

import {Class, getDef, Factory, createGetter} from '../define'
import __debug from 'debug'

const debug = __debug('immutable-di:dispatcher')

export default class Dispatcher {
    constructor({stores, state, container}) {
        this._container = container || new Container({state})
        this._series = new PromiseSeries()
        this._listeners = []
        this._stores = []
        this._storeIds = []

        this.setStores = this.setStores.bind(this)
        this.dispatch = this.dispatch.bind(this)
        this.mount = this.mount.bind(this)
        this.unmount = this.unmount.bind(this)
        this.dispatchAsync = this.dispatchAsync.bind(this)

        if (stores) {
            this.setStores(stores)
        }
    }

    setStores(storeMap) {
        const stores = []
        const keys = this._storeIds = Object.keys(storeMap)
        for(let i = 0; i < keys.length; i++) {
            stores.push(storeMap[keys[i]])
        }
        this._stores = stores
        return this
    }

    dispatch(action, payload) {
        actionToPromise(action, payload)
            .forEach(p => this._series.add(() => p.then(this.dispatchAsync)))

        return this._series.promise
    }

    dispatchAsync({action, payload}) {
        const handler = ({index, id, get}) => this._stores[index].handle(get(id), action, payload)
        debug('dispatchAsync %s:%o', action, payload)
        const updatedScopes = this._container.transformState(p => this._stateTransformer(p, handler))
        return updatedScopes.length
            ? Promise.all(this._listeners.map(this._container.getSync))
            : false
    }

    mount(definition, listener) {
        const {id} = getDef(definition)
        this._listeners.push(Factory(listener, [definition], id + '__listener'))

        return listener
    }

    unmount(listenerDef) {
        this._listeners = this._listeners.filter(d => listenerDef !== d)
    }

    once(definition, resolve) {
        if (Array.isArray(definition) || typeof definition === 'object') {
            definition = createGetter(definition)
        }
        const {getter} = getDef(definition)
        const listenerDef = this.mount(getter, (...args) => {
            this.unmount(listenerDef)
            return resolve(...args)
        })

        return this
    }

    _stateTransformer({get, set}, getState) {
        return this._storeIds.filter((id, index) => {
            const state = getState({id, index, get})
            const isHandled = state !== undefined
            if (isHandled) {
                set(id, state)
            }
            return isHandled
        })
    }
}
Class(Dispatcher, {container: Container})
<commit_msg>dispatchAsync interface changed<commit_after>import actionToPromise from './action-to-promise'
import PromiseSeries from './promise-series'
import Container from '../container'

import {Class, getDef, Factory, createGetter} from '../define'
import __debug from 'debug'

const debug = __debug('immutable-di:dispatcher')

export default class Dispatcher {
    constructor({stores, state, container}) {
        this._container = container || new Container({state})
        this._series = new PromiseSeries()
        this._listeners = []
        this._stores = []
        this._storeIds = []

        this.setStores = this.setStores.bind(this)
        this.dispatch = this.dispatch.bind(this)
        this.mount = this.mount.bind(this)
        this.unmount = this.unmount.bind(this)
        this.dispatchAsync = this.dispatchAsync.bind(this)

        if (stores) {
            this.setStores(stores)
        }
    }

    setStores(storeMap) {
        const stores = []
        const keys = this._storeIds = Object.keys(storeMap)
        for(let i = 0; i < keys.length; i++) {
            stores.push(storeMap[keys[i]])
        }
        this._stores = stores
        return this
    }

    dispatch(action, payload) {
        actionToPromise(action, payload)
            .forEach(p => this._series.add(() => p.then(o => this.dispatchAsync(o.action, o.payload))))

        return this._series.promise
    }

    dispatchAsync(action, payload) {
        const handler = ({index, id, get}) => this._stores[index].handle(get(id), action, payload)
        debug('dispatchAsync %s:%o', action, payload)
        const updatedScopes = this._container.transformState(p => this._stateTransformer(p, handler))
        return updatedScopes.length
            ? Promise.all(this._listeners.map(this._container.getSync))
            : false
    }

    mount(definition, listener) {
        const {id} = getDef(definition)
        this._listeners.push(Factory(listener, [definition], id + '__listener'))

        return listener
    }

    unmount(listenerDef) {
        this._listeners = this._listeners.filter(d => listenerDef !== d)
    }

    once(definition, resolve) {
        if (Array.isArray(definition) || typeof definition === 'object') {
            definition = createGetter(definition)
        }
        const {getter} = getDef(definition)
        const listenerDef = this.mount(getter, (...args) => {
            this.unmount(listenerDef)
            return resolve(...args)
        })

        return this
    }

    _stateTransformer({get, set}, getState) {
        return this._storeIds.filter((id, index) => {
            const state = getState({id, index, get})
            const isHandled = state !== undefined
            if (isHandled) {
                set(id, state)
            }
            return isHandled
        })
    }
}
Class(Dispatcher, {container: Container})

{'fraction_non_alphanumeric': 0.12587535014005602, 'fraction_numerical': 0.00035014005602240897, 'mean_word_length': 2.3253783469150173, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 18, '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': '7211882', 'n_tokens_mistral': 1626, 'n_tokens_neox': 1597, 'n_words': 338}