Basically it's a super testable solution to callback hell.
npm i story# ornpm i --save story
Create the story
// stories/checkGithubStatus.jsimport callback from 'story'import get from 'http'export defaultlet statusCode = yield callbackget ''if statusCode >= 200 && statusCode < 300return 'up'elsereturn 'down'
Run the story
// index.jsimport story from 'story'import example from './stories/example'storycheckGithubStatusthenstatus => console.logstatus // "up"
Test the story
// test/example.jsimport call from 'story'import checkGithubStatus from '../stories/checkGithubStatus'import assert from 'assert'import get from 'http'let iterator = checkGithubStatus// Start the functionlet firstYield = iteratornext// Expect the first instruction to be a request to github.comassertdeepEqualfirstYieldvalue: callbackget ''done: false// Mock a 404 responselet secondYield = iteratornext statusCode: 404// Make sure the function returns "down"assertdeepEqualsecondYieldvalue: 'down'done: true
The API is pretty simple. There are two types of function containers,
poem. A story returns a promise, while a poem returns a generator. Both
support the same yieldables with the exception of
put, which only works inside
poem.wrap can be used to wrap a your function for later use
rather than executing it immediately.
Call a generator and return a promise which will resolve with your last
Convert a generator into a regular function that returns a promise which will
resolve with your last
return value. Use this if you want to use a
story more than once and/or you need to pass in arguments.
story, except returns a Generator instead of a Promise. You can
yield output with
yield put(value). Every time
next() is called on a poem it
will return with a promise that will resolve your next yielded
next() multiple times in a row without waiting for the yielded promise
to resolve will result in an error.
poem// Every second, poll github and see if it's still upwhile trueyield callsleep 1000let status = yield callcheckGithubStatusyield putstatus
poem but instead of executing the GeneratorFunction immediately,
returns another GeneratorFunction that wraps yours for later use.
Use these inside a story or poem to do cool stuff.
Yielding a promise will halt execution until it resolves, then return the resolved value.
You can yield an array or object of yieldables and they will be interpreted in
parallel. Nested arrays and objects are supported. Yielding an array of promises
is the same as yielding
Run a function with a callback and wait for it to complete. Assume a node-style (err, result) argument pair. If the first argument is an error, it will be thrown. Otherwise the second argument will be returned. You can use this to interface with any library that uses callbacks.
import story callback from 'story'import readdir from 'fs'story// List every file in the src directorylet files = yield callbackreaddir __dirnameconsole.logfiles // [index.js, package.json, ...]
Combine two or more streams into a pipeline, handle errors from any of them, and resolve when the final stream finishes.
import story pipe from 'story'import createReadStream createWriteStream from 'fs'import createGzip from 'zlib'story// gzip index.jsyield pipecreateReadStream'index.js'createGzipcreateWriteStream'index.js.gz'
Same as pipe, but does not end the final stream. Useful for combining files. You
will need to manually close your final stream by either calling
using piping something to it with
pipe instead of
import story pipe callback from 'story'import createReadStream createWriteStream from 'fs'storylet bundle = createWriteStream'bundle.js'yield pipeappendcreateReadStream'stuff.js' bundleyield pipeappendcreateReadStream'index.js' bundleyield callbackbundle bundleend
Calls the given function with the given arguments. If it returns a promise, waits for that promise to resolve. The result is returned.
import story call from 'story'storylet status = yield callcheckWebsiteStatus ''console.logstatus // "up"
Calls the given function in the given context with the given arguments. If it returns a promise, waits for that promise to resolve. The result is returned.
Exactly the same as call, but keeps the function bound to the required context.
import story apply from 'story'storylet myRocket =yield applymyRocket myRocketlaunch 'mars'
Only useful inside a poem, the put function yields a result that can be iterated over.
import poem put from 'story'poemlet i = 0while truei++yield callsleep 1000yield puti
Pull an item out of an iterator, and wait for it to resolve if it is a promise.
import story take from 'story'storylet timewhile time = yield takeclockconsole.logtime