-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexec.mjs
72 lines (48 loc) · 1.38 KB
/
exec.mjs
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
import _debug from './debug.mjs'
import curry from './curry.mjs'
import isNil from './is-nil.mjs'
const debug = _debug.extend('reviver')
class SendScriptError extends Error {};
class RefError extends SendScriptError {};
const exec = curry(async (env, expression) => {
debug('exec', expression)
return JSON.parse(expression, reviver(env))
})
const reviver = env => async (key, value) => {
debug(key, await (Array.isArray(await value) ? Promise.all(value) : value))
value = await value
if (isNil(value)) return value
// Await all values for all objects properties
if (!Array.isArray(value)) {
if (typeof value !== 'object') return value
const keys = Object.keys(value)
return keys.reduce(async (_, key) => {
value[key] = await value[key]
return value
}, value)
}
const [operator, ...rest] = await Promise.all(value)
if (operator === 'await') {
const [awaited] = rest
return await awaited
}
if (Array.isArray(operator) && operator[0] === 'quote') {
const [, quoted] = operator
return [quoted, ...rest]
}
if (operator === 'call') {
const [fn, args] = rest
return fn(...args)
}
if (operator === 'ref') {
const [name] = rest
if (Object.hasOwn(env, name)) return env[name]
throw new RefError({ key, value })
}
return Promise.all(value)
}
export {
SendScriptError,
RefError
}
export default exec