-
Notifications
You must be signed in to change notification settings - Fork 232
/
Copy pathindex.ts
85 lines (71 loc) · 2.29 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
75
76
77
78
79
80
81
82
83
84
85
import { CreateRenderer, Renderer, RenderResult, RenderHookOptions } from '../types'
import { asyncUtils } from './asyncUtils'
import { cleanup, addCleanup, removeCleanup } from './cleanup'
import { suppressErrorOutput } from './console'
function resultContainer<TValue>() {
const results: Array<{ value?: TValue; error?: Error }> = []
const resolvers: Array<() => void> = []
const result: RenderResult<TValue> = {
get all() {
return results.map(({ value, error }) => error ?? (value as TValue))
},
get current() {
const { value, error } = results[results.length - 1] ?? {}
if (error) {
throw error
}
return value as TValue
},
get error() {
const { error } = results[results.length - 1] ?? {}
return error
}
}
const updateResult = (value?: TValue, error?: Error) => {
results.push({ value, error })
resolvers.splice(0, resolvers.length).forEach((resolve) => resolve())
}
return {
result,
addResolver: (resolver: () => void) => {
resolvers.push(resolver)
},
setValue: (value: TValue) => updateResult(value),
setError: (error: Error) => updateResult(undefined, error)
}
}
function createRenderHook<
TProps,
TResult,
TRendererOptions extends object,
TRenderer extends Renderer<TProps>
>(createRenderer: CreateRenderer<TProps, TResult, TRendererOptions, TRenderer>) {
const renderHook = (
callback: (props: TProps) => TResult,
options = {} as RenderHookOptions<TProps> & TRendererOptions
) => {
const { result, setValue, setError, addResolver } = resultContainer<TResult>()
const renderProps = { callback, setValue, setError }
let hookProps = options.initialProps
const { render, rerender, unmount, act, ...renderUtils } = createRenderer(renderProps, options)
render(hookProps)
const rerenderHook = (newProps = hookProps) => {
hookProps = newProps
rerender(hookProps)
}
const unmountHook = () => {
removeCleanup(unmountHook)
unmount()
}
addCleanup(unmountHook)
return {
result,
rerender: rerenderHook,
unmount: unmountHook,
...asyncUtils(act, addResolver),
...renderUtils
}
}
return renderHook
}
export { createRenderHook, cleanup, addCleanup, removeCleanup, suppressErrorOutput }