sendscript 0.0.3 → 0.1.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 +13 -0
- package/README.md +10 -10
- package/README.mz +4 -4
- package/api.mjs +10 -10
- package/exec.mjs +6 -44
- package/exec.test.mjs +25 -113
- package/package.json +9 -2
- package/.tap/processinfo/65b0791e-b6b7-4bc9-a201-d723527e67b3.json +0 -784
- package/.tap/processinfo/a23bd004-c2c3-4cb8-865d-19f9a4dfee9e.json +0 -782
- package/.tap/processinfo/b6cdc8e9-f8ff-45e7-93e6-7293b75a0567.json +0 -780
- package/.tap/test-results/api.test.mjs.tap +0 -15
- package/.tap/test-results/curry.test.mjs.tap +0 -26
- package/.tap/test-results/exec.test.mjs.tap +0 -58
- package/api.test.mjs +0 -31
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,21 @@ 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
|
+
#### [v0.1.0](https://github.com/bas080/sendscript/compare/v0.0.4...v0.1.0)
|
|
8
|
+
|
|
9
|
+
- Allow nesting arrays, calls and args [`48e5804`](https://github.com/bas080/sendscript/commit/48e5804891db0ee0ed8c274f20f81d49d6609a54)
|
|
10
|
+
|
|
11
|
+
#### [v0.0.4](https://github.com/bas080/sendscript/compare/v0.0.3...v0.0.4)
|
|
12
|
+
|
|
13
|
+
> 6 October 2023
|
|
14
|
+
|
|
15
|
+
- Add keywords to package.json [`e24d77b`](https://github.com/bas080/sendscript/commit/e24d77b14e67399cedc085294fbef3024a060087)
|
|
16
|
+
- Add .tap to gitignore [`d0abbca`](https://github.com/bas080/sendscript/commit/d0abbcaafab8b915449118b3d2926ca7ff8dc133)
|
|
17
|
+
|
|
7
18
|
#### [v0.0.3](https://github.com/bas080/sendscript/compare/v0.0.2...v0.0.3)
|
|
8
19
|
|
|
20
|
+
> 6 October 2023
|
|
21
|
+
|
|
9
22
|
- Update tap from version 16 to 18 [`465c933`](https://github.com/bas080/sendscript/commit/465c93391097018ee010b51a64ca51d6872b49f1)
|
|
10
23
|
|
|
11
24
|
#### [v0.0.2](https://github.com/bas080/sendscript/compare/v0.0.1...v0.0.2)
|
package/README.md
CHANGED
|
@@ -7,10 +7,6 @@ Write JS code that you can run on servers, browsers or other clients.
|
|
|
7
7
|
[](https://standardjs.com)
|
|
8
8
|
[](./LICENSE.txt)
|
|
9
9
|
|
|
10
|
-
> SendScript leaves it up to you to choose HTTP, web-sockets or any other
|
|
11
|
-
> method of communication between servers and clients that best fits your
|
|
12
|
-
> needs.
|
|
13
|
-
|
|
14
10
|
<!-- toc -->
|
|
15
11
|
|
|
16
12
|
- [Socket example](#socket-example)
|
|
@@ -28,6 +24,10 @@ Write JS code that you can run on servers, browsers or other clients.
|
|
|
28
24
|
|
|
29
25
|
<!-- tocstop -->
|
|
30
26
|
|
|
27
|
+
SendScript leaves it up to you to choose HTTP, web-sockets or any other
|
|
28
|
+
method of communication between servers and clients that best fits your
|
|
29
|
+
needs.
|
|
30
|
+
|
|
31
31
|
## Socket example
|
|
32
32
|
|
|
33
33
|
For this example we'll use [socket.io][socket.io].
|
|
@@ -194,19 +194,19 @@ npm t -- report text-summary
|
|
|
194
194
|
```
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
> sendscript@0.0
|
|
197
|
+
> sendscript@0.1.0 test
|
|
198
198
|
> tap -R silent
|
|
199
199
|
|
|
200
200
|
|
|
201
|
-
> sendscript@0.0
|
|
201
|
+
> sendscript@0.1.0 test
|
|
202
202
|
> tap report text-summary
|
|
203
203
|
|
|
204
204
|
|
|
205
205
|
=============================== Coverage summary ===============================
|
|
206
|
-
Statements : 100% (
|
|
207
|
-
Branches : 100% (
|
|
208
|
-
Functions : 100% (
|
|
209
|
-
Lines : 100% (
|
|
206
|
+
Statements : 100% ( 92/92 )
|
|
207
|
+
Branches : 100% ( 30/30 )
|
|
208
|
+
Functions : 100% ( 10/10 )
|
|
209
|
+
Lines : 100% ( 92/92 )
|
|
210
210
|
================================================================================
|
|
211
211
|
```
|
|
212
212
|
|
package/README.mz
CHANGED
|
@@ -7,12 +7,12 @@ Write JS code that you can run on servers, browsers or other clients.
|
|
|
7
7
|
[](https://standardjs.com)
|
|
8
8
|
[](./LICENSE.txt)
|
|
9
9
|
|
|
10
|
-
> SendScript leaves it up to you to choose HTTP, web-sockets or any other
|
|
11
|
-
> method of communication between servers and clients that best fits your
|
|
12
|
-
> needs.
|
|
13
|
-
|
|
14
10
|
<!-- toc -->
|
|
15
11
|
|
|
12
|
+
SendScript leaves it up to you to choose HTTP, web-sockets or any other
|
|
13
|
+
method of communication between servers and clients that best fits your
|
|
14
|
+
needs.
|
|
15
|
+
|
|
16
16
|
## Socket example
|
|
17
17
|
|
|
18
18
|
For this example we'll use [socket.io][socket.io].
|
package/api.mjs
CHANGED
|
@@ -9,17 +9,17 @@ export default function api (schema, call) {
|
|
|
9
9
|
const then = (program) => (resolve, reject) =>
|
|
10
10
|
Promise.resolve(call(program)).then(resolve, reject)
|
|
11
11
|
|
|
12
|
-
const fn = (...args) =>
|
|
13
|
-
[
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
const fn = (...args) => {
|
|
13
|
+
const toJSON = () => ['call', fn, ...args]
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
[symbol]: symbol,
|
|
17
|
+
toJSON,
|
|
18
|
+
async then (resolve, reject) {
|
|
19
|
+
return then(await promiseOnlyNonAPI(toJSON()))(resolve, reject)
|
|
20
|
+
}
|
|
21
21
|
}
|
|
22
|
-
}
|
|
22
|
+
}
|
|
23
23
|
|
|
24
24
|
fn.toJSON = () => ['ref', name]
|
|
25
25
|
fn.then = then(fn)
|
package/exec.mjs
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import _debug from './debug.mjs'
|
|
2
|
-
import { BlendExpressionError } from './error.mjs'
|
|
3
2
|
import curry from './curry.mjs'
|
|
4
3
|
|
|
5
4
|
const debug = _debug.extend('lisp')
|
|
6
|
-
const debugError = debug.extend('error')
|
|
7
|
-
const isFunction = x => typeof x === 'function'
|
|
8
|
-
const castFunction = x => isFunction(x) ? x : () => x
|
|
9
5
|
|
|
10
6
|
const exec = curry(async (env, expression) => {
|
|
11
7
|
debug('exec', expression)
|
|
@@ -16,54 +12,20 @@ const exec = curry(async (env, expression) => {
|
|
|
16
12
|
|
|
17
13
|
const [operator, ...args] = expression
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
return await operator.call(env, ...(await Promise.all(args.map(exec(env)))))
|
|
23
|
-
} catch (error) {
|
|
24
|
-
debugError(error)
|
|
25
|
-
throw error
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Use JSON value when toJSON is implemented.
|
|
30
|
-
// NECESSARY? if (operator?.toJSON) { operator = operator.toJSON() }
|
|
31
|
-
|
|
32
|
-
if (operator === 'fn') {
|
|
33
|
-
const [body] = args
|
|
34
|
-
|
|
35
|
-
return (fnEnv) => exec(Object.assign(Object.create(env), fnEnv), body)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (operator === 'let') {
|
|
39
|
-
const letEnv = Object.create(env)
|
|
40
|
-
const [letBindings, letBody] = args
|
|
15
|
+
if (operator === 'call') {
|
|
16
|
+
const [fnName, ...fnArgs] = args
|
|
41
17
|
|
|
42
|
-
await
|
|
43
|
-
|
|
44
|
-
}))
|
|
45
|
-
|
|
46
|
-
return exec(letEnv, letBody)
|
|
18
|
+
const fn = await exec(env, fnName)
|
|
19
|
+
return fn.apply(env, await exec(env, fnArgs))
|
|
47
20
|
}
|
|
48
21
|
|
|
49
22
|
if (operator === 'ref') {
|
|
50
23
|
const [name] = args
|
|
51
|
-
return env[name]
|
|
52
|
-
}
|
|
53
24
|
|
|
54
|
-
|
|
55
|
-
return exec(env, [await exec(env, operator), ...args])
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Throw error if operator is not in env.
|
|
59
|
-
if (!(operator in env)) {
|
|
60
|
-
const error = new BlendExpressionError(`Unknown expression: ${operator}`)
|
|
61
|
-
debugError(error)
|
|
62
|
-
throw error
|
|
25
|
+
return env[name]
|
|
63
26
|
}
|
|
64
27
|
|
|
65
|
-
return exec(env
|
|
28
|
+
return await Promise.all(expression.map(exec(env)))
|
|
66
29
|
})
|
|
67
30
|
|
|
68
|
-
export { exec }
|
|
69
31
|
export default exec
|
package/exec.test.mjs
CHANGED
|
@@ -1,125 +1,37 @@
|
|
|
1
1
|
import { test } from 'tap'
|
|
2
|
-
import
|
|
2
|
+
import api from './api.mjs'
|
|
3
|
+
import exec from './exec.mjs'
|
|
3
4
|
|
|
4
|
-
test('should evaluate basic expressions correctly', (t) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
.then((result) => t.equal(result, 3, '1 + 2 = 3'))
|
|
9
|
-
|
|
10
|
-
exec({ '-': (a, b) => a - b }, ['-', 5, 3])
|
|
11
|
-
.then((result) => t.equal(result, 2, '5 - 3 = 2'))
|
|
12
|
-
|
|
13
|
-
exec({ '*': (a, b) => a * b }, ['*', 4, 3])
|
|
14
|
-
.then((result) => t.equal(result, 12, '4 * 3 = 12'))
|
|
15
|
-
|
|
16
|
-
exec({ '/': (a, b) => a / b }, ['/', 10, 2])
|
|
17
|
-
.then((result) => t.equal(result, 5, '10 / 2 = 5'))
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test('should be able to call a partially applied function', async t => {
|
|
21
|
-
const env = {
|
|
22
|
-
'+': a => b => a + b
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
t.equal(typeof (await exec(env, ['+', 1])), 'function')
|
|
26
|
-
t.equal(await exec(env, [['+', 1], 2]), 3)
|
|
27
|
-
t.end()
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('should handle let expressions', (t) => {
|
|
31
|
-
t.plan(1)
|
|
32
|
-
|
|
33
|
-
exec({ '+': (a, b) => a + b }, ['let', [['x', 2], ['y', 3]], ['+', ['x'], ['y']]])
|
|
34
|
-
.then((result) => t.equal(result, 5, 'x + y = 5'))
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('should handle fn expressions', (t) => {
|
|
38
|
-
t.plan(2)
|
|
39
|
-
|
|
40
|
-
exec({}, ['fn', ['+', 1, 'x']])
|
|
41
|
-
.then((result) => t.equal(typeof result, 'function', 'should return a function'))
|
|
42
|
-
|
|
43
|
-
exec({ '+': (a, b) => a + b }, ['fn', ['+', 1, ['x']]])
|
|
44
|
-
.then(async (result) => {
|
|
45
|
-
t.equal(await result({ x: 2 }), 3, '1 + 2 = 3')
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
test('should throw an error for unknown expressions', (t) => {
|
|
50
|
-
t.plan(1)
|
|
51
|
-
|
|
52
|
-
exec({ '+': (a, b) => a + b }, ['-', 1, 2])
|
|
53
|
-
.catch((err) => t.equal(err.message, 'Unknown expression: -', 'should throw an error for unknown expressions'))
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
test('should evaluate nested expressions correctly', (t) => {
|
|
57
|
-
t.plan(1)
|
|
58
|
-
|
|
59
|
-
const env = {
|
|
60
|
-
'+': (a, b) => a + b,
|
|
61
|
-
'*': (a, b) => a * b
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
exec(env, ['*', 2, ['+', 1, 2]])
|
|
65
|
-
.then((result) => t.equal(result, 6, '2 * (1 + 2) = 6'))
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('should concatenate two arrays', async t => {
|
|
69
|
-
t.plan(1)
|
|
70
|
-
|
|
71
|
-
const env = {
|
|
72
|
-
array: (...args) => args,
|
|
5
|
+
test('should evaluate basic expressions correctly', async (t) => {
|
|
6
|
+
const module = {
|
|
7
|
+
add: (a, b) => a + b,
|
|
8
|
+
identity: x => x,
|
|
73
9
|
concat: (a, b) => a.concat(b)
|
|
74
10
|
}
|
|
75
|
-
const expression = ['concat', ['array', 1, 2, 3], ['array', 4, 5, 6]]
|
|
76
|
-
const result = await exec(env, expression)
|
|
77
|
-
|
|
78
|
-
t.same(result, [1, 2, 3, 4, 5, 6])
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
test('should fetch the reference to the item on the env', async t => {
|
|
82
|
-
const value = 'yey'
|
|
83
|
-
|
|
84
|
-
const env = {
|
|
85
|
-
thing: () => value
|
|
86
|
-
}
|
|
87
11
|
|
|
88
|
-
const
|
|
89
|
-
const
|
|
12
|
+
const evaluate = exec(module)
|
|
13
|
+
const { add, concat, identity } = api(Object.keys(module), program =>
|
|
14
|
+
evaluate(JSON.parse(JSON.stringify(program))))
|
|
90
15
|
|
|
91
|
-
t.
|
|
16
|
+
t.equal(
|
|
17
|
+
await evaluate(add(1, 2)),
|
|
18
|
+
3
|
|
19
|
+
)
|
|
92
20
|
|
|
93
|
-
|
|
94
|
-
|
|
21
|
+
t.strictSame(
|
|
22
|
+
await evaluate(concat([1, 2], [[add(1, 2)]])),
|
|
23
|
+
[1, 2, [3]]
|
|
24
|
+
)
|
|
95
25
|
|
|
96
|
-
t.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const error = new Error('BOOM')
|
|
101
|
-
const env = {
|
|
102
|
-
throws () {
|
|
103
|
-
throw error
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
await t.rejects(exec(env, ['throws']))
|
|
108
|
-
|
|
109
|
-
t.end()
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
test('should not exec expressions in an object', async t => {
|
|
113
|
-
const env = {
|
|
114
|
-
throws () {
|
|
115
|
-
throw new Error('Should not have been called.')
|
|
116
|
-
}
|
|
117
|
-
}
|
|
26
|
+
t.strictSame(
|
|
27
|
+
await evaluate(concat([1, 2], [add(1, 2), add(2, 2)])),
|
|
28
|
+
[1, 2, 3, 4]
|
|
29
|
+
)
|
|
118
30
|
|
|
119
|
-
|
|
31
|
+
t.strictSame(
|
|
32
|
+
await evaluate([identity(1), 2, 3]),
|
|
33
|
+
[1, 2, 3]
|
|
34
|
+
)
|
|
120
35
|
|
|
121
|
-
t.same(result, {
|
|
122
|
-
quoted: ['throws']
|
|
123
|
-
})
|
|
124
36
|
t.end()
|
|
125
37
|
})
|
package/package.json
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sendscript",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Blur the line between server and client code.",
|
|
5
5
|
"module": true,
|
|
6
6
|
"main": "index.mjs",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"rpc",
|
|
9
|
+
"json",
|
|
10
|
+
"dsl",
|
|
11
|
+
"lisp",
|
|
12
|
+
"program"
|
|
13
|
+
],
|
|
7
14
|
"repository": {
|
|
8
15
|
"type": "git",
|
|
9
16
|
"url": "git@github.com:bas080/sendscript.git"
|
|
@@ -16,7 +23,7 @@
|
|
|
16
23
|
"author": "Bas Huis",
|
|
17
24
|
"license": "MIT",
|
|
18
25
|
"devDependencies": {
|
|
19
|
-
"tap": "^18.
|
|
26
|
+
"tap": "^18.5.2"
|
|
20
27
|
},
|
|
21
28
|
"dependencies": {
|
|
22
29
|
"debug": "^4.3.4"
|