Home Reference Source Repository

lib/index.js

import { assert } from 'chai'
import { createAction } from 'redux-actions'

/**
 * Creates an action blueprint. Allows delayed assignment of action type which is useful for library designers requiring namespaced action types.
 * @example <caption>Create an action blueprint then translate it to get its action creator at a later time.</caption>
 * const createActionType = blueprintType => `SOME_REDUX_LIB_${blueprintType}`
 * let blueprint = createBlueprint('MOUSE_EVENT', (x, y) => ({x, y}), eventType => ({ eventType }))
 * let actionCreator = blueprint(createActionType)
 * @param  {String}   blueprintType  The name of the action (will be constructed at later time to get action type.)
 * @param  {Function} payloadCreator Function that accepts action args and returns a FSA action payload.
 * @param  {Function} metaCreator    Function that accepts action args and returns a FSA meta payload.
 * @return {Function}                An action blueprint function that accepts an action type creator function as param to return an action creator.
 */
export const createBlueprint = (blueprintType, payloadCreator = args => args, metaCreator = args => args) => translateBlueprintType => {
  return createAction(translateBlueprintType(blueprintType), args => payloadCreator(args), args => metaCreator(args))
}



/**
 * Creates a translator that turns blueprint types into action types.
 * @param  {Function} translateBlueprintType  Function that accepts an action name and returns an action type.
 * @return {blueprintTypeTranslator}          Function that accepts array or object of blueprint type values and returns action types.
 */
export const translateBlueprintTypesWith = translateBlueprintType => blueprintTypes => {
  assert.ok(blueprintTypes, 'blueprint types are required')
  if(Array.isArray(blueprintTypes))
    return blueprintTypes.map(x => translateBlueprintType(x))
  assert(typeof blueprintTypes === 'object', 'blueprint types must be array or object')
  return Object.keys(blueprintTypes).reduce((actionTypes, x) => {
    actionTypes[x] = translateBlueprintType(blueprintTypes[x])
    return actionTypes
  }, {})
}


/**
 * Creates a translator that turns blueprints into redux-actions FSA actionCreators
 * @example <caption>Creates a function that can translate an array or object literal with blueprint values to actions.</caption>
 * const translateBlueprintType = blueprintType => `SOME_REDUX_LIB_${blueprintType}`
 * const translateBlueprints = translateBlueprintsWith(translateBlueprintType)
 * let startBlueprint = createBlueprint('START')
 * let endBlueprint = createBlueprint('END')
 * let { startAction, endAction } = translateBlueprints({ startAction: startBlueprint, endAction: endBlueprint })
 * dispatch(startAction())
 * @param  {Function} translateBlueprintType  Function that accepts an action name and returns an action type.
 * @return {blueprintTranslator}              Function that accepts array or object of blueprint values and returns redux-actions FSA actionCreators.
 */
export const translateBlueprintsWith = translateBlueprintType => blueprints => {
  assert.ok(blueprints, 'blueprints are required')
  if(Array.isArray(blueprints))
    return blueprints.map(x => blueprint(translateBlueprintType))
  assert(typeof blueprints === 'object', 'blueprints must be array or object')
  return Object.keys(blueprints).reduce((actionCreators, x) => {
    actionCreators[x] = blueprints[x](translateBlueprintType)
    return actionCreators
  }, {})
}