Below I create a function called promiseRipple takes in a object literal whose values are functions. Each function can contain synchronous code or an asynchronous promise.
var _ = require('lodash')
var Promise = require('bluebird')
function promiseRipple (start, props) {
  props = (props) ? props : start
  start = (props) ? start : {}
  props = _.mapValues(props, function (prop, key) {
    prop.key = key
    return prop
  })
  return Promise.reduce(_.values(props), function (result, action) {
    if (typeof action !== 'function') throw new Error('property values must be functions')
    return Promise.resolve(action(start)).then(function (value) {
      start[action.key] = value
      return value
    })
  }, null)
  .then(function () {
    return start
  })
}
Here's the basic usage
promiseRipple({zero: 'zero'}, {
  'alpha': function (data) {
    return Promise.resolve(data.zero + ' alpha') // async -> 'zero alpha'
  },
  'beta': function (data) {
    return data.zero + ' beta' // -> 'zero beta'
  },
  'gamma': function (data) {
    return Promise.resolve(data.zero + ' gamma') // async -> 'zero gamma'
  },
  'delta': function (data) {
    return Promise.resolve(data.zero + data.alpha + ' delta') // async -> 'zerozero alpha delta'
  },
}).then(function (results){
  // results -> {
  //   zero: 'zero',
  //   alpha: 'zero alpha',
  //   beta: 'zero beta',
  //   gamma: 'zero gamma',
  //   delta: 'zerozero alpha delta' 
  // }
})
I wanted to add in some functionalty to make is so whenever data was returned within a function, the new data propeties would be extended to the existing.
promiseRipple({zero: 'zero'}, {
  'alpha': function (data) {
    return Promise.resolve(data.zero + ' alpha') // async -> 'zero alpha'
  },
  'beta': function (data) {
    data.foo = data.zero + ' foo' // -> 'zero foo'
    data.bar = data.zero + ' bar' // -> 'zero bar'
    return data
  },
  'gamma': function (data) {
    return Promise.resolve(data.zero + ' gamma') // async -> 'zero gamma'
  },
  'delta': function (data) {
    return Promise.resolve(data.zero + data.alpha + ' delta') // async -> 'zerozero alpha delta'
  },
}).then(function (results){
  // results -> {
  //   zero: 'zero',
  //   alpha: 'zero alpha',
  //   foo: 'zero foo',
  //   bar: 'zero bar',
  //   gamma: 'zero gamma',
  //   delta: 'zerozero alpha delta' 
  // }
})
I tried to make a custom object literal that would allow for me to detect if the returned value from the prop function was data or some new variable. However this does not work.
var _ = require('lodash')
var Promise = require('bluebird')
function Start (data) {
  if (data) return data
  return {}
}
Start.prototype = Object.prototype
function promiseRipple (start, props) {
  props = (props) ? props : start
  start = (props) ? new Start(start) : new Start()
  props = _.mapValues(props, function (prop, key) {
    prop.key = key
    return prop
  })
  return Promise.reduce(_.values(props), function (result, action) {
    if (typeof action !== 'function') throw new Error('property values must be functions')
    return Promise.resolve(action(start)).then(function (value) {
      console.log(value instanceof Start)
      if (value instanceof Start) {
        _.extend(start, value)
        return start
      } else {
        start[action.key] = value
        return value
      }
    })
  }, null)
  .then(function () {
    return start
  })
}
module.exports = promiseRipple
What is a good way to detect if the object returned is the same object that we started out with, without messing with the value of the object?