forked from ccbabi/pea
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
74 lines (63 loc) · 1.82 KB
/
index.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
const fnPro = Function.prototype
const errs = ['e', 'err', 'error']
function fnHasError(fn: Function): boolean {
const matchs = fnPro.toString.call(fn).match(/\((\w+)/)
if (!matchs) return false
return errs.indexOf(matchs[1]) > -1
}
export default class Pea {
private __stack: Function[] = []
private __head = 0
private __tail = 0
constructor(beans?: Array<(...args: any[])=>void>)
constructor(beans?: Array<Pea>)
constructor(beans?: Array<((...args: any[])=>void)|Pea>) {
if (beans && beans instanceof Array) beans.forEach(bean => this.use((bean as Pea)))
}
use(bean: (...args: any[]) => void): Pea
use(bean: Pea): Pea
use(bean: ((...args: any[]) => void)|Pea): Pea {
let fn: Function
if (bean instanceof Pea) {
if ((bean as Pea) === this) return this
fn = (...args: any[]) => {
const pnext = args.pop()
bean.use((...args) => {
args.pop()
pnext.apply(this, args)
})
bean.use((e) => void pnext(e))
bean.start.apply(bean, args)
}
} else fn = bean
this.__tail = this.__stack.push(fn)
return this
}
start(...args: any[]): void {
this.__head = 0
this.__next.apply(this, args)
}
private __next(err?: Error, ...args: any[]): void {
this.__run.apply(this, arguments)
}
private __run(...args: any[]): void {
let bean, err
let first = args[0]
if (first instanceof Error) err = first
if (this.__head >= this.__tail) {
if (err) throw err
return
}
if (first == undefined && args.length) args.shift()
bean = this.__stack[this.__head++]
if ((err && fnHasError(bean)) || (!err && !fnHasError(bean))) {
args.push(this.__next.bind(this))
try {
return void bean.apply(this, args)
} catch (e) {
err = e
}
}
this.__next(err)
}
}