/
flow.ts
90 lines (84 loc) · 3.74 KB
/
flow.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { action } from "./action"
let generatorId = 0
// non-decorator forms
export function flow<R>(generator: () => IterableIterator<any>): () => Promise<R>
export function flow<A1>(generator: (a1: A1) => IterableIterator<any>): (a1: A1) => Promise<any> // Ideally we want to have R instead of Any, but cannot specify R without specifying A1 etc... 'any' as result is better then not specifying request args
export function flow<A1, A2, A3, A4, A5, A6, A7, A8>(
generator: (
a1: A1,
a2: A2,
a3: A3,
a4: A4,
a5: A5,
a6: A6,
a7: A7,
a8: A8
) => IterableIterator<any>
): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8) => Promise<any>
export function flow<A1, A2, A3, A4, A5, A6, A7>(
generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7) => IterableIterator<any>
): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7) => Promise<any>
export function flow<A1, A2, A3, A4, A5, A6>(
generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => IterableIterator<any>
): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => Promise<any>
export function flow<A1, A2, A3, A4, A5>(
generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => IterableIterator<any>
): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => Promise<any>
export function flow<A1, A2, A3, A4>(
generator: (a1: A1, a2: A2, a3: A3, a4: A4) => IterableIterator<any>
): (a1: A1, a2: A2, a3: A3, a4: A4) => Promise<any>
export function flow<A1, A2, A3>(
generator: (a1: A1, a2: A2, a3: A3) => IterableIterator<any>
): (a1: A1, a2: A2, a3: A3) => Promise<any>
export function flow<A1, A2>(
generator: (a1: A1, a2: A2) => IterableIterator<any>
): (a1: A1, a2: A2) => Promise<any>
export function flow<A1>(generator: (a1: A1) => IterableIterator<any>): (a1: A1) => Promise<any>
export function flow(generator: Function) {
if (arguments.length !== 1)
fail(process.env.NODE_ENV && `Flow expects one 1 argument and cannot be used as decorator`)
const name = generator.name || "<unnamed flow>"
// Implementation based on https://github.com/tj/co/blob/master/index.js
return function() {
const ctx = this
const args = arguments
return new Promise(function(resolve, reject) {
const runId = ++generatorId
let stepId = 0
const gen = action(`${name} - runid: ${runId} - init`, generator).apply(ctx, args)
onFulfilled(undefined) // kick off the process
function onFulfilled(res: any) {
let ret
try {
ret = action(`${name} - runid: ${runId} - yield ${stepId++}`, gen.next).call(
gen,
res
)
} catch (e) {
return reject(e)
}
next(ret)
return null
}
function onRejected(err: any) {
let ret
try {
ret = action(`${name} - runid: ${runId} - yield ${stepId++}`, gen.throw).call(
gen,
err
)
} catch (e) {
return reject(e)
}
next(ret)
}
function next(ret: any) {
if (ret.done) return resolve(ret.value)
// TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100
if (!ret.value || typeof ret.value.then !== "function")
fail("Only promises can be yielded to asyncAction, got: " + ret)
return ret.value.then(onFulfilled, onRejected)
}
})
}
}