Skip to content

Instantly share code, notes, and snippets.

@marbemac
Created July 12, 2015 18:08
Show Gist options
  • Save marbemac/27ee149aa5a50ce82823 to your computer and use it in GitHub Desktop.
Save marbemac/27ee149aa5a50ce82823 to your computer and use it in GitHub Desktop.
Signals implementation
const runAction = (name, action, commonArgs, args) => {
console.log(`signals:${name}:${action.name}`, {action: action, commonArgs: commonArgs, args: args})
try {
return action(commonArgs, args)
} catch(e) {
console.error(`Error running ${action.name} action for the ${name} signal.`,
{action: action, err: e, commonArgs: commonArgs, args: args})
return Promise.reject(e)
}
}
const handleAction = (name, actions, counter, path, commonArgs, args, rejectTriggered) => {
let actionChain = actions.slice(counter)
if (typeof actionChain[0] === 'object') {
console.log(`signals:${name}:${path.toUpperCase()}`, rejectTriggered)
if (!actionChain[0][path]) {
console.error(`You have a branching action chain for signal ${name}, but have not defined a ${path} branch!'`, {
actions: actions, counter: counter, chain: actionChain[0]})
}
const afterActions = actionChain[0].after
return runActions(name, actionChain[0][path], commonArgs, args, rejectTriggered).then(() => {
if (afterActions && afterActions.length > 0) {
return runActions(name, afterActions, commonArgs, args, rejectTriggered)
}
}, () => {
if (afterActions && afterActions.length > 0) {
return runActions(name, afterActions, commonArgs, args, rejectTriggered)
}
})
} else {
return runActions(name, actionChain, commonArgs, args, rejectTriggered)
}
}
const runActions = (name, actions, commonArgs, args, rejectTriggered) => {
rejectTriggered = rejectTriggered || false
let counter = 0
for (let i in actions) {
counter += 1
if (actions[i] === undefined) {
let extra = ''
if (counter === 1 && actions.length > 1) {
extra = `, right before the ${actions[counter].name} action`
} else if (counter > 1) {
extra = `, right after the ${actions[counter - 1].name} action`
}
console.error(`You have an undefined action in your ${name} signal${extra}.'`, {actions: actions, counter: counter})
continue
}
let run = runAction(name, actions[i], commonArgs, args)
if (run instanceof Promise) {
return run.then((e) => {
return handleAction(name, actions, counter, 'resolve', commonArgs, args, rejectTriggered)
}).catch((e) => {
rejectTriggered = e
return handleAction(name, actions, counter, 'reject', commonArgs, args, rejectTriggered)
})
}
}
if (rejectTriggered) {
return Promise.reject()
} else {
return Promise.resolve()
}
}
const signalFactory = (obj = {}) => {
obj.signals = {}
// The new function requires at least two arguments.
// The first argument is the name of the action.
// Subsequent arguments are action functions, or chain objects.
//
// An action function has the signature action(commonArgs, args),
// and may return a promise.
//
// A chain object can follow an asyncronous action, and comes in the form
// {
// resolve: [action1, action2],
// reject: [action3],
// after: [action4, action5]
// }
//
// So a full call to .new would look like:
//
// signal.new('myCoolSignal',
// action1,
// ayncAction2,
// {
// resolve: [
// action3,
// asyncAction4,
// {
// resolve: [action6],
// reject: [action5]
// }
// ],
// reject: [action5],
// after: [finishAction]
// }
// )
//
// One can then invoke this signal via signals.myCoolSignal({passed: 'args'})
obj.new = function() {
const args = [].slice.call(arguments)
const name = args[0]
const actions = args.slice(1)
const commonArgs = obj.commonArgs
commonArgs.signals = obj.signals
obj.signals[name] = function() {
console.log('signals', `Running signals ${name}`)
let passedArgs = [].slice.call(arguments)[0] || {}
return runActions(name, actions, commonArgs, passedArgs).then(() => {
// successful signal loop
}, () => {
// unsuccessful signal loop
})
}
}
return obj
}
export default signalFactory
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment