sendscript 1.0.6 → 2.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/.github/workflows/publish.yml +2 -2
- package/.github/workflows/release.yml +45 -0
- package/CHANGELOG.md +22 -0
- package/README.md +161 -45
- package/README.mz +142 -21
- package/example/client.socket.io.mjs +5 -5
- package/example/server.socket.io.mjs +2 -1
- package/example/typescript/client.ts +6 -6
- package/example/typescript/docs/functions/add.md +1 -1
- package/example/typescript/docs/functions/square.md +1 -1
- package/example/typescript/math.client.ts +3 -7
- package/index.test.mjs +126 -11
- package/leaf-serializer-property.test.mjs +149 -0
- package/leaf-serializer.test.mjs +71 -0
- package/package.json +8 -3
- package/parse.mjs +147 -49
- package/references.mjs +59 -0
- package/references.test.mjs +8 -0
- package/stringify.mjs +47 -35
- package/index.mjs +0 -11
- package/module.mjs +0 -52
package/references.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { awaitSymbol, call, ref } from './symbol.mjs'
|
|
2
|
+
|
|
3
|
+
function instrument (path) {
|
|
4
|
+
function reference (...args) {
|
|
5
|
+
const called = instrument(path)
|
|
6
|
+
|
|
7
|
+
called.toJSON = () => ({
|
|
8
|
+
[call]: call,
|
|
9
|
+
call: true,
|
|
10
|
+
ref: reference,
|
|
11
|
+
args
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
return called
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
reference.then = (resolve) => {
|
|
18
|
+
const awaited = instrument(path)
|
|
19
|
+
delete awaited.then
|
|
20
|
+
|
|
21
|
+
awaited.toJSON = () => ({
|
|
22
|
+
[awaitSymbol]: awaitSymbol,
|
|
23
|
+
await: true,
|
|
24
|
+
ref: reference
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return resolve(awaited)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
reference.toJSON = () => ({
|
|
31
|
+
[ref]: ref,
|
|
32
|
+
reference: true,
|
|
33
|
+
path
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return reference
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default function module (schema, parentPath = []) {
|
|
40
|
+
return schema.reduce((acc, item) => {
|
|
41
|
+
if (typeof item === 'string') {
|
|
42
|
+
// leaf function
|
|
43
|
+
acc[item] = instrument([...parentPath, item])
|
|
44
|
+
} else if (Array.isArray(item)) {
|
|
45
|
+
const [name, children] = item
|
|
46
|
+
|
|
47
|
+
if (Array.isArray(children)) {
|
|
48
|
+
// recurse: children can be strings or [name, children] arrays
|
|
49
|
+
acc[name] = module(children, [...parentPath, name])
|
|
50
|
+
} else {
|
|
51
|
+
throw new Error(`Expected children array for namespace "${name}"`)
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
throw new Error('Schema items must be strings or [name, children] arrays')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return acc
|
|
58
|
+
}, {})
|
|
59
|
+
}
|
package/stringify.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Debug from './debug.mjs'
|
|
2
|
-
import isNil from './is-nil.mjs'
|
|
3
2
|
import {
|
|
4
3
|
awaitSymbol,
|
|
5
4
|
call,
|
|
@@ -8,59 +7,72 @@ import {
|
|
|
8
7
|
|
|
9
8
|
const debug = Debug.extend('stringify')
|
|
10
9
|
|
|
11
|
-
const
|
|
12
|
-
const keywords = ['ref', 'call', 'quote', 'await']
|
|
10
|
+
const keywords = ['ref', 'call', 'quote', 'await', 'leaf']
|
|
13
11
|
const isKeyword = (v) => keywords.includes(v)
|
|
14
|
-
let awaitId = -1
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (value[ref]) {
|
|
24
|
-
const result = ['ref', value.name]
|
|
13
|
+
const isPlainObject = (value) => {
|
|
14
|
+
if (!value || typeof value !== 'object') return false
|
|
15
|
+
const proto = Object.getPrototypeOf(value)
|
|
16
|
+
return proto === Object.prototype || proto === null
|
|
17
|
+
}
|
|
25
18
|
|
|
26
|
-
|
|
19
|
+
// Recursively transform a program tree, encoding SendScript operators and leaf values
|
|
20
|
+
function transformValue (value, leafSerializer) {
|
|
21
|
+
debug(value)
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
if (value === null) {
|
|
24
|
+
return null
|
|
29
25
|
}
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
result[replaced] = replaced
|
|
35
|
-
|
|
36
|
-
return result
|
|
27
|
+
// Normalize SendScript wrapper functions (ref, call, await)
|
|
28
|
+
if (typeof value === 'function' && typeof value.toJSON === 'function') {
|
|
29
|
+
return transformValue(value.toJSON(), leafSerializer)
|
|
37
30
|
}
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
// Encode SendScript operators
|
|
33
|
+
if (value && value[ref]) {
|
|
34
|
+
return ['ref', ...value.path]
|
|
35
|
+
}
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
if (value && value[call]) {
|
|
38
|
+
return ['call', transformValue(value.ref, leafSerializer), transformValue(value.args, leafSerializer)]
|
|
39
|
+
}
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
if (value && value[awaitSymbol]) {
|
|
42
|
+
return ['await', transformValue(value.ref, leafSerializer)]
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
if (!value[replaced] && Array.isArray(value)) {
|
|
45
|
+
// Handle arrays: quote keyword operators, transform other arrays recursively
|
|
46
|
+
if (Array.isArray(value)) {
|
|
51
47
|
const [operator, ...rest] = value
|
|
52
48
|
|
|
53
49
|
if (isKeyword(operator)) {
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
// Quote reserved keyword strings to preserve them as data
|
|
51
|
+
return [['quote', operator], ...rest.map((item) => transformValue(item, leafSerializer))]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return value.map((item) => transformValue(item, leafSerializer))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Recurse into plain objects
|
|
58
|
+
if (isPlainObject(value)) {
|
|
59
|
+
const result = {}
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
for (const key of Object.keys(value)) {
|
|
62
|
+
result[key] = transformValue(value[key], leafSerializer)
|
|
58
63
|
}
|
|
64
|
+
|
|
65
|
+
return result
|
|
59
66
|
}
|
|
60
67
|
|
|
61
|
-
|
|
68
|
+
// Encode non-JSON leaf values (Date, RegExp, BigInt, etc.)
|
|
69
|
+
return ['leaf', leafSerializer(value)]
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
export default function stringify (
|
|
65
|
-
|
|
72
|
+
export default function stringify (leafSerializer = JSON.stringify) {
|
|
73
|
+
function stringify (program) {
|
|
74
|
+
return JSON.stringify(transformValue(program, leafSerializer))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return stringify
|
|
66
78
|
}
|
package/index.mjs
DELETED
package/module.mjs
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
awaitSymbol,
|
|
3
|
-
call,
|
|
4
|
-
ref
|
|
5
|
-
} from './symbol.mjs'
|
|
6
|
-
|
|
7
|
-
function instrument (name) {
|
|
8
|
-
function reference (...args) {
|
|
9
|
-
const called = instrument(name)
|
|
10
|
-
|
|
11
|
-
called.toJSON = () => ({
|
|
12
|
-
[call]: call,
|
|
13
|
-
call: true,
|
|
14
|
-
ref: reference,
|
|
15
|
-
args
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
return called
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
reference.then = (resolve) => {
|
|
22
|
-
const awaited = instrument(name)
|
|
23
|
-
|
|
24
|
-
delete awaited.then
|
|
25
|
-
|
|
26
|
-
awaited.toJSON = () => ({
|
|
27
|
-
[awaitSymbol]: awaitSymbol,
|
|
28
|
-
await: true,
|
|
29
|
-
ref: reference
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
return resolve(awaited)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
reference.toJSON = () => ({
|
|
36
|
-
[ref]: ref,
|
|
37
|
-
reference: true,
|
|
38
|
-
name
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
return reference
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export default function module (schema) {
|
|
45
|
-
if (!Array.isArray(schema)) return module(Object.keys(schema))
|
|
46
|
-
|
|
47
|
-
return schema.reduce((api, name) => {
|
|
48
|
-
api[name] = instrument(name)
|
|
49
|
-
|
|
50
|
-
return api
|
|
51
|
-
}, {})
|
|
52
|
-
}
|