tunnckoCore / ideas

:notebook: My centralized place for ideas, thoughts and todos. Raw, PoC implementations and so on... :star:
http://j.mp/1stW47C
6 stars 0 forks source link

dush-actions - finished #85

Open tunnckoCore opened 7 years ago

tunnckoCore commented 7 years ago

Totally finished and crazy good!

module.exports = (options) => (app) => {
  app.actions = {}

  let { effects, reducers, state } = Object.assign({}, options)

  effects = Object.assign({}, effects)
  reducers = Object.assign({}, reducers)

  let STATE = (app.state = Object.assign({}, state))

  Object.keys(Object.assign({}, reducers, effects)).forEach((name) => {
    const action = createAction(app, name)

    // allow calling actions explicitly, instead of "emitting" them; e.g.
    // - app.actions.fooBar({ some: 'data' })
    app.actions[name] = action

    // and the "emitting" style
    // - app.emit('fooBar', { some: 'data' })
    app.on(name, action)
  })

  return app

  function createAction (app, name) {
    return function action (...args) {
      app.emit('action', name, ...args)

      // merge `actions` into `emit` function
      // so THE TWO style are allowed:
      // - (actions, data, foo, arg3) -> actions.fooBar({ some: 'hi ' + data.name })
      // - (emit, str, abc, arg3) -> emit('fooBar', { some: 'data' + str })

      if (effects[name]) {
        return Promise.resolve()
          .then(() => {
            app.emit('effect', name, ...args)
            return effects[name]({ actions: app.actions }, ...args)
          })
          .catch((er) => app.emit('error', er))
      }

      app.emit('reducer', name, ...args)

      const oldState = Object.assign({}, STATE)
      const context = { state: oldState, actions: app.actions }
      let partialState = null

      try {
        // (actions, state, ...args)
        // (emit, state, ...args)
        partialState = reducers[name](context, ...args)
      } catch (er) {
        app.emit('error', er)
        return // ? or return the state?
      }

      const newState = Object.assign({}, oldState, partialState)
      STATE = app.state = newState

      // (currentState, oldState, partialState)
      app.emit('stateUpdate', STATE, oldState, partialState)
      return STATE
    }
  }
}
tunnckoCore commented 7 years ago

example

const dush = require('dush')

const app = dush().use(
  actionsPlugin({
    state: {
      text: 'Hello',
      name: 'Charlike'
    },
    effects: {
      changeBoth: function ({ actions }, data, arg2) {
        actions.changeText({ welcome: data.text })
        actions.changeName(data.name, arg2)
      }
    },
    reducers: {
      changeText: ({ emit, state }, data) => ({ text: data.welcome }),
      changeName: ({ actions, state }, name, arg2) => ({ name, arg2 })
    }
  })
)

app.on('error', (er) => console.error('ER!', er))
app.on('action', (name) => console.log('action:', name))
app.on('stateUpdate', (state, prev, partial) => {
  console.log('state:', state)
  console.log('prev:', prev)
  console.log('partial:', partial)
  console.log('====')
})

app.actions.changeBoth({ text: 'Landing!', name: 'Jon Doe' })
// app.emit.changeBoth({ text: 'Landing!', name: 'Jon Doe' })
// app.emit('changeBoth', { text: 'Landing!', name: 'Jon Doe' })

// app.actions.changeName('Charlike Mike Regent', 'some arg2')
// app.emit.changeName('Charlike Mike Regent', 'some arg2')
// app.emit('changeName', 'Charlike Mike Regent', 'some arg2')

// app.actions.changeText({ welcome: 'Welcome here, buddy!' })
// app.emit.changeText({ welcome: 'Welcome here, buddy!' })
// app.emit('changeText', { welcome: 'Welcome here, buddy!' })