sendscript 2.2.0 → 2.3.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/CHANGELOG.md +7 -0
- package/README.md +25 -25
- package/README.mz +14 -1
- package/example/typescript/docs/functions/add.md +1 -1
- package/example/typescript/docs/functions/square.md +1 -1
- package/index.test.mjs +21 -0
- package/package.json +1 -1
- package/parse.mjs +14 -9
- package/references.mjs +27 -5
- package/stringify.mjs +5 -0
- package/symbol.mjs +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,15 @@ 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.3.0](https://github.com/bas080/sendscript/compare/v2.2.0...v2.3.0)
|
|
8
|
+
|
|
9
|
+
- Add support for then and catch [`c0bbea8`](https://github.com/bas080/sendscript/commit/c0bbea8efcc6b262c091d9043e96ac8c3f7606e1)
|
|
10
|
+
- Document .catch and .then support [`b35009a`](https://github.com/bas080/sendscript/commit/b35009ace9761d32c0c6ef1d1d045bed2ecfe74e)
|
|
11
|
+
|
|
7
12
|
#### [v2.2.0](https://github.com/bas080/sendscript/compare/v2.1.0...v2.2.0)
|
|
8
13
|
|
|
14
|
+
> 10 April 2026
|
|
15
|
+
|
|
9
16
|
- Have default leaf serializer throw if value has no JSON equivalant [`6752f2f`](https://github.com/bas080/sendscript/commit/6752f2f3ed51e252ab93a31b632fe8fbae51d7cb)
|
|
10
17
|
- Test that prototype chain works when parsing [`2cf0e7e`](https://github.com/bas080/sendscript/commit/2cf0e7e7ced32258102382e7ff1e3f8e91a2cc77)
|
|
11
18
|
|
package/README.md
CHANGED
|
@@ -15,7 +15,9 @@ Write JS code that you can run on servers, browsers or other clients.
|
|
|
15
15
|
* [Server](#server)
|
|
16
16
|
* [Client](#client)
|
|
17
17
|
- [Repl](#repl)
|
|
18
|
-
- [
|
|
18
|
+
- [Promises](#promises)
|
|
19
|
+
* [.then / .catch](#then--catch)
|
|
20
|
+
* [await](#await)
|
|
19
21
|
- [TypeScript](#typescript)
|
|
20
22
|
- [Schema and Nested Modules](#schema-and-nested-modules)
|
|
21
23
|
* [Defining a Nested Module](#defining-a-nested-module)
|
|
@@ -27,8 +29,6 @@ Write JS code that you can run on servers, browsers or other clients.
|
|
|
27
29
|
- [Formatting](#formatting)
|
|
28
30
|
- [Changelog](#changelog)
|
|
29
31
|
- [Dependencies](#dependencies)
|
|
30
|
-
- [License](#license)
|
|
31
|
-
- [Roadmap](#roadmap)
|
|
32
32
|
|
|
33
33
|
<!-- tocstop -->
|
|
34
34
|
|
|
@@ -215,7 +215,20 @@ Sendscript ships with a barebones (no-dependencies) node-repl script. One can ru
|
|
|
215
215
|
|
|
216
216
|
> Use the `DEBUG='*'` to enable all logs or `DEBUG='sendscript:*'` for printingonly sendscript logs.
|
|
217
217
|
|
|
218
|
-
##
|
|
218
|
+
## Promises
|
|
219
|
+
|
|
220
|
+
### .then / .catch
|
|
221
|
+
|
|
222
|
+
Supported since vs `v2.3`.
|
|
223
|
+
|
|
224
|
+
```js
|
|
225
|
+
const getOrCreatePost = send(createPost(title).catch(createPost(title)))
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
You will likely need to define better helpers that makes it safer to handle rejections and work with promises. It is however sensible to have
|
|
229
|
+
this basic behavior for the sendscript DSL and parser.
|
|
230
|
+
|
|
231
|
+
### await
|
|
219
232
|
|
|
220
233
|
SendScript supports async/await seamlessly within a single request. This avoids the performance pitfalls of waterfall-style messaging, which can be especially slow on high-latency networks.
|
|
221
234
|
|
|
@@ -429,19 +442,19 @@ npm t -- report text-summary
|
|
|
429
442
|
```
|
|
430
443
|
```
|
|
431
444
|
|
|
432
|
-
> sendscript@2.
|
|
445
|
+
> sendscript@2.3.0 test
|
|
433
446
|
> tap -R silent
|
|
434
447
|
|
|
435
448
|
|
|
436
|
-
> sendscript@2.
|
|
449
|
+
> sendscript@2.3.0 test
|
|
437
450
|
> tap report text-summary
|
|
438
451
|
|
|
439
452
|
|
|
440
453
|
=============================== Coverage summary ===============================
|
|
441
|
-
Statements : 100% (
|
|
442
|
-
Branches : 100% (
|
|
443
|
-
Functions : 100% (
|
|
444
|
-
Lines : 100% (
|
|
454
|
+
Statements : 100% ( 372/372 )
|
|
455
|
+
Branches : 100% ( 137/137 )
|
|
456
|
+
Functions : 100% ( 24/24 )
|
|
457
|
+
Lines : 100% ( 372/372 )
|
|
445
458
|
================================================================================
|
|
446
459
|
```
|
|
447
460
|
|
|
@@ -470,19 +483,6 @@ Check if packages are up to date on release.
|
|
|
470
483
|
npm outdated && echo 'No outdated packages found'
|
|
471
484
|
```
|
|
472
485
|
```
|
|
473
|
-
|
|
486
|
+
Package Current Wanted Latest Location Depended by
|
|
487
|
+
typedoc 0.28.18 0.28.19 0.28.19 node_modules/typedoc master
|
|
474
488
|
```
|
|
475
|
-
|
|
476
|
-
## License
|
|
477
|
-
|
|
478
|
-
See the [LICENSE.txt][license] file for details.
|
|
479
|
-
|
|
480
|
-
## Roadmap
|
|
481
|
-
|
|
482
|
-
- [ ] Support for simple lambdas to compose functions more easily.
|
|
483
|
-
|
|
484
|
-
[license]:./LICENSE.txt
|
|
485
|
-
[socket.io]:https://socket.io/
|
|
486
|
-
[changelog]:./CHANGELOG.md
|
|
487
|
-
[auto-changelog]:https://www.npmjs.com/package/auto-changelog
|
|
488
|
-
[typedoc]:https://github.com/TypeStrong/typedoc
|
package/README.mz
CHANGED
|
@@ -183,7 +183,20 @@ Sendscript ships with a barebones (no-dependencies) node-repl script. One can ru
|
|
|
183
183
|
|
|
184
184
|
> Use the `DEBUG='*'` to enable all logs or `DEBUG='sendscript:*'` for printingonly sendscript logs.
|
|
185
185
|
|
|
186
|
-
##
|
|
186
|
+
## Promises
|
|
187
|
+
|
|
188
|
+
### .then / .catch
|
|
189
|
+
|
|
190
|
+
Supported since vs `v2.3`.
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
const getOrCreatePost = send(createPost(title).catch(createPost(title)))
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
You will likely need to define better helpers that makes it safer to handle rejections and work with promises. It is however sensible to have
|
|
197
|
+
this basic behavior for the sendscript DSL and parser.
|
|
198
|
+
|
|
199
|
+
### await
|
|
187
200
|
|
|
188
201
|
SendScript supports async/await seamlessly within a single request. This avoids the performance pitfalls of waterfall-style messaging, which can be especially slow on high-latency networks.
|
|
189
202
|
|
|
@@ -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/b35009ace9761d32c0c6ef1d1d045bed2ecfe74e/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/b35009ace9761d32c0c6ef1d1d045bed2ecfe74e/example/typescript/math.ts#L2)
|
|
12
12
|
|
|
13
13
|
## Parameters
|
|
14
14
|
|
package/index.test.mjs
CHANGED
|
@@ -28,11 +28,13 @@ const myModuleOrig = {
|
|
|
28
28
|
toArray: (...array) => array,
|
|
29
29
|
always: (x) => () => x,
|
|
30
30
|
multiply3: (a) => (b) => (c) => a * b * c,
|
|
31
|
+
sayHello: x => `hello ${x}`,
|
|
31
32
|
map: (fn) => (array) => array.map(fn),
|
|
32
33
|
filter: (pred) => (array) => array.filter(pred),
|
|
33
34
|
hello: 'world',
|
|
34
35
|
noop: () => {},
|
|
35
36
|
resolve: (x) => Promise.resolve(x),
|
|
37
|
+
reject: x => Promise.reject(x),
|
|
36
38
|
asyncFn: async () => 'my-async-function',
|
|
37
39
|
instanceOf: (x, t) => x instanceof t,
|
|
38
40
|
asyncAdd: async (a, b) => a + b,
|
|
@@ -67,6 +69,7 @@ test('should evaluate basic expressions correctly', async (t) => {
|
|
|
67
69
|
aPromise,
|
|
68
70
|
asyncAdd,
|
|
69
71
|
resolve,
|
|
72
|
+
reject,
|
|
70
73
|
delay,
|
|
71
74
|
delayedIdentity,
|
|
72
75
|
noop,
|
|
@@ -81,9 +84,27 @@ test('should evaluate basic expressions correctly', async (t) => {
|
|
|
81
84
|
identity,
|
|
82
85
|
always,
|
|
83
86
|
multiply3,
|
|
87
|
+
sayHello,
|
|
84
88
|
nested
|
|
85
89
|
} = api
|
|
86
90
|
|
|
91
|
+
t.test('supports .then', async t => {
|
|
92
|
+
t.rejects(run(reject('error')))
|
|
93
|
+
|
|
94
|
+
t.equal(await run(reject('error').catch(sayHello)), 'hello error')
|
|
95
|
+
t.equal(await run(reject('error').then(null, sayHello)), 'hello error')
|
|
96
|
+
|
|
97
|
+
t.equal(await run(resolve('value').then(sayHello)), 'hello value')
|
|
98
|
+
t.equal(await run(resolve('value').then(sayHello, noop)), 'hello value')
|
|
99
|
+
|
|
100
|
+
t.end()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
t.test('resolve and reject callback works for .then', async t => {
|
|
104
|
+
t.equal(await run(resolve(42).then(multiply3(1)(2))), 84)
|
|
105
|
+
t.end()
|
|
106
|
+
})
|
|
107
|
+
|
|
87
108
|
t.test('await evaluation order matches JS semantics', async (t) => {
|
|
88
109
|
const lorder = []
|
|
89
110
|
|
package/package.json
CHANGED
package/parse.mjs
CHANGED
|
@@ -32,8 +32,14 @@ const isPlainObject = (value) => {
|
|
|
32
32
|
return proto === Object.prototype || proto === null
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
const spy = (type, fn) => (...args) => {
|
|
36
|
+
const value = fn(...args)
|
|
37
|
+
debug(type, args, ' => ', value)
|
|
38
|
+
return value
|
|
39
|
+
}
|
|
40
|
+
|
|
35
41
|
// Recursively resolve awaited values in a parsed tree
|
|
36
|
-
const evaluate = (value, awaits = []) => {
|
|
42
|
+
const evaluate = spy('eval', (value, awaits = []) => {
|
|
37
43
|
if (value === undefinedSentinel) return undefined
|
|
38
44
|
|
|
39
45
|
if (Array.isArray(value)) {
|
|
@@ -48,6 +54,11 @@ const evaluate = (value, awaits = []) => {
|
|
|
48
54
|
return awaits[index]
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
if (operator === 'then') {
|
|
58
|
+
const [v, onResolve, onReject] = rest
|
|
59
|
+
return evaluate(v, awaits).then(evaluate(onResolve, awaits), evaluate(onReject, awaits))
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
if (operator === 'call') {
|
|
52
63
|
// Step 1: evaluate the function itself
|
|
53
64
|
let [fn, args] = rest
|
|
@@ -86,13 +97,7 @@ const evaluate = (value, awaits = []) => {
|
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
return value
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const spy = (fn) => (...args) => {
|
|
92
|
-
const value = fn(...args)
|
|
93
|
-
debug(args, ' => ', value)
|
|
94
|
-
return value
|
|
95
|
-
}
|
|
100
|
+
})
|
|
96
101
|
|
|
97
102
|
const defaultLeafDeserializer = (text) => JSON.parse(text)
|
|
98
103
|
|
|
@@ -105,7 +110,7 @@ export default (schemaArg, env, deserialize = defaultLeafDeserializer) => {
|
|
|
105
110
|
|
|
106
111
|
// Creates the list of awaits that will resolve in order
|
|
107
112
|
// and also deserializes the leaves.
|
|
108
|
-
const reviver = spy((key, value) => {
|
|
113
|
+
const reviver = spy('revive', (key, value) => {
|
|
109
114
|
if (value === null) return value
|
|
110
115
|
|
|
111
116
|
if (!Array.isArray(value)) {
|
package/references.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { awaitSymbol, call, ref } from './symbol.mjs'
|
|
1
|
+
import { awaitSymbol, call, ref, then, referenceSymbol } from './symbol.mjs'
|
|
2
2
|
|
|
3
3
|
function instrument (path) {
|
|
4
4
|
function reference (...args) {
|
|
@@ -6,7 +6,6 @@ function instrument (path) {
|
|
|
6
6
|
|
|
7
7
|
called.toJSON = () => ({
|
|
8
8
|
[call]: call,
|
|
9
|
-
call: true,
|
|
10
9
|
ref: reference,
|
|
11
10
|
args
|
|
12
11
|
})
|
|
@@ -14,13 +13,35 @@ function instrument (path) {
|
|
|
14
13
|
return called
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
function dotThen (resolve, reject) {
|
|
17
|
+
const node = instrument(path)
|
|
18
|
+
|
|
19
|
+
node.toJSON = () => ({
|
|
20
|
+
[then]: then,
|
|
21
|
+
ref: reference,
|
|
22
|
+
resolve,
|
|
23
|
+
reject
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
return node
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
reference.catch = (reject) => {
|
|
30
|
+
return dotThen(null, reject)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
reference.then = (resolve, reject) => {
|
|
34
|
+
// That is how we know if it is an await or a .then call.
|
|
35
|
+
if (resolve?.[referenceSymbol] || reject?.[referenceSymbol]) {
|
|
36
|
+
return dotThen(resolve, reject)
|
|
37
|
+
}
|
|
38
|
+
|
|
18
39
|
const awaited = instrument(path)
|
|
40
|
+
// Prevent infinite recur
|
|
19
41
|
delete awaited.then
|
|
20
42
|
|
|
21
43
|
awaited.toJSON = () => ({
|
|
22
44
|
[awaitSymbol]: awaitSymbol,
|
|
23
|
-
await: true,
|
|
24
45
|
ref: reference
|
|
25
46
|
})
|
|
26
47
|
|
|
@@ -29,10 +50,11 @@ function instrument (path) {
|
|
|
29
50
|
|
|
30
51
|
reference.toJSON = () => ({
|
|
31
52
|
[ref]: ref,
|
|
32
|
-
reference: true,
|
|
33
53
|
path
|
|
34
54
|
})
|
|
35
55
|
|
|
56
|
+
reference[referenceSymbol] = referenceSymbol
|
|
57
|
+
|
|
36
58
|
return reference
|
|
37
59
|
}
|
|
38
60
|
|
package/stringify.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import Debug from './debug.mjs'
|
|
|
2
2
|
import { SendScriptSerializationError } from './error.mjs'
|
|
3
3
|
import {
|
|
4
4
|
awaitSymbol,
|
|
5
|
+
then,
|
|
5
6
|
call,
|
|
6
7
|
ref
|
|
7
8
|
} from './symbol.mjs'
|
|
@@ -43,6 +44,10 @@ function transformValue (value, leafSerializer) {
|
|
|
43
44
|
return ['await', transformValue(value.ref, leafSerializer)]
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
if (value && value[then]) {
|
|
48
|
+
return ['then', transformValue(value.ref, leafSerializer), transformValue(value.resolve || null, leafSerializer), transformValue(value.reject || null, leafSerializer)]
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
// Handle arrays: quote keyword operators, transform other arrays recursively
|
|
47
52
|
if (Array.isArray(value)) {
|
|
48
53
|
const [operator, ...rest] = value
|