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 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
  [![Standard Code Style](https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square)](https://standardjs.com)
8
8
  [![License](https://img.shields.io/npm/l/sendscript?color=brightgreen&style=flat-square)](./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.3 test
197
+ > sendscript@0.1.0 test
198
198
  > tap -R silent
199
199
 
200
200
 
201
- > sendscript@0.0.3 test
201
+ > sendscript@0.1.0 test
202
202
  > tap report text-summary
203
203
 
204
204
 
205
205
  =============================== Coverage summary ===============================
206
- Statements : 100% ( 139/139 )
207
- Branches : 100% ( 47/47 )
208
- Functions : 100% ( 12/12 )
209
- Lines : 100% ( 139/139 )
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
  [![Standard Code Style](https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square)](https://standardjs.com)
8
8
  [![License](https://img.shields.io/npm/l/sendscript?color=brightgreen&style=flat-square)](./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
- [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)
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
- // Yey, resolved and all and ready to call.
20
- if (isFunction(operator)) {
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 Promise.all(letBindings.map(async ([name, letExpr]) => {
43
- letEnv[name] = await exec(letEnv, letExpr)
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
- if (Array.isArray(operator)) {
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, [castFunction(env[operator]), ...args])
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 { exec } from './exec.mjs'
2
+ import api from './api.mjs'
3
+ import exec from './exec.mjs'
3
4
 
4
- test('should evaluate basic expressions correctly', (t) => {
5
- t.plan(4)
6
-
7
- exec({ '+': (a, b) => a + b }, ['+', 1, 2])
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 expression = ['ref', 'thing']
89
- const result = await exec(env, expression)
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.same(result(), value)
16
+ t.equal(
17
+ await evaluate(add(1, 2)),
18
+ 3
19
+ )
92
20
 
93
- const result2 = await exec(env, ['thing'])
94
- t.same(result2, value)
21
+ t.strictSame(
22
+ await evaluate(concat([1, 2], [[add(1, 2)]])),
23
+ [1, 2, [3]]
24
+ )
95
25
 
96
- t.end()
97
- })
98
-
99
- test('should reject with the error of the called function', async t => {
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
- const result = await exec(env, { quoted: ['throws'] })
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",
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.4.3"
26
+ "tap": "^18.5.2"
20
27
  },
21
28
  "dependencies": {
22
29
  "debug": "^4.3.4"