import { Store , Action , ActionTree , ActionContext } from 'vuex' ; export type ActionHandler < S , R > = ( injectee : ActionContext < S , R > , payload : any ) => any ; export type ActionHandlerTransform < S , R > = ( handler : ActionHandler < S , R > , key : string ) => ActionHandler < S , R > ; export interface ActionObject < S , R > { root ? : boolean ; handler : ActionHandler < S , R > ; } export interface ActionCache < S , R > { getKey : ( injectee : ActionContext < S , R > , payload : any ) => any ; action : Action < S , R > ; onFree ? : ( result : any ) => any ; } export interface ActionCaches < S , R > { [ key ] : ActionCache < S , R > ; } export interface ActionResultCache < S , R > { getKey ? : ( injectee : ActionContext < S , R > , payload : any ) => any ; getResultKey : ( injectee : ActionContext < S , R > , payload : any ) => any ; action : Action < S , R > ; onFree ? : ( result : any ) => any ; } export interface ActionResultCaches < S , R > { [ key ] : ActionResultCache < S , R > ; } export interface ActionCacheConditional < S , R > { isInvalid : ( injectee : ActionContext < S , R > , payload : any ) => any ; action : Action < S , R > ; onFree ? : ( result : any ) => any ; } export interface ActionCacheConditionals < S , R > { [ key ] : ActionCacheConditional < S , R > ; } export type ActionRouteOtherwise = ( to , from , rejectReason , store , action ) => any ; export type ActionRouteName = string ; export type ActionRouteNameCallback = ( to , from , store ) => string ; export type ActionRouteNameInput = ActionRouteName | ActionRouteNameCallback ; export type ActionLoadingHandler < S , R > = ( injectee : ActionContext < S , R > , loading : boolean ) => any ; export type ActionLoadingInput < S , R > = string | ActionLoadingHandler < S , R > ; export interface ActionsPluginOptions extends ActionsWatchOptions { createCacheKey ( input ) : string ; } export interface ActionsWatchOptions { onActionStart < S , R > ( action , num , injectee , payload ) ; onActionReject < S , R > ( action , num , injectee , payload , reason ) ; onActionResolve < S , R > ( action , num , injectee , payload , resolved ) ; onActionEnd < S , R > ( action , num , injectee , payload , result , resolved ) ; onActionsDone < S , R > ( injectee ) ; } export interface ActionsCacheOptions { createCacheKey ( input ) : string ; } export type ActionsCacheDestroyer = ( ) => any ; const ASSERT_STORE = 'VuexRouterActions must be passed as a plugin to one store' ; const ASSERT_IS_INVALID = 'Cached action isInvalid must be a function.' ; const ASSERT_GET_KEY = 'Cached action getKey must be a function.' ; const ASSERT_GET_RESULT_KEY = 'Cached action getResultKey must be a function.' ; const ASSERT_ACTION_INVALID = 'An action passed is not a valid Vuex action.' ; const DEFAULT_OTHERWISE = ( to , from , rejectReason ) => false ; let defaultStore ; let store ; let options = actionsDefaultOptions ( ) ; let actionNum = 0 ; let actionDone = 0 ; let cacheDestroyers = [ ] ; param _options export default function ( _options ? ) { parseWatchOptions ( options , options , _options ) ; parseCacheOptions ( options , options , _options ) ; return function ( _store ) { assert ( store === undefined , ASSERT_STORE ) ; store = _store ; } ; } /**
 * Destroys the plugin so it can be added to another store. This should only
 * be used for testing purposes.
 */ export function actionsDestroy ( ) { store = defaultStore ; options = actionsDefaultOptions ( ) ; actionNum = 0 ; actionDone = 0 ; actionsDestroyCache ( ) ; } /**
 * Generates the default options for the plugin.
 */ export function actionsDefaultOptions ( ) { return { onActionStart : ( ) => { } , onActionReject : ( ) => { } , onActionResolve : ( ) => { } , onActionEnd : ( ) => { } , onActionsDone : ( ) => { } , createCacheKey : ( input ) => JSON . stringify ( input ) } ; } /**
 * This function destroys all caches created with `actionsCached`,
 * `actionsCachedConditional`, and `actionsCachedResults`. This is a necessary
 * function when you are implementing something like a Sign Out function in
 * your app.
 */ export function actionsDestroyCache ( ) { cacheDestroyers . forEach ( d => d ( ) ) ; cacheDestroyers = [ ] ; } param actionInput param getOtherwise export function actionBeforeRoute ( actionInput , getOtherwise = DEFAULT_OTHERWISE ) { const dispatch = ( to , from , next ) => { assert ( store !== undefined , ASSERT_STORE ) ; const action = toAction ( actionInput , to , from ) ; store . dispatch ( action , { to , from } ) . then ( ( resolved ) => { next ( ) ; } , ( reason ) => { next ( getOtherwise ( to , from , reason , store , action ) ) ; } ) ; } ; return { beforeRouteEnter : dispatch , beforeRouteUpdate : dispatch } ; } param actionInput param waitForFinish export function actionBeforeLeave ( actionInput , waitForFinish = false ) { const dispatch = ( to , from , next ) => { assert ( store !== undefined , ASSERT_STORE ) ; const action = toAction ( actionInput , to , from ) ; const finish = ( ) => waitForFinish ? next ( ) : undefined ; store . dispatch ( action , { to , from } ) . then ( finish , finish ) ; if ( ! waitForFinish ) { next ( ) ; } } ; return { beforeRouteLeave : dispatch } ; } param promise param resolveOnReject returns export function actionOptional < T > ( promise , resolveOnReject = ( ) => null ) { return new Promise ( ( resolve , reject ) => { promise . then ( resolve , reason => resolve ( resolveOnReject ( ) ) ) ; } ) ; } param actions export function actionsCachedConditional < S = any > ( actions ) { return remap ( actions , action => actionCachedConditional ( action ) ) ; } param input export function actionCachedConditional < S = any > ( input ) { const { action , isInvalid , onFree } = input ; assert ( typeof isInvalid === 'function' , ASSERT_IS_INVALID ) ; let cachedResult = undefined ; const clearResult = ( ) => { if ( cachedResult !== undefined && onFree ) { onFree . call ( store , cachedResult ) ; } cachedResult = undefined ; } ; cacheDestroyers . push ( clearResult ) ; return actionTransform ( action , '' , handler => { return function ( context , payload ) { if ( cachedResult === undefined || isInvalid . call ( this , context , payload ) ) { clearResult ( ) ; cachedResult = handler . apply ( this , arguments ) ; } return cachedResult ; } ; } ) ; } param actions param cache export function actionsCached < S = any > ( actions , cache ? ) { const cacheOptions = parseCacheOptions ( { } , options , cache ) ; return remap ( actions , action => actionCached ( action , cacheOptions ) ) ; } param actions param cache export function actionCached < S = any > ( input , cache ? ) { const cacheOptions = parseCacheOptions ( { } , options , cache ) ; const { action , getKey , onFree } = input ; assert ( typeof getKey === 'function' , ASSERT_GET_KEY ) ; let cacheKey = undefined ; let cacheResults = undefined ; const clearResult = ( ) => { if ( cacheResults !== undefined && onFree ) { onFree . call ( store , cacheResults ) ; } cacheKey = undefined ; cacheResults = undefined ; } ; cacheDestroyers . push ( clearResult ) ; return actionTransform ( action , '' , handler => { return function ( context , payload ) { const key = cacheOptions . createCacheKey ( getKey . call ( this , context , payload ) ) ; if ( cacheKey === undefined || key !== cacheKey ) { clearResult ( ) ; cacheKey = key ; cacheResults = handler . apply ( this , arguments ) ; } return cacheResults ; } ; } ) ; } param actions param cache export function actionsCachedResults < S = any > ( actions , cache ? ) { const cacheOptions = parseCacheOptions ( { } , options , cache ) ; return remap ( actions , action => actionCachedResults ( action , cacheOptions ) ) ; } param actions param cache export function actionCachedResults < S = any > ( input , cache ? ) { const cacheOptions = parseCacheOptions ( { } , options , cache ) ; const { action , getKey , getResultKey , onFree } = input ; assert ( typeof getResultKey === 'function' , ASSERT_GET_RESULT_KEY ) ; let cachedKey = undefined ; let cachedResults = Object . create ( null ) ; const clearResult = ( ) => { if ( onFree ) { for ( let resultKey in cachedResults ) { onFree . call ( store , cachedResults [ resultKey ] ) ; } } cachedKey = undefined ; cachedResults = Object . create ( null ) ; } ; cacheDestroyers . push ( clearResult ) ; return actionTransform ( action , '' , handler => { return function ( context , payload ) { const key = getKey ? cacheOptions . createCacheKey ( getKey . call ( this , context , payload ) ) : undefined ; if ( key !== cachedKey ) { clearResult ( ) ; cachedKey = key ; cachedResults = Object . create ( null ) ; } const resultKey = cacheOptions . createCacheKey ( getResultKey . call ( this , context , payload ) ) ; if ( ! ( resultKey in cachedResults ) ) { cachedResults [ resultKey ] = handler . apply ( this , arguments ) ; } return cachedResults [ resultKey ] ; } ; } ) ; } param actions param watch export function actionsWatch < S = any > ( actions , watch ? ) { const watchOptions = parseWatchOptions ( { } , options , watch ) ; const localDoneGiven = watch && watch . onActionsDone ; let localDone = 0 ; let localNum = 0 ; const addDone = ( ) => { if ( localDoneGiven ) return ++ localDone ; else return ++ actionDone ; } ; const getNum = ( ) => { if ( localDoneGiven ) return ++ localNum ; else return ++ actionNum ; } ; const checkDone = ( num , context ) => { if ( addDone ( ) === num ) { watchOptions . onActionsDone ( context ) ; } } ; return actionsTransform ( actions , ( action , key ) => { return function ( context , payload ) { const result = action . apply ( this , arguments ) ; const num = getNum ( ) ; if ( result instanceof Promise ) { watchOptions . onActionStart ( key , num , context , payload ) ; result . then ( ( resolved ) => { watchOptions . onActionResolve ( key , num , context , payload , resolved ) ; watchOptions . onActionEnd ( key , num , context , payload , resolved , true ) ; checkDone ( num , context ) ; } , ( reason ) => { watchOptions . onActionReject ( key , num , context , payload , reason ) ; watchOptions . onActionEnd ( key , num , context , payload , reason , false ) ; checkDone ( num , context ) ; } ) ; } else { watchOptions . onActionStart ( key , num , context , payload ) ; watchOptions . onActionEnd ( key , num , context , payload , result , true ) ; checkDone ( num , context ) ; } return result ; } ; } ) ; } param actions export function actionsProtect < S = any > ( actions ) { return actionsTransform ( actions , action => { return function ( context , payload ) { const result = action . apply ( this , arguments ) ; return toPromise ( result ) ; } ; } ) ; } param mutation param actions export function actionsLoading < S = any > ( input , actions ) { let loadingCount = 0 ; let loading = false ; const start = ( ) => { loadingCount ++ ; } ; const end = ( context ) => { return ( ) => { loadingCount -- ; check ( context ) ; } ; } ; const check = ( context ) => { let loadingNow = loadingCount > 0 ; if ( loadingNow !== loading ) { assert ( store !== undefined , ASSERT_STORE ) ; loading = loadingNow ; if ( isActionLoadingMutation ( input ) ) { store . commit ( input , loading ) ; } else if ( isActionLoadingHandler ( input ) ) { input ( context , loading ) ; } } } ; return actionsTransform ( actions , ( action ) => { return function ( context , payload ) { const result = action . apply ( this , arguments ) ; if ( result instanceof Promise ) { const ender = end ( context ) ; start ( ) ; result . then ( ender , ender ) ; check ( context ) ; } return result ; } ; } ) ; } function parseWatchOptions ( out , defaults , input ? ) { if ( input ) { out . onActionStart = input . onActionStart || defaults . onActionStart ; out . onActionReject = input . onActionReject || defaults . onActionReject ; out . onActionResolve = input . onActionResolve || defaults . onActionResolve ; out . onActionEnd = input . onActionEnd || defaults . onActionEnd ; out . onActionsDone = input . onActionsDone || defaults . onActionsDone ; return out as ActionsWatchOptions ; } return defaults ; } function parseCacheOptions ( out , defaults , input ? ) { if ( input ) { out . createCacheKey = input . createCacheKey || defaults . createCacheKey ; return out as ActionsCacheOptions ; } return defaults ; } function actionsTransform < S = any > ( actions , getHandler ) { return remap ( actions , ( action , key ) => actionTransform ( action , key , getHandler ) ) ; } function actionTransform < S = any > ( action , key , getHandler ) { if ( isActionHandler ( action ) ) { return getHandler ( action , key ) ; } else if ( isActionObject ( action ) ) { return { root : action . root , handler : getHandler ( action . handler , key ) } ; } throw ASSERT_ACTION_INVALID ; } function toAction ( action , to , from ) { if ( typeof action === 'string' ) { return action ; } else if ( typeof action === 'function' ) { return action ( to , from , store ) ; } throw 'Invalid action name or function.' ; } function toPromise < T > ( x ) { return x instanceof Promise ? x : ( x ? Promise . resolve ( x ) : Promise . reject ( x ) ) ; } function isActionHandler < S , R > ( x ) { return typeof x === 'function' ; } function isActionObject < S , R > ( x ) { return typeof x === 'object' && typeof x . handler === 'function' ; } function isActionLoadingMutation ( x ) { return typeof x === 'string' ; } function isActionLoadingHandler < S , R > ( x ) { return typeof x === 'function' ; } function remap < S , E > ( map , mapper ) { const remapped = Object . create ( null ) ; for ( let key in map ) { remapped [ key ] = mapper ( map [ key ] , key ) ; } return remapped ; } function assert ( expectation , message ) { if ( ! expectation ) throw message ; } function assertAction ( x , message ) { assert ( isActionHandler ( x ) || isActionObject ( x ) , message ) ; }