sendscript 0.0.0 → 0.0.1
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 +17 -0
- package/README.md +38 -34
- package/README.mz +21 -18
- package/api.mjs +32 -0
- package/{dsl.test.mjs → api.test.mjs} +3 -3
- package/example/client.socket.io.mjs +3 -3
- package/example/math.mjs +1 -0
- package/exec.test.mjs +15 -0
- package/package.json +1 -1
- package/promise-only.mjs +13 -0
- package/dsl.mjs +0 -40
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
### Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
|
4
|
+
|
|
5
|
+
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
|
+
|
|
7
|
+
#### [v0.0.1](https://github.com/bas080/sendscript/compare/v0.0.0...v0.0.1)
|
|
8
|
+
|
|
9
|
+
- Add square fn to the socket.io example [`8d7cfbd`](https://github.com/bas080/sendscript/commit/8d7cfbddd7933804e7168825cf1e17e792c91fe9)
|
|
10
|
+
- Rename dsl to api [`4a67324`](https://github.com/bas080/sendscript/commit/4a6732456656db743d02c5c35444f93a866d27ec)
|
|
11
|
+
- Move promise only concept to own module [`50adde6`](https://github.com/bas080/sendscript/commit/50adde694b3d23fb025a4ad20dcc83d7bb72b852)
|
|
12
|
+
|
|
13
|
+
#### v0.0.0
|
|
14
|
+
|
|
15
|
+
> 14 September 2023
|
|
16
|
+
|
|
17
|
+
- Initiate project [`2a192b3`](https://github.com/bas080/sendscript/commit/2a192b34e5390ab946b7b77fd299e23180c49f72)
|
package/README.md
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
Write JS code that you can run on servers, browsers or other clients.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/sendscript)
|
|
6
|
+
[](#tests)
|
|
6
7
|
[](https://standardjs.com)
|
|
7
|
-
[](./LICENSE)
|
|
8
|
+
[](./LICENSE.txt)
|
|
8
9
|
|
|
9
|
-
> SendScript leaves it up to you to choose HTTP, web-sockets or any other
|
|
10
|
-
> communication between servers and clients that best fits your
|
|
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.
|
|
11
13
|
|
|
12
14
|
## Socket example
|
|
13
15
|
|
|
@@ -21,17 +23,18 @@ npm install --no-save socket.io socket.io-client
|
|
|
21
23
|
|
|
22
24
|
### Module
|
|
23
25
|
|
|
24
|
-
We write a simple module
|
|
26
|
+
We write a simple module.
|
|
25
27
|
|
|
26
28
|
```js
|
|
27
29
|
// ./example/math.mjs
|
|
28
30
|
|
|
29
31
|
export const add = (a, b) => a + b
|
|
32
|
+
export const square = a => a * a
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
### Server
|
|
33
36
|
|
|
34
|
-
Here a
|
|
37
|
+
Here a socket.io server that runs SendScript programs.
|
|
35
38
|
|
|
36
39
|
```js
|
|
37
40
|
// ./example/server.socket.io.mjs
|
|
@@ -66,7 +69,7 @@ Now for a client that sends a program to the server.
|
|
|
66
69
|
// ./example/client.socket.io.mjs
|
|
67
70
|
|
|
68
71
|
import socketClient from 'socket.io-client'
|
|
69
|
-
import
|
|
72
|
+
import api from '../api.mjs'
|
|
70
73
|
|
|
71
74
|
const port = process.env.PORT || 3000
|
|
72
75
|
const client = socketClient(`http://localhost:${port}`)
|
|
@@ -81,10 +84,10 @@ const exec = program => {
|
|
|
81
84
|
})
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
const { add } =
|
|
87
|
+
const { add, square } = api(['add', 'square'], exec)
|
|
85
88
|
|
|
86
89
|
console.log(
|
|
87
|
-
await add(1, add(add(2, 3), 4))
|
|
90
|
+
await square(add(1, add(add(2, 3), 4)))
|
|
88
91
|
)
|
|
89
92
|
|
|
90
93
|
process.exit(0)
|
|
@@ -102,33 +105,33 @@ node ./example/client.socket.io.mjs
|
|
|
102
105
|
pkill sendscript
|
|
103
106
|
```
|
|
104
107
|
```
|
|
105
|
-
|
|
108
|
+
100
|
|
106
109
|
```
|
|
107
110
|
|
|
108
111
|
## Reference
|
|
109
112
|
|
|
110
|
-
SendScript is essentially a way to serialize a program to then send over the
|
|
111
|
-
and execute it somewhere else.
|
|
113
|
+
SendScript is essentially a way to serialize a program to then send over the
|
|
114
|
+
wire and execute it somewhere else.
|
|
112
115
|
|
|
113
116
|
We only have two modules. One that helps you write programs that can be sent
|
|
114
117
|
over the wire and another for running that program.
|
|
115
118
|
|
|
116
|
-
### `sendscript/
|
|
119
|
+
### `sendscript/api.mjs`
|
|
117
120
|
|
|
118
|
-
The
|
|
121
|
+
The api module exports a function that takes two arguments.
|
|
119
122
|
|
|
120
123
|
1. The schema, which represents the values that are available.
|
|
121
124
|
2. The function that will be called with the serializable version of the
|
|
122
125
|
program.
|
|
123
126
|
|
|
124
127
|
It returns an object that contains functions which are defined in the schema.
|
|
125
|
-
These functions are a JavaScript
|
|
128
|
+
These functions are a JavaScript API for writing programs that can be sent to
|
|
126
129
|
a server.
|
|
127
130
|
|
|
128
131
|
```js
|
|
129
|
-
import
|
|
132
|
+
import api from './api.mjs'
|
|
130
133
|
|
|
131
|
-
const { add, subtract } =
|
|
134
|
+
const { add, subtract } = api(
|
|
132
135
|
['add', 'subtract'],
|
|
133
136
|
serializableProgram => sendSomewhereToBeExecuted(serializableProgram)
|
|
134
137
|
)
|
|
@@ -144,7 +147,7 @@ soon as await or `.then` is used.
|
|
|
144
147
|
> Notice that you do not have to await the subtract call. You only need to
|
|
145
148
|
> await when you want to execute the program.
|
|
146
149
|
|
|
147
|
-
This
|
|
150
|
+
This API is composable and wrappable.
|
|
148
151
|
|
|
149
152
|
### `sendscript/exec.mjs`
|
|
150
153
|
|
|
@@ -161,8 +164,8 @@ exec({
|
|
|
161
164
|
|
|
162
165
|
The array you see here is the LISP that SendScript uses to represent programs.
|
|
163
166
|
|
|
164
|
-
You could use SendScript without knowing the details of how the LISP works. It
|
|
165
|
-
implementation detail and might change over time.
|
|
167
|
+
You could use SendScript without knowing the details of how the LISP works. It
|
|
168
|
+
is an implementation detail and might change over time.
|
|
166
169
|
|
|
167
170
|
## Tests
|
|
168
171
|
|
|
@@ -173,27 +176,28 @@ npx c8 --100 npm t -- -R classic
|
|
|
173
176
|
```
|
|
174
177
|
```
|
|
175
178
|
|
|
176
|
-
> sendscript@0.0.
|
|
179
|
+
> sendscript@0.0.1 test
|
|
177
180
|
> tap *.test.mjs --no-cov -R classic
|
|
178
181
|
|
|
182
|
+
api.test.mjs .......................................... 5/5
|
|
179
183
|
curry.test.mjs ........................................ 4/4
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
total ............................................... 24/24
|
|
184
|
+
exec.test.mjs ....................................... 16/16
|
|
185
|
+
total ............................................... 25/25
|
|
183
186
|
|
|
184
|
-
|
|
187
|
+
25 passing (406.01ms)
|
|
185
188
|
|
|
186
189
|
ok
|
|
187
|
-
|
|
188
|
-
File
|
|
189
|
-
|
|
190
|
-
All files
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
error.mjs
|
|
195
|
-
exec.mjs
|
|
196
|
-
|
|
190
|
+
------------------|---------|----------|---------|---------|-------------------
|
|
191
|
+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
192
|
+
------------------|---------|----------|---------|---------|-------------------
|
|
193
|
+
All files | 100 | 100 | 100 | 100 |
|
|
194
|
+
api.mjs | 100 | 100 | 100 | 100 |
|
|
195
|
+
curry.mjs | 100 | 100 | 100 | 100 |
|
|
196
|
+
debug.mjs | 100 | 100 | 100 | 100 |
|
|
197
|
+
error.mjs | 100 | 100 | 100 | 100 |
|
|
198
|
+
exec.mjs | 100 | 100 | 100 | 100 |
|
|
199
|
+
promise-only.mjs | 100 | 100 | 100 | 100 |
|
|
200
|
+
------------------|---------|----------|---------|---------|-------------------
|
|
197
201
|
```
|
|
198
202
|
|
|
199
203
|
## Formatting
|
package/README.mz
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
Write JS code that you can run on servers, browsers or other clients.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/sendscript)
|
|
6
|
+
[](#tests)
|
|
6
7
|
[](https://standardjs.com)
|
|
7
|
-
[](./LICENSE)
|
|
8
|
+
[](./LICENSE.txt)
|
|
8
9
|
|
|
9
|
-
> SendScript leaves it up to you to choose HTTP, web-sockets or any other
|
|
10
|
-
> communication between servers and clients that best fits your
|
|
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.
|
|
11
13
|
|
|
12
14
|
## Socket example
|
|
13
15
|
|
|
@@ -21,17 +23,18 @@ npm install --no-save socket.io socket.io-client
|
|
|
21
23
|
|
|
22
24
|
### Module
|
|
23
25
|
|
|
24
|
-
We write a simple module
|
|
26
|
+
We write a simple module.
|
|
25
27
|
|
|
26
28
|
```js cat - > ./example/math.mjs
|
|
27
29
|
// ./example/math.mjs
|
|
28
30
|
|
|
29
31
|
export const add = (a, b) => a + b
|
|
32
|
+
export const square = a => a * a
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
### Server
|
|
33
36
|
|
|
34
|
-
Here a
|
|
37
|
+
Here a socket.io server that runs SendScript programs.
|
|
35
38
|
|
|
36
39
|
```js cat - > ./example/server.socket.io.mjs
|
|
37
40
|
// ./example/server.socket.io.mjs
|
|
@@ -66,7 +69,7 @@ Now for a client that sends a program to the server.
|
|
|
66
69
|
// ./example/client.socket.io.mjs
|
|
67
70
|
|
|
68
71
|
import socketClient from 'socket.io-client'
|
|
69
|
-
import
|
|
72
|
+
import api from '../api.mjs'
|
|
70
73
|
|
|
71
74
|
const port = process.env.PORT || 3000
|
|
72
75
|
const client = socketClient(`http://localhost:${port}`)
|
|
@@ -81,10 +84,10 @@ const exec = program => {
|
|
|
81
84
|
})
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
const { add } =
|
|
87
|
+
const { add, square } = api(['add', 'square'], exec)
|
|
85
88
|
|
|
86
89
|
console.log(
|
|
87
|
-
await add(1, add(add(2, 3), 4))
|
|
90
|
+
await square(add(1, add(add(2, 3), 4)))
|
|
88
91
|
)
|
|
89
92
|
|
|
90
93
|
process.exit(0)
|
|
@@ -104,28 +107,28 @@ pkill sendscript
|
|
|
104
107
|
|
|
105
108
|
## Reference
|
|
106
109
|
|
|
107
|
-
SendScript is essentially a way to serialize a program to then send over the
|
|
108
|
-
and execute it somewhere else.
|
|
110
|
+
SendScript is essentially a way to serialize a program to then send over the
|
|
111
|
+
wire and execute it somewhere else.
|
|
109
112
|
|
|
110
113
|
We only have two modules. One that helps you write programs that can be sent
|
|
111
114
|
over the wire and another for running that program.
|
|
112
115
|
|
|
113
|
-
### `sendscript/
|
|
116
|
+
### `sendscript/api.mjs`
|
|
114
117
|
|
|
115
|
-
The
|
|
118
|
+
The api module exports a function that takes two arguments.
|
|
116
119
|
|
|
117
120
|
1. The schema, which represents the values that are available.
|
|
118
121
|
2. The function that will be called with the serializable version of the
|
|
119
122
|
program.
|
|
120
123
|
|
|
121
124
|
It returns an object that contains functions which are defined in the schema.
|
|
122
|
-
These functions are a JavaScript
|
|
125
|
+
These functions are a JavaScript API for writing programs that can be sent to
|
|
123
126
|
a server.
|
|
124
127
|
|
|
125
128
|
```js
|
|
126
|
-
import
|
|
129
|
+
import api from './api.mjs'
|
|
127
130
|
|
|
128
|
-
const { add, subtract } =
|
|
131
|
+
const { add, subtract } = api(
|
|
129
132
|
['add', 'subtract'],
|
|
130
133
|
serializableProgram => sendSomewhereToBeExecuted(serializableProgram)
|
|
131
134
|
)
|
|
@@ -141,7 +144,7 @@ soon as await or `.then` is used.
|
|
|
141
144
|
> Notice that you do not have to await the subtract call. You only need to
|
|
142
145
|
> await when you want to execute the program.
|
|
143
146
|
|
|
144
|
-
This
|
|
147
|
+
This API is composable and wrappable.
|
|
145
148
|
|
|
146
149
|
### `sendscript/exec.mjs`
|
|
147
150
|
|
|
@@ -158,8 +161,8 @@ exec({
|
|
|
158
161
|
|
|
159
162
|
The array you see here is the LISP that SendScript uses to represent programs.
|
|
160
163
|
|
|
161
|
-
You could use SendScript without knowing the details of how the LISP works. It
|
|
162
|
-
implementation detail and might change over time.
|
|
164
|
+
You could use SendScript without knowing the details of how the LISP works. It
|
|
165
|
+
is an implementation detail and might change over time.
|
|
163
166
|
|
|
164
167
|
## Tests
|
|
165
168
|
|
package/api.mjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import promiseOnly from './promise-only.mjs'
|
|
2
|
+
|
|
3
|
+
const symbol = Symbol('api')
|
|
4
|
+
const isNonAPI = v => v?.[symbol] !== symbol
|
|
5
|
+
const promiseOnlyNonAPI = promiseOnly(isNonAPI)
|
|
6
|
+
|
|
7
|
+
export default function api (schema, call) {
|
|
8
|
+
return schema.reduce((api, name) => {
|
|
9
|
+
const then = (program) => (resolve, reject) =>
|
|
10
|
+
Promise.resolve(call(program)).then(resolve, reject)
|
|
11
|
+
|
|
12
|
+
const fn = (...args) => ({
|
|
13
|
+
[symbol]: symbol,
|
|
14
|
+
toJSON () {
|
|
15
|
+
return [fn, ...args]
|
|
16
|
+
},
|
|
17
|
+
async then (resolve, reject) {
|
|
18
|
+
return then(await promiseOnlyNonAPI([
|
|
19
|
+
fn, ...args
|
|
20
|
+
]))(resolve, reject)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
fn.toJSON = () => ['ref', name]
|
|
25
|
+
fn.then = then(fn)
|
|
26
|
+
fn[symbol] = symbol
|
|
27
|
+
|
|
28
|
+
api[name] = fn
|
|
29
|
+
|
|
30
|
+
return api
|
|
31
|
+
}, {})
|
|
32
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { test } from 'tap'
|
|
2
|
-
import
|
|
2
|
+
import api from './api.mjs'
|
|
3
3
|
|
|
4
4
|
test('return a constant value', async t => {
|
|
5
5
|
t.plan(1)
|
|
6
6
|
|
|
7
|
-
const { constant } =
|
|
7
|
+
const { constant } = api(['constant'], v => {
|
|
8
8
|
t.equal(JSON.stringify(v), '["ref","constant"]')
|
|
9
9
|
})
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ test('return a constant value', async t => {
|
|
|
14
14
|
test('use function calls as arguments', async t => {
|
|
15
15
|
t.plan(4)
|
|
16
16
|
|
|
17
|
-
const { add } =
|
|
17
|
+
const { add } = api(['add'], b => {
|
|
18
18
|
t.equal(JSON.stringify(awaited), JSON.stringify(b))
|
|
19
19
|
return 'done'
|
|
20
20
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ./example/client.socket.io.mjs
|
|
2
2
|
|
|
3
3
|
import socketClient from 'socket.io-client'
|
|
4
|
-
import
|
|
4
|
+
import api from '../api.mjs'
|
|
5
5
|
|
|
6
6
|
const port = process.env.PORT || 3000
|
|
7
7
|
const client = socketClient(`http://localhost:${port}`)
|
|
@@ -16,10 +16,10 @@ const exec = program => {
|
|
|
16
16
|
})
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const { add } =
|
|
19
|
+
const { add, square } = api(['add', 'square'], exec)
|
|
20
20
|
|
|
21
21
|
console.log(
|
|
22
|
-
await add(1, add(add(2, 3), 4))
|
|
22
|
+
await square(add(1, add(add(2, 3), 4)))
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
process.exit(0)
|
package/example/math.mjs
CHANGED
package/exec.test.mjs
CHANGED
|
@@ -108,3 +108,18 @@ test('should reject with the error of the called function', async t => {
|
|
|
108
108
|
|
|
109
109
|
t.end()
|
|
110
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
|
+
}
|
|
118
|
+
|
|
119
|
+
const result = await exec(env, { quoted: ['throws'] })
|
|
120
|
+
|
|
121
|
+
t.same(result, {
|
|
122
|
+
quoted: ['throws']
|
|
123
|
+
})
|
|
124
|
+
t.end()
|
|
125
|
+
})
|
package/package.json
CHANGED
package/promise-only.mjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import curry from './curry.mjs'
|
|
2
|
+
|
|
3
|
+
const promiseOnly = curry(function promiseOnly (when, array) {
|
|
4
|
+
return array.reduce(async (asyncAcc, item) => {
|
|
5
|
+
const acc = await asyncAcc
|
|
6
|
+
|
|
7
|
+
acc.push(when(item) ? await item : item)
|
|
8
|
+
|
|
9
|
+
return acc
|
|
10
|
+
}, [])
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export default promiseOnly
|
package/dsl.mjs
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const symbol = Symbol('dsl')
|
|
2
|
-
|
|
3
|
-
// Only await values that are not part of the dsl.
|
|
4
|
-
const promiseAllNonDSL = async values => values.reduce(async (_acc, value) => {
|
|
5
|
-
const acc = await _acc
|
|
6
|
-
|
|
7
|
-
if (value[symbol] === symbol) {
|
|
8
|
-
acc.push(value)
|
|
9
|
-
} else {
|
|
10
|
-
acc.push(await value)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return acc
|
|
14
|
-
}, [])
|
|
15
|
-
|
|
16
|
-
export default function dsl (schema, call) {
|
|
17
|
-
return schema.reduce((api, name) => {
|
|
18
|
-
const then = (program) => (resolve, reject) =>
|
|
19
|
-
Promise.resolve(call(program)).then(resolve, reject)
|
|
20
|
-
|
|
21
|
-
const fn = (...args) => {
|
|
22
|
-
// Only await non dsl values
|
|
23
|
-
const v = [fn, ...args]
|
|
24
|
-
|
|
25
|
-
v[symbol] = symbol
|
|
26
|
-
v.then = async (...thenArgs) => {
|
|
27
|
-
return then(await promiseAllNonDSL(v))(...thenArgs)
|
|
28
|
-
}
|
|
29
|
-
return v
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
fn.toJSON = () => ['ref', name]
|
|
33
|
-
fn.then = then(fn)
|
|
34
|
-
fn[symbol] = symbol
|
|
35
|
-
|
|
36
|
-
api[name] = fn
|
|
37
|
-
|
|
38
|
-
return api
|
|
39
|
-
}, {})
|
|
40
|
-
}
|