sendscript 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +42 -5
- package/CHANGELOG.md +15 -0
- package/README.md +7 -7
- package/README.mz +1 -1
- package/cli.mjs +3 -2
- package/error.mjs +1 -0
- package/example/typescript/docs/functions/add.md +1 -1
- package/example/typescript/docs/functions/square.md +1 -1
- package/index.test.mjs +82 -4
- package/package.json +1 -1
- package/parse.mjs +61 -83
- package/repl.mjs +2 -2
- package/stringify.mjs +12 -1
- package/.github/workflows/release.yml +0 -45
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: Publish
|
|
1
|
+
name: Release and Publish
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
@@ -6,20 +6,57 @@ on:
|
|
|
6
6
|
- '*'
|
|
7
7
|
|
|
8
8
|
permissions:
|
|
9
|
+
contents: write
|
|
9
10
|
id-token: write # Required for OIDC
|
|
10
|
-
contents: read
|
|
11
11
|
|
|
12
12
|
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
node: ['lts/*', 'latest']
|
|
18
|
+
fail-fast: true
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
|
|
23
|
+
- uses: actions/setup-node@v6
|
|
24
|
+
with:
|
|
25
|
+
node-version: ${{ matrix.node }}
|
|
26
|
+
cache: npm
|
|
27
|
+
|
|
28
|
+
- run: npm ci
|
|
29
|
+
- run: npm test
|
|
30
|
+
|
|
31
|
+
release:
|
|
32
|
+
needs: test
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v6
|
|
36
|
+
|
|
37
|
+
- uses: actions/setup-node@v6
|
|
38
|
+
with:
|
|
39
|
+
node-version: 'latest'
|
|
40
|
+
cache: npm
|
|
41
|
+
|
|
42
|
+
- run: npm ci
|
|
43
|
+
- name: Create GitHub Release
|
|
44
|
+
uses: softprops/action-gh-release@v2
|
|
45
|
+
with:
|
|
46
|
+
generate_release_notes: true
|
|
47
|
+
|
|
13
48
|
publish:
|
|
49
|
+
needs: test
|
|
14
50
|
runs-on: ubuntu-latest
|
|
15
51
|
steps:
|
|
16
52
|
- uses: actions/checkout@v6
|
|
17
53
|
|
|
18
54
|
- uses: actions/setup-node@v6
|
|
19
55
|
with:
|
|
20
|
-
node-version: '
|
|
56
|
+
node-version: 'latest'
|
|
57
|
+
cache: npm
|
|
21
58
|
registry-url: 'https://registry.npmjs.org'
|
|
59
|
+
|
|
22
60
|
- run: npm ci
|
|
23
|
-
- run: npm run build --if-present
|
|
24
61
|
- run: npm test
|
|
25
|
-
- run: npm publish
|
|
62
|
+
- run: npm publish
|
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,23 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### [v2.2.0](https://github.com/bas080/sendscript/compare/v2.1.0...v2.2.0)
|
|
8
|
+
|
|
9
|
+
- Have default leaf serializer throw if value has no JSON equivalant [`6752f2f`](https://github.com/bas080/sendscript/commit/6752f2f3ed51e252ab93a31b632fe8fbae51d7cb)
|
|
10
|
+
- Test that prototype chain works when parsing [`2cf0e7e`](https://github.com/bas080/sendscript/commit/2cf0e7e7ced32258102382e7ff1e3f8e91a2cc77)
|
|
11
|
+
|
|
12
|
+
#### [v2.1.0](https://github.com/bas080/sendscript/compare/v2.0.1...v2.1.0)
|
|
13
|
+
|
|
14
|
+
> 9 April 2026
|
|
15
|
+
|
|
16
|
+
- Make eval order when using await inline with JS [`00db8aa`](https://github.com/bas080/sendscript/commit/00db8aaa563378db814035e3e550269593ed82e2)
|
|
17
|
+
- Merge release workflow into publish [`6a5db12`](https://github.com/bas080/sendscript/commit/6a5db128b659dd295390505b2e470c5913617abf)
|
|
18
|
+
- Fix the cli repl [`3cf8b0d`](https://github.com/bas080/sendscript/commit/3cf8b0d9b4531989fb01a53fa9ab4cb6a011c183)
|
|
19
|
+
|
|
7
20
|
#### [v2.0.1](https://github.com/bas080/sendscript/compare/v2.0.0...v2.0.1)
|
|
8
21
|
|
|
22
|
+
> 8 April 2026
|
|
23
|
+
|
|
9
24
|
- Publish to npm on tag push [`357ac0e`](https://github.com/bas080/sendscript/commit/357ac0ef3384f294e4f9bb179d5a675afda5fd19)
|
|
10
25
|
|
|
11
26
|
### [v2.0.0](https://github.com/bas080/sendscript/compare/v1.1.0...v2.0.0)
|
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ composition and even await.
|
|
|
92
92
|
This package is nothing more than the absolute core of sendscript. It
|
|
93
93
|
includes:
|
|
94
94
|
|
|
95
|
-
- The `
|
|
95
|
+
- The `references` function to create stubs to write the programs.
|
|
96
96
|
- `stringify` which takes the program and returns a JSON string.
|
|
97
97
|
- `parse` which takes the `stringify` JSON string and a real module and returns the result.
|
|
98
98
|
|
|
@@ -429,19 +429,19 @@ npm t -- report text-summary
|
|
|
429
429
|
```
|
|
430
430
|
```
|
|
431
431
|
|
|
432
|
-
> sendscript@2.0
|
|
432
|
+
> sendscript@2.2.0 test
|
|
433
433
|
> tap -R silent
|
|
434
434
|
|
|
435
435
|
|
|
436
|
-
> sendscript@2.0
|
|
436
|
+
> sendscript@2.2.0 test
|
|
437
437
|
> tap report text-summary
|
|
438
438
|
|
|
439
439
|
|
|
440
440
|
=============================== Coverage summary ===============================
|
|
441
|
-
Statements : 100% (
|
|
442
|
-
Branches : 100% (
|
|
443
|
-
Functions : 100% (
|
|
444
|
-
Lines : 100% (
|
|
441
|
+
Statements : 100% ( 338/338 )
|
|
442
|
+
Branches : 100% ( 123/123 )
|
|
443
|
+
Functions : 100% ( 22/22 )
|
|
444
|
+
Lines : 100% ( 338/338 )
|
|
445
445
|
================================================================================
|
|
446
446
|
```
|
|
447
447
|
|
package/README.mz
CHANGED
|
@@ -63,7 +63,7 @@ composition and even await.
|
|
|
63
63
|
This package is nothing more than the absolute core of sendscript. It
|
|
64
64
|
includes:
|
|
65
65
|
|
|
66
|
-
- The `
|
|
66
|
+
- The `references` function to create stubs to write the programs.
|
|
67
67
|
- `stringify` which takes the program and returns a JSON string.
|
|
68
68
|
- `parse` which takes the `stringify` JSON string and a real module and returns the result.
|
|
69
69
|
|
package/cli.mjs
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import path from 'path'
|
|
4
4
|
import { pathToFileURL } from 'url'
|
|
5
|
-
import
|
|
5
|
+
import Stringify from './stringify.mjs'
|
|
6
6
|
import repl from './repl.mjs'
|
|
7
7
|
import Parse from './parse.mjs'
|
|
8
8
|
|
|
9
|
+
const stringify = Stringify()
|
|
9
10
|
const modulePath = pathToFileURL(path.resolve(process.cwd(), process.argv[2])).href
|
|
10
11
|
const mod = await import(modulePath)
|
|
11
|
-
const parse = Parse(mod)
|
|
12
|
+
const parse = Parse(Object.keys(mod), mod)
|
|
12
13
|
|
|
13
14
|
const send = program => parse(stringify(program))
|
|
14
15
|
|
package/error.mjs
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> **add**(`a`, `b`): `number`
|
|
10
10
|
|
|
11
|
-
Defined in: [math.ts:1](https://github.com/bas080/sendscript/blob/
|
|
11
|
+
Defined in: [math.ts:1](https://github.com/bas080/sendscript/blob/2cf0e7e7ced32258102382e7ff1e3f8e91a2cc77/example/typescript/math.ts#L1)
|
|
12
12
|
|
|
13
13
|
## Parameters
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> **square**(`a`): `number`
|
|
10
10
|
|
|
11
|
-
Defined in: [math.ts:2](https://github.com/bas080/sendscript/blob/
|
|
11
|
+
Defined in: [math.ts:2](https://github.com/bas080/sendscript/blob/2cf0e7e7ced32258102382e7ff1e3f8e91a2cc77/example/typescript/math.ts#L2)
|
|
12
12
|
|
|
13
13
|
## Parameters
|
|
14
14
|
|
package/index.test.mjs
CHANGED
|
@@ -2,8 +2,11 @@ import { test } from 'tap'
|
|
|
2
2
|
import Stringify from './stringify.mjs'
|
|
3
3
|
import references from './references.mjs'
|
|
4
4
|
import Parse from './parse.mjs'
|
|
5
|
+
import { SendScriptSerializationError } from './error.mjs'
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
+
const order = []
|
|
8
|
+
|
|
9
|
+
const myModuleOrig = {
|
|
7
10
|
nested: {
|
|
8
11
|
again: {
|
|
9
12
|
T: () => true
|
|
@@ -12,6 +15,16 @@ const myModule = {
|
|
|
12
15
|
add: (a, b) => a + b,
|
|
13
16
|
identity: (x) => x,
|
|
14
17
|
concat: (a, b) => a.concat(b),
|
|
18
|
+
delay: (value, ms) => {
|
|
19
|
+
return new Promise(resolve => {
|
|
20
|
+
order.push(`${value} start`)
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
order.push(`${value} end`)
|
|
23
|
+
|
|
24
|
+
resolve(value)
|
|
25
|
+
}, ms)
|
|
26
|
+
})
|
|
27
|
+
},
|
|
15
28
|
toArray: (...array) => array,
|
|
16
29
|
always: (x) => () => x,
|
|
17
30
|
multiply3: (a) => (b) => (c) => a * b * c,
|
|
@@ -33,7 +46,10 @@ const myModule = {
|
|
|
33
46
|
Promise
|
|
34
47
|
}
|
|
35
48
|
|
|
36
|
-
|
|
49
|
+
// We want to support prototype chain when parsing.
|
|
50
|
+
const myModule = Object.create(myModuleOrig)
|
|
51
|
+
const schema = Object.keys(myModuleOrig)
|
|
52
|
+
|
|
37
53
|
schema.push(['nested', [
|
|
38
54
|
['again', ['T']]
|
|
39
55
|
]])
|
|
@@ -51,6 +67,7 @@ test('should evaluate basic expressions correctly', async (t) => {
|
|
|
51
67
|
aPromise,
|
|
52
68
|
asyncAdd,
|
|
53
69
|
resolve,
|
|
70
|
+
delay,
|
|
54
71
|
delayedIdentity,
|
|
55
72
|
noop,
|
|
56
73
|
Promise,
|
|
@@ -67,6 +84,48 @@ test('should evaluate basic expressions correctly', async (t) => {
|
|
|
67
84
|
nested
|
|
68
85
|
} = api
|
|
69
86
|
|
|
87
|
+
t.test('await evaluation order matches JS semantics', async (t) => {
|
|
88
|
+
const lorder = []
|
|
89
|
+
|
|
90
|
+
const ldelay = (label, ms) => new RealPromise((resolve) => {
|
|
91
|
+
lorder.push(label + ' start')
|
|
92
|
+
setTimeout(() => {
|
|
93
|
+
lorder.push(label + ' end')
|
|
94
|
+
resolve(label)
|
|
95
|
+
}, ms)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const lresult = [
|
|
99
|
+
await ldelay('a', 30),
|
|
100
|
+
await ldelay('b', 10)
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
t.same(lresult, ['a', 'b'])
|
|
104
|
+
t.same(lorder, [
|
|
105
|
+
'a start',
|
|
106
|
+
'a end',
|
|
107
|
+
'b start',
|
|
108
|
+
'b end'
|
|
109
|
+
])
|
|
110
|
+
|
|
111
|
+
// TODO: Write it what ss touches
|
|
112
|
+
|
|
113
|
+
const result = await run([
|
|
114
|
+
await delay('a', 30),
|
|
115
|
+
await delay('b', 10)
|
|
116
|
+
])
|
|
117
|
+
|
|
118
|
+
t.same(result, ['a', 'b'])
|
|
119
|
+
t.same(order, [
|
|
120
|
+
'a start',
|
|
121
|
+
'a end',
|
|
122
|
+
'b start',
|
|
123
|
+
'b end'
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
t.end()
|
|
127
|
+
})
|
|
128
|
+
|
|
70
129
|
t.test('mix await without await', async t => {
|
|
71
130
|
const [one, two] = await run([await resolve(1), resolve(2)])
|
|
72
131
|
|
|
@@ -170,12 +229,30 @@ test('should evaluate basic expressions correctly', async (t) => {
|
|
|
170
229
|
t.end()
|
|
171
230
|
})
|
|
172
231
|
|
|
232
|
+
t.test('throws if stringify returns undefined', t => {
|
|
233
|
+
// This is to prevent accidentally sending payloads that make little sense.
|
|
234
|
+
|
|
235
|
+
// Check if it throw the expected error type.
|
|
236
|
+
try {
|
|
237
|
+
run(undefined)
|
|
238
|
+
} catch (error) {
|
|
239
|
+
t.ok(error instanceof SendScriptSerializationError)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
t.throws(() => run(undefined))
|
|
243
|
+
t.throws(() => run(new Set()))
|
|
244
|
+
t.throws(() => run(identity(undefined)))
|
|
245
|
+
t.throws(() => run(() => {}))
|
|
246
|
+
|
|
247
|
+
t.end()
|
|
248
|
+
})
|
|
249
|
+
|
|
173
250
|
t.test('basic types and identity', (t) => {
|
|
174
251
|
t.equal(run(identity(null)), null)
|
|
175
|
-
t.equal(run(identity(undefined)), null)
|
|
176
252
|
t.equal(run(noop()), undefined)
|
|
177
253
|
t.equal(run(identity(1)), 1)
|
|
178
254
|
t.strictSame(run(identity([])), [])
|
|
255
|
+
t.strictSame(run(identity({})), {})
|
|
179
256
|
t.strictSame(run(identity([identity(1), 2, 3])), [1, 2, 3])
|
|
180
257
|
t.strictSame(run(always('hello')()), 'hello')
|
|
181
258
|
t.end()
|
|
@@ -216,7 +293,8 @@ test('should evaluate basic expressions correctly', async (t) => {
|
|
|
216
293
|
|
|
217
294
|
t.test('null-prototype object traversal', (t) => {
|
|
218
295
|
const { nullProto } = api
|
|
219
|
-
|
|
296
|
+
const other = myModule.nullProto()
|
|
297
|
+
t.strictSame(run({ a: nullProto() }), { a: other })
|
|
220
298
|
t.end()
|
|
221
299
|
})
|
|
222
300
|
|
package/package.json
CHANGED
package/parse.mjs
CHANGED
|
@@ -10,12 +10,10 @@ function flattenSchema (schema) {
|
|
|
10
10
|
obj[item] = true
|
|
11
11
|
} else if (Array.isArray(item)) {
|
|
12
12
|
const [name, children] = item
|
|
13
|
-
// TODO: Test this
|
|
14
13
|
if (!Array.isArray(children)) {
|
|
15
14
|
throw new Error(`Expected children array for namespace "${name}"`)
|
|
16
15
|
}
|
|
17
16
|
obj[name] = flattenSchema(children)
|
|
18
|
-
// TODO: Test this also
|
|
19
17
|
} else {
|
|
20
18
|
throw new Error('Schema items must be strings or [name, children] arrays')
|
|
21
19
|
}
|
|
@@ -26,11 +24,6 @@ function flattenSchema (schema) {
|
|
|
26
24
|
|
|
27
25
|
const debug = Debug.extend('parse')
|
|
28
26
|
|
|
29
|
-
const isThenable = (value) => (
|
|
30
|
-
value != null && typeof value.then === 'function'
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
const isAwaitPromise = Symbol('sendscript-await')
|
|
34
27
|
const undefinedSentinel = Symbol('sendscript-undefined')
|
|
35
28
|
|
|
36
29
|
const isPlainObject = (value) => {
|
|
@@ -39,66 +32,57 @@ const isPlainObject = (value) => {
|
|
|
39
32
|
return proto === Object.prototype || proto === null
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
const markAwait = (promise) => {
|
|
43
|
-
promise[isAwaitPromise] = true
|
|
44
|
-
return promise
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const isExplicitAwait = (value) => (
|
|
48
|
-
isThenable(value) && value[isAwaitPromise] === true
|
|
49
|
-
)
|
|
50
|
-
|
|
51
35
|
// Recursively resolve awaited values in a parsed tree
|
|
52
|
-
const
|
|
36
|
+
const evaluate = (value, awaits = []) => {
|
|
53
37
|
if (value === undefinedSentinel) return undefined
|
|
54
38
|
|
|
55
|
-
if (isThenable(value)) {
|
|
56
|
-
return isExplicitAwait(value)
|
|
57
|
-
? markAwait(value.then(resolveAwaitedValues))
|
|
58
|
-
: value
|
|
59
|
-
}
|
|
60
|
-
|
|
61
39
|
if (Array.isArray(value)) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
40
|
+
const [operator, ...rest] = value
|
|
41
|
+
|
|
42
|
+
if (operator === 'await') {
|
|
43
|
+
const [index] = rest
|
|
44
|
+
// No need to check index. It is closely tied to the program.
|
|
45
|
+
// if (typeof index !== 'number' || index < 0 || index >= awaitsResolved.length) {
|
|
46
|
+
// throw new Error(`Invalid await index: ${index}`);
|
|
47
|
+
// }
|
|
48
|
+
return awaits[index]
|
|
49
|
+
}
|
|
68
50
|
|
|
69
|
-
if (
|
|
51
|
+
if (operator === 'call') {
|
|
52
|
+
// Step 1: evaluate the function itself
|
|
53
|
+
let [fn, args] = rest
|
|
54
|
+
fn = evaluate(fn, awaits)
|
|
70
55
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
56
|
+
// Step 2: evaluate each argument AFTER fn is ready
|
|
57
|
+
for (let i = 0; i < args.length; i++) {
|
|
58
|
+
args[i] = evaluate(args[i], awaits)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Step 3: call the function
|
|
62
|
+
return fn(...args)
|
|
63
|
+
}
|
|
79
64
|
|
|
80
|
-
|
|
65
|
+
if (operator === 'quote') {
|
|
66
|
+
const [quoted] = rest
|
|
67
|
+
return quoted // return as-is without evaluating
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// fallback: evaluate each element
|
|
71
|
+
// re-uses the array again.
|
|
72
|
+
|
|
73
|
+
for (let index = 0; index < value.length; index++) {
|
|
74
|
+
const item = value[index]
|
|
75
|
+
value[index] = evaluate(item, awaits)
|
|
76
|
+
}
|
|
77
|
+
return value
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
if (isPlainObject(value)) {
|
|
84
|
-
|
|
85
|
-
const promises = []
|
|
86
|
-
|
|
81
|
+
// We muatate the object itself. No need to make a new one.
|
|
87
82
|
for (const key of Object.keys(value)) {
|
|
88
|
-
|
|
89
|
-
if (isExplicitAwait(resolved)) {
|
|
90
|
-
promises.push(
|
|
91
|
-
Promise.resolve(resolved).then((resolvedValue) => {
|
|
92
|
-
result[key] = resolvedValue
|
|
93
|
-
})
|
|
94
|
-
)
|
|
95
|
-
} else {
|
|
96
|
-
result[key] = resolved
|
|
97
|
-
}
|
|
83
|
+
value[key] = evaluate(value[key], awaits)
|
|
98
84
|
}
|
|
99
|
-
|
|
100
|
-
if (!promises.length) return result
|
|
101
|
-
return markAwait(Promise.all(promises).then(() => result))
|
|
85
|
+
return value
|
|
102
86
|
}
|
|
103
87
|
|
|
104
88
|
return value
|
|
@@ -117,7 +101,10 @@ export default (schemaArg, env, deserialize = defaultLeafDeserializer) => {
|
|
|
117
101
|
|
|
118
102
|
return function parse (program) {
|
|
119
103
|
debug('program', program)
|
|
104
|
+
const awaits = []
|
|
120
105
|
|
|
106
|
+
// Creates the list of awaits that will resolve in order
|
|
107
|
+
// and also deserializes the leaves.
|
|
121
108
|
const reviver = spy((key, value) => {
|
|
122
109
|
if (value === null) return value
|
|
123
110
|
|
|
@@ -134,36 +121,12 @@ export default (schemaArg, env, deserialize = defaultLeafDeserializer) => {
|
|
|
134
121
|
|
|
135
122
|
if (operator === 'await') {
|
|
136
123
|
const [program] = rest
|
|
137
|
-
return markAwait(Promise.resolve(program))
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (Array.isArray(operator) && operator[0] === 'quote') {
|
|
141
|
-
const [, quoted] = operator
|
|
142
|
-
return [quoted, ...rest]
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (operator === 'call') {
|
|
146
|
-
const [fn, args] = rest
|
|
147
|
-
const resolvedFn = isExplicitAwait(fn) ? Promise.resolve(fn) : fn
|
|
148
|
-
const resolvedArgs = resolveAwaitedValues(args)
|
|
149
|
-
|
|
150
|
-
if (isExplicitAwait(resolvedFn) || isExplicitAwait(resolvedArgs)) {
|
|
151
|
-
const promiseFn = isExplicitAwait(resolvedFn)
|
|
152
|
-
? Promise.resolve(resolvedFn)
|
|
153
|
-
: resolvedFn
|
|
154
|
-
const promiseArgs = isExplicitAwait(resolvedArgs)
|
|
155
|
-
? Promise.resolve(resolvedArgs)
|
|
156
|
-
: resolvedArgs
|
|
157
|
-
|
|
158
|
-
return Promise.all([promiseFn, promiseArgs])
|
|
159
|
-
.then(([resolvedFnValue, resolvedArgsValue]) => resolvedFnValue(...resolvedArgsValue))
|
|
160
|
-
}
|
|
161
124
|
|
|
162
|
-
return
|
|
125
|
+
return ['await', awaits.push(program) - 1]
|
|
163
126
|
}
|
|
164
127
|
|
|
165
128
|
if (operator === 'ref') {
|
|
166
|
-
const path = rest
|
|
129
|
+
const path = rest
|
|
167
130
|
let current = env
|
|
168
131
|
let schemaCurrent = schema
|
|
169
132
|
|
|
@@ -183,8 +146,23 @@ export default (schemaArg, env, deserialize = defaultLeafDeserializer) => {
|
|
|
183
146
|
})
|
|
184
147
|
|
|
185
148
|
const parsed = JSON.parse(program, reviver)
|
|
186
|
-
const result = resolveAwaitedValues(parsed)
|
|
187
149
|
|
|
188
|
-
|
|
150
|
+
debug('parsed', parsed)
|
|
151
|
+
|
|
152
|
+
if (awaits.length) {
|
|
153
|
+
debug('awaits', awaits)
|
|
154
|
+
|
|
155
|
+
return (async function () {
|
|
156
|
+
for (let index = 0; index < awaits.length; index++) {
|
|
157
|
+
awaits[index] = await evaluate(awaits[index], awaits)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
debug('awaits(awaited)', awaits)
|
|
161
|
+
|
|
162
|
+
return evaluate(parsed, awaits)
|
|
163
|
+
})()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return evaluate(parsed)
|
|
189
167
|
}
|
|
190
168
|
}
|
package/repl.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import references from './references.mjs'
|
|
2
2
|
import repl from 'node:repl'
|
|
3
3
|
|
|
4
4
|
export default async function sendscriptRepl (send, module) {
|
|
5
|
-
Object.assign(global,
|
|
5
|
+
Object.assign(global, references(Object.keys(module)))
|
|
6
6
|
|
|
7
7
|
async function cb (cmd, context, filename, callback) {
|
|
8
8
|
callback(null, await send(eval(cmd))) // eslint-disable-line no-eval
|
package/stringify.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Debug from './debug.mjs'
|
|
2
|
+
import { SendScriptSerializationError } from './error.mjs'
|
|
2
3
|
import {
|
|
3
4
|
awaitSymbol,
|
|
4
5
|
call,
|
|
@@ -69,7 +70,17 @@ function transformValue (value, leafSerializer) {
|
|
|
69
70
|
return ['leaf', leafSerializer(value)]
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
function strictStringify (x) {
|
|
74
|
+
const typeOf = typeof x
|
|
75
|
+
|
|
76
|
+
if (typeOf === 'object' || typeOf === 'function' || x === undefined) {
|
|
77
|
+
throw new SendScriptSerializationError(`Cannot and should not attempt to serialize ${x}`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return JSON.stringify(x)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default function stringify (leafSerializer = strictStringify) {
|
|
73
84
|
function stringify (program) {
|
|
74
85
|
return JSON.stringify(transformValue(program, leafSerializer))
|
|
75
86
|
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
name: Release on tag
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- '*'
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
test:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
node: ['lts/*', 'latest']
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v4
|
|
20
|
-
|
|
21
|
-
- uses: actions/setup-node@v4
|
|
22
|
-
with:
|
|
23
|
-
node-version: ${{ matrix.node }}
|
|
24
|
-
cache: npm
|
|
25
|
-
|
|
26
|
-
- run: npm ci
|
|
27
|
-
- run: npm test
|
|
28
|
-
|
|
29
|
-
release:
|
|
30
|
-
needs: test
|
|
31
|
-
runs-on: ubuntu-latest
|
|
32
|
-
|
|
33
|
-
steps:
|
|
34
|
-
- uses: actions/checkout@v4
|
|
35
|
-
|
|
36
|
-
- uses: actions/setup-node@v4
|
|
37
|
-
with:
|
|
38
|
-
node-version: 'latest'
|
|
39
|
-
cache: npm
|
|
40
|
-
|
|
41
|
-
- run: npm ci
|
|
42
|
-
- name: Create GitHub Release
|
|
43
|
-
uses: softprops/action-gh-release@v2
|
|
44
|
-
with:
|
|
45
|
-
generate_release_notes: true
|